Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions assets/index.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions assets/index.js.map

Large diffs are not rendered by default.

252 changes: 119 additions & 133 deletions crates/node_sdk/README.md
Original file line number Diff line number Diff line change
@@ -1,186 +1,172 @@
# source-map-parser-node
# source_map_parser_node(Node SDK)

一个高性能的 Source Map 解析库,基于 Rust + WebAssembly 构建,提供 JavaScript 堆栈解析和 Source Map 位置映射功能。
基于 Rust + WebAssembly 的高性能 Source Map 解析库(Node 环境)。提供错误堆栈解析、位置回溯与上下文提取等能力,API 返回已解析好的 JS 对象(内部已完成 JSON.parse)。

> 注意:本包为 Node SDK(ESM 模块)。使用前需先调用一次 `init()` 完成按需加载。

## 安装

```bash
npm install source-map-parser-node
npm install source_map_parser_node
# 或
pnpm add source_map_parser_node
```

## 快速开始

### 基本用法

```javascript
const { lookupToken, mapStackLine } = require('source-map-parser-node');
### 初始化

// 从文件或网络加载 source map 内容
const sourceMapContent = fs.readFileSync('bundle.js.map', 'utf8');
```ts
import { init } from 'source_map_parser_node';

// 映射单个位置
const token = lookupToken(sourceMapContent, 10, 25);
console.log(token);
// {
// "src": "src/index.ts",
// "line": 5,
// "column": 10,
// "name": "myFunction"
// }

// 映射堆栈行
const stackLine = "at myFunction (bundle.js:10:25)";
const mapped = mapStackLine(sourceMapContent, stackLine);
console.log(mapped);
// {
// "src": "src/index.ts",
// "line": 5,
// "column": 10,
// "name": "myFunction",
// "original": "at myFunction (bundle.js:10:25)"
// }
await init(); // 仅需调用一次
```

### 批量处理错误堆栈
### 映射单个位置(lookup_token)

```javascript
const { generateTokenByStackRaw } = require('source-map-parser-node');
```ts
import { init, lookup_token } from 'source_map_parser_node';
import fs from 'node:fs';

const errorStack = `
Error: Something went wrong
at myFunction (bundle.js:10:25)
at anotherFunction (bundle.js:15:8)
at main (bundle.js:20:3)
`;
await init();

// 定义 source map 解析器
const resolver = (sourcePath) => {
if (sourcePath === 'bundle.js') {
return fs.readFileSync('bundle.js.map', 'utf8');
}
return null;
};

const result = generateTokenByStackRaw(errorStack, null, resolver);
console.log(result.success); // 成功映射的 token 列表
console.log(result.fail); // 映射失败的堆栈信息
const sm = fs.readFileSync('bundle.js.map', 'utf8');
const tok = lookup_token(sm, 10, 25);
console.log(tok);
// { src, line, column, name?, source?, original? }
```

## API 参考

### lookupToken(sourceMapContent, line, column)

映射单个位置到源代码位置。

- `sourceMapContent`: string - Source Map 内容字符串
- `line`: number - 编译后代码的行号
- `column`: number - 编译后代码的列号

返回: `{ src: string, line: number, column: number, name?: string }`

### lookupTokenWithContext(sourceMapContent, line, column, contextLines)

映射位置并获取上下文代码。

- `contextLines`: number - 上下文的行数

返回: 包含上下文信息的 token 对象
### 映射单行堆栈(map_stack_line)

### mapStackLine(sourceMapContent, stackLine)
```ts
import { init, map_stack_line } from 'source_map_parser_node';
import fs from 'node:fs';

映射单行堆栈信息。
await init();

- `stackLine`: string - 堆栈行字符串,如 "at myFunction (bundle.js:10:25)"

返回: 映射后的堆栈信息对象

### mapStackTrace(sourceMapContent, stackTrace)

映射完整的堆栈跟踪。

- `stackTrace`: string - 完整的堆栈跟踪字符串
const sm = fs.readFileSync('bundle.js.map', 'utf8');
const stackLine = ' at myFunction (bundle.js:10:25)';
const mapped = map_stack_line(sm, stackLine);
console.log(mapped);
// { src, line, column, name?, source?, original? }
```

返回: 映射后的堆栈信息数组
### 映射完整错误堆栈(map_error_stack)

### mapErrorStack(sourceMapContent, errorStackRaw, contextLines?)
```ts
import { init, map_error_stack } from 'source_map_parser_node';
import fs from 'node:fs';

映射完整的错误堆栈。
await init();

- `errorStackRaw`: string - 原始错误堆栈字符串
- `contextLines`: number (可选) - 上下文行数
const sm = fs.readFileSync('bundle.js.map', 'utf8');
const errorStack = [
'Error: Something went wrong',
' at myFunction (bundle.js:10:25)',
' at anotherFunction (bundle.js:15:8)',
].join('\n');

返回: 映射后的错误堆栈对象
const result = map_error_stack(sm, errorStack, 2);
console.log(result.error_message);
console.log(result.frames_with_context?.length);
```

### generateTokenByStackRaw(stackRaw, formatter?, resolver?, onError?)
## 批量处理错误堆栈(generate_token_by_stack_raw)

批量处理错误堆栈并生成 token。
当你持有“原始错误堆栈文本(含首行消息)”,并且可以按路径解析对应的 Source Map 内容时,推荐用批量 API:

