Skip to content

Commit 020f5fa

Browse files
authored
Merge pull request #45 from takikawa/range-mappings-decode
Range mappings: encoding/decoding support
2 parents 74fc8e1 + 01a4f69 commit 020f5fa

File tree

11 files changed

+225
-75
lines changed

11 files changed

+225
-75
lines changed

packages/gen-mapping/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"test:format": "prettier --check '{src,test}/**/*.ts'",
4848
"test:only": "mocha",
4949
"test:types": "eslint '{src,test}/**/*.ts'",
50+
"test:watch": "mocha --watch --watch-files 'src/**/*.ts,test/**/*.ts'",
5051
"lint": "run-s -n lint:types lint:format",
5152
"lint:format": "npm run test:format -- --write",
5253
"lint:types": "npm run test:types -- --fix",

packages/remapping/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"test:format": "prettier --check '{src,test}/**/*.ts'",
4949
"test:only": "mocha",
5050
"test:types": "eslint '{src,test}/**/*.ts'",
51+
"test:watch": "mocha --watch --watch-files 'src/**/*.ts,test/**/*.ts'",
5152
"lint": "run-s -n lint:types lint:format",
5253
"lint:format": "npm run test:format -- --write",
5354
"lint:types": "npm run test:types -- --fix",

packages/source-map/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"test:format": "prettier --check '{src,test}/**/*.ts'",
4949
"test:only": "mocha",
5050
"test:types": "eslint '{src,test}/**/*.ts'",
51+
"test:watch": "mocha --watch --watch-files 'src/**/*.ts,test/**/*.ts'",
5152
"lint": "run-s -n lint:types lint:format",
5253
"lint:format": "npm run test:format -- --write",
5354
"lint:types": "npm run test:types -- --fix",

packages/sourcemap-codec/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"test:format": "prettier --check '{src,test}/**/*.ts'",
4848
"test:only": "mocha",
4949
"test:types": "eslint '{src,test}/**/*.ts'",
50+
"test:watch": "mocha --watch --watch-files 'src/**/*.ts,test/**/*.ts'",
5051
"lint": "run-s -n lint:types lint:format",
5152
"lint:format": "npm run test:format -- --write",
5253
"lint:types": "npm run test:types -- --fix",
@@ -60,4 +61,4 @@
6061
},
6162
"author": "Justin Ridgewell <justin@ridgewell.name>",
6263
"license": "MIT"
63-
}
64+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { StringReader, StringWriter } from './strings';
2+
import { decodeInteger, encodeInteger, semicolon } from './vlq';
3+
4+
export type MappingIndex = number;
5+
export type RangeMappings = MappingIndex[][];
6+
7+
export function decodeRangeMappings(input: string): RangeMappings {
8+
const { length } = input;
9+
const reader = new StringReader(input);
10+
const rangeMappings: RangeMappings = [];
11+
12+
do {
13+
const semi = reader.indexOf(';');
14+
const indices: MappingIndex[] = [];
15+
let index = -1;
16+
17+
while (reader.pos < semi) {
18+
index += decodeInteger(reader);
19+
indices.push(index);
20+
}
21+
22+
rangeMappings.push(indices);
23+
reader.pos = semi + 1;
24+
} while (reader.pos <= length);
25+
26+
return rangeMappings;
27+
}
28+
29+
export function encodeRangeMappings(decoded: RangeMappings): string {
30+
if (decoded.length === 0) return '';
31+
32+
const writer = new StringWriter();
33+
34+
for (let i = 0; i < decoded.length; i++) {
35+
const indices = decoded[i];
36+
if (i > 0) writer.write(semicolon);
37+
38+
let index = -1;
39+
for (let j = 0; j < indices.length; j++) {
40+
const offset = indices[j];
41+
encodeInteger(writer, offset - index);
42+
index = offset;
43+
}
44+
}
45+
46+
return writer.flush();
47+
}

packages/sourcemap-codec/src/scopes.ts

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import { StringReader, StringWriter } from './strings';
2-
import { comma, decodeInteger, encodeInteger, hasMoreVlq, semicolon } from './vlq';
2+
import {
3+
comma,
4+
decodeInteger,
5+
decodeSign,
6+
encodeInteger,
7+
encodeSign,
8+
hasMoreVlq,
9+
semicolon,
10+
} from './vlq';
311

412
const EMPTY: any[] = [];
513

