chrome-devtools-frontend 1.0.1704172 → 1.0.1706026
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/docs/architecture_of_devtools.md +1 -1
- package/docs/cookbook/localization.md +2 -2
- package/eslint.config.mjs +1 -0
- package/front_end/Images/src/nodejsHex.svg +28 -0
- package/front_end/core/common/README.md +4 -3
- package/front_end/core/sdk/CPUThrottlingManager.ts +14 -10
- package/front_end/core/sdk/DOMModel.ts +65 -20
- package/front_end/core/sdk/DebuggerModel.ts +0 -4
- package/front_end/core/sdk/PageResourceLoader.ts +12 -11
- package/front_end/core/sdk/SourceMap.ts +7 -5
- package/front_end/core/sdk/SourceMapFunctionRanges.ts +22 -37
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +3 -3
- package/front_end/core/sdk/SourceMapScopesInfo.ts +50 -62
- package/front_end/entrypoints/formatter_actions/formatter_actions.ts +18 -0
- package/front_end/entrypoints/formatter_worker/Substitute.ts +9 -8
- package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +9 -4
- package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +140 -20
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -5
- package/front_end/entrypoints/inspector_main/nodeIcon.css +1 -1
- package/front_end/foundation/Universe.ts +9 -0
- package/front_end/generated/InspectorBackendCommands.ts +4 -3
- package/front_end/generated/protocol.ts +17 -1
- package/front_end/models/ai_assistance/AiConversation.ts +16 -3
- package/front_end/models/ai_assistance/skills/accessibility.md +8 -7
- package/front_end/models/formatter/FormatterWorkerPool.ts +14 -4
- package/front_end/models/javascript_metadata/NativeFunctions.ts +6 -2
- package/front_end/models/source_map_scopes/NamesResolver.ts +69 -42
- package/front_end/models/source_map_scopes/ScopeChainModel.ts +13 -45
- package/front_end/models/source_map_scopes/ScopeChainResolver.ts +101 -0
- package/front_end/models/source_map_scopes/source_map_scopes.ts +2 -0
- package/front_end/panels/application/BackgroundServiceView.ts +1 -0
- package/front_end/panels/application/components/AdsView.ts +6 -6
- package/front_end/panels/application/components/BackForwardCacheView.ts +1 -1
- package/front_end/panels/console/ConsolePrompt.ts +2 -1
- package/front_end/panels/elements/CSSRuleValidator.ts +3 -0
- package/front_end/panels/elements/ClassesPaneWidget.ts +4 -1
- package/front_end/panels/elements/LayoutPane.ts +17 -20
- package/front_end/panels/network/NetworkLogViewColumns.ts +10 -3
- package/front_end/panels/network/ShowMoreDetailsWidget.ts +1 -1
- package/front_end/panels/security/SecurityPanel.ts +14 -7
- package/front_end/panels/sources/BreakpointEditDialog.ts +13 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +69 -58
- package/front_end/panels/sources/EditingLocationHistoryManager.ts +6 -6
- package/front_end/panels/sources/OpenFileQuickOpen.ts +2 -2
- package/front_end/panels/sources/Plugin.ts +3 -2
- package/front_end/panels/sources/ResourceOriginPlugin.ts +14 -17
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +2 -2
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/SourcesView.ts +25 -82
- package/front_end/panels/sources/TabbedEditorContainer.ts +75 -21
- package/front_end/panels/sources/UISourceCodeFrame.ts +22 -13
- package/front_end/panels/sources/sourcesView.css +17 -27
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +1 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/source-map-scopes-codec/README.chromium +2 -2
- package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +14 -1
- package/front_end/third_party/source-map-scopes-codec/package/README.md +8 -6
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +4 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +3 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +4 -3
- package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/deno.json +6 -2
- package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +18 -2
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +22 -3
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +33 -5
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +41 -5
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -2
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +4 -3
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +99 -36
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +143 -49
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +3 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +3 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +40 -18
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +51 -21
- package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +4 -3
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +18 -4
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +1 -1
- package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +18 -4
- package/front_end/ui/comments/CommentOverlayManager.ts +23 -10
- package/front_end/ui/components/text_editor/javascript.ts +128 -52
- package/front_end/ui/legacy/README.md +12 -12
- package/front_end/ui/legacy/SearchableView.ts +125 -74
- package/front_end/ui/legacy/components/source_frame/FontView.ts +5 -5
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +13 -13
- package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +2 -6
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +3 -2
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
- package/front_end/Images/nodeIcon.avif +0 -0
|
@@ -14,7 +14,7 @@ import {SourceMapScopeChainEntry} from './SourceMapScopeChainEntry.js';
|
|
|
14
14
|
|
|
15
15
|
export class SourceMapScopesInfo {
|
|
16
16
|
readonly #sourceMap: SourceMap;
|
|
17
|
-
readonly #originalScopes: Array<ScopesCodec.OriginalScope|null>;
|
|
17
|
+
readonly #originalScopes: Array<ScopesCodec.OriginalScope[]|null>;
|
|
18
18
|
readonly #generatedRanges: ScopesCodec.GeneratedRange[];
|
|
19
19
|
|
|
20
20
|
#cachedVariablesAndBindingsPresent: boolean|null = null;
|
|
@@ -35,20 +35,10 @@ export class SourceMapScopesInfo {
|
|
|
35
35
|
sourceMap: SourceMap, scopeTree: Formatter.FormatterWorkerPool.ScopeTreeNode,
|
|
36
36
|
text: TextUtils.Text.Text): SourceMapScopesInfo {
|
|
37
37
|
const numSourceUrls = sourceMap.sourceURLs().length;
|
|
38
|
-
const
|
|
39
|
-
for (let i = 0; i < numSourceUrls; i++) {
|
|
40
|
-
const scope: ScopesCodec.OriginalScope = {
|
|
41
|
-
start: {line: 0, column: 0},
|
|
42
|
-
end: {line: Number.POSITIVE_INFINITY, column: Number.POSITIVE_INFINITY},
|
|
43
|
-
isStackFrame: false,
|
|
44
|
-
variables: [],
|
|
45
|
-
children: [],
|
|
46
|
-
};
|
|
47
|
-
scopeBySourceUrl.push(scope);
|
|
48
|
-
}
|
|
38
|
+
const scopesBySourceUrl: ScopesCodec.OriginalScope[][] = Array.from({length: numSourceUrls}, () => []);
|
|
49
39
|
|
|
50
40
|
// Convert the entire scopeTree. Returns a root range that encompasses everything,
|
|
51
|
-
// and inserts scopes by sourceIndex into the above
|
|
41
|
+
// and inserts scopes by sourceIndex into the above scopesBySourceUrl.
|
|
52
42
|
const stack: Array<{
|
|
53
43
|
node: Formatter.FormatterWorkerPool.ScopeTreeNode,
|
|
54
44
|
parentRange?: ScopesCodec.GeneratedRange,
|
|
@@ -114,10 +104,8 @@ export class SourceMapScopesInfo {
|
|
|
114
104
|
|
|
115
105
|
let nextParentScopeHint = parentScopeHint;
|
|
116
106
|
if (canMapOriginalPosition && scope) {
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
(parentScopeHint && containsOriginal(parentScopeHint, scope)) ? parentScopeHint : rootScope;
|
|
120
|
-
insertInScope(startSearchFrom, scope);
|
|
107
|
+
const startParent = (parentScopeHint && containsOriginal(parentScopeHint, scope)) ? parentScopeHint : undefined;
|
|
108
|
+
insertInScope(sourceIndex, startParent, scope);
|
|
121
109
|
nextParentScopeHint = scope;
|
|
122
110
|
}
|
|
123
111
|
|
|
@@ -126,20 +114,21 @@ export class SourceMapScopesInfo {
|
|
|
126
114
|
}
|
|
127
115
|
}
|
|
128
116
|
|
|
129
|
-
return new SourceMapScopesInfo(sourceMap, {scopes:
|
|
117
|
+
return new SourceMapScopesInfo(sourceMap, {scopes: scopesBySourceUrl, ranges: rootRange ? [rootRange] : []});
|
|
130
118
|
|
|
131
119
|
/**
|
|
132
120
|
* Finds the correct place in the tree to insert the new scope.
|
|
133
121
|
* Maintains the invariant that children are sorted and contained by their parent.
|
|
134
122
|
*/
|
|
135
|
-
function insertInScope(
|
|
136
|
-
|
|
123
|
+
function insertInScope(sourceIndex: number, parent: ScopesCodec.OriginalScope|undefined,
|
|
124
|
+
newScope: ScopesCodec.OriginalScope): void {
|
|
125
|
+
let children = parent ? parent.children : scopesBySourceUrl[sourceIndex];
|
|
137
126
|
// Check if the newScope fits strictly inside any of the existing children.
|
|
138
127
|
// We iterate to find the deepest parent to avoid Maximum Call Stack Size Exceeded
|
|
139
128
|
// errors on highly nested scripts.
|
|
140
129
|
while (true) {
|
|
141
130
|
let deeperParent: ScopesCodec.OriginalScope|null = null;
|
|
142
|
-
for (const child of
|
|
131
|
+
for (const child of children) {
|
|
143
132
|
if (containsOriginal(child, newScope)) {
|
|
144
133
|
deeperParent = child;
|
|
145
134
|
break;
|
|
@@ -147,17 +136,18 @@ export class SourceMapScopesInfo {
|
|
|
147
136
|
}
|
|
148
137
|
if (deeperParent) {
|
|
149
138
|
parent = deeperParent;
|
|
139
|
+
children = deeperParent.children;
|
|
150
140
|
} else {
|
|
151
141
|
break;
|
|
152
142
|
}
|
|
153
143
|
}
|
|
154
144
|
|
|
155
|
-
// When here, newScope belongs directly in parent.
|
|
156
|
-
// However, newScope might encompass some of
|
|
145
|
+
// When here, newScope belongs directly in parent (or at the root of the source file).
|
|
146
|
+
// However, newScope might encompass some of the existing children (due
|
|
157
147
|
// to compiler transform quirks or arbitrary insertion order). We must move
|
|
158
148
|
// those children inside newScope.
|
|
159
149
|
const childrenToKeep: ScopesCodec.OriginalScope[] = [];
|
|
160
|
-
for (const child of
|
|
150
|
+
for (const child of children) {
|
|
161
151
|
if (containsOriginal(newScope, child)) {
|
|
162
152
|
// child is actually inside newScope, so re-parent it.
|
|
163
153
|
newScope.children.push(child);
|
|
@@ -177,8 +167,12 @@ export class SourceMapScopesInfo {
|
|
|
177
167
|
childrenToKeep.splice(insertIndex, 0, newScope);
|
|
178
168
|
}
|
|
179
169
|
|
|
180
|
-
// Update parent's children to only be the ones that don't belong to newScope.
|
|
181
|
-
parent
|
|
170
|
+
// Update parent's children (or root scopes) to only be the ones that don't belong to newScope.
|
|
171
|
+
if (parent) {
|
|
172
|
+
parent.children = childrenToKeep;
|
|
173
|
+
} else {
|
|
174
|
+
scopesBySourceUrl[sourceIndex] = childrenToKeep;
|
|
175
|
+
}
|
|
182
176
|
newScope.parent = parent;
|
|
183
177
|
}
|
|
184
178
|
|
|
@@ -196,7 +190,7 @@ export class SourceMapScopesInfo {
|
|
|
196
190
|
}
|
|
197
191
|
}
|
|
198
192
|
|
|
199
|
-
addOriginalScopes(scopes: Array<ScopesCodec.OriginalScope|null>): void {
|
|
193
|
+
addOriginalScopes(scopes: Array<ScopesCodec.OriginalScope[]|null>): void {
|
|
200
194
|
for (const scope of scopes) {
|
|
201
195
|
this.#originalScopes.push(scope);
|
|
202
196
|
}
|
|
@@ -209,17 +203,17 @@ export class SourceMapScopesInfo {
|
|
|
209
203
|
}
|
|
210
204
|
|
|
211
205
|
hasOriginalScopes(sourceIdx: number): boolean {
|
|
212
|
-
return Boolean(this.#originalScopes[sourceIdx]);
|
|
206
|
+
return Boolean(this.#originalScopes[sourceIdx]?.length);
|
|
213
207
|
}
|
|
214
208
|
|
|
215
209
|
isEmpty(): boolean {
|
|
216
|
-
const noScopes = this.#originalScopes.every(
|
|
210
|
+
const noScopes = this.#originalScopes.every(scopes => scopes === null || scopes.length === 0);
|
|
217
211
|
return noScopes && !this.#generatedRanges.length;
|
|
218
212
|
}
|
|
219
213
|
|
|
220
|
-
addOriginalScopesAtIndex(sourceIdx: number,
|
|
221
|
-
if (!this.#originalScopes[sourceIdx]) {
|
|
222
|
-
this.#originalScopes[sourceIdx] =
|
|
214
|
+
addOriginalScopesAtIndex(sourceIdx: number, scopes: ScopesCodec.OriginalScope[]): void {
|
|
215
|
+
if (!this.#originalScopes[sourceIdx]?.length) {
|
|
216
|
+
this.#originalScopes[sourceIdx] = scopes;
|
|
223
217
|
} else {
|
|
224
218
|
throw new Error(`Trying to re-augment existing scopes for source at index: ${sourceIdx}`);
|
|
225
219
|
}
|
|
@@ -262,9 +256,10 @@ export class SourceMapScopesInfo {
|
|
|
262
256
|
|
|
263
257
|
/**
|
|
264
258
|
* Given a generated position, this returns all the surrounding generated ranges from outer
|
|
265
|
-
* to inner.
|
|
259
|
+
* to inner. When `inlineFrameIndex > 0`, drops inner ranges up to the specified virtual
|
|
260
|
+
* call frame.
|
|
266
261
|
*/
|
|
267
|
-
#findGeneratedRangeChain(line: number, column: number): ScopesCodec.GeneratedRange[] {
|
|
262
|
+
#findGeneratedRangeChain(line: number, column: number, inlineFrameIndex = 0): ScopesCodec.GeneratedRange[] {
|
|
268
263
|
const result: ScopesCodec.GeneratedRange[] = [];
|
|
269
264
|
|
|
270
265
|
(function walkRanges(ranges: ScopesCodec.GeneratedRange[]) {
|
|
@@ -277,6 +272,17 @@ export class SourceMapScopesInfo {
|
|
|
277
272
|
}
|
|
278
273
|
})(this.#generatedRanges);
|
|
279
274
|
|
|
275
|
+
// Drop ranges in the chain until we reach our desired inlined range.
|
|
276
|
+
for (let inlineIndex = 0; inlineIndex < inlineFrameIndex;) {
|
|
277
|
+
const range = result.pop();
|
|
278
|
+
if (!range) {
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
if (range.callSite) {
|
|
282
|
+
++inlineIndex;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
280
286
|
return result;
|
|
281
287
|
}
|
|
282
288
|
|
|
@@ -295,12 +301,8 @@ export class SourceMapScopesInfo {
|
|
|
295
301
|
// We check whether any original scope has a non-empty list of variables, and
|
|
296
302
|
// generated ranges with a non-empty binding list.
|
|
297
303
|
|
|
298
|
-
function walkTree(nodes:
|
|
304
|
+
function walkTree(nodes: ScopesCodec.OriginalScope[]|ScopesCodec.GeneratedRange[]): boolean {
|
|
299
305
|
for (const node of nodes) {
|
|
300
|
-
if (!node) {
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
306
|
if ('variables' in node && node.variables.length > 0) {
|
|
305
307
|
return true;
|
|
306
308
|
}
|
|
@@ -315,7 +317,7 @@ export class SourceMapScopesInfo {
|
|
|
315
317
|
}
|
|
316
318
|
return false;
|
|
317
319
|
}
|
|
318
|
-
return
|
|
320
|
+
return this.#originalScopes.some(scopes => scopes !== null && walkTree(scopes)) && walkTree(this.#generatedRanges);
|
|
319
321
|
}
|
|
320
322
|
|
|
321
323
|
/**
|
|
@@ -387,28 +389,14 @@ export class SourceMapScopesInfo {
|
|
|
387
389
|
return result;
|
|
388
390
|
}
|
|
389
391
|
|
|
390
|
-
/** Similar to #findGeneratedRangeChain, but takes inlineFrameIndex of virtual call frames into account */
|
|
391
392
|
#findGeneratedRangeChainForFrame(callFrame: CallFrame): ScopesCodec.GeneratedRange[] {
|
|
392
393
|
const {line, column} = scriptRelativePosition(callFrame.location());
|
|
393
|
-
|
|
394
|
-
if (callFrame.inlineFrameIndex === 0) {
|
|
395
|
-
return rangeChain;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Drop ranges in the chain until we reach our desired inlined range.
|
|
399
|
-
for (let inlineIndex = 0; inlineIndex < callFrame.inlineFrameIndex;) {
|
|
400
|
-
const range = rangeChain.pop();
|
|
401
|
-
if (range?.callSite) {
|
|
402
|
-
++inlineIndex;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
return rangeChain;
|
|
394
|
+
return this.#findGeneratedRangeChain(line, column, callFrame.inlineFrameIndex);
|
|
407
395
|
}
|
|
408
396
|
|
|
409
|
-
resolveMappedVariablesAtPosition(line: number, column: number,
|
|
410
|
-
|
|
411
|
-
const rangeChain = this.#findGeneratedRangeChain(line, column);
|
|
397
|
+
resolveMappedVariablesAtPosition(line: number, column: number, ignoreInnerBlockScopes = false,
|
|
398
|
+
inlineFrameIndex = 0): Array<Map<string, string|null>>|null {
|
|
399
|
+
const rangeChain = this.#findGeneratedRangeChain(line, column, inlineFrameIndex);
|
|
412
400
|
const startScope = rangeChain.at(-1)?.originalScope;
|
|
413
401
|
const innerMostScope =
|
|
414
402
|
(startScope && ignoreInnerBlockScopes && this.#findFunctionScopeInOriginalScopeChain(startScope)) || startScope;
|
|
@@ -475,7 +463,7 @@ export class SourceMapScopesInfo {
|
|
|
475
463
|
while (rootScope.parent) {
|
|
476
464
|
rootScope = rootScope.parent;
|
|
477
465
|
}
|
|
478
|
-
const sourceIndex = this.#originalScopes.
|
|
466
|
+
const sourceIndex = this.#originalScopes.findIndex(scopes => scopes?.includes(rootScope));
|
|
479
467
|
const url = sourceIndex !== -1 ? this.#sourceMap.sourceURLForSourceIndex(sourceIndex) : undefined;
|
|
480
468
|
|
|
481
469
|
return functionScope ? {scope: functionScope, url} : null;
|
|
@@ -486,8 +474,8 @@ export class SourceMapScopesInfo {
|
|
|
486
474
|
* to inner.
|
|
487
475
|
*/
|
|
488
476
|
#findOriginalScopeChain({sourceIndex, line, column}: ScopesCodec.OriginalPosition): ScopesCodec.OriginalScope[] {
|
|
489
|
-
const
|
|
490
|
-
if (!
|
|
477
|
+
const scopes = this.#originalScopes[sourceIndex];
|
|
478
|
+
if (!scopes) {
|
|
491
479
|
return [];
|
|
492
480
|
}
|
|
493
481
|
|
|
@@ -500,7 +488,7 @@ export class SourceMapScopesInfo {
|
|
|
500
488
|
result.push(scope);
|
|
501
489
|
walkScopes(scope.children);
|
|
502
490
|
}
|
|
503
|
-
})(
|
|
491
|
+
})(scopes);
|
|
504
492
|
|
|
505
493
|
return result;
|
|
506
494
|
}
|
|
@@ -51,6 +51,24 @@ export const enum ScopeKind {
|
|
|
51
51
|
ARROW_FUNCTION = 4,
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Describes a single scope for `javaScriptSubstitute`.
|
|
56
|
+
*/
|
|
57
|
+
export interface ScopeVariableMapping {
|
|
58
|
+
/**
|
|
59
|
+
* Authored variable name -> generated binding expression, or `null` if the variable is unavailable.
|
|
60
|
+
*/
|
|
61
|
+
bindings: Map<string, string|null>;
|
|
62
|
+
/**
|
|
63
|
+
* Generated identifiers declared by this scope. Together with the free identifiers of `bindings`, these
|
|
64
|
+
* shadow bindings of outer scopes that refer to the same generated identifiers.
|
|
65
|
+
*
|
|
66
|
+
* This is needed when a generated identifier doesn't show up in any binding expression, e.g. because
|
|
67
|
+
* multiple generated identifiers map to the same authored name, or the authored name is unknown.
|
|
68
|
+
*/
|
|
69
|
+
generatedNames: string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
54
72
|
export interface ScopeTreeNode {
|
|
55
73
|
variables: Array<{name: string, kind: DefinitionKind, offsets: number[]}>;
|
|
56
74
|
start: number;
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Acorn from '../../third_party/acorn/acorn.js';
|
|
6
|
-
import {DefinitionKind} from '../formatter_actions/formatter_actions.js';
|
|
6
|
+
import {DefinitionKind, type ScopeVariableMapping} from '../formatter_actions/formatter_actions.js';
|
|
7
7
|
|
|
8
8
|
import {ECMA_VERSION} from './AcornTokenizer.js';
|
|
9
9
|
import {ScopeVariableAnalysis, type VariableUses} from './ScopeParser.js';
|
|
10
10
|
|
|
11
|
-
export function substituteExpression(expression: string,
|
|
12
|
-
const replacements = computeSubstitution(expression,
|
|
11
|
+
export function substituteExpression(expression: string, scopes: ScopeVariableMapping[]): string {
|
|
12
|
+
const replacements = computeSubstitution(expression, scopes);
|
|
13
13
|
return applySubstitution(expression, replacements);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -52,12 +52,12 @@ function parseBindingExpression(expression: string): {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Given an |expression| and a
|
|
55
|
+
* Given an |expression| and a list of |scopes| (from inner-most to outer-most), the |computeSubstitution|
|
|
56
56
|
* function returns a list of replacements sorted by the offset. The function throws if
|
|
57
57
|
* it cannot parse the expression or the substitution is impossible to perform (for example
|
|
58
58
|
* if the substitution target is 'this' within a function, it would become bound there).
|
|
59
59
|
**/
|
|
60
|
-
function computeSubstitution(expression: string,
|
|
60
|
+
function computeSubstitution(expression: string, scopes: ScopeVariableMapping[]): Replacement[] {
|
|
61
61
|
// Parse the expression and find variables and scopes.
|
|
62
62
|
const root = Acorn.parse(expression, {
|
|
63
63
|
ecmaVersion: ECMA_VERSION,
|
|
@@ -75,10 +75,11 @@ function computeSubstitution(expression: string, nameMaps: Array<Map<string, str
|
|
|
75
75
|
const allNames = scopeVariables.getAllNames();
|
|
76
76
|
const nameMap = new Map<string, string|null>();
|
|
77
77
|
const parsedBindings = new Map<string, ReturnType<typeof parseBindingExpression>>();
|
|
78
|
+
// Generated identifiers declared by the scopes visited so far. Outer bindings referring to them are shadowed.
|
|
78
79
|
const shadowedNames = new Set<string>();
|
|
79
|
-
for (const
|
|
80
|
-
const scopeNames = new Set<string>();
|
|
81
|
-
for (const [name, rename] of
|
|
80
|
+
for (const {bindings, generatedNames} of scopes) {
|
|
81
|
+
const scopeNames = new Set<string>(generatedNames);
|
|
82
|
+
for (const [name, rename] of bindings.entries()) {
|
|
82
83
|
let parsed: ReturnType<typeof parseBindingExpression>|undefined;
|
|
83
84
|
if (rename !== null) {
|
|
84
85
|
try {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Platform from '../../core/platform/platform.js';
|
|
6
|
-
import {FormatterActions} from '../formatter_actions/formatter_actions.js';
|
|
6
|
+
import {FormatterActions, type ScopeVariableMapping} from '../formatter_actions/formatter_actions.js';
|
|
7
7
|
|
|
8
8
|
import * as FormatterWorker from './formatter_worker.js';
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ Platform.HostRuntime.HOST_RUNTIME.workerScope.onmessage = function(event): void
|
|
|
13
13
|
indentString: string,
|
|
14
14
|
content: string,
|
|
15
15
|
mimeType: string,
|
|
16
|
-
mapping:
|
|
16
|
+
mapping: ScopeVariableMapping[],
|
|
17
17
|
sourceType: 'module'|'script',
|
|
18
18
|
} = event.data.params;
|
|
19
19
|
if (!method) {
|
|
@@ -29,8 +29,13 @@ Platform.HostRuntime.HOST_RUNTIME.workerScope.onmessage = function(event): void
|
|
|
29
29
|
FormatterWorker.CSSRuleParser.parseCSS(params.content, self.postMessage);
|
|
30
30
|
break;
|
|
31
31
|
case FormatterActions.JAVASCRIPT_SUBSTITUTE: {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
let result: string|{error: string};
|
|
33
|
+
try {
|
|
34
|
+
result = FormatterWorker.Substitute.substituteExpression(params.content, params.mapping);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
result = {error: error instanceof Error ? error.message : String(error)};
|
|
37
|
+
}
|
|
38
|
+
Platform.HostRuntime.HOST_RUNTIME.workerScope.postMessage(result);
|
|
34
39
|
break;
|
|
35
40
|
}
|
|
36
41
|
case FormatterActions.JAVASCRIPT_SCOPE_TREE: {
|
|
@@ -99,14 +99,9 @@ interface HeapScan {
|
|
|
99
99
|
scripts: Map<ScriptNodeIndex, ScriptInfo>;
|
|
100
100
|
contextNodes: ContextNodeInfo[];
|
|
101
101
|
liveClosures: LiveClosure[];
|
|
102
|
-
// Maps a ScopeInfo to the script it belongs to.
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// A stored `undefined` is a memoized failed lookup, i.e. walking the
|
|
107
|
-
// `outer_scope_info` chain of that ScopeInfo did not reach a script. It is
|
|
108
|
-
// therefore not the same as an absent entry, which merely means "not resolved
|
|
109
|
-
// yet", so lookups have to distinguish the two through `has()`.
|
|
102
|
+
// Maps a ScopeInfo to the script it belongs to. A stored `undefined` is a memoized
|
|
103
|
+
// failed lookup. It is therefore not the same as an absent entry, which merely means
|
|
104
|
+
// "not resolved yet".
|
|
110
105
|
scopeInfoScriptNodeIndexes: Map<ScopeInfoNodeIndex, ScriptNodeIndex|undefined>;
|
|
111
106
|
}
|
|
112
107
|
|
|
@@ -257,12 +252,11 @@ function scanHeap(snapshot: HeapSnapshot): HeapScan {
|
|
|
257
252
|
|
|
258
253
|
if (rawName.startsWith('system / Script')) {
|
|
259
254
|
processScript(scripts, node);
|
|
255
|
+
processScriptScopeInfos(scopeInfoScriptNodeIndexes, node);
|
|
260
256
|
} else if (snapshot.isContextObject(node)) {
|
|
261
257
|
processContext(contextNodes, node);
|
|
262
258
|
} else if (node.rawType() === nodeClosureType) {
|
|
263
259
|
processClosure(liveClosures, node);
|
|
264
|
-
} else if (rawName.startsWith('system / SharedFunctionInfo')) {
|
|
265
|
-
processSharedFunctionInfo(scopeInfoScriptNodeIndexes, node);
|
|
266
260
|
}
|
|
267
261
|
}
|
|
268
262
|
|
|
@@ -283,6 +277,137 @@ function processScript(scripts: Map<ScriptNodeIndex, ScriptInfo>, node: HeapSnap
|
|
|
283
277
|
});
|
|
284
278
|
}
|
|
285
279
|
|
|
280
|
+
function processScriptScopeInfos(
|
|
281
|
+
scopeInfoScriptNodeIndexes: Map<ScopeInfoNodeIndex, ScriptNodeIndex|undefined>,
|
|
282
|
+
scriptNode: HeapSnapshotNode,
|
|
283
|
+
): void {
|
|
284
|
+
const infos = scriptNode.findInternalEdgeTarget('infos');
|
|
285
|
+
if (!infos) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const scriptNodeIndex = scriptNode.nodeIndex as ScriptNodeIndex;
|
|
290
|
+
const scopeInfoNode = scriptNode.snapshot.createNode();
|
|
291
|
+
|
|
292
|
+
// A script created by a direct `eval` records the scope its `eval` call appeared in. That scope
|
|
293
|
+
// and the ones enclosing it belong to the calling script, so walks from this script's ScopeInfos
|
|
294
|
+
// have to stop there. This is like V8's `Scope::DeserializeScopeChain` detecting eval boundaries.
|
|
295
|
+
//
|
|
296
|
+
// Stopping at the root scope (see `attributeScopeInfoChain`) is not enough here: the eval scope
|
|
297
|
+
// only gets a ScopeInfo if it needs a context. Without one, the ScopeInfo chains of this script's
|
|
298
|
+
// functions skip it and lead straight to the call-site scope, without passing a root scope.
|
|
299
|
+
//
|
|
300
|
+
// The call-site scope itself is assigned by the calling script, which lists it in its `infos`.
|
|
301
|
+
const evalFromScopeInfo = scriptNode.findInternalEdgeTarget('eval_from_scope_info');
|
|
302
|
+
const stopAtNodeIndex = evalFromScopeInfo?.rawName() === 'system / ScopeInfo' ?
|
|
303
|
+
evalFromScopeInfo.nodeIndex as ScopeInfoNodeIndex :
|
|
304
|
+
undefined;
|
|
305
|
+
|
|
306
|
+
for (let iter = infos.edges(); iter.hasNext(); iter.next()) {
|
|
307
|
+
const info = iter.edge.node();
|
|
308
|
+
const infoName = info.rawName();
|
|
309
|
+
|
|
310
|
+
// Besides SharedFunctionInfos, V8 lists the ScopeInfo of the innermost scope with a context
|
|
311
|
+
// around each direct `eval` call of this script. It belongs to this script, as do the scopes
|
|
312
|
+
// enclosing it up to the root scope of this script.
|
|
313
|
+
if (infoName === 'system / ScopeInfo') {
|
|
314
|
+
attributeScopeInfoChain(scopeInfoScriptNodeIndexes, info.nodeIndex as ScopeInfoNodeIndex, stopAtNodeIndex,
|
|
315
|
+
scriptNodeIndex, scopeInfoNode);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (!infoName.startsWith('system / SharedFunctionInfo')) {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const sharedFunctionInfo = info;
|
|
323
|
+
|
|
324
|
+
// A compiled function has a ScopeInfo of its own in `name_or_scope_info`. It belongs to this
|
|
325
|
+
// script, as do the scopes enclosing it up to the root scope of this script.
|
|
326
|
+
const scopeInfo = sharedFunctionInfo.findInternalEdgeTarget('name_or_scope_info');
|
|
327
|
+
if (scopeInfo?.rawName() === 'system / ScopeInfo') {
|
|
328
|
+
attributeScopeInfoChain(scopeInfoScriptNodeIndexes, scopeInfo.nodeIndex as ScopeInfoNodeIndex, stopAtNodeIndex,
|
|
329
|
+
scriptNodeIndex, scopeInfoNode);
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// While a function is uncompiled it has no ScopeInfo of its own, so use the ScopeInfo of its
|
|
334
|
+
// enclosing scope instead. A script's root function is always compiled, but if it weren't, its
|
|
335
|
+
// enclosing scope would lie outside of this script, so skip it.
|
|
336
|
+
const scopeId = sharedFunctionInfo.findInternalEdgeTarget('scope_id')?.nodeValueAsInt();
|
|
337
|
+
if (scopeId === undefined || isScriptRootScopeId(scopeId)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Except for the root function, the enclosing ScopeInfo belongs to this script. The exception
|
|
342
|
+
// is a function in eval'd code whose eval scope has no context: its enclosing ScopeInfo is then
|
|
343
|
+
// the scope around the `eval` call in the calling script (`eval_from_scope_info`), where
|
|
344
|
+
// `attributeScopeInfoChain` stops.
|
|
345
|
+
const outerScopeInfo = sharedFunctionInfo.findInternalEdgeTarget('raw_outer_scope_info_or_feedback_metadata');
|
|
346
|
+
if (outerScopeInfo?.rawName() === 'system / ScopeInfo') {
|
|
347
|
+
attributeScopeInfoChain(scopeInfoScriptNodeIndexes, outerScopeInfo.nodeIndex as ScopeInfoNodeIndex,
|
|
348
|
+
stopAtNodeIndex, scriptNodeIndex, scopeInfoNode);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Assigns the ScopeInfo at `scopeInfoNodeIndex` and the ones enclosing it to the script at
|
|
355
|
+
* `scriptNodeIndex`. Stops at the root scope of the script, or at `stopAtNodeIndex`, the
|
|
356
|
+
* `eval_from_scope_info` of the script, which belongs to the calling script.
|
|
357
|
+
*
|
|
358
|
+
* Only this function assigns ScopeInfos while scanning the heap, and it always continues up to
|
|
359
|
+
* such a boundary. An already assigned ScopeInfo therefore means that its enclosing ScopeInfos
|
|
360
|
+
* are assigned as well, so the walk can stop there too.
|
|
361
|
+
*/
|
|
362
|
+
function attributeScopeInfoChain(
|
|
363
|
+
scopeInfoScriptNodeIndexes: Map<ScopeInfoNodeIndex, ScriptNodeIndex|undefined>,
|
|
364
|
+
scopeInfoNodeIndex: ScopeInfoNodeIndex,
|
|
365
|
+
stopAtNodeIndex: ScopeInfoNodeIndex|undefined,
|
|
366
|
+
scriptNodeIndex: ScriptNodeIndex,
|
|
367
|
+
scopeInfoNode: HeapSnapshotNode,
|
|
368
|
+
): void {
|
|
369
|
+
let currentNodeIndex = scopeInfoNodeIndex;
|
|
370
|
+
for (;;) {
|
|
371
|
+
if (currentNodeIndex === stopAtNodeIndex) {
|
|
372
|
+
// This is the call site of the `eval` that created this script. It belongs to the calling
|
|
373
|
+
// script.
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (scopeInfoScriptNodeIndexes.has(currentNodeIndex)) {
|
|
377
|
+
// This scope info was already assigned to a script.
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
scopeInfoScriptNodeIndexes.set(currentNodeIndex, scriptNodeIndex);
|
|
381
|
+
|
|
382
|
+
scopeInfoNode.nodeIndex = currentNodeIndex;
|
|
383
|
+
// A root scope's `outer_scope_info` leads into another script (e.g. the one calling `eval`), so
|
|
384
|
+
// stop here. This only catches root scopes that have a context. The call site of a context-less
|
|
385
|
+
// eval scope is caught through `stopAtNodeIndex` above.
|
|
386
|
+
if (isScriptRootScopeInfo(scopeInfoNode)) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
// The outer scope of a non-root scope can be assigned to the same script.
|
|
390
|
+
const outerScopeInfo = scopeInfoNode.findInternalEdgeTarget('outer_scope_info');
|
|
391
|
+
if (!outerScopeInfo) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
currentNodeIndex = outerScopeInfo.nodeIndex as ScopeInfoNodeIndex;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function isScriptRootScopeInfo(node: HeapSnapshotNode): boolean {
|
|
399
|
+
const scopeId = node.findInternalEdgeTarget('scope_id')?.nodeValueAsInt();
|
|
400
|
+
return scopeId !== undefined && isScriptRootScopeId(scopeId);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function isScriptRootScopeId(scopeId: number): boolean {
|
|
404
|
+
// -2 is the scope id V8 gives the outermost scope of a script: its script, eval or module scope.
|
|
405
|
+
// V8 derives scope ids from source positions and uses negative ids for scopes that would otherwise
|
|
406
|
+
// start at position 0. The other one is -1 for a wrapped function (`ScriptCompiler::CompileFunction`),
|
|
407
|
+
// which is still enclosed by an eval scope of the same script.
|
|
408
|
+
return scopeId === -2;
|
|
409
|
+
}
|
|
410
|
+
|
|
286
411
|
function processContext(contextNodes: ContextNodeInfo[], node: HeapSnapshotNode): void {
|
|
287
412
|
const scopeInfoNodeIndex = node.findInternalEdgeTarget('scope_info')?.nodeIndex as ScopeInfoNodeIndex | undefined;
|
|
288
413
|
if (scopeInfoNodeIndex === undefined) {
|
|
@@ -315,16 +440,6 @@ function processClosure(liveClosures: LiveClosure[], node: HeapSnapshotNode): vo
|
|
|
315
440
|
}
|
|
316
441
|
}
|
|
317
442
|
|
|
318
|
-
function processSharedFunctionInfo(scopeInfoScriptNodeIndexes: Map<ScopeInfoNodeIndex, ScriptNodeIndex|undefined>,
|
|
319
|
-
node: HeapSnapshotNode): void {
|
|
320
|
-
const scopeInfo = node.findInternalEdgeTarget('name_or_scope_info');
|
|
321
|
-
const script = node.findInternalEdgeTarget('script');
|
|
322
|
-
if (scopeInfo?.rawName() !== 'system / ScopeInfo' || !script?.rawName().startsWith('system / Script')) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
scopeInfoScriptNodeIndexes.set(scopeInfo.nodeIndex as ScopeInfoNodeIndex, script.nodeIndex as ScriptNodeIndex);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
443
|
function buildLiveFunctions(snapshot: HeapSnapshot, liveClosures: LiveClosure[]): ByScope<LiveFunction> {
|
|
329
444
|
const liveFunctionsByScript: ByScope<LiveFunction> = new Map();
|
|
330
445
|
const node = snapshot.createNode();
|
|
@@ -482,6 +597,11 @@ function resolveScopeInfoScriptNodeIndex(
|
|
|
482
597
|
seen.add(currentNodeIndex);
|
|
483
598
|
visited.push(currentNodeIndex);
|
|
484
599
|
node.nodeIndex = currentNodeIndex;
|
|
600
|
+
if (isScriptRootScopeInfo(node)) {
|
|
601
|
+
// This scope belongs to a script of its own, so leaving it through
|
|
602
|
+
// `outer_scope_info` would attribute it to the wrong script.
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
485
605
|
const outerScopeInfo = node.findInternalEdgeTarget('outer_scope_info');
|
|
486
606
|
if (!outerScopeInfo) {
|
|
487
607
|
break;
|
|
@@ -60,16 +60,22 @@ export class HeapSnapshotLoader {
|
|
|
60
60
|
return result;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Parses (possibly negative) integers from `#json` into `#array`. Assumes
|
|
65
|
+
* valid input. Returns true if more input is needed and false once the
|
|
66
|
+
* closing bracket was reached.
|
|
67
|
+
*/
|
|
68
|
+
#parseIntArray(): boolean {
|
|
64
69
|
let index = 0;
|
|
65
70
|
const char0 = '0'.charCodeAt(0);
|
|
66
71
|
const char9 = '9'.charCodeAt(0);
|
|
72
|
+
const minus = '-'.charCodeAt(0);
|
|
67
73
|
const closingBracket = ']'.charCodeAt(0);
|
|
68
74
|
const length = this.#json.length;
|
|
69
75
|
while (true) {
|
|
70
76
|
while (index < length) {
|
|
71
77
|
const code = this.#json.charCodeAt(index);
|
|
72
|
-
if (char0 <= code && code <= char9) {
|
|
78
|
+
if ((char0 <= code && code <= char9) || code === minus) {
|
|
73
79
|
break;
|
|
74
80
|
} else if (code === closingBracket) {
|
|
75
81
|
this.#json = this.#json.slice(index + 1);
|
|
@@ -81,8 +87,13 @@ export class HeapSnapshotLoader {
|
|
|
81
87
|
this.#json = '';
|
|
82
88
|
return true;
|
|
83
89
|
}
|
|
84
|
-
let nextNumber = 0;
|
|
85
90
|
const startIndex = index;
|
|
91
|
+
let negative = false;
|
|
92
|
+
if (this.#json.charCodeAt(index) === minus) {
|
|
93
|
+
negative = true;
|
|
94
|
+
++index;
|
|
95
|
+
}
|
|
96
|
+
let nextNumber = 0;
|
|
86
97
|
while (index < length) {
|
|
87
98
|
const code = this.#json.charCodeAt(index);
|
|
88
99
|
if (char0 > code || code > char9) {
|
|
@@ -99,7 +110,7 @@ export class HeapSnapshotLoader {
|
|
|
99
110
|
if (!this.#array) {
|
|
100
111
|
throw new Error('Array not instantiated');
|
|
101
112
|
}
|
|
102
|
-
this.#array.setValue(this.#arrayIndex++, nextNumber);
|
|
113
|
+
this.#array.setValue(this.#arrayIndex++, negative ? -nextNumber : nextNumber);
|
|
103
114
|
}
|
|
104
115
|
}
|
|
105
116
|
|
|
@@ -170,7 +181,7 @@ export class HeapSnapshotLoader {
|
|
|
170
181
|
this.#array = length === undefined ? Platform.TypedArrayUtilities.createExpandableBigUint32Array() :
|
|
171
182
|
Platform.TypedArrayUtilities.createFixedBigUint32Array(length);
|
|
172
183
|
this.#arrayIndex = 0;
|
|
173
|
-
while (this.#
|
|
184
|
+
while (this.#parseIntArray()) {
|
|
174
185
|
if (length) {
|
|
175
186
|
this.#progress.updateProgress(title, this.#arrayIndex, this.#array.length);
|
|
176
187
|
} else {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
width: var(--sys-size-12);
|
|
9
9
|
height: 26px;
|
|
10
10
|
/* stylelint-disable-next-line custom-property-pattern */
|
|
11
|
-
background-image: var(--image-file-
|
|
11
|
+
background-image: var(--image-file-nodejsHex);
|
|
12
12
|
background-size: 17px 17px;
|
|
13
13
|
background-repeat: no-repeat;
|
|
14
14
|
background-position: center;
|
|
@@ -21,6 +21,7 @@ import * as LiveMetrics from '../models/live-metrics/live-metrics.js';
|
|
|
21
21
|
import * as Logs from '../models/logs/logs.js';
|
|
22
22
|
import * as Persistence from '../models/persistence/persistence.js';
|
|
23
23
|
import * as ProjectSettings from '../models/project_settings/project_settings.js';
|
|
24
|
+
import * as SourceMapScopes from '../models/source_map_scopes/source_map_scopes.js';
|
|
24
25
|
import * as Workspace from '../models/workspace/workspace.js';
|
|
25
26
|
import * as WorkspaceDiff from '../models/workspace_diff/workspace_diff.js';
|
|
26
27
|
|
|
@@ -160,6 +161,10 @@ export class Universe {
|
|
|
160
161
|
resourceMapping, targetManager, ignoreListManager, workspace);
|
|
161
162
|
context.set(Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding, debuggerWorkspaceBinding);
|
|
162
163
|
|
|
164
|
+
const scopeChainResolver =
|
|
165
|
+
new SourceMapScopes.ScopeChainResolver.ScopeChainResolver(targetManager, debuggerWorkspaceBinding);
|
|
166
|
+
context.set(SourceMapScopes.ScopeChainResolver.ScopeChainResolver, scopeChainResolver);
|
|
167
|
+
|
|
163
168
|
const presentationConsoleMessageManager =
|
|
164
169
|
new Bindings.PresentationConsoleMessageHelper.PresentationConsoleMessageManager(
|
|
165
170
|
targetManager, workspace, debuggerWorkspaceBinding, cssWorkspaceBinding);
|
|
@@ -383,6 +388,10 @@ export class Universe {
|
|
|
383
388
|
null;
|
|
384
389
|
}
|
|
385
390
|
|
|
391
|
+
get scopeChainResolver(): SourceMapScopes.ScopeChainResolver.ScopeChainResolver {
|
|
392
|
+
return this.context.get(SourceMapScopes.ScopeChainResolver.ScopeChainResolver);
|
|
393
|
+
}
|
|
394
|
+
|
|
386
395
|
get settings(): Common.Settings.Settings {
|
|
387
396
|
return this.context.get(Common.Settings.Settings);
|
|
388
397
|
}
|