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
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Host from '../../../core/host/host.js';
|
|
6
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
7
|
-
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
8
7
|
import * as Workspace from '../../workspace/workspace.js';
|
|
9
|
-
import {FileContext} from '../contexts/FileContext.js';
|
|
10
8
|
|
|
11
9
|
import {
|
|
12
10
|
type BaseToolCapability,
|
|
@@ -50,23 +48,30 @@ export class ListSourcesTool implements
|
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
static getUISourceCodes(
|
|
53
|
-
|
|
51
|
+
originLock: OriginLockState,
|
|
54
52
|
// eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
|
|
55
53
|
workspace: Workspace.Workspace.WorkspaceImpl = Workspace.Workspace.WorkspaceImpl.instance(),
|
|
56
54
|
): Workspace.UISourceCode.UISourceCode[] {
|
|
57
|
-
if (
|
|
55
|
+
if (originLock.status !== 'ESTABLISHED_ORIGIN' || originLock.origin.isOpaque()) {
|
|
58
56
|
return [];
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
const projects =
|
|
62
|
-
workspace.projects().filter(project => project.type() === Workspace.Workspace.projectTypes.Network);
|
|
63
59
|
const uiSourceCodes = new Map<string, Workspace.UISourceCode.UISourceCode>();
|
|
64
60
|
|
|
65
|
-
for (const project of
|
|
61
|
+
for (const project of workspace.projectsForType(Workspace.Workspace.projectTypes.Network)) {
|
|
62
|
+
const projectOrigin = project.securityOrigin?.();
|
|
63
|
+
if (projectOrigin && !isOriginAllowedByLock(originLock, projectOrigin)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
66
67
|
for (const uiSourceCode of project.uiSourceCodes()) {
|
|
67
68
|
if (uiSourceCode.isIgnoreListed()) {
|
|
68
69
|
continue;
|
|
69
70
|
}
|
|
71
|
+
if (!projectOrigin && !isOriginAllowedByLock(originLock, uiSourceCode.securityOrigin())) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
70
75
|
const url = uiSourceCode.url();
|
|
71
76
|
if (!uiSourceCodes.get(url) || uiSourceCode.contentType().isFromSourceMap()) {
|
|
72
77
|
uiSourceCodes.set(url, uiSourceCode);
|
|
@@ -77,18 +82,19 @@ export class ListSourcesTool implements
|
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
return [...uiSourceCodes.values()].filter(
|
|
82
|
-
file => isOriginAllowedByLock(originLock, FileContext.originForUISourceCode(file)));
|
|
85
|
+
return Array.from(uiSourceCodes.values());
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
static getSourceById(
|
|
86
89
|
id: number,
|
|
87
|
-
|
|
90
|
+
originLock: OriginLockState,
|
|
88
91
|
// eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
|
|
89
92
|
workspace: Workspace.Workspace.WorkspaceImpl = Workspace.Workspace.WorkspaceImpl.instance(),
|
|
90
93
|
): Workspace.UISourceCode.UISourceCode|undefined {
|
|
91
|
-
|
|
94
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return ListSourcesTool.getUISourceCodes(originLock, workspace)
|
|
92
98
|
.find(file => ListSourcesTool.uiSourceCodeId.get(file) === id);
|
|
93
99
|
}
|
|
94
100
|
|
|
@@ -114,12 +120,13 @@ export class ListSourcesTool implements
|
|
|
114
120
|
_params: Record<string, never>,
|
|
115
121
|
context: BaseToolCapability&OriginLockCapability,
|
|
116
122
|
): Promise<DataHandlerResult<{files: SourceSummary[]}>> {
|
|
117
|
-
const
|
|
123
|
+
const originLock = context.getOriginLock();
|
|
124
|
+
const originResult = resolveOriginFromLock(originLock);
|
|
118
125
|
if ('error' in originResult) {
|
|
119
126
|
return originResult;
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
const files = ListSourcesTool.getUISourceCodes(
|
|
129
|
+
const files = ListSourcesTool.getUISourceCodes(originLock);
|
|
123
130
|
|
|
124
131
|
return {
|
|
125
132
|
result: {
|
|
@@ -458,16 +458,9 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
458
458
|
this.removeStubUISourceCode(script);
|
|
459
459
|
|
|
460
460
|
const target = script.target();
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const extractedOrigin = Common.ParsedURL.ParsedURL.extractOrigin(embedderName);
|
|
465
|
-
if (extractedOrigin && extractedOrigin !== 'null') {
|
|
466
|
-
securityOrigin = SDK.SecurityOrigin.SecurityOrigin.create(extractedOrigin);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
const parsedOrigin = securityOrigin ? `:${securityOrigin.siteId()}` : '';
|
|
470
|
-
const projectId = `jsSourceMaps:${script.isContentScript() ? 'extensions' : ''}:${target.id()}${parsedOrigin}`;
|
|
461
|
+
const securityOrigin = script.securityOrigin();
|
|
462
|
+
const originPart = securityOrigin.isOpaque() ? '' : `:${securityOrigin.siteId()}`;
|
|
463
|
+
const projectId = `jsSourceMaps:${script.isContentScript() ? 'extensions' : ''}:${target.id()}${originPart}`;
|
|
471
464
|
let project = this.#projects.get(projectId);
|
|
472
465
|
if (!project) {
|
|
473
466
|
const projectType = script.isContentScript() ? Workspace.Workspace.projectTypes.ContentScripts :
|
|
@@ -593,11 +593,11 @@ export class DebuggerLanguagePluginManager implements
|
|
|
593
593
|
return {rawModuleId, plugin: null};
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
-
uiSourceCodeForURL(debuggerModel: SDK.DebuggerModel.DebuggerModel, url: Platform.DevToolsPath.UrlString
|
|
597
|
-
|
|
596
|
+
uiSourceCodeForURL(debuggerModel: SDK.DebuggerModel.DebuggerModel, url: Platform.DevToolsPath.UrlString,
|
|
597
|
+
script?: SDK.Script.Script): Workspace.UISourceCode.UISourceCode|null {
|
|
598
598
|
const modelData = this.#debuggerModelToData.get(debuggerModel);
|
|
599
599
|
if (modelData) {
|
|
600
|
-
return modelData.
|
|
600
|
+
return modelData.uiSourceCodeForURL(url, script);
|
|
601
601
|
}
|
|
602
602
|
return null;
|
|
603
603
|
}
|
|
@@ -625,7 +625,7 @@ export class DebuggerLanguagePluginManager implements
|
|
|
625
625
|
const sourceLocations = await plugin.rawLocationToSourceLocation(pluginLocation);
|
|
626
626
|
for (const sourceLocation of sourceLocations) {
|
|
627
627
|
const uiSourceCode = this.uiSourceCodeForURL(
|
|
628
|
-
script.debuggerModel, sourceLocation.sourceFileURL as Platform.DevToolsPath.UrlString);
|
|
628
|
+
script.debuggerModel, sourceLocation.sourceFileURL as Platform.DevToolsPath.UrlString, script);
|
|
629
629
|
if (!uiSourceCode) {
|
|
630
630
|
continue;
|
|
631
631
|
}
|
|
@@ -1097,23 +1097,41 @@ export class DebuggerLanguagePluginManager implements
|
|
|
1097
1097
|
}
|
|
1098
1098
|
|
|
1099
1099
|
class ModelData {
|
|
1100
|
-
|
|
1100
|
+
readonly #debuggerModel: SDK.DebuggerModel.DebuggerModel;
|
|
1101
|
+
readonly #workspace: Workspace.Workspace.WorkspaceImpl;
|
|
1102
|
+
readonly #projects = new Map<string, ContentProviderBasedProject>();
|
|
1101
1103
|
readonly uiSourceCodeToScripts: Map<Workspace.UISourceCode.UISourceCode, SDK.Script.Script[]>;
|
|
1102
1104
|
constructor(debuggerModel: SDK.DebuggerModel.DebuggerModel, workspace: Workspace.Workspace.WorkspaceImpl) {
|
|
1103
|
-
this
|
|
1104
|
-
|
|
1105
|
-
Workspace.Workspace.projectTypes.Network, '', false /* isServiceProject */);
|
|
1106
|
-
NetworkProject.setTargetForProject(this.project, debuggerModel.target());
|
|
1107
|
-
|
|
1105
|
+
this.#debuggerModel = debuggerModel;
|
|
1106
|
+
this.#workspace = workspace;
|
|
1108
1107
|
this.uiSourceCodeToScripts = new Map();
|
|
1109
1108
|
}
|
|
1110
1109
|
|
|
1110
|
+
#projectIdForScript(script: SDK.Script.Script): string {
|
|
1111
|
+
const securityOrigin = script.securityOrigin();
|
|
1112
|
+
const originPart = securityOrigin.isOpaque() ? '' : `:${securityOrigin.siteId()}`;
|
|
1113
|
+
return `language_plugins::${this.#debuggerModel.target().id()}${originPart}`;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
#projectForScript(script: SDK.Script.Script): ContentProviderBasedProject {
|
|
1117
|
+
const projectId = this.#projectIdForScript(script);
|
|
1118
|
+
let project = this.#projects.get(projectId);
|
|
1119
|
+
if (!project) {
|
|
1120
|
+
project = new ContentProviderBasedProject(this.#workspace, projectId, Workspace.Workspace.projectTypes.Network,
|
|
1121
|
+
'', false /* isServiceProject */, script.securityOrigin());
|
|
1122
|
+
NetworkProject.setTargetForProject(project, this.#debuggerModel.target());
|
|
1123
|
+
this.#projects.set(projectId, project);
|
|
1124
|
+
}
|
|
1125
|
+
return project;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1111
1128
|
addSourceFiles(script: SDK.Script.Script, urls: Platform.DevToolsPath.UrlString[]): void {
|
|
1129
|
+
const project = this.#projectForScript(script);
|
|
1112
1130
|
const initiator = script.createPageResourceLoadInitiator();
|
|
1113
1131
|
for (const url of urls) {
|
|
1114
|
-
let uiSourceCode =
|
|
1132
|
+
let uiSourceCode = project.uiSourceCodeForURL(url);
|
|
1115
1133
|
if (!uiSourceCode) {
|
|
1116
|
-
uiSourceCode =
|
|
1134
|
+
uiSourceCode = project.createUISourceCode(url, Common.ResourceType.resourceTypes.SourceMapScript);
|
|
1117
1135
|
NetworkProject.setInitialFrameAttribution(uiSourceCode, script.frameId);
|
|
1118
1136
|
|
|
1119
1137
|
// Bind the uiSourceCode to the script first before we add the
|
|
@@ -1129,7 +1147,7 @@ class ModelData {
|
|
|
1129
1147
|
url, Common.ResourceType.resourceTypes.SourceMapScript, initiator,
|
|
1130
1148
|
script.target().targetManager().getPageResourceLoader());
|
|
1131
1149
|
const mimeType = Common.ResourceType.ResourceType.mimeFromURL(url) || 'text/javascript';
|
|
1132
|
-
|
|
1150
|
+
project.addUISourceCodeWithProvider(uiSourceCode, contentProvider, null, mimeType);
|
|
1133
1151
|
} else {
|
|
1134
1152
|
// The same uiSourceCode can be provided by different scripts,
|
|
1135
1153
|
// but we don't expect that to happen frequently.
|
|
@@ -1146,7 +1164,7 @@ class ModelData {
|
|
|
1146
1164
|
scripts = scripts.filter(s => s !== script);
|
|
1147
1165
|
if (scripts.length === 0) {
|
|
1148
1166
|
this.uiSourceCodeToScripts.delete(uiSourceCode);
|
|
1149
|
-
|
|
1167
|
+
uiSourceCode.project().removeUISourceCode(uiSourceCode.url());
|
|
1150
1168
|
} else {
|
|
1151
1169
|
this.uiSourceCodeToScripts.set(uiSourceCode, scripts);
|
|
1152
1170
|
}
|
|
@@ -1154,11 +1172,24 @@ class ModelData {
|
|
|
1154
1172
|
}
|
|
1155
1173
|
|
|
1156
1174
|
dispose(): void {
|
|
1157
|
-
this.
|
|
1175
|
+
for (const project of this.#projects.values()) {
|
|
1176
|
+
project.dispose();
|
|
1177
|
+
}
|
|
1178
|
+
this.#projects.clear();
|
|
1158
1179
|
}
|
|
1159
1180
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1181
|
+
uiSourceCodeForURL(url: Platform.DevToolsPath.UrlString,
|
|
1182
|
+
script?: SDK.Script.Script): Workspace.UISourceCode.UISourceCode|null {
|
|
1183
|
+
if (script) {
|
|
1184
|
+
return this.#projects.get(this.#projectIdForScript(script))?.uiSourceCodeForURL(url) ?? null;
|
|
1185
|
+
}
|
|
1186
|
+
for (const project of this.#projects.values()) {
|
|
1187
|
+
const uiSourceCode = project.uiSourceCodeForURL(url);
|
|
1188
|
+
if (uiSourceCode) {
|
|
1189
|
+
return uiSourceCode;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return null;
|
|
1162
1193
|
}
|
|
1163
1194
|
}
|
|
1164
1195
|
|
|
@@ -312,11 +312,11 @@ export class ResourceScriptFile {
|
|
|
312
312
|
this.script = this.uiSourceCode.contentType().isScript() ? script : null;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
addSourceMapURL(sourceMapURL: Platform.DevToolsPath.UrlString): void {
|
|
315
|
+
addSourceMapURL(sourceMapURL: Platform.DevToolsPath.UrlString, provenance: SDK.SourceMap.SourceMapProvenance): void {
|
|
316
316
|
if (!this.script) {
|
|
317
317
|
return;
|
|
318
318
|
}
|
|
319
|
-
this.script.debuggerModel.setSourceMapURL(this.script, sourceMapURL);
|
|
319
|
+
this.script.debuggerModel.setSourceMapURL(this.script, sourceMapURL, provenance);
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
addDebugInfoURL(debugInfoURL: Platform.DevToolsPath.UrlString): void {
|
|
@@ -310,7 +310,7 @@ export class StyleFile implements TextUtils.ContentProvider.ContentProvider {
|
|
|
310
310
|
const sourceMapManager = this.#cssModel.sourceMapManager();
|
|
311
311
|
this.headers.forEach(header => {
|
|
312
312
|
sourceMapManager.detachSourceMap(header);
|
|
313
|
-
sourceMapManager.attachSourceMap(header, sourceUrl, sourceMapUrl);
|
|
313
|
+
sourceMapManager.attachSourceMap(header, sourceUrl, sourceMapUrl, SDK.SourceMap.SourceMapProvenance.USER);
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
316
|
}
|
|
@@ -14,13 +14,12 @@ export interface CommentThread {
|
|
|
14
14
|
id: string;
|
|
15
15
|
text: string;
|
|
16
16
|
networkRequestId?: string;
|
|
17
|
-
|
|
18
|
-
editor?: CommentManager.EditorAnchorSignature;
|
|
17
|
+
node?: CommentManager.DOMNodeAnchorSignature;
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
export interface RevealTarget {
|
|
22
21
|
networkRequestId?: string;
|
|
23
|
-
|
|
22
|
+
node?: CommentManager.DOMNodeAnchorSignature;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export const enum Events {
|
|
@@ -69,21 +68,65 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
|
69
68
|
Common.EventTarget.removeEventListeners(this.#eventListeners);
|
|
70
69
|
}
|
|
71
70
|
|
|
71
|
+
#getDOMNode(nodeSignature: CommentManager.DOMNodeAnchorSignature): SDK.DOMModel.DOMNode|undefined {
|
|
72
|
+
if (!this.#targetManager) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const target = this.#targetManager.targetById(nodeSignature.targetId) ?? this.#targetManager.primaryPageTarget();
|
|
76
|
+
const domModel = target?.model(SDK.DOMModel.DOMModel);
|
|
77
|
+
if (!domModel) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
for (const node of domModel.idToDOMNode.values()) {
|
|
81
|
+
if (node.backendNodeId() === nodeSignature.backendNodeId) {
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#formatCommentText(thread: CommentManager.CommentThread): string {
|
|
89
|
+
const rawText = thread.comments[0]?.text ?? '';
|
|
90
|
+
const details: string[] = [];
|
|
91
|
+
|
|
92
|
+
if (thread.anchor.textSignature) {
|
|
93
|
+
details.push(`- DevTools element: ${thread.anchor.textSignature}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (thread.anchor.node) {
|
|
97
|
+
const domNode = this.#getDOMNode(thread.anchor.node);
|
|
98
|
+
const simpleSelector = domNode?.simpleSelector();
|
|
99
|
+
if (simpleSelector) {
|
|
100
|
+
details.push(`- DOM node selector: ${simpleSelector}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (thread.anchor.editor) {
|
|
105
|
+
const editorInfo = thread.anchor.editor.filePath ?
|
|
106
|
+
`${thread.anchor.editor.filePath}:${thread.anchor.editor.lineNumber}` :
|
|
107
|
+
`line ${thread.anchor.editor.lineNumber}`;
|
|
108
|
+
details.push(`- Editor: ${editorInfo}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (details.length === 0) {
|
|
112
|
+
return rawText;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return rawText ? `${rawText}\n\n${details.join('\n')}` : details.join('\n');
|
|
116
|
+
}
|
|
117
|
+
|
|
72
118
|
getCommentThreads(): CommentThread[] {
|
|
73
119
|
const threads = this.#commentManager.takeComments();
|
|
74
120
|
return threads.map(thread => {
|
|
75
121
|
const threadPayload: CommentThread = {
|
|
76
122
|
id: thread.id,
|
|
77
|
-
text: thread
|
|
123
|
+
text: this.#formatCommentText(thread),
|
|
78
124
|
};
|
|
79
125
|
if (thread.anchor.networkRequestId) {
|
|
80
126
|
threadPayload.networkRequestId = thread.anchor.networkRequestId;
|
|
81
127
|
}
|
|
82
128
|
if (thread.anchor.node) {
|
|
83
|
-
threadPayload.
|
|
84
|
-
}
|
|
85
|
-
if (thread.anchor.editor) {
|
|
86
|
-
threadPayload.editor = thread.anchor.editor;
|
|
129
|
+
threadPayload.node = {...thread.anchor.node};
|
|
87
130
|
}
|
|
88
131
|
return threadPayload;
|
|
89
132
|
});
|
|
@@ -112,11 +155,11 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
|
112
155
|
}
|
|
113
156
|
}
|
|
114
157
|
|
|
115
|
-
if (target?.
|
|
116
|
-
const
|
|
117
|
-
const domModel =
|
|
158
|
+
if (target?.node && this.#targetManager) {
|
|
159
|
+
const sdkTarget = this.#targetManager.targetById(target.node.targetId) ?? this.#targetManager.primaryPageTarget();
|
|
160
|
+
const domModel = sdkTarget?.model(SDK.DOMModel.DOMModel);
|
|
118
161
|
if (domModel) {
|
|
119
|
-
const cdpNodeId = target.backendNodeId as Protocol.DOM.BackendNodeId;
|
|
162
|
+
const cdpNodeId = target.node.backendNodeId as Protocol.DOM.BackendNodeId;
|
|
120
163
|
const nodeMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([cdpNodeId]));
|
|
121
164
|
const node = nodeMap?.get(cdpNodeId);
|
|
122
165
|
if (node) {
|
|
@@ -4,75 +4,30 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 interface CommentThread {
|
|
68
|
-
id: string;
|
|
69
|
-
anchor: CommentAnchorSignature;
|
|
70
|
-
comments: Comment[];
|
|
71
|
-
status: 'ACTIVE'|'RESOLVED';
|
|
72
|
-
transmitted?: boolean;
|
|
73
|
-
changes?: ChangeRecord[];
|
|
74
|
-
index: number;
|
|
75
|
-
}
|
|
7
|
+
import {
|
|
8
|
+
type ChangeRecord,
|
|
9
|
+
type Comment,
|
|
10
|
+
type CommentAnchorSignature,
|
|
11
|
+
CommentThread,
|
|
12
|
+
type CommentThreadOptions,
|
|
13
|
+
type CommentThreadStatus,
|
|
14
|
+
type DOMNodeAnchorSignature,
|
|
15
|
+
type EditorAnchorSignature,
|
|
16
|
+
Events as CommentThreadEvents,
|
|
17
|
+
type TimelineAnchorSignature,
|
|
18
|
+
} from './CommentThread.js';
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
type ChangeRecord,
|
|
22
|
+
type Comment,
|
|
23
|
+
type CommentAnchorSignature,
|
|
24
|
+
CommentThread,
|
|
25
|
+
type CommentThreadOptions,
|
|
26
|
+
type CommentThreadStatus,
|
|
27
|
+
type DOMNodeAnchorSignature,
|
|
28
|
+
type EditorAnchorSignature,
|
|
29
|
+
type TimelineAnchorSignature,
|
|
30
|
+
};
|
|
76
31
|
|
|
77
32
|
export const enum Events {
|
|
78
33
|
COMMENT_THREADS_CHANGED = 'CommentThreadsChanged',
|
|
@@ -90,7 +45,15 @@ export interface EventTypes {
|
|
|
90
45
|
export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
91
46
|
readonly #commentThreads = new Map<string, CommentThread>();
|
|
92
47
|
#commentMode = false;
|
|
93
|
-
|
|
48
|
+
|
|
49
|
+
constructor() {
|
|
50
|
+
super();
|
|
51
|
+
CommentThread.resetIndex();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#onThreadChanged(): void {
|
|
55
|
+
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
|
|
56
|
+
}
|
|
94
57
|
|
|
95
58
|
setCommentMode(active: boolean): void {
|
|
96
59
|
if (this.#commentMode === active) {
|
|
@@ -110,25 +73,20 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
110
73
|
author: 'DEVELOPER'|'AGENT' = 'DEVELOPER',
|
|
111
74
|
changes?: ChangeRecord[],
|
|
112
75
|
): CommentThread {
|
|
113
|
-
const index = this.#nextId++;
|
|
114
|
-
const id = `comment-${index}`;
|
|
115
76
|
const comments: Comment[] = text ? [{
|
|
116
77
|
author,
|
|
117
78
|
text,
|
|
118
79
|
timestamp: Date.now(),
|
|
119
80
|
}] :
|
|
120
81
|
[];
|
|
121
|
-
const thread
|
|
122
|
-
id,
|
|
82
|
+
const thread = new CommentThread({
|
|
123
83
|
anchor,
|
|
124
84
|
comments,
|
|
125
|
-
status: 'ACTIVE',
|
|
126
|
-
transmitted: false,
|
|
127
85
|
changes,
|
|
128
|
-
|
|
129
|
-
|
|
86
|
+
});
|
|
87
|
+
thread.addEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
|
|
130
88
|
|
|
131
|
-
this.#commentThreads.set(id, thread);
|
|
89
|
+
this.#commentThreads.set(thread.id, thread);
|
|
132
90
|
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
|
|
133
91
|
return thread;
|
|
134
92
|
}
|
|
@@ -144,7 +102,7 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
144
102
|
takeComments(): CommentThread[] {
|
|
145
103
|
const threads: CommentThread[] = [];
|
|
146
104
|
for (const thread of this.#commentThreads.values()) {
|
|
147
|
-
if (!thread.transmitted) {
|
|
105
|
+
if (thread.status === 'ACTIVE' && !thread.transmitted) {
|
|
148
106
|
thread.transmitted = true;
|
|
149
107
|
threads.push(thread);
|
|
150
108
|
}
|
|
@@ -157,30 +115,27 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
157
115
|
if (!thread) {
|
|
158
116
|
return false;
|
|
159
117
|
}
|
|
160
|
-
|
|
161
|
-
const comment: Comment = {
|
|
162
|
-
author: 'AGENT',
|
|
163
|
-
text: replyText.trim(),
|
|
164
|
-
timestamp: Date.now(),
|
|
165
|
-
};
|
|
166
|
-
thread.comments.push(comment);
|
|
167
|
-
}
|
|
168
|
-
thread.status = 'RESOLVED';
|
|
169
|
-
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
|
|
118
|
+
thread.resolve(replyText);
|
|
170
119
|
return true;
|
|
171
120
|
}
|
|
172
121
|
|
|
173
122
|
removeCommentThread(id: string): void {
|
|
174
|
-
|
|
123
|
+
const thread = this.#commentThreads.get(id);
|
|
124
|
+
if (!thread) {
|
|
175
125
|
return;
|
|
176
126
|
}
|
|
127
|
+
thread.removeEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
|
|
177
128
|
this.#commentThreads.delete(id);
|
|
178
129
|
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
|
|
179
130
|
}
|
|
180
131
|
|
|
181
132
|
clear(): void {
|
|
182
133
|
this.setCommentMode(false);
|
|
134
|
+
for (const thread of this.#commentThreads.values()) {
|
|
135
|
+
thread.removeEventListener(CommentThreadEvents.CHANGED, this.#onThreadChanged, this);
|
|
136
|
+
}
|
|
183
137
|
this.#commentThreads.clear();
|
|
138
|
+
CommentThread.resetIndex();
|
|
184
139
|
this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, []);
|
|
185
140
|
}
|
|
186
141
|
}
|