@@ -40,8 +48,8 @@ export function decodeOriginalScopes(input: string): OriginalScope[] {
4048
let line = 0;
4149

4250
for (; reader.pos < length; reader.pos++) {
43-
line = decodeInteger(reader, line);
44-
const column = decodeInteger(reader, 0);
51+
line += decodeSign(decodeInteger(reader));
52+
const column = decodeSign(decodeInteger(reader));
4553

4654
if (!hasMoreVlq(reader, length)) {
4755
const last = stack.pop()!;
@@ -50,19 +58,21 @@ export function decodeOriginalScopes(input: string): OriginalScope[] {
5058
continue;
5159
}
5260

53-
const kind = decodeInteger(reader, 0);
54-
const fields = decodeInteger(reader, 0);
61+
const kind = decodeSign(decodeInteger(reader));
62+
const fields = decodeSign(decodeInteger(reader));
5563
const hasName = fields & 0b0001;
5664

5765
const scope: OriginalScope = (
58-
hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind]
66+
hasName
67+
? [line, column, 0, 0, kind, decodeSign(decodeInteger(reader))]
68+
: [line, column, 0, 0, kind]
5969
) as OriginalScope;
6070

6171
let vars: Var[] = EMPTY;
6272
if (hasMoreVlq(reader, length)) {
6373
vars = [];
6474
do {
65-
const varsIndex = decodeInteger(reader, 0);
75+
const varsIndex = decodeSign(decodeInteger(reader));
6676
vars.push(varsIndex);
6777
} while (hasMoreVlq(reader, length));
6878
}
@@ -98,16 +108,17 @@ function _encodeOriginalScopes(
98108

99109
if (index > 0) writer.write(comma);
100110

101-
state[0] = encodeInteger(writer, startLine, state[0]);
102-
encodeInteger(writer, startColumn, 0);
103-
encodeInteger(writer, kind, 0);
111+
encodeInteger(writer, encodeSign(startLine - state[0]));
112+
state[0] = startLine;
113+
encodeInteger(writer, encodeSign(startColumn));
114+
encodeInteger(writer, encodeSign(kind));
104115

105116
const fields = scope.length === 6 ? 0b0001 : 0;
106-
encodeInteger(writer, fields, 0);
107-
if (scope.length === 6) encodeInteger(writer, scope[5], 0);
117+
encodeInteger(writer, encodeSign(fields));
118+
if (scope.length === 6) encodeInteger(writer, encodeSign(scope[5]));
108119

109120
for (const v of vars) {
110-
encodeInteger(writer, v, 0);
121+
encodeInteger(writer, encodeSign(v));
111122
}
112123

113124
for (index++; index < scopes.length; ) {
@@ -120,8 +131,9 @@ function _encodeOriginalScopes(
120131
}
121132

122133
writer.write(comma);
123-
state[0] = encodeInteger(writer, endLine, state[0]);
124-
encodeInteger(writer, endColumn, 0);
134+
encodeInteger(writer, encodeSign(endLine - state[0]));
135+
state[0] = endLine;
136+
encodeInteger(writer, encodeSign(endColumn));
125137

126138
return index;
127139
}
@@ -146,7 +158,7 @@ export function decodeGeneratedRanges(input: string): GeneratedRange[] {
146158
let genColumn = 0;
147159

148160
for (; reader.pos < semi; reader.pos++) {
149-
genColumn = decodeInteger(reader, genColumn);
161+
genColumn += decodeSign(decodeInteger(reader));
150162

151163
if (!hasMoreVlq(reader, semi)) {
152164
const last = stack.pop()!;
@@ -155,7 +167,7 @@ export function decodeGeneratedRanges(input: string): GeneratedRange[] {
155167
continue;
156168
}
157169

158-
const fields = decodeInteger(reader, 0);
170+
const fields = decodeSign(decodeInteger(reader));
159171
const hasDefinition = fields & 0b0001;
160172
const hasCallsite = fields & 0b0010;
161173
const hasScope = fields & 0b0100;
@@ -164,11 +176,10 @@ export function decodeGeneratedRanges(input: string): GeneratedRange[] {
164176
let bindings: Binding[] = EMPTY;
165177
let range: GeneratedRange;
166178
if (hasDefinition) {
167-
const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
168-
definitionScopeIndex = decodeInteger(
169-
reader,
170-
definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0,
171-
);
179+
const defSourcesIndex = definitionSourcesIndex + decodeSign(decodeInteger(reader));
180+
definitionScopeIndex =
181+
decodeSign(decodeInteger(reader)) +
182+
(definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0);
172183

173184
definitionSourcesIndex = defSourcesIndex;
174185
range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex] as GeneratedRange;
@@ -181,13 +192,12 @@ export function decodeGeneratedRanges(input: string): GeneratedRange[] {
181192
if (hasCallsite) {
182193
const prevCsi = callsiteSourcesIndex;
183194
const prevLine = callsiteLine;
184-
callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
195+
callsiteSourcesIndex += decodeSign(decodeInteger(reader));
185196
const sameSource = prevCsi === callsiteSourcesIndex;
186-
callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
187-
callsiteColumn = decodeInteger(
188-
reader,
189-
sameSource && prevLine === callsiteLine ? callsiteColumn : 0,
190-
);
197+
callsiteLine = (sameSource ? callsiteLine : 0) + decodeSign(decodeInteger(reader));
198+
callsiteColumn =
199+
(sameSource && prevLine === callsiteLine ? callsiteColumn : 0) +
200+
decodeSign(decodeInteger(reader));
191201

192202
callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
193203
}
@@ -198,15 +208,16 @@ export function decodeGeneratedRanges(input: string): GeneratedRange[] {
198208
do {
199209
bindingLine = genLine;
200210
bindingColumn = genColumn;
201-
const expressionsCount = decodeInteger(reader, 0);
211+
const expressionsCount = decodeSign(decodeInteger(reader));
202212
let expressionRanges: BindingExpressionRange[];
203213
if (expressionsCount < -1) {
204-
expressionRanges = [[decodeInteger(reader, 0)]];
214+
expressionRanges = [[decodeSign(decodeInteger(reader))]];
205215
for (let i = -1; i > expressionsCount; i--) {
206216
const prevBl = bindingLine;
207-
bindingLine = decodeInteger(reader, bindingLine);
208-
bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
209-
const expression = decodeInteger(reader, 0);
217+
bindingLine += decodeSign(decodeInteger(reader));
218+
bindingColumn =
219+
(bindingLine === prevBl ? bindingColumn : 0) + decodeSign(decodeInteger(reader));
220+
const expression = decodeSign(decodeInteger(reader));
210221
expressionRanges.push([expression, bindingLine, bindingColumn]);
211222
}
212223
} else {
@@ -273,19 +284,22 @@ function _encodeGeneratedRanges(
273284
writer.write(comma);
274285
}
275286

276-
state[1] = encodeInteger(writer, range[1], state[1]);
287+
encodeInteger(writer, encodeSign(range[1] - state[1]));
288+
state[1] = range[1];
277289

278290
const fields =
279291
(range.length === 6 ? 0b0001 : 0) | (callsite ? 0b0010 : 0) | (isScope ? 0b0100 : 0);
280-
encodeInteger(writer, fields, 0);
292+
encodeInteger(writer, encodeSign(fields));
281293

282294
if (range.length === 6) {
283295
const { 4: sourcesIndex, 5: scopesIndex } = range;
284296
if (sourcesIndex !== state[2]) {
285297
state[3] = 0;
286298
}
287-
state[2] = encodeInteger(writer, sourcesIndex, state[2]);
288-
state[3] = encodeInteger(writer, scopesIndex, state[3]);
299+
encodeInteger(writer, encodeSign(sourcesIndex - state[2]));
300+
state[2] = sourcesIndex;
301+
encodeInteger(writer, encodeSign(scopesIndex - state[3]));
302+
state[3] = scopesIndex;
289303
}
290304

291305
if (callsite) {
@@ -296,23 +310,28 @@ function _encodeGeneratedRanges(
296310
} else if (callLine !== state[5]) {
297311
state[6] = 0;
298312
}
299-
state[4] = encodeInteger(writer, sourcesIndex, state[4]);
300-
state[5] = encodeInteger(writer, callLine, state[5]);
301-
state[6] = encodeInteger(writer, callColumn, state[6]);
313+
encodeInteger(writer, encodeSign(sourcesIndex - state[4]));
314+
state[4] = sourcesIndex;
315+
encodeInteger(writer, encodeSign(callLine - state[5]));
316+
state[5] = callLine;
317+
encodeInteger(writer, encodeSign(callColumn - state[6]));
318+
state[6] = callColumn;
302319
}
303320

304321
if (bindings) {
305322
for (const binding of bindings) {
306-
if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
323+
if (binding.length > 1) encodeInteger(writer, encodeSign(-binding.length));
307324
const expression = binding[0][0];
308-
encodeInteger(writer, expression, 0);
325+
encodeInteger(writer, encodeSign(expression));
309326
let bindingStartLine = startLine;
310327
let bindingStartColumn = startColumn;
311328
for (let i = 1; i < binding.length; i++) {
312329
const expRange = binding[i];
313-
bindingStartLine = encodeInteger(writer, expRange[1]!, bindingStartLine);
314-
bindingStartColumn = encodeInteger(writer, expRange[2]!, bindingStartColumn);
315-
encodeInteger(writer, expRange[0]!, 0);
330+
encodeInteger(writer, encodeSign(expRange[1]! - bindingStartLine));
331+
bindingStartLine = expRange[1]!;
332+
encodeInteger(writer, encodeSign(expRange[2]! - bindingStartColumn));
333+
bindingStartColumn = expRange[2]!;
334+
encodeInteger(writer, encodeSign(expRange[0]!));
316335
}
317336
}
318337
}
@@ -333,7 +352,8 @@ function _encodeGeneratedRanges(
333352
} else {
334353
writer.write(comma);
335354
}
336-
state[1] = encodeInteger(writer, endColumn, state[1]);
355+
encodeInteger(writer, encodeSign(endColumn - state[1]));
356+
state[1] = endColumn;
337357

338358
return index;
339359
}

packages/sourcemap-codec/src/sourcemap-codec.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { comma, decodeInteger, encodeInteger, hasMoreVlq, semicolon } from './vlq';
1+
import {
2+
comma,
3+
decodeInteger,
4+
decodeSign,
5+
encodeInteger,
6+
encodeSign,
7+
hasMoreVlq,
8+
semicolon,
9+
} from './vlq';
210
import { StringWriter, StringReader } from './strings';
311

412
export {
@@ -9,6 +17,9 @@ export {
917
} from './scopes';
1018
export type { OriginalScope, GeneratedRange, CallSite, BindingExpressionRange } from './scopes';
1119

20+
export { decodeRangeMappings, encodeRangeMappings } from './range-mappings';
21+
export type { MappingIndex, RangeMappings } from './range-mappings';
22+
1223
export type SourceMapSegment =
1324
| [number]
1425
| [number, number, number, number]
@@ -36,17 +47,17 @@ export function decode(mappings: string): SourceMapMappings {
3647
while (reader.pos < semi) {
3748
let seg: SourceMapSegment;
3849

39-
genColumn = decodeInteger(reader, genColumn);
50+
genColumn += decodeSign(decodeInteger(reader));
4051
if (genColumn < lastCol) sorted = false;
4152
lastCol = genColumn;
4253

4354
if (hasMoreVlq(reader, semi)) {
44-
sourcesIndex = decodeInteger(reader, sourcesIndex);
45-
sourceLine = decodeInteger(reader, sourceLine);
46-
sourceColumn = decodeInteger(reader, sourceColumn);
55+
sourcesIndex += decodeSign(decodeInteger(reader));
56+
sourceLine += decodeSign(decodeInteger(reader));
57+
sourceColumn += decodeSign(decodeInteger(reader));
4758

4859
if (hasMoreVlq(reader, semi)) {
49-
namesIndex = decodeInteger(reader, namesIndex);
60+
namesIndex += decodeSign(decodeInteger(reader));
5061
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
5162
} else {
5263
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
@@ -95,15 +106,20 @@ export function encode(decoded: Readonly<SourceMapMappings>): string {
95106
const segment = line[j];
96107
if (j > 0) writer.write(comma);
97108

98-
genColumn = encodeInteger(writer, segment[0], genColumn);
109+
encodeInteger(writer, encodeSign(segment[0] - genColumn));
110+
genColumn = segment[0];
99111

100112
if (segment.length === 1) continue;
101-
sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
102-
sourceLine = encodeInteger(writer, segment[2], sourceLine);
103-
sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
113+
encodeInteger(writer, encodeSign(segment[1] - sourcesIndex));
114+
encodeInteger(writer, encodeSign(segment[2] - sourceLine));
115+
encodeInteger(writer, encodeSign(segment[3] - sourceColumn));
116+
sourcesIndex = segment[1];
117+
sourceLine = segment[2];
118+
sourceColumn = segment[3];
104119

105120
if (segment.length === 4) continue;
106-
namesIndex = encodeInteger(writer, segment[4], namesIndex);
121+
encodeInteger(writer, encodeSign(segment[4] - namesIndex));
122+
namesIndex = segment[4];
107123
}
108124
}
109125

0 commit comments

Comments
 (0)