Skip to content

Commit 36c640f

Browse files
committed
Tests for rangeMappings, fix encoding/decoding
1 parent 3c9c774 commit 36c640f

File tree

5 files changed

+367
-15
lines changed

5 files changed

+367
-15
lines changed

packages/trace-mapping/src/flatten-map.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TraceMap, presortedDecodedMap, decodedMappings } from './trace-mapping';
1+
import { TraceMap, presortedDecodedMap, decodedMappings, decodedRangeMappings } from './trace-mapping';
22
import {
33
COLUMN,
44
SOURCES_INDEX,
@@ -149,11 +149,11 @@ function addSection(
149149
const sourcesOffset = sources.length;
150150
const namesOffset = names.length;
151151
const decoded = decodedMappings(map);
152+
const ranges = decodedRangeMappings(map);
152153
const {
153154
resolvedSources,
154155
sourcesContent: contents,
155156
ignoreList: ignores,
156-
rangeMappings: ranges,
157157
} = map;
158158

159159
append(sources, resolvedSources);

packages/trace-mapping/src/trace-mapping.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { encode, decode } from '@jridgewell/sourcemap-codec';
1+
import { encode, decode, encodeRangeMappings, decodeRangeMappings } from '@jridgewell/sourcemap-codec';
22

33
import resolver from './resolve';
44
import maybeSort from './sort';
@@ -75,6 +75,8 @@ interface PublicMap {
7575
_decodedMemo: TraceMap['_decodedMemo'];
7676
_bySources: TraceMap['_bySources'];
7777
_bySourceMemos: TraceMap['_bySourceMemos'];
78+
_encodedRangeMappings: TraceMap['_encodedRangeMappings'];
79+
_decodedRangeMappings: TraceMap['_decodedRangeMappings'];
7880
_rangeSegments: TraceMap['_rangeSegments'];
7981
}
8082

@@ -103,7 +105,6 @@ export class TraceMap implements SourceMap {
103105
declare sources: SourceMapV3['sources'];
104106
declare sourcesContent: SourceMapV3['sourcesContent'];
105107
declare ignoreList: SourceMapV3['ignoreList'];
106-
declare rangeMappings: SourceMapV3['rangeMappings'];
107108

108109
/**
109110
* The fully resolved sources, relative to the mapUrl with sourceRoot
@@ -144,6 +145,16 @@ export class TraceMap implements SourceMap {
144145
*/
145146
declare private _bySourceMemos: MemoState[] | undefined;
146147

148+
/**
149+
* The range mappings encoded as VLQ.
150+
*/
151+
declare private _encodedRangeMappings: string | undefined;
152+
153+
/**
154+
* The range mappings decoded into indexes per line.
155+
*/
156+
declare private _decodedRangeMappings: number[][] | undefined;
157+
147158
/**
148159
* A set of segments that are range mappings.
149160
*/
@@ -163,12 +174,11 @@ export class TraceMap implements SourceMap {
163174
this.sources = sources;
164175
this.sourcesContent = sourcesContent;
165176
this.ignoreList = parsed.ignoreList || (parsed as XInput).x_google_ignoreList;
166-
this.rangeMappings = parsed.rangeMappings;
167177

168178
const resolve = resolver(mapUrl, sourceRoot);
169179
this.resolvedSources = sources.map(resolve);
170180

171-
const { mappings } = parsed;
181+
const { mappings, rangeMappings } = parsed;
172182
if (typeof mappings === 'string') {
173183
this._encoded = mappings;
174184
this._decoded = undefined;
@@ -184,6 +194,14 @@ export class TraceMap implements SourceMap {
184194
this._decodedMemo = memoizedState();
185195
this._bySources = undefined;
186196
this._bySourceMemos = undefined;
197+
198+
if (typeof rangeMappings === 'string') {
199+
this._encodedRangeMappings = rangeMappings;
200+
this._decodedRangeMappings = undefined;
201+
} else {
202+
this._encodedRangeMappings = undefined;
203+
this._decodedRangeMappings = rangeMappings || undefined;
204+
}
187205
this._rangeSegments = undefined;
188206
}
189207
}
@@ -203,13 +221,35 @@ export function encodedMappings(map: TraceMap): EncodedSourceMap['mappings'] {
203221
return (cast(map)._encoded ??= encode(cast(map)._decoded!));
204222
}
205223

224+
/**
225+
* Returns the encoded (VLQ string) form of the SourceMap's rangeMappings field.
226+
*/
227+
export function encodedRangeMappings(map: TraceMap): EncodedSourceMap['rangeMappings'] {
228+
let { _encodedRangeMappings: encoded, _decodedRangeMappings: decoded } = cast(map);
229+
if (encoded != null) return encoded;
230+
if (decoded == null) return encoded;
231+
encoded = encodeRangeMappings(decoded);
232+
return (cast(map)._encodedRangeMappings = encoded);
233+
}
234+
206235
/**
207236
* Returns the decoded (array of lines of segments) form of the SourceMap's mappings field.
208237
*/
209238
export function decodedMappings(map: TraceMap): Readonly<DecodedSourceMap['mappings']> {
210239
return (cast(map)._decoded ||= decode(cast(map)._encoded!));
211240
}
212241

242+
/**
243+
* Returns the decoded (array of lines of indexes) form of the SourceMap's rangeMappings field.
244+
*/
245+
export function decodedRangeMappings(map: TraceMap): DecodedSourceMap['rangeMappings'] {
246+
let { _encodedRangeMappings: encoded, _decodedRangeMappings: decoded } = cast(map);
247+
if (decoded != null) return decoded;
248+
if (encoded == null) return decoded;
249+
decoded = decodeRangeMappings(encoded);
250+
return (cast(map)._decodedRangeMappings = decoded);
251+
}
252+
213253
/**
214254
* A low-level API to find the segment associated with a generated line/column (think, from a
215255
* stack trace). Line and column here are 0-based, unlike `originalPositionFor`.
@@ -362,7 +402,7 @@ export function isIgnored(map: TraceMap, source: string): boolean {
362402
* maps.
363403
*/
364404
export function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): TraceMap {
365-
const tracer = new TraceMap(clone(map, []), mapUrl);
405+
const tracer = new TraceMap(clone(map, [], map.rangeMappings), mapUrl);
366406
cast(tracer)._decoded = map.mappings;
367407
return tracer;
368408
}
@@ -374,15 +414,15 @@ export function presortedDecodedMap(map: DecodedSourceMap, mapUrl?: string): Tra
374414
export function decodedMap(
375415
map: TraceMap,
376416
): Omit<DecodedSourceMap, 'mappings'> & { mappings: readonly SourceMapSegment[][] } {
377-
return clone(map, decodedMappings(map));
417+
return clone(map, decodedMappings(map), decodedRangeMappings(map));
378418
}
379419

380420
/**
381421
* Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
382422
* a sourcemap, or to JSON.stringify.
383423
*/
384424
export function encodedMap(map: TraceMap): EncodedSourceMap {
385-
return clone(map, encodedMappings(map));
425+
return clone(map, encodedMappings(map), encodedRangeMappings(map));
386426
}
387427

388428
/**
@@ -392,6 +432,7 @@ export function encodedMap(map: TraceMap): EncodedSourceMap {
392432
function clone<T extends string | readonly SourceMapSegment[][]>(
393433
map: TraceMap | DecodedSourceMap,
394434
mappings: T,
435+
rangeMappings: (T extends string ? EncodedSourceMap['rangeMappings'] : DecodedSourceMap['rangeMappings']) | undefined,
395436
): T extends string ? EncodedSourceMap : DecodedSourceMap {
396437
const clone = {
397438
version: map.version,
@@ -402,7 +443,7 @@ function clone<T extends string | readonly SourceMapSegment[][]>(
402443
sourcesContent: map.sourcesContent,
403444
mappings: mappings as any,
404445
ignoreList: map.ignoreList || (map as XInput).x_google_ignoreList,
405-
rangeMappings: map.rangeMappings,
446+
rangeMappings: rangeMappings as any,
406447
} satisfies DecodedSourceMap | EncodedSourceMap;
407448
assertExhaustive(undefined as Exclude<keyof DecodedSourceMap, keyof typeof clone>);
408449
return clone;
@@ -661,7 +702,7 @@ function initRangeSegments(map: TraceMap, decoded: readonly SourceMapSegment[][]
661702

662703
const set = new Set<SourceMapSegment>();
663704
cast(map)._rangeSegments = set;
664-
const rangeMappings = map.rangeMappings;
705+
const rangeMappings = decodedRangeMappings(map);
665706
if (rangeMappings == null) return set;
666707

667708
for (let i = 0; i < rangeMappings.length; i++) {

packages/trace-mapping/src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ export interface SourceMapV3 {
99
sourcesContent?: (string | null)[];
1010
version: 3;
1111
ignoreList?: number[];
12-
rangeMappings?: number[][];
1312
}
1413

1514
export interface EncodedSourceMap extends SourceMapV3 {
1615
mappings: string;
16+
rangeMappings?: string;
1717
}
1818

1919
export interface DecodedSourceMap extends SourceMapV3 {
2020
mappings: SourceMapSegment[][];
21+
rangeMappings?: number[][];
2122
}
2223

2324
export interface Section {
@@ -99,7 +100,6 @@ export abstract class SourceMap {
99100
declare sourcesContent: SourceMapV3['sourcesContent'];
100101
declare resolvedSources: SourceMapV3['sources'];
101102
declare ignoreList: SourceMapV3['ignoreList'];
102-
declare rangeMappings: SourceMapV3['rangeMappings'];
103103
}
104104

105105
export type Ro<T> =

packages/trace-mapping/test/flatten-map.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
FlattenMap,
66
encodedMappings,
77
decodedMappings,
8+
decodedRangeMappings,
9+
encodedRangeMappings,
810
type SectionedSourceMap,
911
type SourceMapSegment,
1012
} from '../src/trace-mapping';
@@ -57,7 +59,7 @@ describe('FlattenMap', () => {
5759
sourcesContent: ['thirdsource'],
5860
sourceRoot: 'nested',
5961
mappings: 'AAAAA,CAAA;AAAA',
60-
rangeMappings: [[0]],
62+
rangeMappings: 'B',
6163
},
6264
},
6365
{
@@ -141,7 +143,8 @@ describe('FlattenMap', () => {
141143

142144
it('rangeMappings', () => {
143145
const tracer = new FlattenMap(map);
144-
assert.deepEqual(tracer.rangeMappings, [[], [], [0, 1]]);
146+
assert.deepEqual(decodedRangeMappings(tracer), [[], [], [0, 1]]);
147+
assert.deepEqual(encodedRangeMappings(tracer), ';;BB');
145148
});
146149
});
147150

0 commit comments

Comments
 (0)