- `stackRaw`: string - 原始堆栈文本
- `formatter`: Function (可选) - 源文件路径格式化函数
- `resolver`: Function (可选) - Source Map 内容解析器
- `onError`: Function (可选) - 错误处理回调
```ts
import { init, generate_token_by_stack_raw } from 'source_map_parser_node';
import fs from 'node:fs';

返回: `{ success: Token[], fail: GenerateFailStack[], stacks: Stack[] }`
await init();

## 高级用法
const errorStack = [
'Error: test',
' at foo (bundle.js:10:25)',
' at bar (bundle.js:15:8)',
].join('\n');

### 自定义源文件路径映射
// 可选:统一重写源文件路径(例如附加 .map 或绝对化)
const formatter = (p: string) => p;

```javascript
const formatter = (sourcePath) => {
// 添加 .map 后缀
return sourcePath + '.map';
// 必要:按路径返回 Source Map 内容字符串
const resolver = (p: string) => {
if (p.endsWith('bundle.js')) return fs.readFileSync('bundle.js.map', 'utf8');
return undefined; // 无法解析的帧将被计入 fail
};

const resolver = (formattedPath) => {
return fs.readFileSync(formattedPath, 'utf8');
const onError = (line: string, message: string) => {
console.warn('[map fail]', line, message);
};

const result = generateTokenByStackRaw(errorStack, formatter, resolver);
const r = generate_token_by_stack_raw(errorStack, formatter, resolver, onError);
console.log(r.success.length, r.fail.length);
```

### 异步 Source Map 加载
## 便捷辅助(自动 init):mapErrorStackWithResolver

```javascript
async function asyncResolver(sourcePath) {
const response = await fetch(`/source-maps/${sourcePath}.map`);
return await response.text();
}
对于最常见的“拿到错误堆栈 + 我能根据路径拿到 sourcemap 内容”的场景,可以直接使用内置辅助方法;它会自动调用 `init()` 并返回与批量 API 同结构结果:

// 注意:当前版本需要同步 resolver,异步场景需要在外部处理
```

## 性能特性
```ts
import { mapErrorStackWithResolver } from 'source_map_parser_node';

- 🚀 基于 Rust + WebAssembly 构建,性能卓越
- 📦 零依赖,轻量级包体积
- 🔍 支持多种 JavaScript 引擎堆栈格式(V8、Firefox、Safari)
- 🗺️ 完整的 Source Map v3 规范支持
- 🎯 精确的位置映射和上下文提取
const mapStore = new Map<string, string>();
mapStore.set('https://example.com/app.min.js', '{"version":3,...}');

## 浏览器支持
const result = await mapErrorStackWithResolver({
errorStack: 'Error: boom\n at fn (https://example.com/app.min.js:1:10)',
resolveSourceMap: (p) => mapStore.get(p),
formatter: (p) => p,
});
console.log(result.success.length);
```

支持所有现代浏览器和 Node.js 环境:
## API 参考(与导出一致,全部已 JSON.parse)

- init(): Promise<LowLevelModule>

- 说明:按需加载并缓存 wasm 模块。除 `mapErrorStackWithResolver` 外,使用其它 API 前需手动调用一次。

- lookup_token(sm: string, line: number, column: number): SourceMapToken | null
- lookup_token_with_context(sm: string, line: number, column: number, context_lines: number): Token | null
- lookup_context(sm: string, line: number, column: number, context_lines: number): WasmContextSnippet | null
- map_stack_line(sm: string, stack_line: string): SourceMapToken | null
- map_stack_line_with_context(sm: string, stack_line: string, context_lines: number): Token | null
- map_stack_trace(sm: string, stack_trace: string): SourceMapToken[]
- map_error_stack(sm: string, error_stack_raw: string, context_lines?: number): MappedErrorStack
- generate_token_by_single_stack(line: number, column: number, sm: string, context_offset?: number): Token | null
- generate_token_by_stack_raw(stack_raw: string, formatter?: (p: string) => string, resolver?: (p: string) => string | undefined, on_error?: (rawLine: string, message: string) => void): GenerateResult
- mapErrorStackWithResolver(options: { errorStack: string; resolveSourceMap: (p: string) => string | undefined; formatter?: (p: string) => string; onError?: (rawLine: string, message: string) => void; }): Promise<GenerateResult>

返回类型(节选):

```ts
import type {
SourceMapToken,
Token,
GenerateResult,
MappedErrorStack,
WasmContextSnippet,
} from 'source_map_parser_node';
```

- Node.js 14+
- Chrome 60+
- Firefox 60+
- Safari 14+
- Edge 79+
> 可选参数使用标准的可选写法(不再使用 `| null` 暴露在 API 表面),内部会自动处理与 wasm 层期望的对接。

## 开发构建
## 运行环境与特性

```bash
# 安装 wasm-pack
cargo install wasm-pack
- Node.js 18+(ESM 模块)
- 内部使用 Rust + WebAssembly,性能优异
- 返回值均为已解析的 JS 对象(无需再手动 JSON.parse)

# 构建 WASM 包
wasm-pack build --target nodejs
## 本地开发(可选)

# 运行测试
wasm-pack test --node
```bash
pnpm install
pnpm run build # 构建 wasm + 打包库 + 生成 d.ts
pnpm test # 运行 vitest 测试
```

## 许可证

MIT License
MIT License
5 changes: 3 additions & 2 deletions crates/node_sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.es.js"
"import": "./dist/index.js"
}
},
"scripts": {
"build:lib": "vite build",
"build": "bash ../../scripts/build-wasm-node.sh && vite build",
"build:types": "tsc -p tsconfig.json",
"build": "bash ../../scripts/build-wasm-node.sh && vite build && tsc -p tsconfig.json",
"pretest": "pnpm run build:lib",
"test": "pnpm pretest && vitest --run",
"test:coverage": "vitest --coverage",
Expand Down
Loading
Loading