Skip to content

Commit f3d38f0

Browse files
docs: reframe ECMA-426 support as core + draft proposals
The previous copy claimed "full ECMA-426 compliance", which overstated what's actually in the published core versus what lives in draft proposals (scopes, debugId, rangeMappings, sourcesFunctionMappings). Update README, ROADMAP, crate/package READMEs, and badge text to separate stable core support from explicitly-labelled draft proposal support, and fix ROADMAP links to point at the canonical tc39/ecma426 proposal files.
1 parent 08e80e2 commit f3d38f0

7 files changed

Lines changed: 39 additions & 33 deletions

File tree

README.md

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
[![crates.io](https://img.shields.io/crates/v/srcmap-sourcemap.svg)](https://crates.io/crates/srcmap-sourcemap)
66
[![docs.rs](https://docs.rs/srcmap-sourcemap/badge.svg)](https://docs.rs/srcmap-sourcemap)
77
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8-
[![ECMA-426](https://img.shields.io/badge/ECMA--426-compliant-44cc11.svg)](https://tc39.es/ecma426/)
8+
[![ECMA-426](https://img.shields.io/badge/ECMA--426-core%20%2B%20proposals-44cc11.svg)](https://tc39.es/ecma426/)
99

10-
> The source map SDK for Rust tooling. Parse, generate, remap, and compose — with full [ECMA-426](https://tc39.es/ecma426/) compliance.
10+
> The source map SDK for Rust tooling. Parse, generate, remap, and compose — with stable [ECMA-426](https://tc39.es/ecma426/) core support plus selected draft proposals.
1111
1212
A standalone source map library that any Rust tool can embed. If you're building a bundler, compiler, minifier, linter, or symbolication service — srcmap gives you the complete source map stack so you don't have to build it yourself.
1313

@@ -44,7 +44,7 @@ srcmap-remapping = "0.3" # if you compose/concatenate source maps
4444
| Composition/remapping | **yes** | limited | no | yes |
4545
| Concatenation | **yes** | no | yes | yes |
4646
| Indexed source maps | **yes** | yes | no | no |
47-
| ECMA-426 scopes | **yes** | no | no | no |
47+
| Scopes proposal | **yes** | no | no | no |
4848
| Stack trace symbolication | **yes** | yes | no | no |
4949
| Hermes/React Native | **yes** | yes | no | no |
5050
| RAM bundle parsing | **yes** | no | no | no |
@@ -136,19 +136,23 @@ let mut buf = Vec::new();
136136
vlq_encode(&mut buf, 42);
137137
```
138138

139-
## Spec conformance
139+
## Spec support
140140

141-
Full [ECMA-426](https://tc39.es/ecma426/) (Source Map v3) compliance:
141+
Stable [ECMA-426](https://tc39.es/ecma426/) core support:
142142

143-
- All standard fields: `version`, `file`, `sourceRoot`, `sources`, `sourcesContent`, `names`, `mappings`
144-
- `rangeMappings` for range-based source mapping (ECMA-426 Stage 2 proposal)
145-
- `ignoreList` for filtering third-party sources
146-
- Indexed source maps with `sections` — flattened with source/name deduplication
147-
- Proper `sourceRoot` resolution
148-
- `debugId` for associating generated files with source maps
149-
- Scopes & variables (first Rust implementation of the [ECMA-426 scopes proposal](https://tc39.es/ecma426/) — draft, may evolve)
143+
- Standard Source Map v3 fields: `version`, `file`, `sourceRoot`, `sources`, `sourcesContent`, `names`, `mappings`
144+
- `ignoreList`
145+
- Indexed source maps with `sections`
146+
- `sourceRoot` resolution
147+
- Required extension tolerance for unrecognized properties
150148
- Robust error handling for malformed input
151149

150+
Draft proposal support:
151+
152+
- `debugId` (ECMA-426 draft proposal, not part of the published core standard)
153+
- Scopes & variables via [`srcmap-scopes`](https://crates.io/crates/srcmap-scopes) (first Rust implementation of the [ECMA-426 scopes proposal](https://github.com/tc39/ecma426/blob/main/proposals/scopes.md))
154+
- `rangeMappings` (ECMA-426 Stage 2 proposal)
155+
152156
## Performance
153157

154158
For Rust consumers there is no FFI overhead. Benchmarked with Criterion:

ROADMAP.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ What's next for srcmap, and why.
44

55
## Function Name Mappings
66

7-
**ECMA-426, standardized**[bloomberg.github.io/js-blog/post/standardizing-source-maps](https://bloomberg.github.io/js-blog/post/standardizing-source-maps/)
7+
**Interop work, not part of published ECMA-426 core today**[bloomberg.github.io/js-blog/post/standardizing-source-maps](https://bloomberg.github.io/js-blog/post/standardizing-source-maps/)
88

9-
A `"sourcesFunctionMappings"` array parallel to `"sources"`, where each entry is a VLQ-encoded string mapping generated positions to original function names. Previously the `x_com_bloomberg_sourcesFunctionMappings` extension, now standardized in ECMA-426.
9+
A `"sourcesFunctionMappings"` array parallel to `"sources"`, where each entry is a VLQ-encoded string mapping generated positions to original function names. Previously the `x_com_bloomberg_sourcesFunctionMappings` extension, and worth tracking for ecosystem interoperability.
10+
11+
Note: this repository tracks it as forward-looking ecosystem interoperability work. It is not currently in the published ECMA-426 core standard or the official `tc39/ecma426` proposal set.
1012

1113
This is a simpler alternative to the full scopes proposal for resolving minified function names in stack traces. Tools that don't need full scope/binding information can use this field alone. For tools that support scopes, `FindOriginalFunctionName` from the scopes proposal supersedes this — but both should be supported for interop, since most source maps in the wild won't have scopes data.
1214

@@ -29,7 +31,7 @@ This is a simpler alternative to the full scopes proposal for resolving minified
2931

3032
### Open issues to track
3133

32-
**Boundary rules for generated ranges** ([tc39/ecma426#249](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)): Defines where generated ranges must start and end relative to JavaScript syntax. Key rules:
34+
**Boundary rules for generated ranges** ([tc39/ecma426#249](https://github.com/tc39/ecma426/blob/main/proposals/scopes.md)): Defines where generated ranges must start and end relative to JavaScript syntax. Key rules:
3335

3436
- Generated ranges must be strictly well-nested with syntactic scopes (no partial overlap)
3537
- For callable scopes (functions, arrows, methods), the range starts inside the opening boundary (before default parameter evaluation)
@@ -39,31 +41,31 @@ This is a simpler alternative to the full scopes proposal for resolving minified
3941
- `BlockStatement`: opening = `{`, closing = `}`, not callable
4042
- `ClassDeclaration`: opening = `class` to `{`, closing = `}`, not callable
4143

42-
**Stack frame reconstruction algorithm** ([tc39/ecma426#219](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)): Three operations being standardized:
44+
**Stack frame reconstruction algorithm** ([tc39/ecma426#219](https://github.com/tc39/ecma426/blob/main/proposals/scopes.md)): Three operations being standardized:
4345

4446
1. `FindOriginalFunctionName(position)` — find innermost generated range, walk scope chain outward to find `isStackFrame = true` scope
4547
2. `SymbolizeStackTrace(rawFrames)` — translate generated stack traces to original, expand inlined frames and collapse outlined frames across different bundles
4648
3. `BuildScopeChain(position)` — return `OriginalScopeWithValues[]` mapping original variables to concrete JS values
4749

48-
**Hidden scopes** ([tc39/ecma426#113](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)): A generated range without an `originalScope` reference signals compiler-generated code. Combined with `isFunctionScope`: if `range.isFunctionScope && !range.hasDefinition`, the function frame should be omitted from stack traces.
50+
**Hidden scopes** ([tc39/ecma426#113](https://github.com/tc39/ecma426/blob/main/proposals/scopes.md)): A generated range without an `originalScope` reference signals compiler-generated code. Combined with `isFunctionScope`: if `range.isFunctionScope && !range.hasDefinition`, the function frame should be omitted from stack traces.
4951

50-
**Null variable names** ([tc39/ecma426#244](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)): When a `names` index is invalid, the variable entry becomes `null` (or empty string) instead of causing a parse error. Variables array type becomes `(string | null)[]`.
52+
**Null variable names** ([tc39/ecma426#244](https://github.com/tc39/ecma426/blob/main/proposals/scopes.md)): When a `names` index is invalid, the variable entry becomes `null` (or empty string) instead of causing a parse error. Variables array type becomes `(string | null)[]`.
5153

5254
### What to implement
5355

5456
- [ ] Validate generated range boundaries against JavaScript syntax rules (#249)
55-
- [ ] `FindOriginalFunctionName` in the symbolicate crate
57+
- [x] `FindOriginalFunctionName` in the symbolicate crate
5658
- [ ] `SymbolizeStackTrace` with inlining expansion and outlining collapse (#219)
5759
- [ ] `BuildScopeChain` for debugger integration
58-
- [ ] Handle hidden scopes (`isFunctionScope && !hasDefinition`) in stack trace output
60+
- [x] Handle hidden scopes (`isFunctionScope && !hasDefinition`) in stack trace output
5961
- [ ] Tolerate null variable names (#244)
6062
- [ ] Track Chrome DevTools scopes codec ([@chrome-devtools/source-map-scopes-codec](https://jsr.io/@chrome-devtools/source-map-scopes-codec)) for compatibility
6163

6264
---
6365

6466
## Sources Hash `[Stage 1 — not implementing yet]`
6567

66-
**ECMA-426 proposal, Stage 1**[tc39/ecma426#208](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)
68+
**ECMA-426 proposal, Stage 1**[sources-hash proposal](https://github.com/tc39/ecma426/blob/main/proposals/sources-hash.md)
6769

6870
A new `"sourcesHash"` array parallel to `"sources"`, containing content hashes for source file integrity verification.
6971

@@ -94,7 +96,7 @@ Hash algorithm is implementation-defined (SHA-256 recommended). Format is a pref
9496

9597
## Debug ID Extraction `[Stage 2 — not implementing yet]`
9698

97-
**ECMA-426 proposal, Stage 2**[tc39/ecma426#207](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)
99+
**ECMA-426 proposal, Stage 2**[debug-id proposal](https://github.com/tc39/ecma426/blob/main/proposals/debug-id.md)
98100

99101
srcmap already parses `debugId` from source map JSON. What's missing is extracting it from generated JavaScript/CSS files via the `//# debugId=<UUID>` comment.
100102

@@ -119,7 +121,7 @@ srcmap already parses `debugId` from source map JSON. What's missing is extracti
119121

120122
## Mappings v2 Encoding `[Discussion — not implementing yet]`
121123

122-
**ECMA-426 discussion**[tc39/ecma426#155](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)
124+
**ECMA-426 discussion**[range-mappings proposal](https://github.com/tc39/ecma426/blob/main/proposals/range-mappings.md)
123125

124126
A proposed encoding that eliminates `,` and `;` separators and packs metadata into VLQ bits. Claims ~35-50% raw size reduction.
125127

@@ -154,7 +156,7 @@ This is early-stage and may never land. Worth implementing as an experimental en
154156

155157
## Env Metadata `[Stage 1 — not implementing yet]`
156158

157-
**ECMA-426 proposal, Stage 1**[tc39/ecma426 proposals/env.md](https://github.com/nicolo-ribaudo/ecma-426/blob/main/proposals/range-mappings.md)
159+
**ECMA-426 proposal, Stage 1**[env proposal](https://github.com/tc39/ecma426/blob/main/proposals/env.md)
158160

159161
Environment metadata for source maps. The proposal is minimal at Stage 1 — track for details before implementing.
160162

crates/cli/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ cargo install srcmap-cli
2727
| `concat` | Concatenate multiple source maps into one |
2828
| `remap` | Compose/remap source maps through a transform chain |
2929
| `symbolicate` | Symbolicate a stack trace using source maps |
30-
| `scopes` | Inspect ECMA-426 scopes and variable bindings |
30+
| `scopes` | Inspect scopes-proposal data and variable bindings |
3131
| `fetch` | Fetch a JS/CSS bundle and its source map from a URL |
3232
| `sources` | List or extract original sources from a source map |
3333
| `schema` | Describe all commands as JSON (for agent introspection) |
@@ -65,7 +65,7 @@ srcmap remap minified.js.map --dir ./sourcemaps -o original.js.map
6565
# Symbolicate a stack trace
6666
srcmap symbolicate stacktrace.txt --dir ./sourcemaps
6767

68-
# Inspect ECMA-426 scopes
68+
# Inspect scopes-proposal data
6969
srcmap scopes bundle.js.map
7070

7171
# Fetch a bundle and its source map from a URL

crates/generator/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ On-the-fly VLQ encoder that emits mappings as they are added, without collecting
8080
| `add_source(path) -> u32` | Register a source file (deduped) |
8181
| `add_name(name) -> u32` | Register a name (deduped) |
8282
| `set_source_root(root)` | Set the `sourceRoot` prefix |
83-
| `set_debug_id(id)` | Set the `debugId` field |
83+
| `set_debug_id(id)` | Set the `debugId` proposal field |
8484
| `add_to_ignore_list(source_idx)` | Mark a source as ignored (third-party) |
8585
| `add_mapping(...)` | Add a mapping (encoded immediately) |
8686
| `add_named_mapping(...)` | Add a mapping with a name |
87-
| `add_range_mapping(...)` | Add a range mapping (ECMA-426) |
87+
| `add_range_mapping(...)` | Add a range mapping (ECMA-426 Stage 2 proposal) |
8888
| `add_named_range_mapping(...)` | Add a named range mapping |
8989
| `to_json() -> String` | Serialize to source map v3 JSON |
9090
| `to_decoded_map() -> SourceMap` | Build a `SourceMap` directly |

crates/sourcemap/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ assert_eq!(pos.column, 0);
130130
- **Lazy reverse index** built on first `generated_position_for` call
131131
- **Indexed source maps** (`sections`) with automatic flattening
132132
- **Zero-copy JSON parsing** via borrowed mappings string
133-
- **Range mappings** (`rangeMappings` field, ECMA-426 Stage 2) with cross-line delta lookup
133+
- **Range mappings** (`rangeMappings` field, ECMA-426 Stage 2 proposal) with cross-line delta lookup
134134
- **Lazy iterator** (`MappingsIter`) for zero-allocation streaming over encoded mappings
135135
- **Robust error handling** for malformed input
136136

crates/symbolicate/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ println!("{result}"); // Pretty-printed symbolicated stack
3737
| `parse_stack_trace_full(input)` | Parse into `ParsedStack` (message + frames) |
3838
| `symbolicate(stack, loader)` | Parse and resolve through source maps |
3939
| `symbolicate_batch(stacks, maps)` | Batch symbolication with pre-loaded maps |
40-
| `resolve_by_debug_id(id, maps)` | Find a source map by its ECMA-426 debug ID |
40+
| `resolve_by_debug_id(id, maps)` | Find a source map by its `debugId` proposal field |
4141
| `to_json(stack)` | Serialize a `SymbolicatedStack` to JSON |
4242

4343
## Supported stack trace formats

packages/sourcemap-wasm/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Parse a source map from a JSON string.
116116
| `ignoreList` | `number[]` | Source ignore list indices |
117117
| `file` | `string \| undefined` | Output filename |
118118
| `sourceRoot` | `string \| undefined` | Source root prefix |
119-
| `debugId` | `string \| undefined` | ECMA-426 debug ID |
119+
| `debugId` | `string \| undefined` | `debugId` proposal field |
120120
| `lineCount` | `number` | Number of generated lines |
121121
| `mappingCount` | `number` | Total decoded mappings |
122122
| `hasRangeMappings` | `boolean` | Whether any range mappings exist |
@@ -158,7 +158,7 @@ A fast-scan alternative to `SourceMap` that defers VLQ decoding until lookup tim
158158
| `ignoreList` | `number[]` | Source ignore list indices |
159159
| `file` | `string \| undefined` | Output filename |
160160
| `sourceRoot` | `string \| undefined` | Source root prefix |
161-
| `debugId` | `string \| undefined` | ECMA-426 debug ID |
161+
| `debugId` | `string \| undefined` | `debugId` proposal field |
162162
| `lineCount` | `number` | Number of generated lines |
163163

164164
---
@@ -211,7 +211,7 @@ sm.free();
211211
| `ignoreList` | `number[]` | Source ignore list indices |
212212
| `file` | `string \| undefined` | Output filename |
213213
| `sourceRoot` | `string \| undefined` | Source root prefix |
214-
| `debugId` | `string \| undefined` | ECMA-426 debug ID |
214+
| `debugId` | `string \| undefined` | `debugId` proposal field |
215215
| `lineCount` | `number` | Number of generated lines |
216216

217217
## Performance

0 commit comments

Comments
 (0)