chrome-devtools-frontend 1.0.1697998 → 1.0.1699061
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/devtools-verification/SKILL.md +19 -0
- package/.agents/skills/{repro-flaky-tests → fix-tests}/SKILL.md +2 -2
- 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 +6 -56
- package/front_end/core/sdk/DebuggerModel.ts +9 -8
- package/front_end/core/sdk/NetworkManager.ts +2 -2
- package/front_end/core/sdk/NetworkRequest.ts +1 -1
- package/front_end/core/sdk/OverlayModel.ts +11 -12
- 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 +109 -15
- 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 +54 -1
- 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/CookieIssue.ts +0 -13
- 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/source_map_scopes/NamesResolver.ts +11 -3
- package/front_end/models/source_map_scopes/ScopeChainModel.ts +10 -6
- package/front_end/models/workspace/UISourceCode.ts +20 -0
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +281 -3
- package/front_end/panels/accessibility/accessibilityAnnouncementRecordingView.css +85 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +5 -8
- package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/application/CrashReportContextView.ts +1 -1
- package/front_end/panels/application/IndexedDBViews.ts +1 -1
- package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
- package/front_end/panels/application/components/AdsView.ts +63 -1
- package/front_end/panels/application/components/adsView.css +11 -1
- package/front_end/{ui/comments → panels/common}/CommentThreadWidget.ts +5 -20
- 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}/commentThreadWidget.css +0 -12
- 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/CSSRuleValidator.ts +1 -1
- package/front_end/panels/elements/ElementsPanel.ts +9 -5
- package/front_end/panels/elements/ElementsTreeElement.ts +11 -3
- package/front_end/panels/elements/ElementsTreeOutline.ts +69 -74
- 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 +11 -5
- package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
- package/front_end/panels/event_listeners/EventListenersView.ts +33 -44
- package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
- 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/mobile_throttling/NetworkPanelIndicator.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +1 -1
- package/front_end/panels/recorder/StepView.ts +19 -4
- package/front_end/panels/recorder/TimelineSection.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/settings/BackendLinkingSettingsTab.ts +2 -1
- package/front_end/panels/settings/EditFileSystemView.ts +1 -1
- package/front_end/panels/sources/CallStackSidebarPane.ts +1 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +2 -2
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
- package/front_end/panels/sources/sources-meta.ts +1 -1
- package/front_end/panels/timeline/components/DetailsView.ts +3 -3
- package/front_end/panels/timeline/components/OriginMap.ts +1 -1
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -3
- 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/components/buttons/Button.ts +19 -1
- package/front_end/ui/legacy/ContextMenu.ts +16 -1
- package/front_end/ui/legacy/PlusButton.ts +5 -6
- package/front_end/ui/legacy/Treeoutline.ts +6 -0
- package/front_end/ui/legacy/Widget.ts +33 -0
- package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +3 -0
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +14 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +36 -32
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/package.json +1 -1
- package/.agents/skills/devtools-ci/SKILL.md +0 -65
- package/.agents/skills/evaluate-ai-css-completion/SKILL.md +0 -143
- package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +0 -104
- package/.agents/skills/fixing-skipped-tests/SKILL.md +0 -32
- package/.agents/skills/gerrit-cli/SKILL.md +0 -74
- package/.agents/skills/gerrit-cli/references/commands.md +0 -169
- package/.agents/skills/gerrit-cli/references/workflows.md +0 -63
- package/.agents/skills/gerrit-cli/scripts/import_upstream.py +0 -85
- package/front_end/models/issues_manager/descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +0 -4
|
@@ -44,6 +44,7 @@ import {ConsoleModel} from './ConsoleModel.js';
|
|
|
44
44
|
import {CSSModel} from './CSSModel.js';
|
|
45
45
|
import type {FrameManager} from './FrameManager.js';
|
|
46
46
|
import {OverlayModel} from './OverlayModel.js';
|
|
47
|
+
import {focusInPage, scrollIntoViewInPage, toggleClassAndInjectStyleRule} from './PageFunctions.js';
|
|
47
48
|
import {RemoteObject} from './RemoteObject.js';
|
|
48
49
|
import {Events as ResourceTreeModelEvents, type ResourceTreeFrame, ResourceTreeModel} from './ResourceTreeModel.js';
|
|
49
50
|
import {RuntimeModel} from './RuntimeModel.js';
|
|
@@ -1127,47 +1128,6 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
|
|
|
1127
1128
|
[{value: pseudoElementName}, {value: !hidden}]);
|
|
1128
1129
|
object.release();
|
|
1129
1130
|
this.setMarker('hidden-marker', hidden ? null : true);
|
|
1130
|
-
|
|
1131
|
-
function toggleClassAndInjectStyleRule(this: Element, pseudoElementName: string|null, hidden: boolean): void {
|
|
1132
|
-
const classNamePrefix = '__web-inspector-hide';
|
|
1133
|
-
const classNameSuffix = '-shortcut__';
|
|
1134
|
-
const styleTagId = '__web-inspector-hide-shortcut-style__';
|
|
1135
|
-
const pseudoElementNameEscaped = pseudoElementName ? pseudoElementName.replace(/[\(\)\:]/g, '_') : '';
|
|
1136
|
-
const className = classNamePrefix + pseudoElementNameEscaped + classNameSuffix;
|
|
1137
|
-
this.classList.toggle(className, hidden);
|
|
1138
|
-
|
|
1139
|
-
let localRoot: Element|HTMLHeadElement = this;
|
|
1140
|
-
while (localRoot.parentNode) {
|
|
1141
|
-
localRoot = (localRoot.parentNode as Element);
|
|
1142
|
-
}
|
|
1143
|
-
if (localRoot.nodeType === Node.DOCUMENT_NODE) {
|
|
1144
|
-
localRoot = document.head;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
let style = localRoot.querySelector('style#' + styleTagId);
|
|
1148
|
-
if (!style) {
|
|
1149
|
-
const selectors = [];
|
|
1150
|
-
selectors.push('.__web-inspector-hide-shortcut__');
|
|
1151
|
-
selectors.push('.__web-inspector-hide-shortcut__ *');
|
|
1152
|
-
const selector = selectors.join(', ');
|
|
1153
|
-
const ruleBody = ' visibility: hidden !important;';
|
|
1154
|
-
const rule = '\n' + selector + '\n{\n' + ruleBody + '\n}\n';
|
|
1155
|
-
|
|
1156
|
-
style = document.createElement('style');
|
|
1157
|
-
style.id = styleTagId;
|
|
1158
|
-
style.textContent = rule;
|
|
1159
|
-
|
|
1160
|
-
localRoot.appendChild(style);
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
// In addition to putting them on the element we want to hide, we will
|
|
1164
|
-
// also add pseudo element classes to the style element to keep track of
|
|
1165
|
-
// which pseudo elements we have style rules for.
|
|
1166
|
-
if (pseudoElementName && !style.classList.contains(className)) {
|
|
1167
|
-
style.classList.add(className);
|
|
1168
|
-
style.textContent = `.${className}${pseudoElementName}, ${style.textContent}`;
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
1131
|
}
|
|
1172
1132
|
|
|
1173
1133
|
isToggledToHidden(): boolean {
|
|
@@ -1329,8 +1289,8 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
|
|
|
1329
1289
|
return node;
|
|
1330
1290
|
}
|
|
1331
1291
|
|
|
1332
|
-
async callFunction<T, U extends string|number>(fn: (this:
|
|
1333
|
-
|
|
1292
|
+
async callFunction<T, U extends string|number, This = never>(fn: (this: This, ...args: U[]) => T,
|
|
1293
|
+
args: U[] = []): Promise<{value: T}|null> {
|
|
1334
1294
|
const object = await this.resolveToObject();
|
|
1335
1295
|
if (!object) {
|
|
1336
1296
|
return null;
|
|
@@ -1359,16 +1319,10 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
|
|
|
1359
1319
|
return;
|
|
1360
1320
|
}
|
|
1361
1321
|
|
|
1362
|
-
|
|
1363
|
-
if
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1322
|
+
// Highlight synchronously before scrolling to avoid out-of-order highlights
|
|
1323
|
+
// if asynchronous scroll calls resolve late during rapid navigation.
|
|
1367
1324
|
node.highlightForTwoSeconds();
|
|
1368
|
-
|
|
1369
|
-
function scrollIntoViewInPage(this: Element): void {
|
|
1370
|
-
this.scrollIntoViewIfNeeded(true);
|
|
1371
|
-
}
|
|
1325
|
+
await node.callFunction(scrollIntoViewInPage);
|
|
1372
1326
|
}
|
|
1373
1327
|
|
|
1374
1328
|
async focus(): Promise<void> {
|
|
@@ -1383,10 +1337,6 @@ export class DOMNode extends Common.ObjectWrapper.ObjectWrapper<DOMNodeEventType
|
|
|
1383
1337
|
|
|
1384
1338
|
node.highlightForTwoSeconds();
|
|
1385
1339
|
await this.#domModel.target().pageAgent().invoke_bringToFront();
|
|
1386
|
-
|
|
1387
|
-
function focusInPage(this: HTMLElement): void {
|
|
1388
|
-
this.focus();
|
|
1389
|
-
}
|
|
1390
1340
|
}
|
|
1391
1341
|
|
|
1392
1342
|
simpleSelector(): string {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
pauseOnExceptionEnabledSettingDescriptor,
|
|
24
24
|
pauseOnUncaughtExceptionSettingDescriptor,
|
|
25
25
|
} from './SDKSettings.js';
|
|
26
|
-
import {SourceMap} from './SourceMap.js';
|
|
26
|
+
import {SourceMap, SourceMapProvenance} from './SourceMap.js';
|
|
27
27
|
import {SourceMapManager} from './SourceMapManager.js';
|
|
28
28
|
import {Capability, type Target} from './Target.js';
|
|
29
29
|
|
|
@@ -189,10 +189,10 @@ export class DebuggerModel extends SDKModel<EventTypes> {
|
|
|
189
189
|
this.agent = target.debuggerAgent();
|
|
190
190
|
this.#runtimeModel = (target.model(RuntimeModel) as RuntimeModel);
|
|
191
191
|
|
|
192
|
-
this.#sourceMapManager =
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
this.#sourceMapManager = new SourceMapManager(
|
|
193
|
+
target,
|
|
194
|
+
(compiledURL, sourceMappingURL, payload, script, provenance) => new SourceMap(
|
|
195
|
+
compiledURL, sourceMappingURL, payload, target.targetManager().getConsole(), script, provenance));
|
|
196
196
|
|
|
197
197
|
const settings = this.target().targetManager().settings;
|
|
198
198
|
this.#pauseOnExceptionEnabledSetting = settings.resolve(pauseOnExceptionEnabledSettingDescriptor);
|
|
@@ -719,7 +719,7 @@ export class DebuggerModel extends SDKModel<EventTypes> {
|
|
|
719
719
|
|
|
720
720
|
if ((!selectedDebugSymbol || selectedDebugSymbol.type === Protocol.Debugger.DebugSymbolsType.SourceMap) &&
|
|
721
721
|
script.sourceMapURL && !hasSyntaxError) {
|
|
722
|
-
this.#sourceMapManager.attachSourceMap(script, script.sourceURL, script.sourceMapURL);
|
|
722
|
+
this.#sourceMapManager.attachSourceMap(script, script.sourceURL, script.sourceMapURL, SourceMapProvenance.CDP);
|
|
723
723
|
}
|
|
724
724
|
|
|
725
725
|
const isDiscardable = hasSyntaxError && script.isAnonymousScript();
|
|
@@ -730,11 +730,12 @@ export class DebuggerModel extends SDKModel<EventTypes> {
|
|
|
730
730
|
return script;
|
|
731
731
|
}
|
|
732
732
|
|
|
733
|
-
setSourceMapURL(script: Script, newSourceMapURL: Platform.DevToolsPath.UrlString
|
|
733
|
+
setSourceMapURL(script: Script, newSourceMapURL: Platform.DevToolsPath.UrlString,
|
|
734
|
+
provenance: SourceMapProvenance): void {
|
|
734
735
|
// Detach any previous source map from the `script` first.
|
|
735
736
|
this.#sourceMapManager.detachSourceMap(script);
|
|
736
737
|
script.sourceMapURL = newSourceMapURL;
|
|
737
|
-
this.#sourceMapManager.attachSourceMap(script, script.sourceURL, script.sourceMapURL);
|
|
738
|
+
this.#sourceMapManager.attachSourceMap(script, script.sourceURL, script.sourceMapURL, provenance);
|
|
738
739
|
}
|
|
739
740
|
|
|
740
741
|
async setDebugInfoURL(script: Script, _externalURL: Platform.DevToolsPath.UrlString): Promise<void> {
|
|
@@ -93,14 +93,14 @@ const UIStrings = {
|
|
|
93
93
|
* @example {GET} PH2
|
|
94
94
|
* @example {https://example.com} PH3
|
|
95
95
|
*/
|
|
96
|
-
sFailedLoadingSS: '{PH1} failed loading: {PH2} "{PH3}"
|
|
96
|
+
sFailedLoadingSS: '{PH1} failed loading: {PH2} "{PH3}"',
|
|
97
97
|
/**
|
|
98
98
|
* @description Console message when a request finished loading.
|
|
99
99
|
* @example {XHR} PH1
|
|
100
100
|
* @example {GET} PH2
|
|
101
101
|
* @example {https://example.com} PH3
|
|
102
102
|
*/
|
|
103
|
-
sFinishedLoadingSS: '{PH1} finished loading: {PH2} "{PH3}"
|
|
103
|
+
sFinishedLoadingSS: '{PH1} finished loading: {PH2} "{PH3}"',
|
|
104
104
|
/**
|
|
105
105
|
* @description One of direct socket connection statuses.
|
|
106
106
|
*/
|
|
@@ -1566,7 +1566,7 @@ export class NetworkRequest extends Common.ObjectWrapper.ObjectWrapper<EventType
|
|
|
1566
1566
|
return this.#signedExchangeInfo;
|
|
1567
1567
|
}
|
|
1568
1568
|
|
|
1569
|
-
async populateImageSource(image:
|
|
1569
|
+
async populateImageSource(image: {src: string}): Promise<void> {
|
|
1570
1570
|
const contentData = await this.requestContentData();
|
|
1571
1571
|
if (TextUtils.ContentData.ContentData.isError(contentData)) {
|
|
1572
1572
|
return;
|
|
@@ -342,13 +342,13 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
|
|
|
342
342
|
// overlay, so that it is not cleared by the highlight
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
|
-
|
|
346
|
-
|
|
345
|
+
clearTimeout(this.#hideHighlightTimeout);
|
|
346
|
+
this.#hideHighlightTimeout = undefined;
|
|
347
347
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
const highlightConfig = this.buildHighlightConfig(mode);
|
|
349
|
+
if (typeof showInfo !== 'undefined') {
|
|
350
|
+
highlightConfig.showInfo = showInfo;
|
|
351
|
+
}
|
|
352
352
|
this.#highlighter.highlightInOverlay(data, highlightConfig);
|
|
353
353
|
}
|
|
354
354
|
|
|
@@ -496,12 +496,11 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
|
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
private delayedHideHighlight(delay: number): void {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
499
|
+
clearTimeout(this.#hideHighlightTimeout);
|
|
500
|
+
this.#hideHighlightTimeout = globalThis.setTimeout(
|
|
501
|
+
() => this.highlightInOverlay({clear: true}),
|
|
502
|
+
delay,
|
|
503
|
+
);
|
|
505
504
|
}
|
|
506
505
|
|
|
507
506
|
highlightFrame(frameId: Protocol.Page.FrameId): void {
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import type * as Protocol from '../../generated/protocol.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Functions in this file are serialized via `.toString()` and evaluated in the
|
|
9
|
+
* inspected page context over CDP (e.g. `Runtime.callFunctionOn`). Because they
|
|
10
|
+
* execute in the inspected browser environment, they use standard DOM types.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export function scrollListenerInPage(this: HTMLElement|Document, id: number, reportScrollPositionBindingName: string,
|
|
14
|
+
scrollListenerNameInPage: string): void {
|
|
15
|
+
if ('scrollingElement' in this && !this.scrollingElement) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const scrollingElement = ('scrollingElement' in this ? this.scrollingElement : this) as HTMLElement;
|
|
20
|
+
// @ts-expect-error We're setting a custom field on `Element` or `Document` for retaining the function on the page.
|
|
21
|
+
this[scrollListenerNameInPage] = () => {
|
|
22
|
+
// @ts-expect-error `reportScrollPosition` binding is injected to the page before calling the function.
|
|
23
|
+
globalThis[reportScrollPositionBindingName](
|
|
24
|
+
JSON.stringify({scrollTop: scrollingElement.scrollTop, scrollLeft: scrollingElement.scrollLeft, id}));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// @ts-expect-error We've already defined the function used below.
|
|
28
|
+
this.addEventListener('scroll', this[scrollListenerNameInPage], true);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function removeScrollListenerInPage(this: HTMLElement|Document, scrollListenerNameInPage: string): void {
|
|
32
|
+
// @ts-expect-error We've already set this custom field while adding scroll listener.
|
|
33
|
+
this.removeEventListener('scroll', this[scrollListenerNameInPage]);
|
|
34
|
+
// @ts-expect-error We've already set this custom field while adding scroll listener.
|
|
35
|
+
delete this[scrollListenerNameInPage];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function scrollTopInPage(this: Element|Document): number {
|
|
39
|
+
if ('scrollingElement' in this) {
|
|
40
|
+
if (!this.scrollingElement) {
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return this.scrollingElement.scrollTop;
|
|
45
|
+
}
|
|
46
|
+
return this.scrollTop;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function scrollLeftInPage(this: Element|Document): number {
|
|
50
|
+
if ('scrollingElement' in this) {
|
|
51
|
+
if (!this.scrollingElement) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return this.scrollingElement.scrollLeft;
|
|
56
|
+
}
|
|
57
|
+
return this.scrollLeft;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function setScrollTopInPage(this: Element|Document, offsetInPage: number): void {
|
|
61
|
+
if ('scrollingElement' in this) {
|
|
62
|
+
if (!this.scrollingElement) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.scrollingElement.scrollTop = offsetInPage;
|
|
67
|
+
} else {
|
|
68
|
+
this.scrollTop = offsetInPage;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function setScrollLeftInPage(this: Element|Document, offsetInPage: number): void {
|
|
73
|
+
if ('scrollingElement' in this) {
|
|
74
|
+
if (!this.scrollingElement) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.scrollingElement.scrollLeft = offsetInPage;
|
|
79
|
+
} else {
|
|
80
|
+
this.scrollLeft = offsetInPage;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function verticalScrollRangeInPage(this: Element|Document): number {
|
|
85
|
+
if ('scrollingElement' in this) {
|
|
86
|
+
if (!this.scrollingElement) {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return this.scrollingElement.scrollHeight - this.scrollingElement.clientHeight;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this.scrollHeight - this.clientHeight;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function horizontalScrollRangeInPage(this: Element|Document): number {
|
|
97
|
+
if ('scrollingElement' in this) {
|
|
98
|
+
if (!this.scrollingElement) {
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return this.scrollingElement.scrollWidth - this.scrollingElement.clientWidth;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return this.scrollWidth - this.clientWidth;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function toggleClassAndInjectStyleRule(this: Element, pseudoElementName: string|null, hidden: boolean): void {
|
|
109
|
+
const classNamePrefix = '__web-inspector-hide';
|
|
110
|
+
const classNameSuffix = '-shortcut__';
|
|
111
|
+
const styleTagId = '__web-inspector-hide-shortcut-style__';
|
|
112
|
+
const pseudoElementNameEscaped = pseudoElementName ? pseudoElementName.replace(/[\(\)\:]/g, '_') : '';
|
|
113
|
+
const className = classNamePrefix + pseudoElementNameEscaped + classNameSuffix;
|
|
114
|
+
this.classList.toggle(className, hidden);
|
|
115
|
+
|
|
116
|
+
let localRoot: Element|HTMLHeadElement = this;
|
|
117
|
+
while (localRoot.parentNode) {
|
|
118
|
+
localRoot = (localRoot.parentNode as Element);
|
|
119
|
+
}
|
|
120
|
+
if (localRoot.nodeType === Node.DOCUMENT_NODE) {
|
|
121
|
+
localRoot = document.head;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let style = localRoot.querySelector('style#' + styleTagId);
|
|
125
|
+
if (!style) {
|
|
126
|
+
const selectors = [];
|
|
127
|
+
selectors.push('.__web-inspector-hide-shortcut__');
|
|
128
|
+
selectors.push('.__web-inspector-hide-shortcut__ *');
|
|
129
|
+
const selector = selectors.join(', ');
|
|
130
|
+
const ruleBody = ' visibility: hidden !important;';
|
|
131
|
+
const rule = '\n' + selector + '\n{\n' + ruleBody + '\n}\n';
|
|
132
|
+
|
|
133
|
+
style = document.createElement('style');
|
|
134
|
+
style.id = styleTagId;
|
|
135
|
+
style.textContent = rule;
|
|
136
|
+
|
|
137
|
+
localRoot.appendChild(style);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// In addition to putting them on the element we want to hide, we will
|
|
141
|
+
// also add pseudo element classes to the style element to keep track of
|
|
142
|
+
// which pseudo elements we have style rules for.
|
|
143
|
+
if (pseudoElementName && !style.classList.contains(className)) {
|
|
144
|
+
style.classList.add(className);
|
|
145
|
+
style.textContent = `.${className}${pseudoElementName}, ${style.textContent}`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function scrollIntoViewInPage(this: Element): void {
|
|
150
|
+
this.scrollIntoViewIfNeeded(true);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function focusInPage(this: HTMLElement): void {
|
|
154
|
+
this.focus();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function toStringForClipboard(this: Object, data: {
|
|
158
|
+
subtype: string|undefined,
|
|
159
|
+
indent: string,
|
|
160
|
+
}): string|undefined {
|
|
161
|
+
const subtype = data.subtype;
|
|
162
|
+
const indent = data.indent;
|
|
163
|
+
|
|
164
|
+
if (subtype === 'node') {
|
|
165
|
+
return this instanceof Element ? this.outerHTML : undefined;
|
|
166
|
+
}
|
|
167
|
+
if (subtype && typeof this === 'undefined') {
|
|
168
|
+
return String(subtype);
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
return JSON.stringify(this, null, indent);
|
|
172
|
+
} catch {
|
|
173
|
+
return String(this);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function saveVariable(this: Window, value: Protocol.Runtime.CallArgument): string {
|
|
178
|
+
const prefix = 'temp';
|
|
179
|
+
let index = 1;
|
|
180
|
+
while ((prefix + index) in this) {
|
|
181
|
+
++index;
|
|
182
|
+
}
|
|
183
|
+
const name = prefix + index;
|
|
184
|
+
// @ts-expect-error Assignment to global object
|
|
185
|
+
this[name] = value;
|
|
186
|
+
return name;
|
|
187
|
+
}
|
|
@@ -199,7 +199,7 @@ export class Resource implements TextUtils.ContentProvider.ContentProvider {
|
|
|
199
199
|
return TextUtils.TextUtils.performSearchInSearchMatches(result.result || [], query, caseSensitive, isRegex);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
async populateImageSource(image:
|
|
202
|
+
async populateImageSource(image: {src: string}): Promise<void> {
|
|
203
203
|
const contentData = await this.requestContentData();
|
|
204
204
|
if (TextUtils.ContentData.ContentData.isError(contentData)) {
|
|
205
205
|
return;
|
|
@@ -10,6 +10,7 @@ import type * as Platform from '../platform/platform.js';
|
|
|
10
10
|
|
|
11
11
|
import {DebuggerModel, type FunctionDetails} from './DebuggerModel.js';
|
|
12
12
|
import {HeapProfilerModel} from './HeapProfilerModel.js';
|
|
13
|
+
import {toStringForClipboard} from './PageFunctions.js';
|
|
13
14
|
import {
|
|
14
15
|
RemoteFunction,
|
|
15
16
|
RemoteObject,
|
|
@@ -313,26 +314,6 @@ export class RuntimeModel extends SDKModel<EventTypes> {
|
|
|
313
314
|
}])
|
|
314
315
|
.then(Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText.bind(
|
|
315
316
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance));
|
|
316
|
-
|
|
317
|
-
function toStringForClipboard(this: Object, data: {
|
|
318
|
-
subtype: string,
|
|
319
|
-
indent: string,
|
|
320
|
-
}): string|undefined {
|
|
321
|
-
const subtype = data.subtype;
|
|
322
|
-
const indent = data.indent;
|
|
323
|
-
|
|
324
|
-
if (subtype === 'node') {
|
|
325
|
-
return this instanceof Element ? this.outerHTML : undefined;
|
|
326
|
-
}
|
|
327
|
-
if (subtype && typeof this === 'undefined') {
|
|
328
|
-
return String(subtype);
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
return JSON.stringify(this, null, indent);
|
|
332
|
-
} catch {
|
|
333
|
-
return String(this);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
317
|
}
|
|
337
318
|
|
|
338
319
|
private async queryObjectsRequested(object: RemoteObject, executionContextId?: number): Promise<void> {
|
|
@@ -43,6 +43,7 @@ import type {FrameAssociated} from './FrameAssociated.js';
|
|
|
43
43
|
import type {PageResourceLoadInitiator} from './PageResourceLoader.js';
|
|
44
44
|
import {ResourceTreeModel} from './ResourceTreeModel.js';
|
|
45
45
|
import type {ExecutionContext} from './RuntimeModel.js';
|
|
46
|
+
import {SecurityOrigin} from './SecurityOrigin.js';
|
|
46
47
|
import type {DebugId, SourceMap} from './SourceMap.js';
|
|
47
48
|
import type {Target} from './Target.js';
|
|
48
49
|
|
|
@@ -88,6 +89,7 @@ export class Script implements TextUtils.ContentProvider.ContentProvider, FrameA
|
|
|
88
89
|
readonly #language: string|null;
|
|
89
90
|
#contentPromise: Promise<TextUtils.ContentData.ContentDataOrError>|null;
|
|
90
91
|
readonly #embedderName: Platform.DevToolsPath.UrlString|null;
|
|
92
|
+
readonly #securityOrigin: SecurityOrigin;
|
|
91
93
|
readonly isModule: boolean|null;
|
|
92
94
|
readonly buildId: string|null;
|
|
93
95
|
constructor(debuggerModel: DebuggerModel, scriptId: Protocol.Runtime.ScriptId,
|
|
@@ -119,12 +121,31 @@ export class Script implements TextUtils.ContentProvider.ContentProvider, FrameA
|
|
|
119
121
|
this.#language = scriptLanguage;
|
|
120
122
|
this.#contentPromise = null;
|
|
121
123
|
this.#embedderName = embedderName;
|
|
124
|
+
this.#securityOrigin = SecurityOrigin.create(this.#embedderName ?? '');
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
embedderName(): Platform.DevToolsPath.UrlString|null {
|
|
125
128
|
return this.#embedderName;
|
|
126
129
|
}
|
|
127
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Returns the security origin of the script derived exclusively from its
|
|
133
|
+
* embedder/network URL (`#embedderName`), or a unique opaque origin if the
|
|
134
|
+
* script has no valid network provenance (e.g. `eval()` or buffer-based Wasm).
|
|
135
|
+
*
|
|
136
|
+
* Security note: Do NOT fall back to `this.sourceURL` or
|
|
137
|
+
* `this.target().inspectedSecurityOrigin()`:
|
|
138
|
+
* - `sourceURL` is overwritten by `//# sourceURL=` comments, allowing a script
|
|
139
|
+
* to spoof an arbitrary origin.
|
|
140
|
+
* - Third-party scripts (`<script src="https://attacker.example/...">`) run in
|
|
141
|
+
* the same target/frame as the main page; falling back to the target's
|
|
142
|
+
* origin would allow them to launder their origin by dynamically evaluating
|
|
143
|
+
* code via `eval()` or `WebAssembly.instantiate(buffer)`.
|
|
144
|
+
*/
|
|
145
|
+
securityOrigin(): SecurityOrigin {
|
|
146
|
+
return this.#securityOrigin;
|
|
147
|
+
}
|
|
148
|
+
|
|
128
149
|
target(): Target {
|
|
129
150
|
return this.debuggerModel.target();
|
|
130
151
|
}
|
|
@@ -130,6 +130,12 @@ interface SourceInfo {
|
|
|
130
130
|
reverseMappings: number[]|null;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
export const enum SourceMapProvenance {
|
|
134
|
+
CDP = 'cdp',
|
|
135
|
+
EXTENSION = 'extension',
|
|
136
|
+
USER = 'user',
|
|
137
|
+
}
|
|
138
|
+
|
|
133
139
|
export class SourceMap {
|
|
134
140
|
static retainRawSourceMaps = false;
|
|
135
141
|
|
|
@@ -149,13 +155,15 @@ export class SourceMap {
|
|
|
149
155
|
|
|
150
156
|
#scopesFallbackPromise?: Promise<void>;
|
|
151
157
|
readonly #console: Common.Console.Console;
|
|
158
|
+
readonly #provenance: SourceMapProvenance;
|
|
152
159
|
|
|
153
160
|
/**
|
|
154
161
|
* Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps
|
|
155
162
|
* for format description.
|
|
156
163
|
*/
|
|
157
164
|
constructor(compiledURL: Platform.DevToolsPath.UrlString, sourceMappingURL: Platform.DevToolsPath.UrlString,
|
|
158
|
-
payload: SourceMapV3, console: Common.Console.Console, script?: Script
|
|
165
|
+
payload: SourceMapV3, console: Common.Console.Console, script?: Script,
|
|
166
|
+
provenance: SourceMapProvenance = SourceMapProvenance.CDP) {
|
|
159
167
|
this.#json = payload;
|
|
160
168
|
this.#script = script;
|
|
161
169
|
this.#compiledURL = compiledURL;
|
|
@@ -163,6 +171,7 @@ export class SourceMap {
|
|
|
163
171
|
this.#baseURL = (Common.ParsedURL.schemeIs(sourceMappingURL, 'data:')) ? compiledURL : sourceMappingURL;
|
|
164
172
|
this.#debugId = 'debugId' in payload ? (payload.debugId as DebugId | undefined) : undefined;
|
|
165
173
|
this.#console = console;
|
|
174
|
+
this.#provenance = provenance;
|
|
166
175
|
|
|
167
176
|
if ('sections' in this.#json) {
|
|
168
177
|
if (this.#json.sections.find(section => 'url' in section)) {
|
|
@@ -172,6 +181,10 @@ export class SourceMap {
|
|
|
172
181
|
this.eachSection(this.parseSources.bind(this));
|
|
173
182
|
}
|
|
174
183
|
|
|
184
|
+
provenance(): SourceMapProvenance {
|
|
185
|
+
return this.#provenance;
|
|
186
|
+
}
|
|
187
|
+
|
|
175
188
|
json(): SourceMapV3|null {
|
|
176
189
|
return this.#json;
|
|
177
190
|
}
|
|
@@ -823,7 +836,7 @@ export class SourceMap {
|
|
|
823
836
|
|
|
824
837
|
resolveScopeChain(frame: CallFrame): ScopeChainEntry[]|null {
|
|
825
838
|
this.#ensureSourceMapProcessed();
|
|
826
|
-
if (this.#
|
|
839
|
+
if (this.#provenance === SourceMapProvenance.USER || !this.#scopesInfo?.hasVariablesAndBindings()) {
|
|
827
840
|
return null;
|
|
828
841
|
}
|
|
829
842
|
|
|
@@ -2,15 +2,14 @@
|
|
|
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
|
|
5
|
+
import * as Platform from '../platform/platform.js';
|
|
6
6
|
|
|
7
7
|
import type {DebugId, SourceMapV3} from './SourceMap.js';
|
|
8
8
|
|
|
9
9
|
/** A thin wrapper around the Cache API to store source map JSONs keyed on Debug IDs */
|
|
10
10
|
export class SourceMapCache {
|
|
11
11
|
static create(): SourceMapCache {
|
|
12
|
-
if (
|
|
13
|
-
// TODO(crbug.com/451502260): Move this behind a `HostRuntime` interface.
|
|
12
|
+
if (!Platform.HostRuntime.HOST_RUNTIME.getCacheStorage()) {
|
|
14
13
|
return IN_MEMORY_INSTANCE as unknown as
|
|
15
14
|
SourceMapCache; // TS doesn't like that our in-memory class doesn't have the same private fields.
|
|
16
15
|
}
|
|
@@ -22,7 +21,7 @@ export class SourceMapCache {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
readonly #name: string;
|
|
25
|
-
#cachePromise?: Promise<
|
|
24
|
+
#cachePromise?: Promise<Platform.HostRuntime.CacheEntry>;
|
|
26
25
|
|
|
27
26
|
private constructor(name: string) {
|
|
28
27
|
this.#name = name;
|
|
@@ -30,21 +29,25 @@ export class SourceMapCache {
|
|
|
30
29
|
|
|
31
30
|
async set(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString, sourceMap: SourceMapV3): Promise<void> {
|
|
32
31
|
const cache = await this.#cache();
|
|
33
|
-
await cache
|
|
32
|
+
await cache?.put(SourceMapCache.#urlForDebugId(debugId, securityOrigin), new Response(JSON.stringify(sourceMap)));
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
async get(debugId: DebugId, securityOrigin: Platform.DevToolsPath.UrlString): Promise<SourceMapV3|null> {
|
|
37
36
|
const cache = await this.#cache();
|
|
38
|
-
const response = await cache
|
|
39
|
-
return await response?.json() ?? null;
|
|
37
|
+
const response = await cache?.match(SourceMapCache.#urlForDebugId(debugId, securityOrigin));
|
|
38
|
+
return (await response?.json() as SourceMapV3 | undefined) ?? null;
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
async #cache(): Promise<
|
|
41
|
+
async #cache(): Promise<Platform.HostRuntime.CacheEntry|undefined> {
|
|
43
42
|
if (this.#cachePromise) {
|
|
44
43
|
return await this.#cachePromise;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
const cacheStorage = Platform.HostRuntime.HOST_RUNTIME.getCacheStorage();
|
|
47
|
+
if (!cacheStorage) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
this.#cachePromise = cacheStorage.open(this.#name);
|
|
48
51
|
return await this.#cachePromise;
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -54,7 +57,7 @@ export class SourceMapCache {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
async disposeForTest(): Promise<void> {
|
|
57
|
-
await
|
|
60
|
+
await Platform.HostRuntime.HOST_RUNTIME.getCacheStorage()?.delete(this.#name);
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
|