@srcmap/sourcemap 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +95 -0
  2. package/index.d.ts +139 -15
  3. package/package.json +20 -11
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @srcmap/sourcemap
2
+
3
+ [![npm](https://img.shields.io/npm/v/@srcmap/sourcemap.svg)](https://www.npmjs.com/package/@srcmap/sourcemap)
4
+ [![CI](https://github.com/BartWaardenburg/srcmap/actions/workflows/ci.yml/badge.svg)](https://github.com/BartWaardenburg/srcmap/actions/workflows/ci.yml)
5
+ [![Coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/BartWaardenburg/srcmap/badges/coverage.json)](https://github.com/BartWaardenburg/srcmap/actions/workflows/coverage.yml)
6
+
7
+ High-performance source map parser and consumer powered by Rust via [NAPI](https://napi.rs).
8
+
9
+ Parses source map JSON and provides position lookups. Implements [ECMA-426](https://tc39.es/ecma426/) (Source Map v3). Alternative to [`@jridgewell/trace-mapping`](https://github.com/jridgewell/trace-mapping).
10
+
11
+ > For batch lookups in Node.js, consider [`@srcmap/sourcemap-wasm`](https://www.npmjs.com/package/@srcmap/sourcemap-wasm) which avoids NAPI per-call overhead and is faster for bulk operations.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @srcmap/sourcemap
17
+ ```
18
+
19
+ Prebuilt binaries are available for:
20
+ - macOS (x64, arm64)
21
+ - Linux (x64, arm64, glibc + musl)
22
+ - Windows (x64)
23
+
24
+ ## Usage
25
+
26
+ ```js
27
+ import { SourceMap } from '@srcmap/sourcemap';
28
+
29
+ const sm = new SourceMap(jsonString);
30
+
31
+ // Forward lookup: generated -> original (0-based lines and columns)
32
+ const loc = sm.originalPositionFor(42, 10);
33
+ // { source: 'src/app.ts', line: 10, column: 4, name: 'handleClick' }
34
+ // Returns null if no mapping exists
35
+
36
+ // Reverse lookup: original -> generated
37
+ const pos = sm.generatedPositionFor('src/app.ts', 10, 4);
38
+ // { line: 42, column: 10 }
39
+
40
+ // Batch lookup — amortizes NAPI overhead
41
+ const positions = [42, 10, 43, 0, 44, 5];
42
+ const results = sm.originalPositionsFor(positions);
43
+ // number[] [srcIdx, line, col, nameIdx, ...]
44
+ // -1 means no mapping / no name
45
+
46
+ // Resolve indices
47
+ const source = sm.source(results[0]);
48
+ const name = results[3] >= 0 ? sm.name(results[3]) : null;
49
+ ```
50
+
51
+ ## API
52
+
53
+ ### `new SourceMap(json: string)`
54
+
55
+ Parse a source map from a JSON string.
56
+
57
+ ### Instance methods
58
+
59
+ | Method | Returns | Description |
60
+ |--------|---------|-------------|
61
+ | `originalPositionFor(line, column)` | `{ source, line, column, name } \| null` | Forward lookup (0-based) |
62
+ | `generatedPositionFor(source, line, column)` | `{ line, column } \| null` | Reverse lookup (0-based) |
63
+ | `originalPositionsFor(positions: number[])` | `number[]` | Batch forward lookup |
64
+ | `source(index)` | `string` | Resolve source index to filename |
65
+ | `name(index)` | `string` | Resolve name index to string |
66
+
67
+ ### Instance properties
68
+
69
+ | Property | Type | Description |
70
+ |----------|------|-------------|
71
+ | `lineCount` | `number` | Number of generated lines |
72
+ | `mappingCount` | `number` | Total decoded mappings |
73
+ | `hasRangeMappings` | `boolean` | Whether any range mappings exist |
74
+ | `rangeMappingCount` | `number` | Number of range mappings |
75
+ | `sources` | `string[]` | All source filenames |
76
+ | `names` | `string[]` | All names |
77
+
78
+ ## Performance
79
+
80
+ | Operation | @srcmap/sourcemap | @jridgewell/trace-mapping |
81
+ |-----------|-------------------|---------------------------|
82
+ | 1000x batch lookup (large) | 160 us | 15 us |
83
+ | Single lookup | 345 ns | 24 ns |
84
+
85
+ NAPI has ~300ns overhead per call. For bulk operations, use the batch API (`originalPositionsFor`) or consider the [WASM package](https://www.npmjs.com/package/@srcmap/sourcemap-wasm) which has lower per-call overhead.
86
+
87
+ ## Part of [srcmap](https://github.com/BartWaardenburg/srcmap)
88
+
89
+ High-performance source map tooling written in Rust. See also:
90
+ - [`@srcmap/codec`](https://www.npmjs.com/package/@srcmap/codec) - VLQ codec (NAPI)
91
+ - [`@srcmap/sourcemap-wasm`](https://www.npmjs.com/package/@srcmap/sourcemap-wasm) - Source map parser (WASM, recommended for batch ops)
92
+
93
+ ## License
94
+
95
+ MIT
package/index.d.ts CHANGED
@@ -1,42 +1,166 @@
1
+ /**
2
+ * An original source position resolved from a generated position.
3
+ *
4
+ * All values are 0-based. Use `source` and `name` directly as resolved strings.
5
+ */
1
6
  export interface OriginalPosition {
7
+ /** Original source filename (e.g. `"src/app.ts"`). */
2
8
  source: string | null
9
+ /** 0-based line in the original source. */
3
10
  line: number
11
+ /** 0-based column in the original source. */
4
12
  column: number
13
+ /** Original identifier name, if available. */
5
14
  name: string | null
6
15
  }
7
16
 
17
+ /**
18
+ * A generated position resolved from an original source position.
19
+ *
20
+ * All values are 0-based.
21
+ */
8
22
  export interface GeneratedPosition {
23
+ /** 0-based line in the generated output. */
9
24
  line: number
25
+ /** 0-based column in the generated output. */
10
26
  column: number
11
27
  }
12
28
 
29
+ /**
30
+ * High-performance source map parser and consumer powered by Rust via NAPI.
31
+ *
32
+ * Parses source map JSON (v3 / ECMA-426) and provides O(log n) position lookups.
33
+ * Supports regular and indexed (sectioned) source maps.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { SourceMap } from '@srcmap/sourcemap'
38
+ *
39
+ * const sm = new SourceMap(jsonString)
40
+ *
41
+ * // Forward lookup: generated -> original (0-based)
42
+ * const loc = sm.originalPositionFor(42, 10)
43
+ * if (loc) {
44
+ * console.log(`${loc.source}:${loc.line}:${loc.column}`)
45
+ * }
46
+ *
47
+ * // Reverse lookup: original -> generated (0-based)
48
+ * const pos = sm.generatedPositionFor('src/app.ts', 10, 4)
49
+ * ```
50
+ */
13
51
  export declare class SourceMap {
14
- /** Parse a source map from a JSON string. Supports regular and indexed (sectioned) maps. */
52
+ /**
53
+ * Parse a source map from a JSON string.
54
+ *
55
+ * Accepts both regular source maps and indexed source maps with `sections`.
56
+ *
57
+ * @param json - Source map JSON string (must have `"version": 3`)
58
+ * @throws If the JSON is invalid or the source map version is unsupported
59
+ */
15
60
  constructor(json: string)
16
61
 
17
- /** Look up the original source position for a generated position. 0-based line and column. */
62
+ /**
63
+ * Look up the original source position for a generated position.
64
+ *
65
+ * Uses greatest-lower-bound search (finds the closest mapping at or before the column).
66
+ *
67
+ * @param line - 0-based generated line
68
+ * @param column - 0-based generated column
69
+ * @returns The original position, or `null` if no mapping exists
70
+ */
18
71
  originalPositionFor(line: number, column: number): OriginalPosition | null
19
72
 
20
- /** Look up the generated position for an original source position. 0-based line and column. */
73
+ /**
74
+ * Look up the original source position with a search bias.
75
+ *
76
+ * @param line - 0-based generated line
77
+ * @param column - 0-based generated column
78
+ * @param bias - `0` for greatest-lower-bound (default), `-1` for least-upper-bound
79
+ * @returns The original position, or `null` if no mapping exists
80
+ */
81
+ originalPositionForWithBias(line: number, column: number, bias: 0 | -1): OriginalPosition | null
82
+
83
+ /**
84
+ * Look up the generated position for an original source position.
85
+ *
86
+ * Uses least-upper-bound search (finds the first mapping at or after the position).
87
+ *
88
+ * @param source - Original source filename (e.g. `"src/app.ts"`)
89
+ * @param line - 0-based original line
90
+ * @param column - 0-based original column
91
+ * @returns The generated position, or `null` if no mapping exists
92
+ */
21
93
  generatedPositionFor(source: string, line: number, column: number): GeneratedPosition | null
22
94
 
23
95
  /**
24
- * Batch lookup: find original positions for multiple generated positions.
25
- * Takes a flat array [line0, col0, line1, col1, ...].
26
- * Returns a flat array [srcIdx0, line0, col0, nameIdx0, srcIdx1, ...].
27
- * -1 means no mapping found / no name.
96
+ * Look up the generated position with a search bias.
97
+ *
98
+ * @param source - Original source filename
99
+ * @param line - 0-based original line
100
+ * @param column - 0-based original column
101
+ * @param bias - `0` for default, `-1` for least-upper-bound, `1` for greatest-lower-bound
102
+ * @returns The generated position, or `null` if no mapping exists
103
+ */
104
+ generatedPositionForWithBias(source: string, line: number, column: number, bias: -1 | 0 | 1): GeneratedPosition | null
105
+
106
+ /**
107
+ * Batch forward lookup for multiple generated positions.
108
+ *
109
+ * Amortizes NAPI overhead by processing all positions in a single call.
110
+ * Input is a flat array of `[line0, col0, line1, col1, ...]` pairs.
111
+ * Output is a flat array of `[srcIdx0, line0, col0, nameIdx0, ...]` quads.
112
+ * `-1` indicates no mapping found or no name.
113
+ *
114
+ * @param positions - Flat array of 0-based `[line, column]` pairs
115
+ * @returns Flat array of `[sourceIndex, line, column, nameIndex]` quads
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * const positions = [42, 10, 43, 0, 44, 5]
120
+ * const results = sm.originalPositionsFor(positions)
121
+ * // results: [srcIdx, line, col, nameIdx, srcIdx, line, col, nameIdx, ...]
122
+ * const source = results[0] >= 0 ? sm.source(results[0]) : null
123
+ * ```
28
124
  */
29
125
  originalPositionsFor(positions: number[]): number[]
30
126
 
31
- /** Source file paths. */
32
- get sources(): string[]
127
+ /**
128
+ * Resolve a source index to a source filename.
129
+ *
130
+ * @param index - Source index from a lookup result
131
+ * @returns The source filename
132
+ */
133
+ source(index: number): string
134
+
135
+ /**
136
+ * Resolve a name index to a name string.
137
+ *
138
+ * @param index - Name index from a lookup result
139
+ * @returns The name string
140
+ */
141
+ name(index: number): string
142
+
143
+ /** All source filenames in the source map. */
144
+ readonly sources: string[]
145
+
146
+ /** All names in the source map. */
147
+ readonly names: string[]
148
+
149
+ /** Debug ID (UUID) for associating generated files with source maps (ECMA-426). */
150
+ readonly debugId: string | null
151
+
152
+ /** Total number of decoded mappings. */
153
+ readonly mappingCount: number
154
+
155
+ /** Number of generated lines covered by mappings. */
156
+ readonly lineCount: number
33
157
 
34
- /** Name identifiers. */
35
- get names(): string[]
158
+ /** Whether the source map contains range mappings. */
159
+ readonly hasRangeMappings: boolean
36
160
 
37
- /** Total number of decoded mapping segments. */
38
- get mappingCount(): number
161
+ /** Number of range mappings in the source map. */
162
+ readonly rangeMappingCount: number
39
163
 
40
- /** Number of generated lines. */
41
- get lineCount(): number
164
+ /** Get the encoded range mappings string, or null if none. */
165
+ encodedRangeMappings(): string | null
42
166
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srcmap/sourcemap",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "High-performance source map parser and consumer powered by Rust",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -26,27 +26,36 @@
26
26
  "license": "MIT",
27
27
  "files": [
28
28
  "index.js",
29
- "index.d.ts"
29
+ "index.d.ts",
30
+ "README.md"
30
31
  ],
31
32
  "optionalDependencies": {
32
- "@srcmap/sourcemap-darwin-x64": "0.1.2",
33
- "@srcmap/sourcemap-darwin-arm64": "0.1.2",
34
- "@srcmap/sourcemap-linux-x64-gnu": "0.1.2",
35
- "@srcmap/sourcemap-linux-x64-musl": "0.1.2",
36
- "@srcmap/sourcemap-linux-arm64-gnu": "0.1.2",
37
- "@srcmap/sourcemap-linux-arm64-musl": "0.1.2",
38
- "@srcmap/sourcemap-win32-x64-msvc": "0.1.2"
33
+ "@srcmap/sourcemap-darwin-x64": "0.1.3",
34
+ "@srcmap/sourcemap-darwin-arm64": "0.1.3",
35
+ "@srcmap/sourcemap-linux-x64-gnu": "0.1.3",
36
+ "@srcmap/sourcemap-linux-x64-musl": "0.1.3",
37
+ "@srcmap/sourcemap-linux-arm64-gnu": "0.1.3",
38
+ "@srcmap/sourcemap-linux-arm64-musl": "0.1.3",
39
+ "@srcmap/sourcemap-win32-x64-msvc": "0.1.3"
40
+ },
41
+ "dependencies": {
42
+ "detect-libc": "^2.0.0"
39
43
  },
40
44
  "devDependencies": {
41
45
  "@napi-rs/cli": "^3.0.0"
42
46
  },
43
47
  "scripts": {
48
+ "artifacts": "napi artifacts",
44
49
  "build": "napi build --release --platform",
45
- "build:debug": "napi build --platform"
50
+ "build:debug": "napi build --platform",
51
+ "test": "node --test __tests__/sourcemap.test.mjs",
52
+ "test:coverage": "mkdir -p coverage && node --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-reporter=spec --test-reporter-destination=stdout __tests__/sourcemap.test.mjs",
53
+ "prepublishOnly": "napi prepublish -t npm",
54
+ "version": "napi version"
46
55
  },
47
56
  "repository": {
48
57
  "type": "git",
49
- "url": "https://github.com/BartWaardenburg/srcmap"
58
+ "url": "git+https://github.com/BartWaardenburg/srcmap.git"
50
59
  },
51
60
  "keywords": [
52
61
  "sourcemap",