chrome-devtools-frontend 1.0.1703574 → 1.0.1704172
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/front_end/core/common/ParsedURL.ts +54 -0
- package/front_end/core/platform/StringUtilities.ts +65 -0
- package/front_end/core/sdk/CPUThrottlingManager.ts +3 -3
- package/front_end/core/sdk/SourceMap.ts +3 -3
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +4 -3
- package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -5
- package/front_end/entrypoints/main/MainImpl.ts +3 -3
- package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
- package/front_end/models/har/HARFormat.ts +7 -2
- package/front_end/models/source_map_scopes/NamesResolver.ts +13 -5
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingListView.ts +33 -1
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +4 -12
- package/front_end/panels/application/ApplicationPanelSidebar.ts +58 -60
- package/front_end/panels/application/BackForwardCacheTreeElement.ts +1 -1
- package/front_end/panels/application/FrameDetailsView.ts +64 -82
- package/front_end/panels/application/OpenedWindowDetailsView.ts +20 -21
- package/front_end/panels/application/PreloadingTreeElement.ts +3 -3
- package/front_end/panels/common/CommentsOverlayWidget.ts +145 -72
- package/front_end/panels/common/commentsOverlay.css +34 -23
- package/front_end/panels/elements/DOMTreeWidget.ts +29 -10
- package/front_end/panels/network/RequestPayloadView.ts +7 -2
- package/front_end/panels/network/ShowMoreDetailsWidget.ts +12 -9
- package/front_end/panels/sources/DebuggerPlugin.ts +49 -16
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/sources/SourcesView.ts +3 -12
- package/front_end/panels/sources/TabbedEditorContainer.ts +0 -3
- package/front_end/panels/sources/components/HeadersView.ts +193 -123
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +24 -32
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js +15 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js +8 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +0 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +0 -24
- package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts +12 -0
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js +79 -17
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/package.json +4 -4
- package/front_end/third_party/puppeteer/package/src/api/ElementHandle.ts +15 -2
- package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +10 -1
- package/front_end/third_party/puppeteer/package/src/common/Debug.ts +0 -27
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +96 -17
- package/front_end/third_party/puppeteer/package/src/node-env-setup.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +60 -22
- package/front_end/ui/comments/CommentOverlayManager.ts +78 -25
- package/front_end/ui/legacy/components/data_grid/DataGridExporter.ts +7 -13
- package/front_end/ui/legacy/components/inline_editor/PositionAreaEditor.ts +51 -57
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +101 -42
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
- package/package.json +1 -1
package/AUTHORS
CHANGED
|
@@ -99,6 +99,7 @@ Ryuhei Shima <shimaryuhei@gmail.com>
|
|
|
99
99
|
Samuel Maddock <samuelmaddock@electronjs.org>
|
|
100
100
|
Satvic Dhawan <satvicdhawan14@gmail.com>
|
|
101
101
|
Sebastian Markbåge <sebastian@calyptus.eu>
|
|
102
|
+
Semih Dogan <semih702do@gmail.com>
|
|
102
103
|
Serg Kryvonos <sergeikrivonos@gmail.com>
|
|
103
104
|
Sergio Avalos <sergio.avalos@gmail.com>
|
|
104
105
|
Shelley Vohr <shelley.vohr@gmail.com>
|
|
@@ -46,6 +46,60 @@ export function schemeIs(url: Platform.DevToolsPath.UrlString|URL, scheme: strin
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Schemes safe for unprivileged web contexts (matching ChildProcessSecurityPolicyImpl::RegisterDefaultSchemes).
|
|
51
|
+
*/
|
|
52
|
+
const WEB_SAFE_SCHEMES = new Set([
|
|
53
|
+
'http:',
|
|
54
|
+
'https:',
|
|
55
|
+
'ws:',
|
|
56
|
+
'wss:',
|
|
57
|
+
'data:',
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns true if the URL uses an unprivileged web-safe scheme (or is a `blob:` URL wrapping one).
|
|
62
|
+
*/
|
|
63
|
+
export function hasWebSafeScheme(url: Platform.DevToolsPath.UrlString|URL|string): boolean {
|
|
64
|
+
try {
|
|
65
|
+
const parsed = new URL(url);
|
|
66
|
+
if (parsed.protocol === 'blob:') {
|
|
67
|
+
return hasWebSafeScheme(parsed.pathname);
|
|
68
|
+
}
|
|
69
|
+
return WEB_SAFE_SCHEMES.has(parsed.protocol);
|
|
70
|
+
} catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Privileged browser and local schemes that must not be opened via external/new-tab links by default.
|
|
77
|
+
*/
|
|
78
|
+
const PRIVILEGED_SCHEMES = new Set([
|
|
79
|
+
'chrome:',
|
|
80
|
+
'chrome-extension:',
|
|
81
|
+
'chrome-search:',
|
|
82
|
+
'chrome-untrusted:',
|
|
83
|
+
'devtools:',
|
|
84
|
+
'file:',
|
|
85
|
+
'isolated-app:',
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns true if the URL uses a privileged scheme (or is a `blob:` URL wrapping one).
|
|
90
|
+
*/
|
|
91
|
+
export function isPrivilegedScheme(url: Platform.DevToolsPath.UrlString|URL|string): boolean {
|
|
92
|
+
try {
|
|
93
|
+
const parsed = new URL(url);
|
|
94
|
+
if (parsed.protocol === 'blob:') {
|
|
95
|
+
return isPrivilegedScheme(parsed.pathname);
|
|
96
|
+
}
|
|
97
|
+
return PRIVILEGED_SCHEMES.has(parsed.protocol);
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
49
103
|
/**
|
|
50
104
|
* File paths in DevTools that are represented either as unencoded absolute or relative paths, or encoded paths, or URLs.
|
|
51
105
|
* @example
|
|
@@ -740,3 +740,68 @@ export const concatBase64 = function(lhs: string, rhs: string): string {
|
|
|
740
740
|
const lhsToDecode = lhs.substring(lhs.length - 4);
|
|
741
741
|
return lhsLeaveAsIs + globalThis.btoa(globalThis.atob(lhsToDecode) + globalThis.atob(rhs));
|
|
742
742
|
};
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Characters that cause spreadsheet viewers (Excel, Google Sheets, LibreOffice
|
|
746
|
+
* Calc) to evaluate a cell as a formula rather than rendering it as plain text
|
|
747
|
+
* when they appear at the start of a cell.
|
|
748
|
+
*/
|
|
749
|
+
const CSV_FORMULA_TRIGGERS = new Set(['=', '+', '-', '@', '\t', '\r']);
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Matches plain numeric literals (e.g. `-42`, `+3.14`, `-1e-3`).
|
|
753
|
+
* Even though negative/signed numbers start with `-` or `+`, spreadsheets parse
|
|
754
|
+
* them as numbers rather than formulas, so we exempt them from `'` prefixing to
|
|
755
|
+
* keep numeric columns usable.
|
|
756
|
+
*/
|
|
757
|
+
const CSV_PLAIN_NUMBER = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Returns true if a spreadsheet viewer could interpret `value` as a formula
|
|
761
|
+
* (for example `=SUM(A1:A2)`, `"- Loading..."`, or `"@alice"`).
|
|
762
|
+
*/
|
|
763
|
+
function isCsvFormula(value: string): boolean {
|
|
764
|
+
// Check both the raw string and the leading-whitespace-trimmed string, since
|
|
765
|
+
// some spreadsheet parsers ignore leading spaces before `=`, `+`, `-`, or `@`.
|
|
766
|
+
const trimmed = value.trimStart();
|
|
767
|
+
if (!CSV_FORMULA_TRIGGERS.has(value[0]) && !CSV_FORMULA_TRIGGERS.has(trimmed[0])) {
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
return !CSV_PLAIN_NUMBER.test(trimmed.trimEnd());
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Formats and escapes `value` so it can be safely written as a single CSV cell.
|
|
775
|
+
*
|
|
776
|
+
* This handles two separate layers of escaping:
|
|
777
|
+
* 1. Spreadsheet formula escaping (CWE-1236 & viewer fidelity):
|
|
778
|
+
* RFC 4180 double-quoting (`"=1+1"` or `"- Loading..."`) only groups text
|
|
779
|
+
* into a single CSV column; spreadsheet apps strip the outer `"` and still
|
|
780
|
+
* evaluate cells starting with `=`, `+`, `-`, or `@` as formulas (often
|
|
781
|
+
* resulting in `#NAME?` errors or unintended formula execution). Prefixing
|
|
782
|
+
* the value with a single quote (`'`) tells spreadsheet apps to treat the
|
|
783
|
+
* cell as literal text (and they hide the leading `'` when displaying it).
|
|
784
|
+
* - Example without commas: `=SUM(A1:A2)` -> `'=SUM(A1:A2)`
|
|
785
|
+
* 2. RFC 4180 structural CSV quoting:
|
|
786
|
+
* If the cell also contains commas (`,`), double quotes (`"`), or newlines,
|
|
787
|
+
* it is wrapped in `"..."` (with inner `"` doubled to `""`) so CSV parsers
|
|
788
|
+
* do not split the cell across columns or rows.
|
|
789
|
+
* - Example with commas: `=SUM(1,2)` -> `"'=SUM(1,2)"`
|
|
790
|
+
* - Example starting with a literal quote: `"=SUM(1,2)"` -> `"""=SUM(1,2)"""`
|
|
791
|
+
* (not treated as a formula since the first character is `"`, not `=`).
|
|
792
|
+
*/
|
|
793
|
+
export const escapeCsvCell = function(value: string): string {
|
|
794
|
+
// Step 1: Prefix formula-like text with `'` so spreadsheets render it as literal text.
|
|
795
|
+
let escaped = isCsvFormula(value) ? `'${value}` : value;
|
|
796
|
+
|
|
797
|
+
// Step 2: Apply standard RFC 4180 double-quoting if the cell contains quotes,
|
|
798
|
+
// commas, or line breaks so the CSV structure stays intact.
|
|
799
|
+
if (escaped.includes('"')) {
|
|
800
|
+
escaped = escaped.replace(/"/g, '""');
|
|
801
|
+
return `"${escaped}"`;
|
|
802
|
+
}
|
|
803
|
+
if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('\r')) {
|
|
804
|
+
return `"${escaped}"`;
|
|
805
|
+
}
|
|
806
|
+
return escaped;
|
|
807
|
+
};
|
|
@@ -282,9 +282,9 @@ export class CPUThrottlingManager extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
async updateHostDefaultCPUPerformanceTier(): Promise<void> {
|
|
285
|
-
if (this.#
|
|
286
|
-
// We do not want to update the host default tier when it is
|
|
287
|
-
//
|
|
285
|
+
if (this.#isCPUPerformanceOverrideActive()) {
|
|
286
|
+
// We do not want to update the host default tier when it is overridden
|
|
287
|
+
// (in which case, `navigator.cpuPerformance` would return the override).
|
|
288
288
|
return;
|
|
289
289
|
}
|
|
290
290
|
const target = this.#targetManager.primaryPageTarget();
|
|
@@ -12,7 +12,7 @@ import {scopeTreeForScript} from './ScopeTreeCache.js';
|
|
|
12
12
|
import type {Script} from './Script.js';
|
|
13
13
|
import {buildOriginalScopes, decodePastaRanges, type NamedFunctionRange} from './SourceMapFunctionRanges.js';
|
|
14
14
|
import {decodeRangeMappings} from './SourceMapRangeMappings.js';
|
|
15
|
-
import {SourceMapScopesInfo, type TranslatedFrame} from './SourceMapScopesInfo.js';
|
|
15
|
+
import {scriptRelativePosition, SourceMapScopesInfo, type TranslatedFrame} from './SourceMapScopesInfo.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Type of the base source map JSON object, which contains the sources and the mappings at the very least, plus
|
|
@@ -850,8 +850,8 @@ export class SourceMap {
|
|
|
850
850
|
return null;
|
|
851
851
|
}
|
|
852
852
|
|
|
853
|
-
|
|
854
|
-
|
|
853
|
+
const {line, column} = scriptRelativePosition(location);
|
|
854
|
+
return this.#scopesInfo.resolveMappedVariablesAtPosition(line, column, ignoreInnerBlockScopes);
|
|
855
855
|
}
|
|
856
856
|
|
|
857
857
|
findOriginalFunctionName(position: ScopesCodec.Position): string|null {
|
|
@@ -8,7 +8,7 @@ import * as i18n from '../i18n/i18n.js';
|
|
|
8
8
|
|
|
9
9
|
import type {CallFrame, LocationRange, ScopeChainEntry} from './DebuggerModel.js';
|
|
10
10
|
import {type GetPropertiesResult, type RemoteObject, RemoteObjectImpl, RemoteObjectProperty} from './RemoteObject.js';
|
|
11
|
-
import {findExpression} from './SourceMapScopesInfo.js';
|
|
11
|
+
import {findExpression, scriptRelativePosition} from './SourceMapScopesInfo.js';
|
|
12
12
|
|
|
13
13
|
const UIStrings = {
|
|
14
14
|
/**
|
|
@@ -263,8 +263,9 @@ class SourceMapScopeRemoteObject extends RemoteObjectImpl {
|
|
|
263
263
|
|
|
264
264
|
/** @returns null if the variable is unavailable at the current paused location */
|
|
265
265
|
#findExpression(index: number): string|null {
|
|
266
|
-
const
|
|
267
|
-
|
|
266
|
+
const pausedLocation = this.#callFrame.location();
|
|
267
|
+
const pausedPosition = pausedLocation ? scriptRelativePosition(pausedLocation) : undefined;
|
|
268
|
+
return findExpression(this.#range, index, pausedPosition?.line, pausedPosition?.column);
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
static #unavailableProperty(name: string): RemoteObjectProperty {
|
|
@@ -8,7 +8,7 @@ import type * as ScopesCodec from '../../third_party/source-map-scopes-codec/sou
|
|
|
8
8
|
import type * as Platform from '../platform/platform.js';
|
|
9
9
|
import type * as TextUtils from '../text_utils/text_utils.js';
|
|
10
10
|
|
|
11
|
-
import type {CallFrame, Scope, ScopeChainEntry} from './DebuggerModel.js';
|
|
11
|
+
import type {CallFrame, Location, Scope, ScopeChainEntry} from './DebuggerModel.js';
|
|
12
12
|
import type {SourceMap} from './SourceMap.js';
|
|
13
13
|
import {SourceMapScopeChainEntry} from './SourceMapScopeChainEntry.js';
|
|
14
14
|
|
|
@@ -389,8 +389,8 @@ export class SourceMapScopesInfo {
|
|
|
389
389
|
|
|
390
390
|
/** Similar to #findGeneratedRangeChain, but takes inlineFrameIndex of virtual call frames into account */
|
|
391
391
|
#findGeneratedRangeChainForFrame(callFrame: CallFrame): ScopesCodec.GeneratedRange[] {
|
|
392
|
-
const
|
|
393
|
-
|
|
392
|
+
const {line, column} = scriptRelativePosition(callFrame.location());
|
|
393
|
+
const rangeChain = this.#findGeneratedRangeChain(line, column);
|
|
394
394
|
if (callFrame.inlineFrameIndex === 0) {
|
|
395
395
|
return rangeChain;
|
|
396
396
|
}
|
|
@@ -611,6 +611,18 @@ export function comparePositions(a: ScopesCodec.Position, b: ScopesCodec.Positio
|
|
|
611
611
|
return a.column - b.column;
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
+
/**
|
|
615
|
+
* Converts a raw V8 {@link location} into a generated position relative to the start of its script.
|
|
616
|
+
*
|
|
617
|
+
* Positions in source maps (mappings and generated ranges) are relative to the start of the script,
|
|
618
|
+
* while V8 reports locations in inline `<script>`s (without `//# sourceURL`) relative to the start of
|
|
619
|
+
* the surrounding document.
|
|
620
|
+
*/
|
|
621
|
+
export function scriptRelativePosition(location: Location): ScopesCodec.Position {
|
|
622
|
+
const {lineNumber, columnNumber} = location.script()?.rawLocationToRelativeLocation(location) ?? location;
|
|
623
|
+
return {line: lineNumber, column: columnNumber};
|
|
624
|
+
}
|
|
625
|
+
|
|
614
626
|
function positionRange(callFrame: CallFrame, scope: Scope): {start: ScopesCodec.Position, end: ScopesCodec.Position}|
|
|
615
627
|
null {
|
|
616
628
|
const range = scope.range();
|
|
@@ -619,8 +631,8 @@ function positionRange(callFrame: CallFrame, scope: Scope): {start: ScopesCodec.
|
|
|
619
631
|
return null;
|
|
620
632
|
}
|
|
621
633
|
return {
|
|
622
|
-
start:
|
|
623
|
-
end:
|
|
634
|
+
start: scriptRelativePosition(range.start),
|
|
635
|
+
end: scriptRelativePosition(range.end),
|
|
624
636
|
};
|
|
625
637
|
}
|
|
626
638
|
|
|
@@ -121,9 +121,9 @@ const UIStrings = {
|
|
|
121
121
|
*/
|
|
122
122
|
aiModelDownloaded: 'AI model downloaded',
|
|
123
123
|
/**
|
|
124
|
-
* @description Title of the menu item in the customize and control menu leading to the DevTools
|
|
124
|
+
* @description Title of the menu item in the customize and control menu leading to the Chrome DevTools for agents repository.
|
|
125
125
|
*/
|
|
126
|
-
|
|
126
|
+
getChromeDevToolsForAgents: 'Give your agent access to `DevTools`',
|
|
127
127
|
} as const;
|
|
128
128
|
const str_ = i18n.i18n.registerUIStrings('entrypoints/main/MainImpl.ts', UIStrings);
|
|
129
129
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -893,7 +893,7 @@ export class MainMenuItem implements UI.Toolbar.Provider {
|
|
|
893
893
|
|
|
894
894
|
contextMenu.defaultSection().appendAction('freestyler.main-menu', undefined, /* optional */ true);
|
|
895
895
|
|
|
896
|
-
contextMenu.defaultSection().appendItem(i18nString(UIStrings.
|
|
896
|
+
contextMenu.defaultSection().appendItem(i18nString(UIStrings.getChromeDevToolsForAgents), () => {
|
|
897
897
|
UIHelpers.openInNewTab('https://github.com/ChromeDevTools/chrome-devtools-mcp');
|
|
898
898
|
}, {
|
|
899
899
|
additionalElement: UI.UIUtils.maybeCreateNewBadge('get-devtools-mcp'),
|
|
@@ -348,7 +348,7 @@ export class CompilerScriptMapping implements DebuggerSourceMapping {
|
|
|
348
348
|
return false;
|
|
349
349
|
}
|
|
350
350
|
const {sourceMap, script} = sourceMapAndScript;
|
|
351
|
-
const {lineNumber, columnNumber} = script.
|
|
351
|
+
const {lineNumber, columnNumber} = script.rawLocationToRelativeLocation(frame);
|
|
352
352
|
|
|
353
353
|
if (!sourceMap.isOutlinedFrame(lineNumber, columnNumber)) {
|
|
354
354
|
const frames = sourceMap.translateCallSite(lineNumber, columnNumber);
|
|
@@ -2,6 +2,7 @@
|
|
|
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 * as Common from '../../core/common/common.js';
|
|
5
6
|
import type * as Platform from '../../core/platform/platform.js';
|
|
6
7
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
7
8
|
import type * as Protocol from '../../generated/protocol.js';
|
|
@@ -420,7 +421,9 @@ export class HARInitiator extends HARBase {
|
|
|
420
421
|
super(data);
|
|
421
422
|
this.type = (HARBase.optionalString(data['type']) ?? SDK.NetworkRequest.InitiatorType.OTHER) as
|
|
422
423
|
Protocol.Network.InitiatorType;
|
|
423
|
-
|
|
424
|
+
const url = HARBase.optionalString(data['url']);
|
|
425
|
+
// Ignore privileged/non-web schemes in imported HARs.
|
|
426
|
+
this.url = url && Common.ParsedURL.hasWebSafeScheme(url) ? url : undefined;
|
|
424
427
|
this.lineNumber = HARBase.optionalNumber(data['lineNumber']);
|
|
425
428
|
this.requestId = HARBase.optionalString(data['requestId']) as Protocol.Network.RequestId;
|
|
426
429
|
if (data['stack']) {
|
|
@@ -477,7 +480,9 @@ export class HARCallFrame extends HARBase {
|
|
|
477
480
|
|
|
478
481
|
this.functionName = HARBase.optionalString(data['functionName']) ?? '';
|
|
479
482
|
this.scriptId = (HARBase.optionalString(data['scriptId']) ?? '') as Protocol.Runtime.ScriptId;
|
|
480
|
-
|
|
483
|
+
const url = HARBase.optionalString(data['url']) ?? '';
|
|
484
|
+
// Ignore privileged/non-web schemes in imported HARs.
|
|
485
|
+
this.url = Common.ParsedURL.hasWebSafeScheme(url) ? url : '';
|
|
481
486
|
this.lineNumber = HARBase.optionalNumber(data['lineNumber']) ?? -1;
|
|
482
487
|
this.columnNumber = HARBase.optionalNumber(data['columnNumber']) ?? -1;
|
|
483
488
|
}
|
|
@@ -119,9 +119,11 @@ export async function findScopeChainForDebuggerScope(scope: SDK.DebuggerModel.Sc
|
|
|
119
119
|
const {scopeTree, text} = scopeTreeAndText;
|
|
120
120
|
|
|
121
121
|
// Compute the offset within the scope tree coordinate space.
|
|
122
|
+
const start = script.rawLocationToRelativeLocation(startLocation);
|
|
123
|
+
const end = script.rawLocationToRelativeLocation(endLocation);
|
|
122
124
|
const scopeOffsets = {
|
|
123
|
-
start: text.offsetFromPosition(
|
|
124
|
-
end: text.offsetFromPosition(
|
|
125
|
+
start: text.offsetFromPosition(start.lineNumber, start.columnNumber),
|
|
126
|
+
end: text.offsetFromPosition(end.lineNumber, end.columnNumber),
|
|
125
127
|
};
|
|
126
128
|
|
|
127
129
|
return findScopeChain(scopeTree, scopeOffsets);
|
|
@@ -482,7 +484,8 @@ export const allVariablesAtPosition =
|
|
|
482
484
|
}
|
|
483
485
|
|
|
484
486
|
const {scopeTree, text} = scopeTreeAndText;
|
|
485
|
-
const
|
|
487
|
+
const {lineNumber, columnNumber} = script.rawLocationToRelativeLocation(location);
|
|
488
|
+
const locationOffset = text.offsetFromPosition(lineNumber, columnNumber);
|
|
486
489
|
const scopeChain = findScopeChain(scopeTree, {start: locationOffset, end: locationOffset});
|
|
487
490
|
|
|
488
491
|
while (scopeChain.length > 0) {
|
|
@@ -746,8 +749,8 @@ export class RemoteObject extends SDK.RemoteObject.RemoteObject {
|
|
|
746
749
|
* start or if the function scope does not start with a left paren (e.g., arrow
|
|
747
750
|
* function with one parameter), the resolution returns null.
|
|
748
751
|
**/
|
|
749
|
-
async function getFunctionNameFromScopeStart(
|
|
750
|
-
|
|
752
|
+
async function getFunctionNameFromScopeStart(script: SDK.Script.Script, rawLineNumber: number,
|
|
753
|
+
rawColumnNumber: number): Promise<string|null> {
|
|
751
754
|
// To reduce the overhead of resolving function names,
|
|
752
755
|
// we check for source maps first and immediately leave
|
|
753
756
|
// this function if the script doesn't have a sourcemap.
|
|
@@ -756,6 +759,11 @@ async function getFunctionNameFromScopeStart(
|
|
|
756
759
|
return null;
|
|
757
760
|
}
|
|
758
761
|
|
|
762
|
+
// The source map and the script text are relative to the start of the script, whereas
|
|
763
|
+
// raw V8 positions in inline scripts are relative to the start of the document.
|
|
764
|
+
const {lineNumber, columnNumber} =
|
|
765
|
+
script.rawLocationToRelativeLocation({lineNumber: rawLineNumber, columnNumber: rawColumnNumber});
|
|
766
|
+
|
|
759
767
|
const scopeName = sourceMap.findOriginalFunctionName({line: lineNumber, column: columnNumber});
|
|
760
768
|
if (scopeName !== null) {
|
|
761
769
|
return scopeName;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import '../../ui/legacy/components/data_grid/data_grid.js';
|
|
6
6
|
|
|
7
|
+
import * as Host from '../../core/host/host.js';
|
|
7
8
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
9
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
9
10
|
import * as Lit from '../../ui/lit/lit.js';
|
|
@@ -45,6 +46,14 @@ const UIStrings = {
|
|
|
45
46
|
* @description Accessible title for the announcements data grid.
|
|
46
47
|
*/
|
|
47
48
|
ariaLiveRecordingList: 'Accessibility Announcements',
|
|
49
|
+
/**
|
|
50
|
+
* @description Context menu item for copying the announcement message text to the clipboard.
|
|
51
|
+
*/
|
|
52
|
+
copyMessage: 'Copy message',
|
|
53
|
+
/**
|
|
54
|
+
* @description Context menu item for copying the announcement element HTML snippet to the clipboard.
|
|
55
|
+
*/
|
|
56
|
+
copyElementHtml: 'Copy element HTML',
|
|
48
57
|
} as const;
|
|
49
58
|
const str_ =
|
|
50
59
|
i18n.i18n.registerUIStrings('panels/accessibility/AccessibilityAnnouncementRecordingListView.ts', UIStrings);
|
|
@@ -53,6 +62,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
53
62
|
export interface ViewInput {
|
|
54
63
|
items: readonly A11yAnnouncement[];
|
|
55
64
|
selectedItem: A11yAnnouncement|null;
|
|
65
|
+
onContextMenu: (menu: UI.ContextMenu.ContextMenu, item: A11yAnnouncement) => void;
|
|
56
66
|
onSelect: (item: A11yAnnouncement) => void;
|
|
57
67
|
onDeselect: () => void;
|
|
58
68
|
}
|
|
@@ -92,7 +102,12 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
92
102
|
return html`
|
|
93
103
|
<tr
|
|
94
104
|
?selected=${item === input.selectedItem}
|
|
95
|
-
@select=${() => input.onSelect(item)}
|
|
105
|
+
@select=${() => input.onSelect(item)}
|
|
106
|
+
@contextmenu=${(e: CustomEvent<UI.ContextMenu.ContextMenu>) => {
|
|
107
|
+
if (e.detail instanceof UI.ContextMenu.ContextMenu) {
|
|
108
|
+
input.onContextMenu(e.detail, item);
|
|
109
|
+
}
|
|
110
|
+
}}>
|
|
96
111
|
<td data-value=${item.time}>
|
|
97
112
|
<span>${timeString}</span>
|
|
98
113
|
</td>
|
|
@@ -159,10 +174,27 @@ export class AccessibilityAnnouncementRecordingListView extends UI.Widget.VBox {
|
|
|
159
174
|
this.requestUpdate();
|
|
160
175
|
}
|
|
161
176
|
|
|
177
|
+
#populateContextMenu(contextMenu: UI.ContextMenu.ContextMenu, item: A11yAnnouncement): void {
|
|
178
|
+
if (item.message) {
|
|
179
|
+
contextMenu.clipboardSection().appendItem(i18nString(UIStrings.copyMessage), () => {
|
|
180
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(item.message);
|
|
181
|
+
}, {jslogContext: 'copy-message'});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (item.element) {
|
|
185
|
+
contextMenu.clipboardSection().appendItem(i18nString(UIStrings.copyElementHtml), () => {
|
|
186
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(item.element);
|
|
187
|
+
}, {jslogContext: 'copy-element-html'});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
162
191
|
override performUpdate(): void {
|
|
163
192
|
const input: ViewInput = {
|
|
164
193
|
items: this.#items,
|
|
165
194
|
selectedItem: this.#selectedItem,
|
|
195
|
+
onContextMenu: (contextMenu: UI.ContextMenu.ContextMenu, item: A11yAnnouncement) => {
|
|
196
|
+
this.#populateContextMenu(contextMenu, item);
|
|
197
|
+
},
|
|
166
198
|
onSelect: (item: A11yAnnouncement) => {
|
|
167
199
|
this.selectedItem = item;
|
|
168
200
|
this.#onSelect?.(item);
|
|
@@ -744,14 +744,6 @@ export function validateAndSanitizeAnnouncement(payload: unknown): A11yAnnouncem
|
|
|
744
744
|
};
|
|
745
745
|
}
|
|
746
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
747
|
export function buildCsvContent(announcements: readonly A11yAnnouncement[]): string {
|
|
756
748
|
const csvRows: string[] = [];
|
|
757
749
|
csvRows.push(['Time', 'API', 'Politeness', 'Message'].join(','));
|
|
@@ -759,10 +751,10 @@ export function buildCsvContent(announcements: readonly A11yAnnouncement[]): str
|
|
|
759
751
|
for (const item of announcements) {
|
|
760
752
|
const timeString = new Date(item.time).toISOString();
|
|
761
753
|
const row = [
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
754
|
+
Platform.StringUtilities.escapeCsvCell(timeString),
|
|
755
|
+
Platform.StringUtilities.escapeCsvCell(item.api),
|
|
756
|
+
Platform.StringUtilities.escapeCsvCell(item.politeness),
|
|
757
|
+
Platform.StringUtilities.escapeCsvCell(item.message),
|
|
766
758
|
];
|
|
767
759
|
csvRows.push(row.join(','));
|
|
768
760
|
}
|