Skip to content

Commit 4ccc690

Browse files
szuendDevtools-frontend LUCI CQ
authored andcommitted
[source-map] Restructure 'scopes' proposal decoding
This CL prepares 'SourceMapScopesInfo' and 'SourceMap' to support index source map support for the 'scopes' proposal. We split the existing 'SourceMapScopesInfo.parseFromMap' function into 'decodeScopes' and a dedicated test helper. 'SourceMapScopesInfo' no longer parses anything, but instead just receives already decoded scopes and ranges. We also add two methods so OriginalScopes and GeneratedRanges can be added to an existing SourceMapScopesInfo after the fact. We'll make use of these two methods for multiple things: 1) Accumulate all the scopes info in an index source map into a single SourceMapScopesInfo object 2) Convert bloomberg pasta function ranges into OriginalScopes and add them to a SourceMap's SourceMapScopesInfo. 3) Allow an extension API to incrementally add OriginalScope trees to a SourceMap's SourceMapScopesInfo. [email protected] Bug: 390337576 Change-Id: Ifb911f4daded05f58a470cfed8759cf44e86425b Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6185441 Commit-Queue: Simon Zünd <[email protected]> Reviewed-by: Kim-Anh Tran <[email protected]>
1 parent f4c36fa commit 4ccc690

File tree

4 files changed

+59
-46
lines changed

4 files changed

+59
-46
lines changed

front_end/core/sdk/SourceMap.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import * as Platform from '../platform/platform.js';
3838
import * as Root from '../root/root.js';
3939

4040
import type {CallFrame, ScopeChainEntry} from './DebuggerModel.js';
41+
import {decodeScopes} from './SourceMapScopes.js';
4142
import {SourceMapScopesInfo} from './SourceMapScopesInfo.js';
4243

4344
/**
@@ -636,7 +637,8 @@ export class SourceMap {
636637

637638
#parseScopes(map: SourceMapV3Object): void {
638639
if (map.originalScopes && map.generatedRanges) {
639-
this.#scopesInfo = SourceMapScopesInfo.parseFromMap(this, map);
640+
const {originalScopes, generatedRanges} = decodeScopes(map);
641+
this.#scopesInfo = new SourceMapScopesInfo(this, originalScopes, generatedRanges);
640642
}
641643
}
642644

front_end/core/sdk/SourceMapScopes.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* in this file to change frequently.
1313
*/
1414

15-
import {TokenIterator} from './SourceMap.js';
15+
import {type SourceMapV3Object, TokenIterator} from './SourceMap.js';
1616

