chrome-devtools-frontend 1.0.1706026 → 1.0.1708524
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/.agents/skills/code-review/SKILL.md +121 -0
- package/front_end/core/sdk/DOMModel.ts +13 -6
- package/front_end/core/sdk/NetworkRequest.ts +43 -7
- package/front_end/core/sdk/SourceMap.ts +4 -13
- package/front_end/core/sdk/SourceMapScopesInfo.ts +134 -86
- package/front_end/core/text_utils/ContentData.ts +18 -1
- package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +102 -4
- package/front_end/generated/InspectorBackendCommands.ts +7 -1
- package/front_end/generated/SupportedCSSProperties.ts +11 -2
- package/front_end/generated/protocol-mapping.d.ts +31 -0
- package/front_end/generated/protocol-proxy-api.d.ts +32 -0
- package/front_end/generated/protocol.ts +11 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +1 -0
- package/front_end/models/ai_assistance/data_formatters/LighthouseFormatter.ts +26 -3
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +15 -16
- package/front_end/models/ai_assistance/skills/Skill.ts +1 -2
- package/front_end/models/ai_assistance/skills/SkillRegistry.ts +2 -0
- package/front_end/models/ai_assistance/skills/lighthouse.md +33 -0
- package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +6 -6
- package/front_end/models/ai_assistance/tools/RunLighthouse.ts +8 -5
- package/front_end/models/bindings/CompilerScriptMapping.ts +102 -45
- package/front_end/models/bindings/DebuggerLanguagePlugins.ts +25 -33
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +33 -39
- package/front_end/models/bindings/StylesSourceMapping.ts +3 -0
- package/front_end/models/extensions/ExtensionEndpoint.ts +27 -6
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +106 -21
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +4 -2
- package/front_end/models/javascript_metadata/NativeFunctions.ts +6 -2
- package/front_end/models/persistence/NetworkPersistenceManager.ts +4 -3
- package/front_end/models/source_map_scopes/NamesResolver.ts +0 -8
- package/front_end/models/stack_trace/StackTraceImpl.ts +138 -47
- package/front_end/models/stack_trace/StackTraceModel.ts +117 -84
- package/front_end/models/stack_trace/Trie.ts +27 -0
- package/front_end/panels/accessibility/ARIAAttributesView.ts +6 -6
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +2 -2
- package/front_end/panels/accessibility/AccessibilityNodeView.ts +6 -9
- package/front_end/panels/accessibility/AccessibilitySidebarView.ts +83 -69
- package/front_end/panels/accessibility/AccessibilitySubPane.ts +24 -9
- package/front_end/panels/accessibility/SourceOrderView.ts +7 -3
- package/front_end/panels/accessibility/accessibilitySidebarView.css +5 -3
- package/front_end/panels/application/serviceWorkersView.css +1 -1
- package/front_end/panels/common/CommentThreadWidget.ts +30 -1
- package/front_end/panels/common/CommentsOverlayWidget.ts +42 -38
- package/front_end/panels/common/common-meta.ts +21 -9
- package/front_end/panels/console/ConsoleInsightTeaser.ts +25 -19
- package/front_end/panels/console/ConsoleViewMessage.ts +51 -21
- package/front_end/panels/console/console-meta.ts +1 -5
- package/front_end/panels/elements/DOMTreeWidget.ts +207 -586
- package/front_end/panels/elements/ElementsPanel.ts +1 -5
- package/front_end/panels/elements/StylePropertyTreeElement.ts +100 -5
- package/front_end/panels/lighthouse/LighthouseController.ts +9 -4
- package/front_end/panels/network/NetworkConfigView.ts +231 -187
- package/front_end/panels/network/RequestPayloadView.ts +22 -14
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +0 -1
- package/front_end/panels/recorder/RecordingView.ts +42 -47
- package/front_end/panels/recorder/StepEditor.ts +1 -0
- package/front_end/panels/recorder/recordingView.css +4 -4
- package/front_end/panels/sources/CSSPlugin.ts +11 -0
- package/front_end/panels/sources/CoveragePlugin.ts +34 -23
- package/front_end/panels/sources/NavigatorView.ts +97 -52
- package/front_end/panels/sources/Plugin.ts +15 -1
- package/front_end/panels/sources/SourcesView.ts +47 -80
- package/front_end/panels/sources/TabbedEditorContainer.ts +27 -2
- package/front_end/panels/sources/UISourceCodeFrame.ts +11 -2
- package/front_end/panels/sources/navigatorTree.css +2 -2
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +17 -0
- package/front_end/ui/components/suggestion_input/SuggestionInput.ts +10 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionTeaser.ts +1 -1
- package/front_end/ui/components/text_editor/AiCodeGenerationTeaser.ts +2 -2
- package/front_end/ui/components/text_editor/aiCodeCompletionTeaser.css +0 -11
- package/front_end/ui/components/text_editor/aiCodeGenerationTeaser.css +0 -11
- package/front_end/ui/legacy/SoftDropDown.ts +17 -4
- package/front_end/ui/legacy/StackPane.ts +141 -0
- package/front_end/ui/legacy/TextPrompt.ts +37 -7
- package/front_end/ui/legacy/Toolbar.ts +7 -5
- package/front_end/ui/legacy/Widget.ts +3 -3
- package/front_end/ui/legacy/components/inline_editor/PositionAreaEditor.ts +85 -0
- package/front_end/ui/legacy/components/inline_editor/positionAreaEditor.css +61 -0
- package/front_end/ui/legacy/components/utils/Linkifier.ts +21 -45
- package/front_end/ui/legacy/inspectorCommon.css +11 -0
- package/front_end/ui/legacy/legacy.ts +2 -0
- package/front_end/ui/legacy/softContextMenu.css +2 -0
- package/front_end/ui/settings/ConsoleSettings.ts +7 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +10 -0
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import type * as LHModel from '../../lighthouse/lighthouse.js';
|
|
7
|
-
import {LighthouseFormatter} from '../data_formatters/LighthouseFormatter.js';
|
|
7
|
+
import {type LighthouseCategoryArg, LighthouseFormatter} from '../data_formatters/LighthouseFormatter.js';
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
type BaseToolCapability,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
|
|
18
18
|
export interface RunLighthouseArgs extends ToolArgs {
|
|
19
19
|
explanation: string;
|
|
20
|
-
categoryId:
|
|
20
|
+
categoryId: LighthouseCategoryArg;
|
|
21
21
|
mode?: LHModel.RunTypes.RunMode;
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -39,7 +39,9 @@ export class RunLighthouseTool implements
|
|
|
39
39
|
},
|
|
40
40
|
categoryId: {
|
|
41
41
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
42
|
-
|
|
42
|
+
// The experimental 'agentic-browsing' category is intentionally omitted from the prompt description so the agent does not invoke it unprompted. It is also excluded when 'all' is provided.
|
|
43
|
+
description:
|
|
44
|
+
'Lighthouse category. Use "all" to run all categories, or specify a category: "accessibility", "performance", "best-practices", "seo".',
|
|
43
45
|
nullable: false,
|
|
44
46
|
},
|
|
45
47
|
mode: {
|
|
@@ -64,16 +66,17 @@ export class RunLighthouseTool implements
|
|
|
64
66
|
Promise<DataHandlerResult<{audits: string}>> {
|
|
65
67
|
const mode = params.mode ?? 'snapshot';
|
|
66
68
|
try {
|
|
69
|
+
// Passing undefined for categoryIds instructs the Lighthouse runner to audit all categories supported by the mode when isAIControlled is true.
|
|
67
70
|
const report = await context.runLighthouse({
|
|
68
71
|
mode,
|
|
69
|
-
categoryIds: [params.categoryId],
|
|
72
|
+
categoryIds: params.categoryId === 'all' ? undefined : [params.categoryId],
|
|
70
73
|
isAIControlled: true,
|
|
71
74
|
});
|
|
72
75
|
if (!report) {
|
|
73
76
|
return {error: 'Error: Failed to record new audits.'};
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
const audits = new LighthouseFormatter().
|
|
79
|
+
const audits = new LighthouseFormatter().formatReport(report, params.categoryId);
|
|
77
80
|
const isSnapshot = mode === 'snapshot';
|
|
78
81
|
return {
|
|
79
82
|
result: {audits},
|
|
@@ -75,6 +75,11 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
75
75
|
ranges: SDK.SourceMapFunctionRanges.NamedFunctionRange[]): void {
|
|
76
76
|
for (const sourceMap of this.#uiSourceCodeToSourceMaps.get(uiSourceCode)) {
|
|
77
77
|
sourceMap.augmentWithScopes(uiSourceCode.url(), ranges);
|
|
78
|
+
// The scopes information changed, so stack traces of the script need to be re-translated.
|
|
79
|
+
const script = this.#sourceMapManager.clientForSourceMap(sourceMap);
|
|
80
|
+
if (script) {
|
|
81
|
+
void this.#debuggerWorkspaceBinding.updateLocations(script);
|
|
82
|
+
}
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
|
|
@@ -96,6 +101,11 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
|
|
104
|
+
/** @returns whether `uiSourceCode` is a placeholder for a script whose source map is still loading. */
|
|
105
|
+
isStubUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
|
|
106
|
+
return uiSourceCode.project() === this.#stubProject;
|
|
107
|
+
}
|
|
108
|
+
|
|
99
109
|
getLocationRangesForSameSourceLocation(rawLocation: SDK.DebuggerModel.Location): SDK.DebuggerModel.LocationRange[] {
|
|
100
110
|
const debuggerModel = rawLocation.debuggerModel;
|
|
101
111
|
const script = rawLocation.script();
|
|
@@ -322,60 +332,92 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
322
332
|
return new Workspace.UISourceCode.UIFunctionBounds(uiSourceCode, range, name);
|
|
323
333
|
}
|
|
324
334
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
335
|
+
/**
|
|
336
|
+
* Translates a raw frame using the "scopes" information of its script's source map. Frames of compiler helpers
|
|
337
|
+
* are dropped (see {@link SDK.SourceMapScopesInfo.GeneratedFrameKind}).
|
|
338
|
+
*
|
|
339
|
+
* Outlined frames are merged at read time by the stack_trace model (see `consolidate`). The function keys
|
|
340
|
+
* tell it which authored function the top and bottom frames of a translation belong to. A frame at an
|
|
341
|
+
* unmapped position still gets its keys from the generated ranges; it shows the generated location, named
|
|
342
|
+
* after the authored function.
|
|
343
|
+
*
|
|
344
|
+
* @returns null if the raw frame can't be translated via "scopes" information, e.g. because the script doesn't
|
|
345
|
+
* have a source map (with scopes information), the source map is still loading, or neither mappings nor
|
|
346
|
+
* generated ranges know the position. It's then left to the default mapping.
|
|
347
|
+
*/
|
|
348
|
+
async translateRawFrame(rawFrame: StackTraceImpl.Trie.RawFrame):
|
|
349
|
+
Promise<StackTraceImpl.StackTraceModel.TranslatedRawFrame|null> {
|
|
350
|
+
const translation = await this.#scopesTranslation(rawFrame);
|
|
351
|
+
if (!translation) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
if (translation.kind === SDK.SourceMapScopesInfo.GeneratedFrameKind.HIDDEN) {
|
|
355
|
+
// Compiler helpers don't represent any authored code.
|
|
356
|
+
return {kind: StackTraceImpl.Trie.FrameKind.HIDDEN, frames: []};
|
|
357
|
+
}
|
|
358
|
+
const {frames} = translation;
|
|
359
|
+
if (!frames.length) {
|
|
360
|
+
return null;
|
|
331
361
|
}
|
|
362
|
+
return {
|
|
363
|
+
kind: translation.kind === SDK.SourceMapScopesInfo.GeneratedFrameKind.OUTLINED ?
|
|
364
|
+
StackTraceImpl.Trie.FrameKind.OUTLINED :
|
|
365
|
+
StackTraceImpl.Trie.FrameKind.VISIBLE,
|
|
366
|
+
frames: await this.#toUIFrames(translation, rawFrame),
|
|
367
|
+
functionKeys: {top: functionKey(frames[0]), bottom: functionKey(frames[frames.length - 1])},
|
|
368
|
+
};
|
|
369
|
+
}
|
|
332
370
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
371
|
+
/** The raw translation of `rawFrame` by the "scopes" information of its script's source map, if any. */
|
|
372
|
+
async #scopesTranslation(rawFrame: StackTraceImpl.Trie.RawFrame): Promise<ScopesTranslation|null> {
|
|
373
|
+
if (StackTraceImpl.Trie.isBuiltinFrame(rawFrame)) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
340
376
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
377
|
+
const script = this.#debuggerModel.scriptForId(rawFrame.scriptId ?? '');
|
|
378
|
+
if (!script || this.#stubUISourceCodes.has(script)) {
|
|
379
|
+
// Use fallback while source map is being loaded.
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
345
382
|
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
383
|
+
const sourceMap = script.sourceMap();
|
|
384
|
+
await sourceMap?.waitForScopeInfo();
|
|
385
|
+
if (!sourceMap?.hasScopeInfo()) {
|
|
386
|
+
return null;
|
|
349
387
|
}
|
|
350
|
-
const {sourceMap, script} = sourceMapAndScript;
|
|
351
|
-
const {lineNumber, columnNumber} = script.rawLocationToRelativeLocation(frame);
|
|
352
388
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
389
|
+
const {lineNumber, columnNumber} = script.rawLocationToRelativeLocation(rawFrame);
|
|
390
|
+
const translation = sourceMap.translateRawFrame(lineNumber, columnNumber);
|
|
391
|
+
return translation ? {...translation, sourceMap, script} : null;
|
|
392
|
+
}
|
|
358
393
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
url: uiSourceCode ? undefined : frame.url,
|
|
370
|
-
uiSourceCode: uiSourceCode ?? undefined,
|
|
371
|
-
});
|
|
394
|
+
/**
|
|
395
|
+
* Switch out url for UISourceCode where we have it. A top frame without position (unmapped generated position)
|
|
396
|
+
* gets the generated location of `rawFrame`.
|
|
397
|
+
*/
|
|
398
|
+
async #toUIFrames({sourceMap, script, frames}: ScopesTranslation, rawFrame: StackTraceImpl.Trie.RawFrame):
|
|
399
|
+
Promise<StackTraceImpl.StackTraceModel.TranslatedUIFrame[]> {
|
|
400
|
+
const project = this.#sourceMapToProject.get(sourceMap);
|
|
401
|
+
return await Promise.all(frames.map(async ({line, column, name, url}) => {
|
|
402
|
+
if (line === undefined || column === undefined) {
|
|
403
|
+
return {...await this.#generatedUIFrame(script, rawFrame), name};
|
|
372
404
|
}
|
|
405
|
+
const uiSourceCode = url ? project?.uiSourceCodeForURL(url) : undefined;
|
|
406
|
+
return {line, column, name, url: uiSourceCode ? undefined : url, uiSourceCode: uiSourceCode ?? undefined};
|
|
407
|
+
}));
|
|
408
|
+
}
|
|
373
409
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
410
|
+
/** The location of `rawFrame` in terms of the generated `script`, as the non-compiler mappings would show it. */
|
|
411
|
+
async #generatedUIFrame(script: SDK.Script.Script, rawFrame: StackTraceImpl.Trie.RawFrame):
|
|
412
|
+
Promise<StackTraceImpl.StackTraceModel.TranslatedUIFrame> {
|
|
413
|
+
const rawLocation = this.#debuggerModel.createRawLocation(script, rawFrame.lineNumber, rawFrame.columnNumber);
|
|
414
|
+
// Goes through the DebuggerWorkspaceBinding so that e.g. inline scripts resolve to their document.
|
|
415
|
+
const uiLocation = await this.#debuggerWorkspaceBinding.rawLocationToUILocation(rawLocation);
|
|
416
|
+
if (uiLocation) {
|
|
417
|
+
const {uiSourceCode, lineNumber: line, columnNumber} = uiLocation;
|
|
418
|
+
return {uiSourceCode, line, column: columnNumber ?? -1};
|
|
419
|
+
}
|
|
420
|
+
return {url: rawFrame.url, line: rawFrame.lineNumber, column: rawFrame.columnNumber};
|
|
379
421
|
}
|
|
380
422
|
|
|
381
423
|
/**
|
|
@@ -594,3 +636,18 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
594
636
|
this.#stubProject.dispose();
|
|
595
637
|
}
|
|
596
638
|
}
|
|
639
|
+
|
|
640
|
+
type ScopesTranslation = SDK.SourceMapScopesInfo.RawFrameTranslation&{
|
|
641
|
+
sourceMap: SDK.SourceMap.SourceMap,
|
|
642
|
+
script: SDK.Script.Script,
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Identifies the authored function of a translated frame. The frames can originate from different source maps
|
|
647
|
+
* (bundles), so we can't compare original scopes directly. The start position tells apart anonymous and
|
|
648
|
+
* same-named functions in one file. All top-level code of a file shares a key.
|
|
649
|
+
*/
|
|
650
|
+
function functionKey(frame: SDK.SourceMapScopesInfo.TranslatedFrame): string {
|
|
651
|
+
const start = frame.functionStart ? `${frame.functionStart.line}:${frame.functionStart.column}` : '';
|
|
652
|
+
return `${frame.url ?? ''}\n${frame.name ?? ''}\n${start}`;
|
|
653
|
+
}
|
|
@@ -12,7 +12,7 @@ import * as TextUtils from '../../core/text_utils/text_utils.js';
|
|
|
12
12
|
import * as Protocol from '../../generated/protocol.js';
|
|
13
13
|
import * as StackTrace from '../stack_trace/stack_trace.js';
|
|
14
14
|
// eslint-disable-next-line @devtools/es-modules-import
|
|
15
|
-
import
|
|
15
|
+
import * as StackTraceImpl from '../stack_trace/stack_trace_impl.js';
|
|
16
16
|
import * as Workspace from '../workspace/workspace.js';
|
|
17
17
|
|
|
18
18
|
import {ContentProviderBasedProject} from './ContentProviderBasedProject.js';
|
|
@@ -166,7 +166,8 @@ class SourceScopeRemoteObject extends SDK.RemoteObject.RemoteObjectImpl {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
const properties = [];
|
|
169
|
-
const namespaces: Record<string, SDK.RemoteObject.RemoteObject> =
|
|
169
|
+
const namespaces: Record<string, SDK.RemoteObject.RemoteObject> =
|
|
170
|
+
Object.create(null) as Record<string, SDK.RemoteObject.RemoteObject>;
|
|
170
171
|
|
|
171
172
|
function makeProperty(name: string, obj: SDK.RemoteObject.RemoteObject): SDK.RemoteObject.RemoteObjectProperty {
|
|
172
173
|
return new SDK.RemoteObject.RemoteObjectProperty(
|
|
@@ -190,7 +191,7 @@ class SourceScopeRemoteObject extends SDK.RemoteObject.RemoteObjectImpl {
|
|
|
190
191
|
const nestedName = variable.nestedName[index];
|
|
191
192
|
let child: NamespaceObject|SDK.RemoteObject.RemoteObject = parent[nestedName];
|
|
192
193
|
if (!child) {
|
|
193
|
-
child = new NamespaceObject(
|
|
194
|
+
child = new NamespaceObject(Object.create(null));
|
|
194
195
|
parent[nestedName] = child;
|
|
195
196
|
}
|
|
196
197
|
parent = child.value;
|
|
@@ -561,6 +562,9 @@ export class DebuggerLanguagePluginManager implements
|
|
|
561
562
|
// new instance of the #plugin added before we remove
|
|
562
563
|
// the previous instance.
|
|
563
564
|
this.parsedScriptSource({data: script});
|
|
565
|
+
if (!this.hasPluginForScript(script)) {
|
|
566
|
+
void this.#debuggerWorkspaceBinding.updateLocations(script);
|
|
567
|
+
}
|
|
564
568
|
}
|
|
565
569
|
}
|
|
566
570
|
|
|
@@ -731,25 +735,24 @@ export class DebuggerLanguagePluginManager implements
|
|
|
731
735
|
return ranges;
|
|
732
736
|
}
|
|
733
737
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
738
|
+
/**
|
|
739
|
+
* Translates a raw frame via the language plugin responsible for its script.
|
|
740
|
+
*
|
|
741
|
+
* @returns null if no plugin is responsible for the frame. Otherwise the frame is translated, either
|
|
742
|
+
* successfully, or identity mapped with the "missing debug info details" attached.
|
|
743
|
+
*/
|
|
744
|
+
async translateRawFrame(frame: StackTraceImpl.Trie.RawFrame,
|
|
745
|
+
target: SDK.Target.Target): Promise<StackTraceImpl.StackTraceModel.TranslatedRawFrame|null> {
|
|
739
746
|
const script = target.model(SDK.DebuggerModel.DebuggerModel)?.scriptForId(frame.scriptId ?? '');
|
|
740
747
|
if (!script) {
|
|
741
|
-
return
|
|
748
|
+
return null;
|
|
742
749
|
}
|
|
743
750
|
|
|
744
751
|
const functionInfo = await this.getFunctionInfo(script, frame);
|
|
745
752
|
if (!functionInfo) {
|
|
746
|
-
return
|
|
753
|
+
return null;
|
|
747
754
|
}
|
|
748
755
|
|
|
749
|
-
// The plugin is responsible for translating this frame. The only question is whether it was successful,
|
|
750
|
-
// or if we identity map the raw frame and attach the "missing debug info details".
|
|
751
|
-
rawFrames.shift();
|
|
752
|
-
|
|
753
756
|
if ('frames' in functionInfo && functionInfo.frames.length) {
|
|
754
757
|
const framePromises = functionInfo.frames.map(async ({name}, index) => {
|
|
755
758
|
const rawLocation = new SDK.DebuggerModel.Location(
|
|
@@ -758,8 +761,7 @@ export class DebuggerLanguagePluginManager implements
|
|
|
758
761
|
return translatedFromUILocation(uiLocation, name, frame);
|
|
759
762
|
});
|
|
760
763
|
|
|
761
|
-
|
|
762
|
-
return true;
|
|
764
|
+
return {kind: StackTraceImpl.Trie.FrameKind.VISIBLE, frames: await Promise.all(framePromises), unmapped: false};
|
|
763
765
|
}
|
|
764
766
|
|
|
765
767
|
// Translate the location only. We go through via "DebuggerWorkspaceBinding". It'll still try the plugin
|
|
@@ -768,28 +770,18 @@ export class DebuggerLanguagePluginManager implements
|
|
|
768
770
|
new SDK.DebuggerModel.Location(script.debuggerModel, script.scriptId, frame.lineNumber, frame.columnNumber));
|
|
769
771
|
const mappedFrame = translatedFromUILocation(uiLocation, frame.functionName, frame);
|
|
770
772
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
missingDebugInfo: {
|
|
773
|
+
const missingDebugInfo: StackTrace.StackTrace.MissingDebugInfo =
|
|
774
|
+
'missingSymbolFiles' in functionInfo && functionInfo.missingSymbolFiles.length ?
|
|
775
|
+
{
|
|
775
776
|
type: StackTrace.StackTrace.MissingDebugInfoType.PARTIAL_INFO,
|
|
776
777
|
missingDebugFiles: functionInfo.missingSymbolFiles,
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
translatedFrames.push([{
|
|
781
|
-
...mappedFrame,
|
|
782
|
-
missingDebugInfo: {
|
|
783
|
-
type: StackTrace.StackTrace.MissingDebugInfoType.NO_INFO,
|
|
784
|
-
},
|
|
785
|
-
}]);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
return true;
|
|
778
|
+
} :
|
|
779
|
+
{type: StackTrace.StackTrace.MissingDebugInfoType.NO_INFO};
|
|
780
|
+
return {kind: StackTraceImpl.Trie.FrameKind.VISIBLE, frames: [{...mappedFrame, missingDebugInfo}], unmapped: true};
|
|
789
781
|
|
|
790
782
|
function translatedFromUILocation(
|
|
791
783
|
uiLocation: Workspace.UISourceCode.UILocation|null, name: string|undefined,
|
|
792
|
-
fallback: StackTraceImpl.Trie.RawFrame):
|
|
784
|
+
fallback: StackTraceImpl.Trie.RawFrame): StackTraceImpl.StackTraceModel.TranslatedUIFrame {
|
|
793
785
|
if (uiLocation) {
|
|
794
786
|
return {
|
|
795
787
|
uiSourceCode: uiLocation.uiSourceCode,
|
|
@@ -517,32 +517,29 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
517
517
|
|
|
518
518
|
async #translateRawFrames(frames: readonly StackTraceImpl.Trie.RawFrame[], target: SDK.Target.Target):
|
|
519
519
|
ReturnType<StackTraceImpl.StackTraceModel.TranslateRawFrames> {
|
|
520
|
-
|
|
521
|
-
const translatedFrames: Awaited<ReturnType<StackTraceImpl.StackTraceModel.TranslateRawFrames>> = [];
|
|
522
|
-
while (rawFrames.length) {
|
|
523
|
-
await this.#translateRawFramesStep(rawFrames, translatedFrames, target);
|
|
524
|
-
}
|
|
525
|
-
return translatedFrames;
|
|
520
|
+
return await Promise.all(frames.map(frame => this.#translateRawFrame(frame, target)));
|
|
526
521
|
}
|
|
527
522
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (
|
|
533
|
-
return;
|
|
523
|
+
/** Translates a single raw frame: language plugins first, then the script mappings of the frame's debugger model. */
|
|
524
|
+
async #translateRawFrame(frame: StackTraceImpl.Trie.RawFrame,
|
|
525
|
+
target: SDK.Target.Target): Promise<StackTraceImpl.StackTraceModel.TranslatedRawFrame> {
|
|
526
|
+
const pluginTranslation = await this.pluginManager.translateRawFrame(frame, target);
|
|
527
|
+
if (pluginTranslation) {
|
|
528
|
+
return pluginTranslation;
|
|
534
529
|
}
|
|
535
530
|
|
|
536
531
|
const modelData =
|
|
537
532
|
this.#debuggerModelToData.get(target.model(SDK.DebuggerModel.DebuggerModel) as SDK.DebuggerModel.DebuggerModel);
|
|
538
533
|
if (modelData) {
|
|
539
|
-
await modelData.
|
|
540
|
-
return;
|
|
534
|
+
return await modelData.translateRawFrame(frame);
|
|
541
535
|
}
|
|
542
536
|
|
|
543
|
-
const frame = rawFrames.shift() as StackTraceImpl.Trie.RawFrame;
|
|
544
537
|
const {url, lineNumber, columnNumber, functionName} = frame;
|
|
545
|
-
|
|
538
|
+
return {
|
|
539
|
+
kind: StackTraceImpl.Trie.FrameKind.VISIBLE,
|
|
540
|
+
frames: [{url, line: lineNumber, column: columnNumber, name: functionName}],
|
|
541
|
+
unmapped: true,
|
|
542
|
+
};
|
|
546
543
|
}
|
|
547
544
|
}
|
|
548
545
|
|
|
@@ -592,8 +589,12 @@ class ModelData {
|
|
|
592
589
|
}
|
|
593
590
|
|
|
594
591
|
rawLocationToUILocation(rawLocation: SDK.DebuggerModel.Location): Workspace.UISourceCode.UILocation|null {
|
|
595
|
-
|
|
596
|
-
|
|
592
|
+
return this.compilerMapping.rawLocationToUILocation(rawLocation) ||
|
|
593
|
+
this.#nonCompilerRawLocationToUILocation(rawLocation);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
#nonCompilerRawLocationToUILocation(rawLocation: SDK.DebuggerModel.Location): Workspace.UISourceCode.UILocation|null {
|
|
597
|
+
let uiLocation = this.#resourceScriptMapping.rawLocationToUILocation(rawLocation);
|
|
597
598
|
uiLocation = uiLocation || this.#resourceMapping.jsLocationToUILocation(rawLocation);
|
|
598
599
|
uiLocation = uiLocation || this.#defaultMapping.rawLocationToUILocation(rawLocation);
|
|
599
600
|
return uiLocation;
|
|
@@ -646,37 +647,30 @@ class ModelData {
|
|
|
646
647
|
return scope;
|
|
647
648
|
}
|
|
648
649
|
|
|
649
|
-
async
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (!await this.compilerMapping.translateRawFramesStep(rawFrames, translatedFrames)) {
|
|
653
|
-
this.#defaultTranslateRawFramesStep(rawFrames, translatedFrames);
|
|
654
|
-
}
|
|
650
|
+
async translateRawFrame(frame: StackTraceImpl.Trie.RawFrame):
|
|
651
|
+
Promise<StackTraceImpl.StackTraceModel.TranslatedRawFrame> {
|
|
652
|
+
return await this.compilerMapping.translateRawFrame(frame) ?? this.#defaultTranslateRawFrame(frame);
|
|
655
653
|
}
|
|
656
654
|
|
|
657
|
-
/** The default
|
|
658
|
-
#
|
|
659
|
-
rawFrames: StackTraceImpl.Trie.RawFrame[],
|
|
660
|
-
translatedFrames: Awaited<ReturnType<StackTraceImpl.StackTraceModel.TranslateRawFrames>>): void {
|
|
661
|
-
const frame = rawFrames.shift() as StackTraceImpl.Trie.RawFrame;
|
|
655
|
+
/** The default translation only translates the location, but not the function name. */
|
|
656
|
+
#defaultTranslateRawFrame(frame: StackTraceImpl.Trie.RawFrame): StackTraceImpl.StackTraceModel.TranslatedRawFrame {
|
|
662
657
|
const {scriptId, url, lineNumber, columnNumber, functionName} = frame;
|
|
663
658
|
const rawLocation = scriptId ? this.#debuggerModel.createRawLocationByScriptId(scriptId, lineNumber, columnNumber) :
|
|
664
659
|
url ? this.#debuggerModel.createRawLocationByURL(url, lineNumber, columnNumber) :
|
|
665
660
|
null;
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
661
|
+
const mapped = rawLocation && this.compilerMapping.rawLocationToUILocation(rawLocation);
|
|
662
|
+
// A stub UISourceCode shows the generated script while its source map is loading.
|
|
663
|
+
const unmapped = !mapped || this.compilerMapping.isStubUISourceCode(mapped.uiSourceCode);
|
|
664
|
+
const uiLocation = mapped || (rawLocation && this.#nonCompilerRawLocationToUILocation(rawLocation));
|
|
665
|
+
const translatedFrame: StackTraceImpl.StackTraceModel.TranslatedUIFrame = uiLocation ?
|
|
666
|
+
{
|
|
670
667
|
uiSourceCode: uiLocation.uiSourceCode,
|
|
671
668
|
name: functionName,
|
|
672
669
|
line: uiLocation.lineNumber,
|
|
673
670
|
column: uiLocation.columnNumber ?? -1,
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
translatedFrames.push([{url, line: lineNumber, column: columnNumber, name: functionName}]);
|
|
671
|
+
} :
|
|
672
|
+
{url, line: lineNumber, column: columnNumber, name: functionName};
|
|
673
|
+
return {kind: StackTraceImpl.Trie.FrameKind.VISIBLE, frames: [translatedFrame], unmapped};
|
|
680
674
|
}
|
|
681
675
|
|
|
682
676
|
getMappedLines(uiSourceCode: Workspace.UISourceCode.UISourceCode): Set<number>|null {
|
|
@@ -176,6 +176,9 @@ export class StyleFile implements TextUtils.ContentProvider.ContentProvider {
|
|
|
176
176
|
this.uiSourceCode = this.#project.createUISourceCode(url, header.contentType());
|
|
177
177
|
uiSourceCodeToStyleMap.set(this.uiSourceCode, this);
|
|
178
178
|
NetworkProject.setInitialFrameAttribution(this.uiSourceCode, header.frameId);
|
|
179
|
+
if (header.hasSourceURL) {
|
|
180
|
+
NetworkProject.setSourceURLSynthesized(this.uiSourceCode);
|
|
181
|
+
}
|
|
179
182
|
this.#project.addUISourceCodeWithProvider(this.uiSourceCode, this, metadata, 'text/css');
|
|
180
183
|
|
|
181
184
|
this.#eventListeners = [
|
|
@@ -14,6 +14,13 @@ interface EventMessage {
|
|
|
14
14
|
event: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
interface Message {
|
|
18
|
+
data: Response|EventMessage;
|
|
19
|
+
}
|
|
20
|
+
type ResultValidator<T> = (result: unknown) => result is T;
|
|
21
|
+
|
|
22
|
+
const isUndefined = (result: unknown): result is undefined => result === undefined;
|
|
23
|
+
|
|
17
24
|
export class ExtensionEndpoint {
|
|
18
25
|
private readonly port: Platform.HostRuntime.WorkerMessagePort;
|
|
19
26
|
private nextRequestId = 0;
|
|
@@ -24,16 +31,30 @@ export class ExtensionEndpoint {
|
|
|
24
31
|
|
|
25
32
|
constructor(port: Platform.HostRuntime.WorkerMessagePort) {
|
|
26
33
|
this.port = port;
|
|
27
|
-
this.port.addEventListener('message', (event: unknown) => this.onResponse(event as
|
|
34
|
+
this.port.addEventListener('message', (event: unknown) => this.onResponse(event as Message));
|
|
28
35
|
(this.port as {start?: () => void}).start?.();
|
|
29
36
|
(this.port as {unref?: () => void}).unref?.();
|
|
30
37
|
this.pendingRequests = new Map();
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
sendRequest
|
|
34
|
-
|
|
40
|
+
sendRequest(method: string, parameters: unknown): Promise<void>;
|
|
41
|
+
sendRequest<ReturnType>(method: string, parameters: unknown,
|
|
42
|
+
validate: ResultValidator<ReturnType>): Promise<ReturnType>;
|
|
43
|
+
sendRequest<ReturnType>(method: string, parameters: unknown,
|
|
44
|
+
validate: ResultValidator<ReturnType>|
|
|
45
|
+
ResultValidator<undefined> = isUndefined): Promise<ReturnType|void> {
|
|
46
|
+
return new Promise<ReturnType|void>((resolve, reject) => {
|
|
35
47
|
const requestId = this.nextRequestId++;
|
|
36
|
-
this.pendingRequests.set(requestId, {
|
|
48
|
+
this.pendingRequests.set(requestId, {
|
|
49
|
+
resolve: (result: unknown) => {
|
|
50
|
+
if (!validate(result)) {
|
|
51
|
+
reject(new Error(`Extension returned malformed ${method} result`));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
resolve(result);
|
|
55
|
+
},
|
|
56
|
+
reject,
|
|
57
|
+
});
|
|
37
58
|
this.port.postMessage({requestId, method, parameters});
|
|
38
59
|
});
|
|
39
60
|
}
|
|
@@ -46,8 +67,8 @@ export class ExtensionEndpoint {
|
|
|
46
67
|
this.port.close();
|
|
47
68
|
}
|
|
48
69
|
|
|
49
|
-
private onResponse(event:
|
|
50
|
-
const data = event.data
|
|
70
|
+
private onResponse(event: Message): void {
|
|
71
|
+
const data = event.data;
|
|
51
72
|
if ('event' in data) {
|
|
52
73
|
this.handleEvent(data);
|
|
53
74
|
return;
|