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

Commit 3519872

Browse files
authored
Merge pull request #171 from ampproject/gen-mapping
Extract GenMapping
2 parents 5285f27 + b9f392f commit 3519872

File tree

9 files changed

+1151
-1258
lines changed

9 files changed

+1151
-1258
lines changed

package-lock.json

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

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,23 @@
4141
"test:watch": "jest --coverage --watch"
4242
},
4343
"devDependencies": {
44-
"@rollup/plugin-typescript": "8.3.0",
45-
"@types/jest": "27.4.0",
46-
"@typescript-eslint/eslint-plugin": "5.10.2",
47-
"@typescript-eslint/parser": "5.10.2",
48-
"eslint": "8.8.0",
49-
"eslint-config-prettier": "8.3.0",
50-
"jest": "27.4.7",
51-
"jest-config": "27.4.7",
44+
"@rollup/plugin-typescript": "8.3.2",
45+
"@types/jest": "27.4.1",
46+
"@typescript-eslint/eslint-plugin": "5.20.0",
47+
"@typescript-eslint/parser": "5.20.0",
48+
"eslint": "8.14.0",
49+
"eslint-config-prettier": "8.5.0",
50+
"jest": "27.5.1",
51+
"jest-config": "27.5.1",
5252
"npm-run-all": "4.1.5",
53-
"prettier": "2.5.1",
54-
"rollup": "2.67.0",
55-
"ts-jest": "27.1.3",
56-
"tslib": "2.3.1",
57-
"typescript": "4.5.5"
53+
"prettier": "2.6.2",
54+
"rollup": "2.70.2",
55+
"ts-jest": "27.1.4",
56+
"tslib": "2.4.0",
57+
"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.1.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/build-source-map-tree.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { TraceMap } from '@jridgewell/trace-mapping';
22

33
import { OriginalSource, MapSource } from './source-map-tree';
44

5-
import type { Sources } from './source-map-tree';
5+
import type { Sources, MapSource as MapSourceType } from './source-map-tree';
66
import type { SourceMapInput, SourceMapLoader, LoaderContext } from './types';
77

88
function asArray<T>(value: T | T[]): T[] {
@@ -24,7 +24,7 @@ function asArray<T>(value: T | T[]): T[] {
2424
export default function buildSourceMapTree(
2525
input: SourceMapInput | SourceMapInput[],
2626
loader: SourceMapLoader
27-
): Sources {
27+
): MapSourceType {
2828
const maps = asArray(input).map((m) => new TraceMap(m, ''));
2929
const map = maps.pop()!;
3030

@@ -49,7 +49,7 @@ function build(
4949
loader: SourceMapLoader,
5050
importer: string,
5151
importerDepth: number
52-
): Sources {
52+
): MapSourceType {
5353
const { resolvedSources, sourcesContent } = map;
5454

5555
const depth = importerDepth + 1;

src/source-map-tree.ts

Lines changed: 43 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
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-
13-
type OriginalSource = {
31+
export type OriginalSource = {
1432
map: TraceMap;
1533
sources: Sources[];
1634
source: string;
1735
content: string | null;
1836
};
1937

20-
type MapSource = {
38+
export type MapSource = {
2139
map: TraceMap;
2240
sources: Sources[];
2341
source: string;
@@ -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: MapSource): GenMapping {
82+
const gen = new GenMapping({ file: 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: 12 additions & 13 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,19 +16,18 @@ 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 as SourceMap['mappings'];
24+
this.names = out.names as SourceMap['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;
28+
this.sources = out.sources as SourceMap['sources'];
29+
if (!options.excludeContent) {
30+
this.sourcesContent = out.sourcesContent as SourceMap['sourcesContent'];
3231
}
3332
}
3433

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)