Skip to content
This repository was archived by the owner on Jun 28, 2025. It is now read-only.

Commit b5e335c

Browse files
committed
Switch to GenMapping
1 parent e7e168c commit b5e335c

File tree

7 files changed

+133
-165
lines changed

7 files changed

+133
-165
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"typescript": "4.6.3"
5858
},
5959
"dependencies": {
60-
"@jridgewell/set-array": "^1.0.0",
61-
"@jridgewell/trace-mapping": "^0.3.0"
60+
"@jridgewell/gen-mapping": "^0.0.0",
61+
"@jridgewell/trace-mapping": "^0.3.9"
6262
}
6363
}

rollup.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function configure(esm) {
1212
entryFileNames: '[name].umd.js',
1313
sourcemap: true,
1414
globals: {
15+
'@jridgewell/gen-mapping': 'genMapping',
1516
'@jridgewell/trace-mapping': 'traceMapping',
1617
},
1718
},

src/source-map-tree.ts

Lines changed: 41 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1-
import { SetArray, put } from '@jridgewell/set-array';
2-
import { presortedDecodedMap, traceSegment, decodedMappings } from '@jridgewell/trace-mapping';
1+
import { GenMapping, addSegment, setSourceContent } from '@jridgewell/gen-mapping';
2+
import { traceSegment, decodedMappings } from '@jridgewell/trace-mapping';
33

44
import type { TraceMap } from '@jridgewell/trace-mapping';
5-
import type { SourceMapSegment, SourceMapSegmentObject } from './types';
65

7-
const INVALID_MAPPING = undefined;
8-
const SOURCELESS_MAPPING = null;
6+
export type SourceMapSegmentObject =
7+
| {
8+
column: number;
9+
line: number;
10+
name: string;
11+
source: string;
12+
content: string | null;
13+
}
14+
| {
15+
column: null;
16+
line: null;
17+
name: null;
18+
source: null;
19+
content: null;
20+
};
21+
22+
const SOURCELESS_MAPPING = {
23+
source: null,
24+
column: null,
25+
line: null,
26+
name: null,
27+
content: null,
28+
};
929
const EMPTY_SOURCES: Sources[] = [];
1030

