Skip to content

Commit bd89c1f

Browse files
MasonChowCopilot
andauthored
Refactor node SDK initialization and update tests
* Refactor node SDK initialization and update tests - Commented out the re-export of low-level APIs to maintain backward compatibility. - Changed the initialization logic to use dynamic import for better control in SSR/custom loading scenarios. - Updated tests to reflect the new initialization method, ensuring the WASM module is loaded correctly. - Removed the unused top-level await plugin from Vite configuration and adjusted the target to 'node20' for consistency with WASM bindings. * feat: Refactor Node SDK for source map parsing - Rename package from to for consistency. - Update README with new usage examples and API references. - Implement a new initialization method for loading the WASM module. - Enhance API functions to return parsed JS objects instead of raw JSON strings. - Add TypeScript definitions for better type safety and developer experience. - Introduce a new for TypeScript compilation settings. - Modify build scripts to include type generation and improve output structure. - Update integration tests to load source maps from the repository for more realistic testing scenarios. - Ensure all API functions are aligned with the new type definitions and return values. * Update crates/source_map_parser/tests/integration.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update crates/node_sdk/src/index.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update crates/node_sdk/src/index.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent b9d22fe commit bd89c1f

File tree

10 files changed

+799
-200
lines changed

10 files changed

+799
-200
lines changed

assets/index.js

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/index.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/node_sdk/README.md

Lines changed: 119 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,186 +1,172 @@
1-
# source-map-parser-node
1+
# source_map_parser_node(Node SDK)
22

3-
一个高性能的 Source Map 解析库,基于 Rust + WebAssembly 构建,提供 JavaScript 堆栈解析和 Source Map 位置映射功能。
3+
基于 Rust + WebAssembly 的高性能 Source Map 解析库(Node 环境)。提供错误堆栈解析、位置回溯与上下文提取等能力,API 返回已解析好的 JS 对象(内部已完成 JSON.parse)。
4+
5+
> 注意:本包为 Node SDK(ESM 模块)。使用前需先调用一次 `init()` 完成按需加载。
46
57
## 安装
68

79
```bash
8-
npm install source-map-parser-node
10+
npm install source_map_parser_node
11+
#
12+
pnpm add source_map_parser_node
913
```
1014

1115
## 快速开始
1216

13-
### 基本用法
14-
15-
```javascript
16-
const { lookupToken, mapStackLine } = require('source-map-parser-node');
17+
### 初始化
1718

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

21-
// 映射单个位置
22-
const token = lookupToken(sourceMapContent, 10, 25);
23-
console.log(token);
24-
// {
25-
// "src": "src/index.ts",
26-
// "line": 5,
27-
// "column": 10,
28-
// "name": "myFunction"
29-
// }
30-
31-
// 映射堆栈行
32-
const stackLine = "at myFunction (bundle.js:10:25)";
33-
const mapped = mapStackLine(sourceMapContent, stackLine);
34-
console.log(mapped);
35-
// {
36-
// "src": "src/index.ts",
37-
// "line": 5,
38-
// "column": 10,
39-
// "name": "myFunction",
40-
// "original": "at myFunction (bundle.js:10:25)"
41-
// }
22+
await init(); // 仅需调用一次
4223
```
4324

44-
### 批量处理错误堆栈
25+
### 映射单个位置(lookup_token)
4526

46-
```javascript
47-
const { generateTokenByStackRaw } = require('source-map-parser-node');
27+
```ts
28+
import { init, lookup_token } from 'source_map_parser_node';
29+
import fs from 'node:fs';
4830

49-
const errorStack = `
50-
Error: Something went wrong
51-
at myFunction (bundle.js:10:25)
52-
at anotherFunction (bundle.js:15:8)
53-
at main (bundle.js:20:3)
54-
`;
31+
await init();
5532

56-
// 定义 source map 解析器
57-
const resolver = (sourcePath) => {
58-
if (sourcePath === 'bundle.js') {
59-
return fs.readFileSync('bundle.js.map', 'utf8');
60-
}
61-
return null;
62-
};
63-
64-
const result = generateTokenByStackRaw(errorStack, null, resolver);
65-
console.log(result.success); // 成功映射的 token 列表
66-
console.log(result.fail); // 映射失败的堆栈信息
33+
const sm = fs.readFileSync('bundle.js.map', 'utf8');
34+
const tok = lookup_token(sm, 10, 25);
35+
console.log(tok);
36+
// { src, line, column, name?, source?, original? }
6737
```
6838

69-
## API 参考
70-
71-
### lookupToken(sourceMapContent, line, column)
72-
73-
映射单个位置到源代码位置。
74-
75-
- `sourceMapContent`: string - Source Map 内容字符串
76-
- `line`: number - 编译后代码的行号
77-
- `column`: number - 编译后代码的列号
78-
79-
返回: `{ src: string, line: number, column: number, name?: string }`
80-
81-
### lookupTokenWithContext(sourceMapContent, line, column, contextLines)
82-
83-
映射位置并获取上下文代码。
84-
85-
- `contextLines`: number - 上下文的行数
86-
87-
返回: 包含上下文信息的 token 对象
39+
### 映射单行堆栈(map_stack_line)
8840

89-
### mapStackLine(sourceMapContent, stackLine)
41+
```ts
42+
import { init, map_stack_line } from 'source_map_parser_node';
43+
import fs from 'node:fs';
9044

91-
映射单行堆栈信息。
45+
await init();
9246

