chrome-devtools-frontend 1.0.1700561 → 1.0.1702515
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/eslint.config.mjs +3 -1
- package/front_end/core/host/UserMetricsEnums.ts +2 -1
- package/front_end/core/root/ExperimentNames.ts +1 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +10 -10
- package/front_end/core/sdk/NetworkManager.ts +7 -0
- package/front_end/core/sdk/SecurityOrigin.ts +1 -0
- package/front_end/core/sdk/SourceMap.ts +12 -1
- package/front_end/core/sdk/SourceMapCache.ts +12 -0
- package/front_end/core/sdk/SourceMapManager.ts +17 -8
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +2 -19
- package/front_end/core/sdk/SourceMapScopesInfo.ts +21 -0
- package/front_end/devtools_compatibility.js +2 -1
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +7 -3
- package/front_end/entrypoints/formatter_worker/Substitute.ts +90 -26
- package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
- package/front_end/entrypoints/main/ExecutionContextSelector.ts +17 -4
- package/front_end/entrypoints/main/MainImpl.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +4 -6
- package/front_end/generated/protocol-mapping.d.ts +0 -8
- package/front_end/generated/protocol-proxy-api.d.ts +0 -6
- package/front_end/generated/protocol.ts +4 -25
- package/front_end/models/ai_assistance/AiAgent2.ts +13 -1
- package/front_end/models/ai_assistance/AiConversation.ts +1 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +13 -19
- package/front_end/models/ai_assistance/debug.ts +10 -2
- package/front_end/models/change_tracker/ChangeTracker.ts +5 -64
- package/front_end/models/comment_manager/CD4ABridge.ts +2 -2
- package/front_end/models/comment_manager/CommentManager.ts +6 -5
- package/front_end/models/comment_manager/CommentThread.ts +30 -13
- package/front_end/models/formatter/FormatterWorkerPool.ts +2 -2
- package/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +6 -7
- package/front_end/models/issues_manager/DeprecationIssue.ts +1 -1
- package/front_end/models/issues_manager/MarkdownIssueDescription.ts +14 -5
- package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -4
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md +0 -1
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantReadOptOut.md +5 -0
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md +0 -1
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSetOptOut.md +5 -0
- package/front_end/models/issues_manager/descriptions/deprecation.md +1 -1
- package/front_end/models/issues_manager/descriptions/sriValidationFailedIntegrityMismatch.md +2 -0
- package/front_end/models/javascript_metadata/NativeFunctions.ts +7 -2
- package/front_end/models/persistence/NetworkPersistenceManager.ts +14 -2
- package/front_end/models/source_map_scopes/NamesResolver.ts +42 -39
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +70 -1
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +1 -1
- package/front_end/panels/common/CommentThreadWidget.ts +29 -10
- package/front_end/panels/common/CommentsOverlayWidget.ts +77 -14
- package/front_end/panels/common/ExtensionServer.ts +18 -8
- package/front_end/panels/common/commentThreadWidget.css +11 -0
- package/front_end/panels/console/ConsolePrompt.ts +1 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
- package/front_end/panels/elements/ClassesPaneWidget.ts +2 -1
- package/front_end/panels/elements/DOMTreeContextMenu.ts +1 -1
- package/front_end/panels/elements/{ElementsTreeOutline.ts → DOMTreeWidget.ts} +34 -24
- package/front_end/panels/elements/ElementsPanel.ts +1 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/ShortcutTreeElement.ts +1 -1
- package/front_end/panels/elements/StylePropertiesSection.ts +10 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +105 -55
- package/front_end/panels/elements/TopLayerContainer.ts +1 -1
- package/front_end/panels/elements/components/CSSQuery.ts +1 -1
- package/front_end/panels/elements/components/cssQuery.css +4 -0
- package/front_end/panels/elements/elements.ts +3 -3
- package/front_end/panels/elements/stylesSidebarPane.css +6 -0
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +1 -1
- package/front_end/panels/profiler/HeapProfileView.ts +8 -6
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +8 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +6 -4
- package/front_end/panels/security/SecurityPanel.ts +87 -99
- package/front_end/panels/sensors/SensorsView.ts +87 -0
- package/front_end/panels/sensors/sensors-meta.ts +69 -1
- package/front_end/panels/settings/keybindsSettingsTab.css +1 -1
- package/front_end/panels/sources/ResourceOriginPlugin.ts +8 -3
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -4
- package/front_end/panels/sources/TabbedEditorContainer.ts +339 -126
- package/front_end/panels/sources/UISourceCodeFrame.ts +9 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/chromium/client-variations/ClientVariations.js +25 -96
- package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/legacy.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/package.json +4 -1
- package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
- package/front_end/ui/comments/CommentOverlayManager.ts +11 -10
- package/front_end/ui/components/markdown_view/MarkdownPlaceholderLitRenderer.ts +117 -0
- package/front_end/ui/components/markdown_view/markdown_view.ts +2 -0
- package/front_end/ui/legacy/Treeoutline.ts +30 -20
- package/front_end/ui/legacy/UIUtils.ts +1 -1
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +228 -343
- package/front_end/ui/legacy/components/object_ui/objectPropertiesSection.css +2 -27
- package/front_end/ui/legacy/treeoutline.css +2 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
|
@@ -13,12 +13,14 @@ import * as Marked from '../../third_party/marked/marked.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export interface MarkdownIssueDescription {
|
|
15
15
|
file: string;
|
|
16
|
+
title?: string;
|
|
16
17
|
substitutions?: Map<string, string>;
|
|
17
18
|
links: Array<{link: string, linkTitle: string}>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface LazyMarkdownIssueDescription {
|
|
21
22
|
file: string;
|
|
23
|
+
title?: () => string;
|
|
22
24
|
substitutions?: Map<string, () => string>;
|
|
23
25
|
links: Array<{link: string, linkTitle: () => string}>;
|
|
24
26
|
}
|
|
@@ -38,8 +40,9 @@ export function resolveLazyDescription(lazyDescription: LazyMarkdownIssueDescrip
|
|
|
38
40
|
substitutionMap.set(key, value());
|
|
39
41
|
});
|
|
40
42
|
|
|
41
|
-
const description = {
|
|
43
|
+
const description: MarkdownIssueDescription = {
|
|
42
44
|
file: lazyDescription.file,
|
|
45
|
+
title: lazyDescription.title?.(),
|
|
43
46
|
links: lazyDescription.links.map(linksMap),
|
|
44
47
|
substitutions: substitutionMap,
|
|
45
48
|
};
|
|
@@ -54,6 +57,7 @@ export interface IssueDescription {
|
|
|
54
57
|
title: string;
|
|
55
58
|
markdown: Marked.Marked.Token[];
|
|
56
59
|
links: Array<{link: string, linkTitle: string}>;
|
|
60
|
+
substitutions?: Map<string, string>;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
export async function getFileContent(url: URL): Promise<string> {
|
|
@@ -82,15 +86,16 @@ export async function createIssueDescriptionFromMarkdown(description: MarkdownIs
|
|
|
82
86
|
export function createIssueDescriptionFromRawMarkdown(
|
|
83
87
|
markdown: string, description: MarkdownIssueDescription): IssueDescription {
|
|
84
88
|
const markdownAst = Marked.Marked.lexer(markdown);
|
|
85
|
-
const
|
|
86
|
-
if (!
|
|
89
|
+
const markdownTitle = findTitleFromMarkdownAst(markdownAst);
|
|
90
|
+
if (!markdownTitle) {
|
|
87
91
|
throw new Error('Markdown issue descriptions must start with a heading');
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
return {
|
|
91
|
-
title,
|
|
95
|
+
title: description.title ?? markdownTitle,
|
|
92
96
|
markdown: markdownAst.slice(1),
|
|
93
97
|
links: description.links,
|
|
98
|
+
substitutions: description.substitutions,
|
|
94
99
|
};
|
|
95
100
|
}
|
|
96
101
|
|
|
@@ -148,5 +153,9 @@ export async function getIssueTitleFromMarkdownDescription(description: Markdown
|
|
|
148
153
|
Promise<string|null> {
|
|
149
154
|
const rawMarkdown = await getMarkdownFileContent(description.file);
|
|
150
155
|
const markdownAst = Marked.Marked.lexer(rawMarkdown);
|
|
151
|
-
|
|
156
|
+
const markdownTitle = findTitleFromMarkdownAst(markdownAst);
|
|
157
|
+
if (!markdownTitle) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
return description.title ?? markdownTitle;
|
|
152
161
|
}
|
|
@@ -77,10 +77,8 @@ export class SRIMessageSignatureIssue extends Issue<Protocol.Audits.SRIMessageSi
|
|
|
77
77
|
description.substitutions?.set('PLACEHOLDER_signatureBase', () => details.signatureBase);
|
|
78
78
|
}
|
|
79
79
|
if (details.error === Protocol.Audits.SRIMessageSignatureError.ValidationFailedIntegrityMismatch) {
|
|
80
|
-
description.substitutions?.set('PLACEHOLDER_integrityAssertions',
|
|
81
|
-
|
|
82
|
-
return prefix + this.details().integrityAssertions.join(prefix);
|
|
83
|
-
});
|
|
80
|
+
description.substitutions?.set('PLACEHOLDER_integrityAssertions',
|
|
81
|
+
() => this.details().integrityAssertions.join('\n'));
|
|
84
82
|
}
|
|
85
83
|
return resolveLazyDescription(description);
|
|
86
84
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
# Third-party websites are allowed to read cookies on this page
|
|
2
2
|
|
|
3
3
|
One or more websites are allowed to bypass user settings to read third-party cookies on this page. Web developers should take steps to remove these reads without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage).
|
|
4
|
-
{PLACEHOLDER_topleveloptout}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Third-party websites are allowed to read cookies on this page
|
|
2
|
+
|
|
3
|
+
One or more websites are allowed to bypass user settings to read third-party cookies on this page. Web developers should take steps to remove these reads without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage).
|
|
4
|
+
|
|
5
|
+
(Top level site opt-out: {PLACEHOLDER_optOutPercentage}% - [learn more](gracePeriodStagedControlExplainer))
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
# Third-party websites are allowed to set cookies on this page
|
|
2
2
|
|
|
3
3
|
One or more websites are allowed to bypass user settings to set third-party cookies on this page. Web developers should take steps to remove these sets without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage).
|
|
4
|
-
{PLACEHOLDER_topleveloptout}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Third-party websites are allowed to set cookies on this page
|
|
2
|
+
|
|
3
|
+
One or more websites are allowed to bypass user settings to set third-party cookies on this page. Web developers should take steps to remove these sets without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage).
|
|
4
|
+
|
|
5
|
+
(Top level site opt-out: {PLACEHOLDER_optOutPercentage}% - [learn more](gracePeriodStagedControlExplainer))
|
|
@@ -1367,6 +1367,11 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
1367
1367
|
signatures: [["message","?options"],["message","transfer"],["message","targetOrigin","?transfer"]],
|
|
1368
1368
|
receivers: ["Window"]
|
|
1369
1369
|
},
|
|
1370
|
+
{
|
|
1371
|
+
name: "postMessage",
|
|
1372
|
+
signatures: [["message","targetOrigin"],["message","?options"]],
|
|
1373
|
+
receivers: ["HTMLPersistentWidgetElement","PersistentWidgetOpener"]
|
|
1374
|
+
},
|
|
1370
1375
|
{
|
|
1371
1376
|
name: "deleteRule",
|
|
1372
1377
|
signatures: [["index"]],
|
|
@@ -2050,7 +2055,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
2050
2055
|
},
|
|
2051
2056
|
{
|
|
2052
2057
|
name: "write",
|
|
2053
|
-
signatures: [["...text"]
|
|
2058
|
+
signatures: [["...text"]],
|
|
2054
2059
|
receivers: ["Document"]
|
|
2055
2060
|
},
|
|
2056
2061
|
{
|
|
@@ -2489,7 +2494,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
|
|
|
2489
2494
|
},
|
|
2490
2495
|
{
|
|
2491
2496
|
name: "writeln",
|
|
2492
|
-
signatures: [["...text"]
|
|
2497
|
+
signatures: [["...text"]]
|
|
2493
2498
|
},
|
|
2494
2499
|
{
|
|
2495
2500
|
name: "elementFromPoint",
|
|
@@ -270,6 +270,8 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
270
270
|
encodeURI(pathPart).replace(/[\/\*]/g, match => '%' + match[0].charCodeAt(0).toString(16).toUpperCase());
|
|
271
271
|
if (encodedName === '..') {
|
|
272
272
|
encodedName = '%2E%2E';
|
|
273
|
+
} else if (encodedName === '.') {
|
|
274
|
+
encodedName = '%2E';
|
|
273
275
|
}
|
|
274
276
|
if (Host.Platform.isWin()) {
|
|
275
277
|
// Windows does not allow ':' and '?' in filenames
|
|
@@ -335,7 +337,10 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
335
337
|
if (!encodedFilePath) {
|
|
336
338
|
return null;
|
|
337
339
|
}
|
|
338
|
-
const encodedPath = Common.ParsedURL.ParsedURL.
|
|
340
|
+
const encodedPath = Common.ParsedURL.ParsedURL.substr(encodedFilePath, 0, encodedFilePath.lastIndexOf('/'));
|
|
341
|
+
if (!encodedPath) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
339
344
|
uiSourceCode = await this.#project.createFile(encodedPath, HEADERS_FILENAME, '');
|
|
340
345
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.HeaderOverrideFileCreated);
|
|
341
346
|
}
|
|
@@ -525,6 +530,10 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
525
530
|
const encodedFileName = Common.ParsedURL.ParsedURL.substring(encodedPath, lastIndexOfSlash + 1);
|
|
526
531
|
const rawFileName = Common.ParsedURL.ParsedURL.encodedPathToRawPathString(encodedFileName);
|
|
527
532
|
encodedPath = Common.ParsedURL.ParsedURL.substr(encodedPath, 0, lastIndexOfSlash);
|
|
533
|
+
if (!encodedPath || rawFileName === HEADERS_FILENAME) {
|
|
534
|
+
this.#savingForOverrides.delete(uiSourceCode);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
528
537
|
if (this.#project) {
|
|
529
538
|
await this.#project.createFile(encodedPath, rawFileName, content ?? '', isEncoded);
|
|
530
539
|
}
|
|
@@ -564,7 +573,7 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
564
573
|
const relativePathParts = FileSystemWorkspaceBinding.relativePath(uiSourceCode);
|
|
565
574
|
// Decode twice to handle paths generated on Windows OS.
|
|
566
575
|
const host = this.decodeLocalPathToUrlPath(this.decodeLocalPathToUrlPath(relativePathParts[0] || '')).toLowerCase();
|
|
567
|
-
return ['chrome:', 'data:', 'blob:', 'javascript:', 'about:', 'mailto:', 'vbscript:'].includes(host) ||
|
|
576
|
+
return ['chrome:', 'data:', 'blob:', 'javascript:', 'about:', 'mailto:', 'vbscript:', '.', '..'].includes(host) ||
|
|
568
577
|
forbiddenUrls.includes(host);
|
|
569
578
|
}
|
|
570
579
|
|
|
@@ -578,6 +587,9 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
578
587
|
if (!url) {
|
|
579
588
|
return false;
|
|
580
589
|
}
|
|
590
|
+
if ((url.scheme === 'http' || url.scheme === 'https') && (!url.host || url.host === '.' || url.host === '..')) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
581
593
|
return !['http', 'https', 'file'].includes(url.scheme) || forbiddenUrls.includes(url.host);
|
|
582
594
|
}
|
|
583
595
|
|
|
@@ -15,7 +15,7 @@ interface CachedScopeMap {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const scopeToCachedIdentifiersMap = new WeakMap<Formatter.FormatterWorkerPool.ScopeTreeNode, CachedScopeMap>();
|
|
18
|
-
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Map<string, string|null
|
|
18
|
+
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Array<Map<string, string|null>>>();
|
|
19
19
|
|
|
20
20
|
export async function getTextFor(contentProvider: TextUtils.ContentProvider.ContentProvider):
|
|
21
21
|
Promise<TextUtils.Text.Text|null> {
|
|
@@ -401,56 +401,61 @@ export const resolveScopeChain =
|
|
|
401
401
|
return scopes.map(scope => new ScopeWithSourceMappedVariables(scope, thisObject, debuggerWorkspaceBinding));
|
|
402
402
|
};
|
|
403
403
|
|
|
404
|
+
function reverseScopeMapping(variableMapping: Map<string, string>): Map<string, string|null> {
|
|
405
|
+
const result = new Map<string, string|null>();
|
|
406
|
+
for (const [compiledName, originalName] of variableMapping) {
|
|
407
|
+
if (originalName && !result.has(originalName)) {
|
|
408
|
+
result.set(originalName, compiledName);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return result;
|
|
412
|
+
}
|
|
413
|
+
|
|
404
414
|
/**
|
|
405
|
-
* @returns
|
|
406
|
-
* shadowed) we set it to `null`.
|
|
415
|
+
* @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
|
|
407
416
|
*/
|
|
408
417
|
export const allVariablesInCallFrame = async(
|
|
409
418
|
callFrame: SDK.DebuggerModel.CallFrame,
|
|
410
419
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
|
|
411
|
-
Promise<Map<string, string|null
|
|
420
|
+
Promise<Array<Map<string, string|null>>> => {
|
|
412
421
|
if (!callFrame.debuggerModel.target()
|
|
413
422
|
.targetManager()
|
|
414
423
|
.settings.resolve(SDK.SDKSettings.jsSourceMapsEnabledSettingDescriptor)
|
|
415
424
|
.get()) {
|
|
416
|
-
return
|
|
425
|
+
return [];
|
|
417
426
|
}
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
420
|
-
return
|
|
427
|
+
const cached = cachedMapByCallFrame.get(callFrame);
|
|
428
|
+
if (cached) {
|
|
429
|
+
return cached;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
|
|
433
|
+
const sourceMap = callFrame.script.sourceMap() ??
|
|
434
|
+
await callFrame.debuggerModel.sourceMapManager().sourceMapForClientPromise(callFrame.script);
|
|
435
|
+
const mappedVariables =
|
|
436
|
+
sourceMap?.resolveMappedVariablesAtPosition(callFrame.location(), callFrame.returnValue() !== null);
|
|
437
|
+
if (mappedVariables) {
|
|
438
|
+
cachedMapByCallFrame.set(callFrame, mappedVariables);
|
|
439
|
+
return mappedVariables;
|
|
440
|
+
}
|
|
421
441
|
}
|
|
422
442
|
|
|
423
443
|
const scopeChain = callFrame.scopeChain().filter(scope => !scope.empty());
|
|
424
444
|
const nameMappings =
|
|
425
445
|
await Promise.all(scopeChain.map(scope => resolveDebuggerScope(scope, debuggerWorkspaceBinding)));
|
|
426
|
-
const reverseMapping =
|
|
427
|
-
const compiledNames = new Set<string>();
|
|
428
|
-
for (const {variableMapping} of nameMappings) {
|
|
429
|
-
for (const [compiledName, originalName] of variableMapping) {
|
|
430
|
-
if (!originalName) {
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
if (!reverseMapping.has(originalName)) {
|
|
434
|
-
// An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
|
|
435
|
-
const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
|
|
436
|
-
reverseMapping.set(originalName, compiledNameOrNull);
|
|
437
|
-
}
|
|
438
|
-
compiledNames.add(compiledName);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
446
|
+
const reverseMapping = nameMappings.map(({variableMapping}) => reverseScopeMapping(variableMapping));
|
|
441
447
|
cachedMapByCallFrame.set(callFrame, reverseMapping);
|
|
442
448
|
return reverseMapping;
|
|
443
449
|
};
|
|
444
450
|
|
|
445
451
|
/**
|
|
446
|
-
* @returns
|
|
447
|
-
* shadowed) we set it to `null`.
|
|
452
|
+
* @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
|
|
448
453
|
*/
|
|
449
454
|
export const allVariablesAtPosition =
|
|
450
455
|
async(location: SDK.DebuggerModel.Location,
|
|
451
456
|
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
|
|
452
|
-
Promise<Map<string, string|null
|
|
453
|
-
const reverseMapping
|
|
457
|
+
Promise<Array<Map<string, string|null>>> => {
|
|
458
|
+
const reverseMapping: Array<Map<string, string|null>> = [];
|
|
454
459
|
const script = location.script();
|
|
455
460
|
if (!script) {
|
|
456
461
|
return reverseMapping;
|
|
@@ -462,6 +467,15 @@ export const allVariablesAtPosition =
|
|
|
462
467
|
return reverseMapping;
|
|
463
468
|
}
|
|
464
469
|
|
|
470
|
+
if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
|
|
471
|
+
const sourceMap =
|
|
472
|
+
script.sourceMap() ?? await script.debuggerModel.sourceMapManager().sourceMapForClientPromise(script);
|
|
473
|
+
const mappedVariables = sourceMap?.resolveMappedVariablesAtPosition(location);
|
|
474
|
+
if (mappedVariables) {
|
|
475
|
+
return mappedVariables;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
465
479
|
const scopeTreeAndText = await computeScopeTree(script);
|
|
466
480
|
if (!scopeTreeAndText) {
|
|
467
481
|
return reverseMapping;
|
|
@@ -470,21 +484,10 @@ export const allVariablesAtPosition =
|
|
|
470
484
|
const {scopeTree, text} = scopeTreeAndText;
|
|
471
485
|
const locationOffset = text.offsetFromPosition(location.lineNumber, location.columnNumber);
|
|
472
486
|
const scopeChain = findScopeChain(scopeTree, {start: locationOffset, end: locationOffset});
|
|
473
|
-
const compiledNames = new Set<string>();
|
|
474
487
|
|
|
475
488
|
while (scopeChain.length > 0) {
|
|
476
489
|
const {variableMapping} = await resolveScope(script, scopeChain, debuggerWorkspaceBinding);
|
|
477
|
-
|
|
478
|
-
if (!originalName) {
|
|
479
|
-
continue;
|
|
480
|
-
}
|
|
481
|
-
if (!reverseMapping.has(originalName)) {
|
|
482
|
-
// An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
|
|
483
|
-
const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
|
|
484
|
-
reverseMapping.set(originalName, compiledNameOrNull);
|
|
485
|
-
}
|
|
486
|
-
compiledNames.add(compiledName);
|
|
487
|
-
}
|
|
490
|
+
reverseMapping.push(reverseScopeMapping(variableMapping));
|
|
488
491
|
scopeChain.pop();
|
|
489
492
|
}
|
|
490
493
|
return reverseMapping;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
|
+
import * as Platform from '../../core/platform/platform.js';
|
|
7
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
8
9
|
import type * as Protocol from '../../generated/protocol.js';
|
|
9
10
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
@@ -35,6 +36,10 @@ const UIStrings = {
|
|
|
35
36
|
* @description Tooltip for the clear announcements button in the announcements tool.
|
|
36
37
|
*/
|
|
37
38
|
clearAnnouncements: 'Clear announcements',
|
|
39
|
+
/**
|
|
40
|
+
* @description Tooltip for the export to CSV button in the announcements tool.
|
|
41
|
+
*/
|
|
42
|
+
exportCsv: 'Export to CSV',
|
|
38
43
|
/**
|
|
39
44
|
* @description Label/title for the dropdown filter to select which announcement types to record.
|
|
40
45
|
*/
|
|
@@ -108,6 +113,8 @@ export interface ViewInput {
|
|
|
108
113
|
isRecording: boolean;
|
|
109
114
|
onToggleRecording: () => void;
|
|
110
115
|
onClear: () => void;
|
|
116
|
+
onExportCsv: () => void;
|
|
117
|
+
canExport: boolean;
|
|
111
118
|
recordTypeFilter: RecordTypeFilter;
|
|
112
119
|
onRecordTypeFilterChange: (type: RecordTypeFilter) => void;
|
|
113
120
|
textFilter: string;
|
|
@@ -144,6 +151,14 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
144
151
|
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
145
152
|
.jslogContext=${'accessibility.clear-announcements'}>
|
|
146
153
|
</devtools-button>
|
|
154
|
+
<devtools-button
|
|
155
|
+
title=${i18nString(UIStrings.exportCsv)}
|
|
156
|
+
.iconName=${'download'}
|
|
157
|
+
.disabled=${!input.canExport}
|
|
158
|
+
@click=${input.onExportCsv}
|
|
159
|
+
.variant=${Buttons.Button.Variant.TOOLBAR}
|
|
160
|
+
.jslogContext=${'accessibility.export-csv'}>
|
|
161
|
+
</devtools-button>
|
|
147
162
|
<div class="toolbar-divider" role="separator"></div>
|
|
148
163
|
<select
|
|
149
164
|
title=${i18nString(UIStrings.filterByType)}
|
|
@@ -729,6 +744,32 @@ export function validateAndSanitizeAnnouncement(payload: unknown): A11yAnnouncem
|
|
|
729
744
|
};
|
|
730
745
|
}
|
|
731
746
|
|
|
747
|
+
export function escapeCsvValue(val: string): string {
|
|
748
|
+
const escaped = val.replace(/"/g, '""');
|
|
749
|
+
if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('\r') || escaped.includes('"')) {
|
|
750
|
+
return `"${escaped}"`;
|
|
751
|
+
}
|
|
752
|
+
return escaped;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
export function buildCsvContent(announcements: readonly A11yAnnouncement[]): string {
|
|
756
|
+
const csvRows: string[] = [];
|
|
757
|
+
csvRows.push(['Time', 'API', 'Politeness', 'Message'].join(','));
|
|
758
|
+
|
|
759
|
+
for (const item of announcements) {
|
|
760
|
+
const timeString = new Date(item.time).toISOString();
|
|
761
|
+
const row = [
|
|
762
|
+
escapeCsvValue(timeString),
|
|
763
|
+
escapeCsvValue(item.api),
|
|
764
|
+
escapeCsvValue(item.politeness),
|
|
765
|
+
escapeCsvValue(item.message),
|
|
766
|
+
];
|
|
767
|
+
csvRows.push(row.join(','));
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return csvRows.join('\r\n');
|
|
771
|
+
}
|
|
772
|
+
|
|
732
773
|
export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane implements SDK.TargetManager.Observer {
|
|
733
774
|
#announcements: A11yAnnouncement[] = [];
|
|
734
775
|
#filteredAnnouncements: readonly A11yAnnouncement[]|null = null;
|
|
@@ -984,6 +1025,29 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
984
1025
|
this.requestUpdate();
|
|
985
1026
|
}
|
|
986
1027
|
|
|
1028
|
+
#exportCsv(): void {
|
|
1029
|
+
const csvContent = this.#buildCsvContent();
|
|
1030
|
+
const blob = new Blob(['\ufeff', csvContent], {type: 'text/csv;charset=utf-8'});
|
|
1031
|
+
const url = URL.createObjectURL(blob);
|
|
1032
|
+
/* eslint-disable-next-line @devtools/no-imperative-dom-api */
|
|
1033
|
+
const link = document.createElement('a');
|
|
1034
|
+
link.setAttribute('href', url);
|
|
1035
|
+
link.setAttribute('download', `aria-live-announcements-${Platform.DateUtilities.toISO8601Compact(new Date())}.csv`);
|
|
1036
|
+
link.style.visibility = 'hidden';
|
|
1037
|
+
document.body.appendChild(link);
|
|
1038
|
+
link.click();
|
|
1039
|
+
document.body.removeChild(link);
|
|
1040
|
+
URL.revokeObjectURL(url);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
#buildCsvContent(): string {
|
|
1044
|
+
return buildCsvContent(this.filteredAnnouncements);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
exportCsvForTest(): string {
|
|
1048
|
+
return this.#buildCsvContent();
|
|
1049
|
+
}
|
|
1050
|
+
|
|
987
1051
|
override performUpdate(): void {
|
|
988
1052
|
const blockedTargets: BlockedTargetInfo[] = [];
|
|
989
1053
|
for (const [target, reason] of this.#blockedTargets) {
|
|
@@ -991,6 +1055,7 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
991
1055
|
blockedTargets.push({targetName, reason});
|
|
992
1056
|
}
|
|
993
1057
|
|
|
1058
|
+
const filteredAnnouncements = this.filteredAnnouncements;
|
|
994
1059
|
const input: ViewInput = {
|
|
995
1060
|
isRecording: this.#isRecording,
|
|
996
1061
|
onToggleRecording: () => {
|
|
@@ -1003,6 +1068,10 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
1003
1068
|
onClear: () => {
|
|
1004
1069
|
this.clearAnnouncements();
|
|
1005
1070
|
},
|
|
1071
|
+
onExportCsv: () => {
|
|
1072
|
+
this.#exportCsv();
|
|
1073
|
+
},
|
|
1074
|
+
canExport: filteredAnnouncements.length > 0,
|
|
1006
1075
|
recordTypeFilter: this.#recordTypeFilter,
|
|
1007
1076
|
onRecordTypeFilterChange: (type: RecordTypeFilter) => {
|
|
1008
1077
|
this.setRecordTypeFilter(type);
|
|
@@ -1012,7 +1081,7 @@ export class AccessibilityAnnouncementRecordingView extends AccessibilitySubPane
|
|
|
1012
1081
|
this.setTextFilter(text);
|
|
1013
1082
|
},
|
|
1014
1083
|
blockedTargets,
|
|
1015
|
-
announcements:
|
|
1084
|
+
announcements: filteredAnnouncements,
|
|
1016
1085
|
};
|
|
1017
1086
|
this.#view(input, undefined, this.contentElement);
|
|
1018
1087
|
}
|
|
@@ -1636,7 +1636,7 @@ async function makeDomTreeWidget(widgetData: AiAssistanceModel.AiAgent.DomTreeAi
|
|
|
1636
1636
|
// clang-format off
|
|
1637
1637
|
const renderedWidget = html`
|
|
1638
1638
|
${networkRequest ? renderNetworkRequestPreview(networkRequest) : Lit.nothing}
|
|
1639
|
-
<devtools-widget class="dom-tree-widget" ${widget(Elements.
|
|
1639
|
+
<devtools-widget class="dom-tree-widget" ${widget(Elements.DOMTreeWidget.DOMTreeWidget, {
|
|
1640
1640
|
maxTreeDepth: 2,
|
|
1641
1641
|
enableContextMenu: false,
|
|
1642
1642
|
showComments: false,
|
|
@@ -7,6 +7,7 @@ import '../../ui/components/tooltips/tooltips.js';
|
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
8
|
import type * as SDK from '../../core/sdk/sdk.js';
|
|
9
9
|
import type * as CommentManager from '../../models/comment_manager/comment_manager.js';
|
|
10
|
+
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
10
11
|
import * as Input from '../../ui/components/input/input.js';
|
|
11
12
|
import * as MarkdownView from '../../ui/components/markdown_view/markdown_view.js';
|
|
12
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
@@ -41,6 +42,10 @@ const UIStrings = {
|
|
|
41
42
|
* @description aria-label for the comment text area.
|
|
42
43
|
*/
|
|
43
44
|
commentInputAriaLabel: 'Comment input',
|
|
45
|
+
/**
|
|
46
|
+
* @description Tooltip and aria-label for the close button in the comment thread header.
|
|
47
|
+
*/
|
|
48
|
+
close: 'Close',
|
|
44
49
|
} as const;
|
|
45
50
|
|
|
46
51
|
const UIStringsNotTranslate = {
|
|
@@ -70,6 +75,7 @@ export interface ViewInput {
|
|
|
70
75
|
textAreaRef: Lit.Directives.Ref<HTMLTextAreaElement>;
|
|
71
76
|
onAddComment: (text: string) => void;
|
|
72
77
|
onCommentTextChange: (event: Event) => void;
|
|
78
|
+
onClose?: () => void;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
export type ViewOutput = undefined;
|
|
@@ -87,16 +93,27 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
87
93
|
widget(DOMNodeLink, {node: input.title.node}) :
|
|
88
94
|
html`<span class="selected-item-text">${input.title.text}</span>`}
|
|
89
95
|
</span>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
<div class="header-actions">
|
|
97
|
+
${hasComment ? html`
|
|
98
|
+
<div class="sent-status">
|
|
99
|
+
<devtools-icon
|
|
100
|
+
class="check-icon"
|
|
101
|
+
name="checkmark"
|
|
102
|
+
aria-label=${i18nString(UIStrings.sentCheckmark)}>
|
|
103
|
+
</devtools-icon>
|
|
104
|
+
<span>${i18nString(UIStrings.sent)}</span>
|
|
105
|
+
</div>
|
|
106
|
+
` : Lit.nothing}
|
|
107
|
+
<devtools-button
|
|
108
|
+
class="close-button"
|
|
109
|
+
aria-label=${i18nString(UIStrings.close)}
|
|
110
|
+
.iconName=${'cross'}
|
|
111
|
+
.variant=${Buttons.Button.Variant.ICON}
|
|
112
|
+
.size=${Buttons.Button.Size.SMALL}
|
|
113
|
+
.title=${i18nString(UIStrings.close)}
|
|
114
|
+
@click=${input.onClose}
|
|
115
|
+
></devtools-button>
|
|
116
|
+
</div>
|
|
100
117
|
</div>
|
|
101
118
|
|
|
102
119
|
${hasComment ? html`
|
|
@@ -171,6 +188,7 @@ export class CommentThreadWidget extends UI.Widget.Widget {
|
|
|
171
188
|
#textAreaRef = createRef<HTMLTextAreaElement>();
|
|
172
189
|
#view: View;
|
|
173
190
|
onAddComment?: (text: string) => void;
|
|
191
|
+
onClose?: () => void;
|
|
174
192
|
|
|
175
193
|
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
176
194
|
super(element);
|
|
@@ -213,6 +231,7 @@ export class CommentThreadWidget extends UI.Widget.Widget {
|
|
|
213
231
|
textAreaRef: this.#textAreaRef,
|
|
214
232
|
onAddComment: this.#handleAddComment,
|
|
215
233
|
onCommentTextChange: this.#handleCommentTextChange,
|
|
234
|
+
onClose: this.onClose,
|
|
216
235
|
};
|
|
217
236
|
this.#view(viewInput, undefined, this.contentElement);
|
|
218
237
|
}
|