11-
type MappingSource = SourceMapSegmentObject | typeof INVALID_MAPPING | typeof SOURCELESS_MAPPING;
12-
1331
type OriginalSource = {
1432
map: TraceMap;
1533
sources: Sources[];
@@ -60,28 +78,24 @@ export function OriginalSource(source: string, content: string | null): Original
6078
* traceMappings is only called on the root level SourceMapTree, and begins the process of
6179
* resolving each mapping in terms of the original source files.
6280
*/
63-
export function traceMappings(tree: Sources): TraceMap {
64-
const mappings: SourceMapSegment[][] = [];
65-
const names = new SetArray();
66-
const sources = new SetArray();
67-
const sourcesContent: (string | null)[] = [];
81+
export function traceMappings(tree: Sources): GenMapping {
82+
const gen = new GenMapping(tree.map.file);
6883
const { sources: rootSources, map } = tree;
6984
const rootNames = map.names;
7085
const rootMappings = decodedMappings(map);
7186

72-
let lastLineWithSegment = -1;
7387
for (let i = 0; i < rootMappings.length; i++) {
7488
const segments = rootMappings[i];
75-
const tracedSegments: SourceMapSegment[] = [];
7689

77-
let lastSourcesIndex = -1;
78-
let lastSourceLine = -1;
79-
let lastSourceColumn = -1;
90+
let lastSource = null;
91+
let lastSourceLine = null;
92+
let lastSourceColumn = null;
8093

8194
for (let j = 0; j < segments.length; j++) {
8295
const segment = segments[j];
96+
const genCol = segment[0];
97+
let traced: SourceMapSegmentObject | null = SOURCELESS_MAPPING;
8398

84-
let traced: MappingSource = SOURCELESS_MAPPING;
8599
// 1-length segments only move the current generated column, there's no source information
86100
// to gather from it.
87101
if (segment.length !== 1) {
@@ -95,71 +109,26 @@ export function traceMappings(tree: Sources): TraceMap {
95109

96110
// If the trace is invalid, then the trace ran into a sourcemap that doesn't contain a
97111
// respective segment into an original source.
98-
if (traced === INVALID_MAPPING) continue;
99-
}
100-
101-
const genCol = segment[0];
102-
if (traced === SOURCELESS_MAPPING) {
103-
if (lastSourcesIndex === -1) {
104-
// This is a consecutive source-less segment, which doesn't carry any new information.
105-
continue;
106-
}
107-
lastSourcesIndex = lastSourceLine = lastSourceColumn = -1;
108-
tracedSegments.push([genCol]);
109-
continue;
112+
if (traced == null) continue;
110113
}
111114

112115
// So we traced a segment down into its original source file. Now push a
113116
// new segment pointing to this location.
114117
const { column, line, name, content, source } = traced;
115-
116-
// Store the source location, and ensure we keep sourcesContent up to
117-
// date with the sources array.
118-
const sourcesIndex = put(sources, source);
119-
sourcesContent[sourcesIndex] = content;
120-
121-
if (
122-
lastSourcesIndex === sourcesIndex &&
123-
lastSourceLine === line &&
124-
lastSourceColumn === column
125-
) {
126-
// This is a duplicate mapping pointing at the exact same starting point in the source
127-
// file. It doesn't carry any new information, and only bloats the sourcemap.
118+
if (line === lastSourceLine && column === lastSourceColumn && source === lastSource) {
128119
continue;
129120
}
130-
lastLineWithSegment = i;
131-
lastSourcesIndex = sourcesIndex;
132121
lastSourceLine = line;
133122
lastSourceColumn = column;
123+
lastSource = source;
134124

135-
// This looks like unnecessary duplication, but it noticeably increases performance. If we
136-
// were to push the nameIndex onto length-4 array, v8 would internally allocate 22 slots!
137-
// That's 68 wasted bytes! Array literals have the same capacity as their length, saving
138-
// memory.
139-
tracedSegments.push(
140-
name
141-
? [genCol, sourcesIndex, line, column, put(names, name)]
142-
: [genCol, sourcesIndex, line, column]
143-
);
125+
// Sigh, TypeScript can't figure out source/line/column are either all null, or all non-null...
126+
(addSegment as any)(gen, i, genCol, source, line, column, name);
127+
if (content != null) setSourceContent(gen, source, content);
144128
}
145-
146-
mappings.push(tracedSegments);
147129
}
148130

149-
if (mappings.length > lastLineWithSegment + 1) {
150-
mappings.length = lastLineWithSegment + 1;
151-
}
152-
153-
return presortedDecodedMap(
154-
Object.assign({}, tree.map, {
155-
mappings,
156-
// TODO: Make all sources relative to the sourceRoot.
157-
sourceRoot: undefined,
158-
names: names.array,
159-
sources: sources.array,
160-
sourcesContent,
161-
})
162-
);
131+
return gen;
163132
}
164133

165134
/**
@@ -171,15 +140,15 @@ export function originalPositionFor(
171140
line: number,
172141
column: number,
173142
name: string
174-
): MappingSource {
143+
): SourceMapSegmentObject | null {
175144
if (!source.map) {
176145
return { column, line, name, source: source.source, content: source.content };
177146
}
178147

179148
const segment = traceSegment(source.map, line, column);
180149

181150
// If we couldn't find a segment, then this doesn't exist in the sourcemap.
182-
if (segment == null) return INVALID_MAPPING;
151+
if (segment == null) return null;
183152
// 1-length segments only move the current generated column, there's no source information
184153
// to gather from it.
185154
if (segment.length === 1) return SOURCELESS_MAPPING;

src/source-map.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { encodedMappings, decodedMappings } from '@jridgewell/trace-mapping';
1+
import { decodedMap, encodedMap } from '@jridgewell/gen-mapping';
22

3-
import type { TraceMap } from '@jridgewell/trace-mapping';
3+
import type { GenMapping } from '@jridgewell/gen-mapping';
44
import type { DecodedSourceMap, EncodedSourceMap, Options } from './types';
55

66
/**
@@ -16,20 +16,17 @@ export default class SourceMap {
1616
declare sourcesContent?: (string | null)[];
1717
declare version: 3;
1818

19-
constructor(map: TraceMap, options: Options) {
20-
this.version = 3; // SourceMap spec says this should be first.
21-
this.file = map.file;
22-
this.mappings = options.decodedMappings
23-
? (decodedMappings(map) as DecodedSourceMap['mappings'])
24-
: encodedMappings(map);
25-
this.names = map.names;
19+
constructor(map: GenMapping, options: Options) {
20+
const out = options.decodedMappings ? decodedMap(map) : encodedMap(map);
21+
this.version = out.version; // SourceMap spec says this should be first.
22+
this.file = out.file;
23+
this.mappings = out.mappings;
24+
this.names = out.names;
2625

27-
this.sourceRoot = map.sourceRoot;
26+
this.sourceRoot = out.sourceRoot;
2827

29-
this.sources = map.sources;
30-
if (!options.excludeContent && 'sourcesContent' in map) {
31-
this.sourcesContent = map.sourcesContent;
32-
}
28+
this.sources = out.sources;
29+
if (!options.excludeContent) this.sourcesContent = out.sourcesContent;
3330
}
3431

3532
toString(): string {

src/types.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ export type {
88

99
export type { SourceMapInput };
1010

11-
export interface SourceMapSegmentObject {
12-
column: number;
13-
line: number;
14-
name: string;
15-
source: string;
16-
content: string | null;
17-
}
18-
1911
export type LoaderContext = {
2012
readonly importer: string;
2113
readonly depth: number;

0 commit comments

Comments
 (0)