chrome-devtools-frontend 1.0.1697998 → 1.0.1698733
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/version-control/SKILL.md +21 -9
- package/front_end/core/platform/HostRuntime.ts +12 -0
- package/front_end/core/platform/api/HostRuntime.ts +13 -0
- package/front_end/core/platform/browser/HostRuntime.ts +34 -0
- package/front_end/core/platform/node/HostRuntime.ts +40 -0
- package/front_end/core/sdk/AnimationModel.ts +12 -98
- package/front_end/core/sdk/CSSModel.ts +4 -2
- package/front_end/core/sdk/CSSPropertyParser.ts +4 -4
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +4 -44
- package/front_end/core/sdk/Connections.ts +6 -1
- package/front_end/core/sdk/ConsoleModel.ts +1 -12
- package/front_end/core/sdk/DOMModel.ts +3 -51
- package/front_end/core/sdk/DebuggerModel.ts +9 -8
- package/front_end/core/sdk/NetworkRequest.ts +1 -1
- package/front_end/core/sdk/PageFunctions.ts +187 -0
- package/front_end/core/sdk/Resource.ts +1 -1
- package/front_end/core/sdk/RuntimeModel.ts +1 -20
- package/front_end/core/sdk/Script.ts +21 -0
- package/front_end/core/sdk/SourceMap.ts +15 -2
- package/front_end/core/sdk/SourceMapCache.ts +13 -10
- package/front_end/core/sdk/SourceMapManager.ts +11 -9
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +59 -17
- package/front_end/core/sdk/SourceMapScopesInfo.ts +8 -2
- package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +635 -0
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +26 -12
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +4 -4
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker.ts +2 -0
- package/front_end/entrypoints/shell/shell.ts +1 -1
- package/front_end/models/ai_assistance/DOMHelpers.ts +95 -0
- package/front_end/models/ai_assistance/EvaluateAction.ts +5 -42
- package/front_end/models/ai_assistance/ExtensionScope.ts +2 -31
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -4
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +10 -7
- package/front_end/models/ai_assistance/contexts/FileContext.ts +2 -10
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +3 -2
- package/front_end/models/ai_assistance/tools/ListSources.ts +21 -14
- package/front_end/models/bindings/CompilerScriptMapping.ts +3 -10
- package/front_end/models/bindings/DebuggerLanguagePlugins.ts +48 -17
- package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
- package/front_end/models/bindings/StylesSourceMapping.ts +1 -1
- package/front_end/models/comment_manager/CD4ABridge.ts +55 -12
- package/front_end/models/comment_manager/CommentManager.ts +46 -91
- package/front_end/models/comment_manager/CommentThread.ts +145 -0
- package/front_end/models/comment_manager/comment_manager.ts +2 -0
- package/front_end/models/emulation/DeviceModeModel.ts +53 -0
- package/front_end/models/extensions/ExtensionAPI.ts +8 -6
- package/front_end/models/extensions/ExtensionEndpoint.ts +11 -8
- package/front_end/models/extensions/HostUrlPattern.ts +4 -3
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +3 -2
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +2 -1
- package/front_end/models/formatter/FormatterWorkerPool.ts +4 -6
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +55 -0
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +18 -14
- package/front_end/models/issues_manager/IssuesManager.ts +5 -0
- package/front_end/models/issues_manager/WebInstallIssue.ts +63 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestMissingId.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallNoManifest.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallStartUrlInvalid.md +3 -0
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/workspace/UISourceCode.ts +20 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +4 -6
- package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
- package/front_end/{ui/comments → panels/common}/CommentThreadWidget.ts +4 -4
- package/front_end/{ui/comments → panels/common}/CommentsOverlayWidget.ts +39 -62
- package/front_end/{ui/comments → panels/common}/CommentsStatusBarPill.ts +5 -5
- package/front_end/panels/common/ExtensionServer.ts +2 -1
- package/front_end/{ui/comments → panels/common}/commentsOverlay.css +2 -1
- package/front_end/{ui/comments/comments-meta.ts → panels/common/common-meta.ts} +11 -11
- package/front_end/panels/common/common.ts +3 -0
- package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +3 -3
- package/front_end/panels/elements/ElementsPanel.ts +5 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +4 -1
- package/front_end/panels/elements/ElementsTreeOutline.ts +58 -51
- package/front_end/panels/elements/PropertiesWidget.ts +11 -10
- package/front_end/panels/elements/PropertyRenderer.ts +29 -25
- package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -6
- package/front_end/panels/elements/elementsTreeOutline.css +7 -1
- package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
- package/front_end/panels/event_listeners/EventListenersView.ts +33 -44
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +6 -7
- package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +5 -1
- package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -1
- package/front_end/panels/recorder/stepView.css +1 -0
- package/front_end/panels/security/SecurityPanel.ts +5 -5
- package/front_end/panels/security/SecurityPanelSidebar.ts +2 -11
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
- package/front_end/panels/sources/sources-meta.ts +1 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +0 -3
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/comments/CommentOverlayManager.ts +28 -110
- package/front_end/ui/comments/comments.ts +0 -6
- package/front_end/ui/legacy/Treeoutline.ts +4 -0
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +14 -7
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -1
- /package/front_end/{ui/comments → panels/common}/commentThreadWidget.css +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import * as Common from '../../core/common/common.js';
|
|
6
|
+
|
|
7
|
+
export interface EditorAnchorSignature {
|
|
8
|
+
/** 1-based line number for CodeMirror text editor anchors */
|
|
9
|
+
lineNumber: number;
|
|
10
|
+
/** File path associated with the editor */
|
|
11
|
+
filePath?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DOMNodeAnchorSignature {
|
|
15
|
+
/** Backend NodeId for DOM nodes (`data-backend-node-id`) */
|
|
16
|
+
backendNodeId: number;
|
|
17
|
+
/** Target ID associated with the DOM node (`data-target-id`) */
|
|
18
|
+
targetId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface TimelineAnchorSignature {
|
|
22
|
+
/** Identifier of the trace to scope comments to a specific recording */
|
|
23
|
+
traceId: string;
|
|
24
|
+
/** Serializable key from Trace.EventsSerializer (e.g. 'r-123', 'p-1-2-3-4', 's-5') */
|
|
25
|
+
traceEventKey: string;
|
|
26
|
+
/** Primary event title or category name */
|
|
27
|
+
entryName: string;
|
|
28
|
+
/** Event start timestamp in microseconds */
|
|
29
|
+
startTimeMicro: number;
|
|
30
|
+
/** Chart location */
|
|
31
|
+
chartLocation: 'main'|'network';
|
|
32
|
+
/** Event duration in microseconds (omitted for instant markers) */
|
|
33
|
+
durationMicro?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface CommentAnchorSignature {
|
|
37
|
+
/** Visual logging tree path, e.g. "Panel: elements > Pane: styles > TreeOutline > TreeItem: color" */
|
|
38
|
+
vePath: string;
|
|
39
|
+
/** Normalized text content of the target node */
|
|
40
|
+
textSignature: string;
|
|
41
|
+
/** Text content of the parent container VE node for sibling disambiguation */
|
|
42
|
+
parentTextSignature?: string;
|
|
43
|
+
/** 0-indexed position among siblings sharing the same visual logging path */
|
|
44
|
+
siblingIndex?: number;
|
|
45
|
+
/** Optional backend RequestId for Network panel elements (`data-network-request-id`) */
|
|
46
|
+
networkRequestId?: string;
|
|
47
|
+
/** Optional DOM node identifiers (`data-backend-node-id`, `data-target-id`) */
|
|
48
|
+
node?: DOMNodeAnchorSignature;
|
|
49
|
+
/** Optional editor anchor coordinates for CodeMirror text editors */
|
|
50
|
+
editor?: EditorAnchorSignature;
|
|
51
|
+
/** Optional timeline flamechart anchor coordinates for Performance panel trace entries */
|
|
52
|
+
timeline?: TimelineAnchorSignature;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface Comment {
|
|
56
|
+
author: 'DEVELOPER'|'AGENT';
|
|
57
|
+
text: string;
|
|
58
|
+
timestamp: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface ChangeRecord {
|
|
62
|
+
id: string;
|
|
63
|
+
description: string;
|
|
64
|
+
timestamp: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type CommentThreadStatus = 'DRAFT'|'ACTIVE'|'RESOLVED';
|
|
68
|
+
|
|
69
|
+
export const enum Events {
|
|
70
|
+
CHANGED = 'Changed',
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface EventTypes {
|
|
74
|
+
[Events.CHANGED]: void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface CommentThreadOptions {
|
|
78
|
+
anchor: CommentAnchorSignature;
|
|
79
|
+
comments?: Comment[];
|
|
80
|
+
changes?: ChangeRecord[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class CommentThread extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
84
|
+
static #nextIndex = 1;
|
|
85
|
+
|
|
86
|
+
static resetIndex(): void {
|
|
87
|
+
CommentThread.#nextIndex = 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
readonly id: string = crypto.randomUUID();
|
|
91
|
+
readonly anchor: CommentAnchorSignature;
|
|
92
|
+
#savedIndex?: number;
|
|
93
|
+
comments: Comment[];
|
|
94
|
+
status: CommentThreadStatus = 'DRAFT';
|
|
95
|
+
transmitted: boolean = false;
|
|
96
|
+
changes?: ChangeRecord[];
|
|
97
|
+
|
|
98
|
+
constructor(options: CommentThreadOptions) {
|
|
99
|
+
super();
|
|
100
|
+
this.anchor = options.anchor;
|
|
101
|
+
this.comments = options.comments ?? [];
|
|
102
|
+
this.changes = options.changes;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get index(): number {
|
|
106
|
+
return this.#savedIndex ?? CommentThread.#nextIndex;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
save(text?: string, author: 'DEVELOPER'|'AGENT' = 'DEVELOPER'): void {
|
|
110
|
+
let changed = false;
|
|
111
|
+
if (text && text.trim().length > 0) {
|
|
112
|
+
this.comments.push({
|
|
113
|
+
author,
|
|
114
|
+
text: text.trim(),
|
|
115
|
+
timestamp: Date.now(),
|
|
116
|
+
});
|
|
117
|
+
changed = true;
|
|
118
|
+
}
|
|
119
|
+
if (this.status === 'DRAFT') {
|
|
120
|
+
if (this.#savedIndex === undefined) {
|
|
121
|
+
this.#savedIndex = CommentThread.#nextIndex++;
|
|
122
|
+
}
|
|
123
|
+
this.status = 'ACTIVE';
|
|
124
|
+
changed = true;
|
|
125
|
+
}
|
|
126
|
+
if (changed) {
|
|
127
|
+
this.dispatchEventToListeners(Events.CHANGED);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
resolve(replyText?: string): void {
|
|
132
|
+
if (replyText && replyText.trim().length > 0) {
|
|
133
|
+
this.comments.push({
|
|
134
|
+
author: 'AGENT',
|
|
135
|
+
text: replyText.trim(),
|
|
136
|
+
timestamp: Date.now(),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (this.#savedIndex === undefined) {
|
|
140
|
+
this.#savedIndex = CommentThread.#nextIndex++;
|
|
141
|
+
}
|
|
142
|
+
this.status = 'RESOLVED';
|
|
143
|
+
this.dispatchEventToListeners(Events.CHANGED);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -107,6 +107,8 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
107
107
|
#appliedUserAgentType: UA;
|
|
108
108
|
readonly #scaleSetting: Common.Settings.Setting<number>;
|
|
109
109
|
#scale: number;
|
|
110
|
+
readonly #autoAdjustScaleSetting: Common.Settings.Setting<boolean>;
|
|
111
|
+
readonly #deviceScaleMapSetting: Common.Settings.Setting<Record<string, {scale: number, autoAdjust: boolean}>>;
|
|
110
112
|
#widthSetting: Common.Settings.Setting<number>;
|
|
111
113
|
#heightSetting: Common.Settings.Setting<number>;
|
|
112
114
|
#uaSetting: Common.Settings.Setting<UA>;
|
|
@@ -153,6 +155,9 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
153
155
|
this.#scaleSetting.addChangeListener(this.scaleSettingChanged, this);
|
|
154
156
|
this.#scale = 1;
|
|
155
157
|
|
|
158
|
+
this.#autoAdjustScaleSetting = this.#settings.createSetting('emulation.auto-adjust-scale', true);
|
|
159
|
+
this.#deviceScaleMapSetting = this.#settings.createSetting('emulation.device-scale-map', {});
|
|
160
|
+
|
|
156
161
|
this.#widthSetting = this.#settings.createSetting('emulation.device-width', 400);
|
|
157
162
|
if (this.#widthSetting.get() < MinDeviceSize) {
|
|
158
163
|
this.#widthSetting.set(MinDeviceSize);
|
|
@@ -327,12 +332,44 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
327
332
|
|
|
328
333
|
emulate(type: Type, device: EmulatedDevice|null, mode: Mode|null, scale?: number): void {
|
|
329
334
|
const resetPageScaleFactor = this.#type !== type || this.#device !== device || this.#mode !== mode;
|
|
335
|
+
const deviceChanged = this.#type !== type || this.#device !== device;
|
|
336
|
+
|
|
337
|
+
if (deviceChanged) {
|
|
338
|
+
if (this.#type === Type.Device && this.#device) {
|
|
339
|
+
const map = this.#deviceScaleMapSetting.get();
|
|
340
|
+
map[this.#device.title] = {
|
|
341
|
+
scale: this.#scaleSetting.get(),
|
|
342
|
+
autoAdjust: this.#autoAdjustScaleSetting.get(),
|
|
343
|
+
};
|
|
344
|
+
this.#deviceScaleMapSetting.set(map);
|
|
345
|
+
} else if (this.#type === Type.Responsive) {
|
|
346
|
+
const map = this.#deviceScaleMapSetting.get();
|
|
347
|
+
map['Responsive'] = {
|
|
348
|
+
scale: this.#scaleSetting.get(),
|
|
349
|
+
autoAdjust: this.#autoAdjustScaleSetting.get(),
|
|
350
|
+
};
|
|
351
|
+
this.#deviceScaleMapSetting.set(map);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
330
355
|
this.#type = type;
|
|
331
356
|
|
|
332
357
|
if (type === Type.Device && device && mode) {
|
|
333
358
|
console.assert(Boolean(device) && Boolean(mode), 'Must pass device and mode for device emulation');
|
|
334
359
|
this.#mode = mode;
|
|
335
360
|
this.#device = device;
|
|
361
|
+
|
|
362
|
+
if (deviceChanged) {
|
|
363
|
+
const map = this.#deviceScaleMapSetting.get();
|
|
364
|
+
const savedDevice = map[device.title];
|
|
365
|
+
if (savedDevice) {
|
|
366
|
+
this.#autoAdjustScaleSetting.set(savedDevice.autoAdjust);
|
|
367
|
+
scale = savedDevice.autoAdjust ? undefined : savedDevice.scale;
|
|
368
|
+
} else {
|
|
369
|
+
this.#autoAdjustScaleSetting.set(scale === undefined);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
336
373
|
if (scale !== undefined) {
|
|
337
374
|
this.#autoFitScaleOnInitialize = false;
|
|
338
375
|
this.#scaleSetting.set(scale);
|
|
@@ -346,6 +383,22 @@ export class DeviceModeModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
346
383
|
this.#device = null;
|
|
347
384
|
this.#mode = null;
|
|
348
385
|
this.#autoFitScaleOnInitialize = false;
|
|
386
|
+
|
|
387
|
+
if (deviceChanged && type === Type.Responsive) {
|
|
388
|
+
const map = this.#deviceScaleMapSetting.get();
|
|
389
|
+
const savedDevice = map['Responsive'];
|
|
390
|
+
if (savedDevice) {
|
|
391
|
+
this.#autoAdjustScaleSetting.set(savedDevice.autoAdjust);
|
|
392
|
+
if (!savedDevice.autoAdjust) {
|
|
393
|
+
this.#scaleSetting.set(savedDevice.scale);
|
|
394
|
+
} else {
|
|
395
|
+
this.#scaleSetting.set(this.calculateFitScale(this.#widthSetting.get(), this.#heightSetting.get()));
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
this.#autoAdjustScaleSetting.set(true);
|
|
399
|
+
this.#scaleSetting.set(1);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
349
402
|
}
|
|
350
403
|
|
|
351
404
|
if (type !== Type.None) {
|
|
@@ -404,6 +404,8 @@ declare global {
|
|
|
404
404
|
chrome: PublicAPI.Chrome.DevTools.Chrome;
|
|
405
405
|
webInspector?: APIImpl.InspectorExtensionAPI;
|
|
406
406
|
}
|
|
407
|
+
var injectedExtensionAPI: Window['injectedExtensionAPI'];
|
|
408
|
+
var buildExtensionAPIInjectedScript: Window['buildExtensionAPIInjectedScript'];
|
|
407
409
|
}
|
|
408
410
|
|
|
409
411
|
export interface ExtensionDescriptor {
|
|
@@ -511,7 +513,7 @@ namespace APIImpl {
|
|
|
511
513
|
}
|
|
512
514
|
}
|
|
513
515
|
|
|
514
|
-
|
|
516
|
+
globalThis.injectedExtensionAPI = function(
|
|
515
517
|
extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
|
|
516
518
|
testHook: (extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown,
|
|
517
519
|
injectedScriptId: number, targetWindowForTest?: Window): void {
|
|
@@ -1763,22 +1765,22 @@ self.injectedExtensionAPI = function(
|
|
|
1763
1765
|
testHook(extensionServer, coreAPI);
|
|
1764
1766
|
};
|
|
1765
1767
|
|
|
1766
|
-
|
|
1768
|
+
globalThis.buildExtensionAPIInjectedScript = function(
|
|
1767
1769
|
extensionInfo: {
|
|
1768
1770
|
startPage: string,
|
|
1769
1771
|
name: string,
|
|
1770
1772
|
exposeExperimentalAPIs: boolean,
|
|
1771
1773
|
},
|
|
1772
1774
|
inspectedTabId: string, themeName: string, keysToForward: number[],
|
|
1773
|
-
testHook:
|
|
1774
|
-
|
|
1775
|
-
undefined): string {
|
|
1775
|
+
testHook: ((extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) =>
|
|
1776
|
+
unknown)|undefined): string {
|
|
1776
1777
|
const argumentsJSON =
|
|
1777
1778
|
[extensionInfo, inspectedTabId || null, themeName, keysToForward].map(_ => JSON.stringify(_)).join(',');
|
|
1778
1779
|
if (!testHook) {
|
|
1779
1780
|
testHook = (): void => {};
|
|
1780
1781
|
}
|
|
1781
1782
|
return '(function(injectedScriptId){ ' +
|
|
1782
|
-
'(' +
|
|
1783
|
+
'(' + globalThis.injectedExtensionAPI.toString() + ')(' + argumentsJSON + ',' + testHook +
|
|
1784
|
+
', injectedScriptId);' +
|
|
1783
1785
|
'})';
|
|
1784
1786
|
};
|
|
@@ -2,29 +2,31 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import type * as Platform from '../../core/platform/platform.js';
|
|
6
|
+
|
|
5
7
|
interface Response {
|
|
6
8
|
requestId: number;
|
|
7
9
|
result: unknown;
|
|
8
10
|
error: Error|null;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
interface
|
|
13
|
+
interface EventMessage {
|
|
12
14
|
event: string;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
type Message = MessageEvent<Response|Event>;
|
|
16
|
-
|
|
17
17
|
export class ExtensionEndpoint {
|
|
18
|
-
private readonly port:
|
|
18
|
+
private readonly port: Platform.HostRuntime.WorkerMessagePort;
|
|
19
19
|
private nextRequestId = 0;
|
|
20
20
|
private pendingRequests: Map<number, {
|
|
21
21
|
resolve: (arg: unknown) => void,
|
|
22
22
|
reject: (error: Error) => void,
|
|
23
23
|
}>;
|
|
24
24
|
|
|
25
|
-
constructor(port:
|
|
25
|
+
constructor(port: Platform.HostRuntime.WorkerMessagePort) {
|
|
26
26
|
this.port = port;
|
|
27
|
-
this.port.
|
|
27
|
+
this.port.addEventListener('message', (event: unknown) => this.onResponse(event as MessageEvent));
|
|
28
|
+
(this.port as {start?: () => void}).start?.();
|
|
29
|
+
(this.port as {unref?: () => void}).unref?.();
|
|
28
30
|
this.pendingRequests = new Map();
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -44,7 +46,8 @@ export class ExtensionEndpoint {
|
|
|
44
46
|
this.port.close();
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
private onResponse(
|
|
49
|
+
private onResponse(event: MessageEvent): void {
|
|
50
|
+
const data = event.data as Response | EventMessage;
|
|
48
51
|
if ('event' in data) {
|
|
49
52
|
this.handleEvent(data);
|
|
50
53
|
return;
|
|
@@ -63,7 +66,7 @@ export class ExtensionEndpoint {
|
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
protected handleEvent(_event:
|
|
69
|
+
protected handleEvent(_event: EventMessage): void {
|
|
67
70
|
throw new Error('handleEvent is not implemented');
|
|
68
71
|
}
|
|
69
72
|
}
|
|
@@ -77,8 +77,9 @@ function parseHostAndPort(pattern: string, scheme: string): {host: string, port:
|
|
|
77
77
|
asUrl.hostname = asUrl.hostname.substr(0, asUrl.hostname.length - 1);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
// The URL constructor
|
|
81
|
-
|
|
80
|
+
// The URL constructor in Chrome replaces '*' with '%2A', whereas Node preserves '*'.
|
|
81
|
+
const isWildcardHost = asUrl.hostname === '%2A' || asUrl.hostname === '*';
|
|
82
|
+
if (!isWildcardHost && (asUrl.hostname.includes('%2A') || asUrl.hostname.includes('*'))) {
|
|
82
83
|
return undefined;
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -93,7 +94,7 @@ function parseHostAndPort(pattern: string, scheme: string): {host: string, port:
|
|
|
93
94
|
return undefined;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
const host =
|
|
97
|
+
const host = !isWildcardHost ? (pattern.startsWith('*.') ? `*.${asUrl.hostname}` : asUrl.hostname) : '*';
|
|
97
98
|
return {
|
|
98
99
|
host,
|
|
99
100
|
port,
|
|
@@ -13,7 +13,7 @@ import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
|
|
13
13
|
class LanguageExtensionEndpointImpl extends ExtensionEndpoint {
|
|
14
14
|
private plugin: LanguageExtensionEndpoint;
|
|
15
15
|
#pluginManager: Bindings.DebuggerLanguagePlugins.DebuggerLanguagePluginManager;
|
|
16
|
-
constructor(plugin: LanguageExtensionEndpoint, port:
|
|
16
|
+
constructor(plugin: LanguageExtensionEndpoint, port: Platform.HostRuntime.WorkerMessagePort,
|
|
17
17
|
pluginManager: Bindings.DebuggerLanguagePlugins.DebuggerLanguagePluginManager) {
|
|
18
18
|
super(port);
|
|
19
19
|
this.plugin = plugin;
|
|
@@ -46,7 +46,8 @@ export class LanguageExtensionEndpoint implements Bindings.DebuggerLanguagePlugi
|
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
47
47
|
symbol_types: string[],
|
|
48
48
|
},
|
|
49
|
-
port:
|
|
49
|
+
port: Platform.HostRuntime.WorkerMessagePort,
|
|
50
|
+
pluginManager: Bindings.DebuggerLanguagePlugins.DebuggerLanguagePluginManager) {
|
|
50
51
|
this.name = name;
|
|
51
52
|
this.extensionOrigin = extensionOrigin;
|
|
52
53
|
this.supportedScriptTypes = supportedScriptTypes;
|
|
@@ -15,7 +15,8 @@ export class RecorderExtensionEndpoint extends ExtensionEndpoint {
|
|
|
15
15
|
readonly #extensionOrigin: Platform.DevToolsPath.UrlString;
|
|
16
16
|
readonly #recorderPluginManager: RecorderPluginManager;
|
|
17
17
|
|
|
18
|
-
constructor(name: string, port:
|
|
18
|
+
constructor(name: string, port: Platform.HostRuntime.WorkerMessagePort,
|
|
19
|
+
capabilities: PrivateAPI.RecordingExtensionPluginCapability[],
|
|
19
20
|
extensionOrigin: Platform.DevToolsPath.UrlString, recorderPluginManager: RecorderPluginManager,
|
|
20
21
|
mediaType?: string) {
|
|
21
22
|
super(port);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import type * as PlatformApi from '../../core/platform/api/api.js';
|
|
6
5
|
import * as Platform from '../../core/platform/platform.js';
|
|
7
6
|
import * as FormatterActions from '../../entrypoints/formatter_actions/formatter_actions.js';
|
|
8
7
|
|
|
@@ -12,7 +11,7 @@ let formatterWorkerPoolInstance: FormatterWorkerPool|undefined;
|
|
|
12
11
|
|
|
13
12
|
export class FormatterWorkerPool {
|
|
14
13
|
private taskQueue: Task[];
|
|
15
|
-
private workerTasks: Map<
|
|
14
|
+
private workerTasks: Map<Platform.HostRuntime.Worker, Task|null>;
|
|
16
15
|
private entrypointURL: string;
|
|
17
16
|
|
|
18
17
|
constructor(entrypointURL?: string) {
|
|
@@ -46,7 +45,7 @@ export class FormatterWorkerPool {
|
|
|
46
45
|
formatterWorkerPoolInstance = undefined;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
private createWorker():
|
|
48
|
+
private createWorker(): Platform.HostRuntime.Worker {
|
|
50
49
|
const worker = Platform.HostRuntime.HOST_RUNTIME.createWorker(this.entrypointURL);
|
|
51
50
|
worker.onmessage = this.onWorkerMessage.bind(this, worker);
|
|
52
51
|
worker.onerror = this.onWorkerError.bind(this, worker);
|
|
@@ -75,8 +74,7 @@ export class FormatterWorkerPool {
|
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
private onWorkerMessage(worker:
|
|
79
|
-
void {
|
|
77
|
+
private onWorkerMessage(worker: Platform.HostRuntime.Worker, event: Platform.HostRuntime.WorkerMessageEvent): void {
|
|
80
78
|
const task = this.workerTasks.get(worker);
|
|
81
79
|
if (!task) {
|
|
82
80
|
return;
|
|
@@ -91,7 +89,7 @@ export class FormatterWorkerPool {
|
|
|
91
89
|
task.callback(event.data ? event.data : null);
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
private onWorkerError(worker:
|
|
92
|
+
private onWorkerError(worker: Platform.HostRuntime.Worker, event: Event): void {
|
|
95
93
|
console.error(event);
|
|
96
94
|
const task = this.workerTasks.get(worker);
|
|
97
95
|
worker.terminate();
|
|
@@ -363,6 +363,61 @@ export interface ObjectInfo {
|
|
|
363
363
|
retainerCount: number;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
export interface ContextAnalysisResult {
|
|
367
|
+
/** Scopes with dead fields, sorted by their highest-ranked context. */
|
|
368
|
+
scopes: ScopeAnalysis[];
|
|
369
|
+
/** Scripts with live contexts that could not be analyzed because they lack embedded scope metadata. */
|
|
370
|
+
scriptsWithoutScopes: ScriptWithoutScopes[];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface ScopeAnalysis {
|
|
374
|
+
scopeInfoNodeIndex: number;
|
|
375
|
+
scopeInfoNodeId: number;
|
|
376
|
+
scriptNodeIndex: number;
|
|
377
|
+
scriptNodeId: number;
|
|
378
|
+
scriptName: string;
|
|
379
|
+
/** Source name of the scope, when available. */
|
|
380
|
+
scopeName?: string;
|
|
381
|
+
scopeStart: number;
|
|
382
|
+
scopeEnd: number;
|
|
383
|
+
/** Number of context-typed fields in each context belonging to this scope. */
|
|
384
|
+
contextFieldCount: number;
|
|
385
|
+
/** Contexts with dead fields, sorted descending by deadFieldsRetainedSizeSum. */
|
|
386
|
+
contexts: ContextAnalysis[];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface ContextAnalysis {
|
|
390
|
+
contextNodeIndex: number;
|
|
391
|
+
contextNodeId: number;
|
|
392
|
+
retainedSize: number;
|
|
393
|
+
/**
|
|
394
|
+
* The sum of the retained sizes of values in fields classified as dead.
|
|
395
|
+
* This is a ranking heuristic, not the number of bytes that would be
|
|
396
|
+
* reclaimed by clearing the fields.
|
|
397
|
+
*/
|
|
398
|
+
deadFieldsRetainedSizeSum: number;
|
|
399
|
+
/** Fields classified as dead in this context, sorted descending by retainedSize. */
|
|
400
|
+
deadFields: ContextField[];
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export interface ContextField {
|
|
404
|
+
name: string;
|
|
405
|
+
valueNodeIndex: number;
|
|
406
|
+
valueNodeId: number;
|
|
407
|
+
valueName: string;
|
|
408
|
+
valueType: string;
|
|
409
|
+
selfSize: number;
|
|
410
|
+
retainedSize: number;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface ScriptWithoutScopes {
|
|
414
|
+
scriptNodeIndex: number;
|
|
415
|
+
scriptNodeId: number;
|
|
416
|
+
scriptName: string;
|
|
417
|
+
/** Number of live context instances belonging to this script. */
|
|
418
|
+
contextCount: number;
|
|
419
|
+
}
|
|
420
|
+
|
|
366
421
|
export interface HeapQueryOptions {
|
|
367
422
|
className?: string;
|
|
368
423
|
propertyName?: string;
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
|
-
import type * as PlatformApi from '../../core/platform/api/api.js';
|
|
7
6
|
import * as Platform from '../../core/platform/platform.js';
|
|
8
7
|
|
|
9
8
|
import type {ChildrenProvider} from './ChildrenProvider.js';
|
|
@@ -17,7 +16,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
17
16
|
callbacks: Map<number, (error?: string, result?: unknown) => void> =
|
|
18
17
|
new Map<number, (error?: string, result?: unknown) => void>();
|
|
19
18
|
readonly previousCallbacks: Set<number> = new Set<number>();
|
|
20
|
-
readonly worker:
|
|
19
|
+
readonly worker: Platform.HostRuntime.Worker;
|
|
21
20
|
interval?: ReturnType<typeof setInterval>;
|
|
22
21
|
readonly workerUrl?: string;
|
|
23
22
|
|
|
@@ -69,17 +68,18 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
69
68
|
this.postMessage({callId, disposition: 'evaluateForTest', source: script});
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
callFactoryMethod<T extends Object>(
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
callFactoryMethod<T extends Object>(callback: null, objectId: string, methodName: string,
|
|
72
|
+
proxyConstructor: new(...arg1: any[]) => T,
|
|
73
|
+
transfer: Platform.HostRuntime.WorkerTransferable[],
|
|
74
|
+
...methodArguments: any[]): T;
|
|
75
75
|
callFactoryMethod<T extends Object>(callback: ((error?: string, result?: T) => void), objectId: string,
|
|
76
76
|
methodName: string, proxyConstructor: new(...arg1: any[]) => T,
|
|
77
|
-
transfer:
|
|
77
|
+
transfer: Platform.HostRuntime.WorkerTransferable[],
|
|
78
78
|
...methodArguments: any[]): null;
|
|
79
79
|
callFactoryMethod<T extends Object>(callback: ((error?: string, result?: T) => void)|null, objectId: string,
|
|
80
80
|
methodName: string, proxyConstructor: new(...arg1: any[]) => T,
|
|
81
|
-
transfer:
|
|
82
|
-
|
|
81
|
+
transfer: Platform.HostRuntime.WorkerTransferable[], ...methodArguments: any[]): T
|
|
82
|
+
|null {
|
|
83
83
|
const callId = this.nextCallId++;
|
|
84
84
|
const newObjectId = this.nextObjectId++;
|
|
85
85
|
|
|
@@ -154,7 +154,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
setupForSecondaryInit(port:
|
|
157
|
+
setupForSecondaryInit(port: Platform.HostRuntime.WorkerMessagePort): Promise<void> {
|
|
158
158
|
const callId = this.nextCallId++;
|
|
159
159
|
const done = new Promise<void>((resolve, reject) => {
|
|
160
160
|
this.callbacks.set(callId, error => {
|
|
@@ -175,7 +175,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
175
175
|
return done;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
messageReceived(event:
|
|
178
|
+
messageReceived(event: Platform.HostRuntime.WorkerMessageEvent): void {
|
|
179
179
|
const data = event.data;
|
|
180
180
|
if (data.eventName) {
|
|
181
181
|
if (this.eventHandler) {
|
|
@@ -199,7 +199,7 @@ export class HeapSnapshotWorkerProxy extends Common.ObjectWrapper.ObjectWrapper<
|
|
|
199
199
|
callback(undefined, data.result);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
postMessage(message: unknown, transfer?:
|
|
202
|
+
postMessage(message: unknown, transfer?: Platform.HostRuntime.WorkerTransferable[]): void {
|
|
203
203
|
this.worker.postMessage(message, transfer);
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -231,9 +231,9 @@ export class HeapSnapshotProxyObject {
|
|
|
231
231
|
return this.worker.callFactoryMethod(null, String(this.objectId), methodName, proxyConstructor, [], ...args);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
callFactoryMethodPromise<T extends Object>(
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
callFactoryMethodPromise<T extends Object>(methodName: string, proxyConstructor: new(...arg1: any[]) => T,
|
|
235
|
+
transfer: Platform.HostRuntime.WorkerTransferable[],
|
|
236
|
+
...args: any[]): Promise<T> {
|
|
237
237
|
return new Promise((resolve, reject) => this.worker.callFactoryMethod((error, result) => {
|
|
238
238
|
if (error) {
|
|
239
239
|
reject(new Error(error));
|
|
@@ -348,6 +348,10 @@ export class HeapSnapshotProxy extends HeapSnapshotProxyObject {
|
|
|
348
348
|
return this.callMethodPromise('getObjectInfo', nodeIndex);
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
+
analyzeContexts(): Promise<HeapSnapshotModel.ContextAnalysisResult> {
|
|
352
|
+
return this.callMethodPromise('analyzeContexts');
|
|
353
|
+
}
|
|
354
|
+
|
|
351
355
|
createEdgesProvider(nodeIndex: number, options?: HeapSnapshotModel.HeapEdgesQueryOptions): HeapSnapshotProviderProxy {
|
|
352
356
|
return this.callFactoryMethod('createEdgesProvider', HeapSnapshotProviderProxy, nodeIndex, options);
|
|
353
357
|
}
|
|
@@ -38,6 +38,7 @@ import {SourceFrameIssuesManager} from './SourceFrameIssuesManager.js';
|
|
|
38
38
|
import {SRIMessageSignatureIssue} from './SRIMessageSignatureIssue.js';
|
|
39
39
|
import {StylesheetLoadingIssue} from './StylesheetLoadingIssue.js';
|
|
40
40
|
import {UnencodedDigestIssue} from './UnencodedDigestIssue.js';
|
|
41
|
+
import {WebInstallIssue} from './WebInstallIssue.js';
|
|
41
42
|
|
|
42
43
|
export {Events} from './IssuesManagerEvents.js';
|
|
43
44
|
|
|
@@ -149,6 +150,10 @@ const issueCodeHandlers =
|
|
|
149
150
|
Protocol.Audits.InspectorIssueCode.ConnectionAllowlistIssue,
|
|
150
151
|
ConnectionAllowlistIssue.fromInspectorIssue,
|
|
151
152
|
],
|
|
153
|
+
[
|
|
154
|
+
Protocol.Audits.InspectorIssueCode.WebInstallIssue,
|
|
155
|
+
WebInstallIssue.fromInspectorIssue,
|
|
156
|
+
],
|
|
152
157
|
[
|
|
153
158
|
Protocol.Audits.InspectorIssueCode.PermissionElementIssue,
|
|
154
159
|
PermissionElementIssue.fromInspectorIssue,
|