1717
/**
1818
* A scope in the authored source.
@@ -98,6 +98,17 @@ interface OriginalScopeTree {
9898
readonly scopeForItemIndex: Map<number, OriginalScope>;
9999
}
100100

101+
export function decodeScopes(map: Pick<SourceMapV3Object, 'names'|'originalScopes'|'generatedRanges'>):
102+
{originalScopes: OriginalScope[], generatedRanges: GeneratedRange[]} {
103+
if (!map.originalScopes || map.generatedRanges === undefined) {
104+
throw new Error('Cant decode scopes without "originalScopes" or "generatedRanges"');
105+
}
106+
const scopeTrees = decodeOriginalScopes(map.originalScopes, map.names ?? []);
107+
const originalScopes = scopeTrees.map(tree => tree.root);
108+
const generatedRanges = decodeGeneratedRanges(map.generatedRanges, scopeTrees, map.names ?? []);
109+
return {originalScopes, generatedRanges};
110+
}
111+
101112
export function decodeOriginalScopes(encodedOriginalScopes: string[], names: string[]): OriginalScopeTree[] {
102113
return encodedOriginalScopes.map(scope => decodeOriginalScope(scope, names));
103114
}

front_end/core/sdk/SourceMapScopesInfo.test.ts

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ const {urlString} = Platform.DevToolsPath;
1414
const {SourceMapScopesInfo} = SDK.SourceMapScopesInfo;
1515

1616
describe('SourceMapScopesInfo', () => {
17+
function parseFromMap(
18+
sourceMap: SDK.SourceMap.SourceMap,
19+
sourceMapJson: Pick<SDK.SourceMap.SourceMapV3Object, 'names'|'originalScopes'|'generatedRanges'>):
20+
SDK.SourceMapScopesInfo.SourceMapScopesInfo {
21+
const {originalScopes, generatedRanges} = SDK.SourceMapScopes.decodeScopes(sourceMapJson);
22+
return new SourceMapScopesInfo(sourceMap, originalScopes, generatedRanges);
23+
}
24+
1725
describe('findInlinedFunctions', () => {
1826
it('returns the single original function name if nothing was inlined', () => {
1927
const names: string[] = [];
@@ -31,8 +39,8 @@ describe('SourceMapScopesInfo', () => {
3139
.end(0, 5)
3240
.build();
3341

34-
const info = SourceMapScopesInfo.parseFromMap(
35-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
42+
const info =
43+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
3644

3745
assert.deepEqual(info.findInlinedFunctions(0, 3), {originalFunctionName: 'foo', inlinedFunctions: []});
3846
});
@@ -63,8 +71,8 @@ describe('SourceMapScopesInfo', () => {
6371
.end(0, 10)
6472
.build();
6573

66-
const info = SourceMapScopesInfo.parseFromMap(
67-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
74+
const info =
75+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
6876

6977
assert.deepEqual(info.findInlinedFunctions(0, 4), {originalFunctionName: 'foo', inlinedFunctions: []});
7078
assert.deepEqual(info.findInlinedFunctions(0, 7), {
@@ -139,8 +147,8 @@ describe('SourceMapScopesInfo', () => {
139147
.end(3, 0)
140148
.build();
141149

142-
const info = SourceMapScopesInfo.parseFromMap(
143-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
150+
const info =
151+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
144152

145153
{
146154
const callFrame = setUpCallFrame({line: 0, column: 13}, 'n'); // Pause on 'print'.
@@ -212,8 +220,8 @@ describe('SourceMapScopesInfo', () => {
212220
.end(2, 0)
213221
.build();
214222

215-
const info = SourceMapScopesInfo.parseFromMap(
216-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
223+
const info =
224+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
217225

218226
{
219227
const callFrame = setUpCallFrame({line: 0, column: 22}, 'm'); // Pause on 'print'.
@@ -287,8 +295,8 @@ describe('SourceMapScopesInfo', () => {
287295
.end(1, 0)
288296
.build();
289297

290-
const info = SourceMapScopesInfo.parseFromMap(
291-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
298+
const info =
299+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
292300

293301
{
294302
const callFrame = setUpCallFrame({line: 0, column: 0}, ''); // Pause on 'print'.
@@ -322,8 +330,8 @@ describe('SourceMapScopesInfo', () => {
322330
.end(0, 30)
323331
.build();
324332

325-
const info = SourceMapScopesInfo.parseFromMap(
326-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
333+
const info =
334+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
327335

328336
assert.isFalse(info.hasVariablesAndBindings());
329337
});
@@ -344,8 +352,8 @@ describe('SourceMapScopesInfo', () => {
344352
.end(0, 30)
345353
.build();
346354

347-
const info = SourceMapScopesInfo.parseFromMap(
348-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
355+
const info =
356+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
349357

350358
assert.isFalse(info.hasVariablesAndBindings());
351359
});
@@ -367,8 +375,8 @@ describe('SourceMapScopesInfo', () => {
367375
.end(0, 30)
368376
.build();
369377

370-
const info = SourceMapScopesInfo.parseFromMap(
371-
sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
378+
const info =
379+
parseFromMap(sinon.createStubInstance(SDK.SourceMap.SourceMap), {names, originalScopes, generatedRanges});
372380

373381
assert.isTrue(info.hasVariablesAndBindings());
374382
});
@@ -421,7 +429,7 @@ describe('SourceMapScopesInfo', () => {
421429
.build();
422430

423431
const {sourceMap, callFrame} = setUpCallFrameAndSourceMap({generatedPausedPosition: {line: 0, column: 15}});
424-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
432+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
425433

426434
const scopeChain = info.resolveMappedScopeChain(callFrame);
427435

@@ -439,7 +447,7 @@ describe('SourceMapScopesInfo', () => {
439447
generatedPausedPosition: {line: 0, column: 50},
440448
mappedPausedPosition: {sourceIndex: 0, line: 10, column: 0},
441449
});
442-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
450+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
443451

444452
const scopeChain = info.resolveMappedScopeChain(callFrame);
445453

@@ -469,7 +477,7 @@ describe('SourceMapScopesInfo', () => {
469477
generatedPausedPosition: {line: 0, column: 50},
470478
mappedPausedPosition: {sourceIndex: 0, line: 10, column: 0},
471479
});
472-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
480+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
473481

474482
const scopeChain = info.resolveMappedScopeChain(callFrame);
475483

@@ -502,7 +510,7 @@ describe('SourceMapScopesInfo', () => {
502510
mappedPausedPosition: {sourceIndex: 0, line: 10, column: 0},
503511
returnValue: new SDK.RemoteObject.LocalJSONObject(42),
504512
});
505-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
513+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
506514

507515
const scopeChain = info.resolveMappedScopeChain(callFrame);
508516

@@ -555,7 +563,7 @@ describe('SourceMapScopesInfo', () => {
555563
generatedPausedPosition: {line: 0, column: 50},
556564
mappedPausedPosition: {sourceIndex: 0, line: 15, column: 0},
557565
});
558-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
566+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
559567

560568
const scopeChain = info.resolveMappedScopeChain(callFrame);
561569

@@ -623,7 +631,7 @@ describe('SourceMapScopesInfo', () => {
623631
generatedPausedPosition: {line: 0, column: 50},
624632
mappedPausedPosition: {sourceIndex: 0, line: 5, column: 0},
625633
});
626-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
634+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
627635

628636
const scopeChain = info.resolveMappedScopeChain(callFrame);
629637

@@ -705,7 +713,7 @@ describe('SourceMapScopesInfo', () => {
705713
generatedPausedPosition: {line: 0, column: 10},
706714
mappedPausedPosition: {sourceIndex: 0, line: 3, column: 2},
707715
});
708-
const info = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
716+
const info = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
709717

710718
{
711719
const scopeChain = info.resolveMappedScopeChain(callFrame);
@@ -778,8 +786,7 @@ describe('SourceMapScopesInfo', () => {
778786
.end(60, 1)
779787
.end(70, 0)
780788
.build()];
781-
const scopeInfoWithMappings =
782-
SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges: ''});
789+
const scopeInfoWithMappings = parseFromMap(sourceMap, {names, originalScopes, generatedRanges: ''});
783790
const generatedRanges = new GeneratedRangeBuilder(names)
784791
.start(0, 0, {definition: {sourceIdx: 0, scopeIdx: 0}})
785792
.start(0, 20, {definition: {sourceIdx: 0, scopeIdx: 1}})
@@ -792,7 +799,7 @@ describe('SourceMapScopesInfo', () => {
792799
.end(0, 160)
793800
.end(0, 180)
794801
.build();
795-
const scopeInfoWithRanges = SourceMapScopesInfo.parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
802+
const scopeInfoWithRanges = parseFromMap(sourceMap, {names, originalScopes, generatedRanges});
796803
return [scopeInfoWithRanges, scopeInfoWithMappings];
797804
})();
798805

front_end/core/sdk/SourceMapScopesInfo.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,9 @@
55
import * as Protocol from '../../generated/protocol.js';
66

77
import type {CallFrame, ScopeChainEntry} from './DebuggerModel.js';
8-
import type {SourceMap, SourceMapV3Object} from './SourceMap.js';
8+
import type {SourceMap} from './SourceMap.js';
99
import {SourceMapScopeChainEntry} from './SourceMapScopeChainEntry.js';
10-
import {
11-
decodeGeneratedRanges,
12-
decodeOriginalScopes,
13-
type GeneratedRange,
14-
type OriginalPosition,
15-
type OriginalScope,
16-
type Position,
17-
} from './SourceMapScopes.js';
10+
import type {GeneratedRange, OriginalPosition, OriginalScope, Position,} from './SourceMapScopes.js';
1811

1912
export class SourceMapScopesInfo {
2013
readonly #sourceMap: SourceMap;
@@ -29,16 +22,16 @@ export class SourceMapScopesInfo {
2922
this.#generatedRanges = generatedRanges;
3023
}
3124

32-
static parseFromMap(
33-
sourceMap: SourceMap,
34-
sourceMapJson: Pick<SourceMapV3Object, 'names'|'originalScopes'|'generatedRanges'>): SourceMapScopesInfo {
35-
if (!sourceMapJson.originalScopes || sourceMapJson.generatedRanges === undefined) {
36-
throw new Error('Cant create SourceMapScopesInfo without encoded scopes');
25+
addOriginalScopes(scopes: OriginalScope[]): void {
26+
for (const scope of scopes) {
27+
this.#originalScopes.push(scope);
28+
}
29+
}
30+
31+
addGeneratedRanges(ranges: GeneratedRange[]): void {
32+
for (const range of ranges) {
33+
this.#generatedRanges.push(range);
3734
}
38-
const scopeTrees = decodeOriginalScopes(sourceMapJson.originalScopes, sourceMapJson.names ?? []);
39-
const originalScopes = scopeTrees.map(tree => tree.root);
40-
const generatedRanges = decodeGeneratedRanges(sourceMapJson.generatedRanges, scopeTrees, sourceMapJson.names ?? []);
41-
return new SourceMapScopesInfo(sourceMap, originalScopes, generatedRanges);
4235
}
4336

4437
/**

0 commit comments

Comments
 (0)