93-
- `stackLine`: string - 堆栈行字符串,如 "at myFunction (bundle.js:10:25)"
94-
95-
返回: 映射后的堆栈信息对象
96-
97-
### mapStackTrace(sourceMapContent, stackTrace)
98-
99-
映射完整的堆栈跟踪。
100-
101-
- `stackTrace`: string - 完整的堆栈跟踪字符串
47+
const sm = fs.readFileSync('bundle.js.map', 'utf8');
48+
const stackLine = ' at myFunction (bundle.js:10:25)';
49+
const mapped = map_stack_line(sm, stackLine);
50+
console.log(mapped);
51+
// { src, line, column, name?, source?, original? }
52+
```
10253

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

105-
### mapErrorStack(sourceMapContent, errorStackRaw, contextLines?)
56+
```ts
57+
import { init, map_error_stack } from 'source_map_parser_node';
58+
import fs from 'node:fs';
10659

107-
映射完整的错误堆栈。
60+
await init();
10861

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

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

114-
### generateTokenByStackRaw(stackRaw, formatter?, resolver?, onError?)
74+
## 批量处理错误堆栈(generate_token_by_stack_raw)
11575

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

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

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

125-
## 高级用法
84+
const errorStack = [
85+
'Error: test',
86+
' at foo (bundle.js:10:25)',
87+
' at bar (bundle.js:15:8)',
88+
].join('\n');
12689

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

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

135-
const resolver = (formattedPath) => {
136-
return fs.readFileSync(formattedPath, 'utf8');
99+
const onError = (line: string, message: string) => {
100+
console.warn('[map fail]', line, message);
137101
};
138102

139-
const result = generateTokenByStackRaw(errorStack, formatter, resolver);
103+
const r = generate_token_by_stack_raw(errorStack, formatter, resolver, onError);
104+
console.log(r.success.length, r.fail.length);
140105
```
141106

142-
### 异步 Source Map 加载
107+
## 便捷辅助(自动 init):mapErrorStackWithResolver
143108

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

150-
// 注意:当前版本需要同步 resolver,异步场景需要在外部处理
151-
```
152-
153-
## 性能特性
111+
```ts
112+
import { mapErrorStackWithResolver } from 'source_map_parser_node';
154113

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

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

163-
支持所有现代浏览器和 Node.js 环境:
125+
## API 参考(与导出一致,全部已 JSON.parse)
126+
127+
- init(): Promise<LowLevelModule>
128+
129+
- 说明:按需加载并缓存 wasm 模块。除 `mapErrorStackWithResolver` 外,使用其它 API 前需手动调用一次。
130+
131+
- lookup_token(sm: string, line: number, column: number): SourceMapToken | null
132+
- lookup_token_with_context(sm: string, line: number, column: number, context_lines: number): Token | null
133+
- lookup_context(sm: string, line: number, column: number, context_lines: number): WasmContextSnippet | null
134+
- map_stack_line(sm: string, stack_line: string): SourceMapToken | null
135+
- map_stack_line_with_context(sm: string, stack_line: string, context_lines: number): Token | null
136+
- map_stack_trace(sm: string, stack_trace: string): SourceMapToken[]
137+
- map_error_stack(sm: string, error_stack_raw: string, context_lines?: number): MappedErrorStack
138+
- generate_token_by_single_stack(line: number, column: number, sm: string, context_offset?: number): Token | null
139+
- 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
140+
- mapErrorStackWithResolver(options: { errorStack: string; resolveSourceMap: (p: string) => string | undefined; formatter?: (p: string) => string; onError?: (rawLine: string, message: string) => void; }): Promise<GenerateResult>
141+
142+
返回类型(节选):
143+
144+
```ts
145+
import type {
146+
SourceMapToken,
147+
Token,
148+
GenerateResult,
149+
MappedErrorStack,
150+
WasmContextSnippet,
151+
} from 'source_map_parser_node';
152+
```
164153

165-
- Node.js 14+
166-
- Chrome 60+
167-
- Firefox 60+
168-
- Safari 14+
169-
- Edge 79+
154+
> 可选参数使用标准的可选写法(不再使用 `| null` 暴露在 API 表面),内部会自动处理与 wasm 层期望的对接。
170155
171-
## 开发构建
156+
## 运行环境与特性
172157

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

177-
# 构建 WASM 包
178-
wasm-pack build --target nodejs
162+
## 本地开发(可选)
179163

180-
# 运行测试
181-
wasm-pack test --node
164+
```bash
165+
pnpm install
166+
pnpm run build # 构建 wasm + 打包库 + 生成 d.ts
167+
pnpm test # 运行 vitest 测试
182168
```
183169

184170
## 许可证
185171

186-
MIT License
172+
MIT License

crates/node_sdk/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
"types": "dist/index.d.ts",
1616
"exports": {
1717
".": {
18-
"import": "./dist/index.es.js"
18+
"import": "./dist/index.js"
1919
}
2020
},
2121
"scripts": {
2222
"build:lib": "vite build",
23-
"build": "bash ../../scripts/build-wasm-node.sh && vite build",
23+
"build:types": "tsc -p tsconfig.json",
24+
"build": "bash ../../scripts/build-wasm-node.sh && vite build && tsc -p tsconfig.json",
2425
"pretest": "pnpm run build:lib",
2526
"test": "pnpm pretest && vitest --run",
2627
"test:coverage": "vitest --coverage",

0 commit comments

Comments
 (0)