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.
Files changed (145) hide show
  1. package/.agents/skills/devtools-verification/SKILL.md +19 -0
  2. package/.agents/skills/{repro-flaky-tests → fix-tests}/SKILL.md +2 -2
  3. package/.agents/skills/version-control/SKILL.md +21 -9
  4. package/front_end/core/platform/HostRuntime.ts +12 -0
  5. package/front_end/core/platform/api/HostRuntime.ts +13 -0
  6. package/front_end/core/platform/browser/HostRuntime.ts +34 -0
  7. package/front_end/core/platform/node/HostRuntime.ts +40 -0
  8. package/front_end/core/sdk/AnimationModel.ts +12 -98
  9. package/front_end/core/sdk/CSSModel.ts +4 -2
  10. package/front_end/core/sdk/CSSPropertyParser.ts +4 -4
  11. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +4 -44
  12. package/front_end/core/sdk/Connections.ts +6 -1
  13. package/front_end/core/sdk/ConsoleModel.ts +1 -12
  14. package/front_end/core/sdk/DOMModel.ts +6 -56
  15. package/front_end/core/sdk/DebuggerModel.ts +9 -8
  16. package/front_end/core/sdk/NetworkManager.ts +2 -2
  17. package/front_end/core/sdk/NetworkRequest.ts +1 -1
  18. package/front_end/core/sdk/OverlayModel.ts +11 -12
  19. package/front_end/core/sdk/PageFunctions.ts +187 -0
  20. package/front_end/core/sdk/Resource.ts +1 -1
  21. package/front_end/core/sdk/RuntimeModel.ts +1 -20
  22. package/front_end/core/sdk/Script.ts +21 -0
  23. package/front_end/core/sdk/SourceMap.ts +15 -2
  24. package/front_end/core/sdk/SourceMapCache.ts +13 -10
  25. package/front_end/core/sdk/SourceMapManager.ts +11 -9
  26. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +109 -15
  27. package/front_end/core/sdk/SourceMapScopesInfo.ts +8 -2
  28. package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +635 -0
  29. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +26 -12
  30. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -2
  31. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +4 -4
  32. package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker.ts +2 -0
  33. package/front_end/entrypoints/shell/shell.ts +1 -1
  34. package/front_end/models/ai_assistance/DOMHelpers.ts +95 -0
  35. package/front_end/models/ai_assistance/EvaluateAction.ts +5 -42
  36. package/front_end/models/ai_assistance/ExtensionScope.ts +2 -31
  37. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
  38. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -4
  39. package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
  40. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +10 -7
  41. package/front_end/models/ai_assistance/contexts/FileContext.ts +2 -10
  42. package/front_end/models/ai_assistance/tools/GetSourceContent.ts +3 -2
  43. package/front_end/models/ai_assistance/tools/ListSources.ts +21 -14
  44. package/front_end/models/bindings/CompilerScriptMapping.ts +3 -10
  45. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +48 -17
  46. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
  47. package/front_end/models/bindings/StylesSourceMapping.ts +1 -1
  48. package/front_end/models/comment_manager/CD4ABridge.ts +55 -12
  49. package/front_end/models/comment_manager/CommentManager.ts +46 -91
  50. package/front_end/models/comment_manager/CommentThread.ts +145 -0
  51. package/front_end/models/comment_manager/comment_manager.ts +2 -0
  52. package/front_end/models/emulation/DeviceModeModel.ts +54 -1
  53. package/front_end/models/extensions/ExtensionAPI.ts +8 -6
  54. package/front_end/models/extensions/ExtensionEndpoint.ts +11 -8
  55. package/front_end/models/extensions/HostUrlPattern.ts +4 -3
  56. package/front_end/models/extensions/LanguageExtensionEndpoint.ts +3 -2
  57. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +2 -1
  58. package/front_end/models/formatter/FormatterWorkerPool.ts +4 -6
  59. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +55 -0
  60. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +18 -14
  61. package/front_end/models/issues_manager/CookieIssue.ts +0 -13
  62. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  63. package/front_end/models/issues_manager/WebInstallIssue.ts +63 -0
  64. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingId.md +3 -0
  65. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
  66. package/front_end/models/issues_manager/descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
  67. package/front_end/models/issues_manager/descriptions/webInstallNoManifest.md +3 -0
  68. package/front_end/models/issues_manager/descriptions/webInstallStartUrlInvalid.md +3 -0
  69. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  70. package/front_end/models/source_map_scopes/NamesResolver.ts +11 -3
  71. package/front_end/models/source_map_scopes/ScopeChainModel.ts +10 -6
  72. package/front_end/models/workspace/UISourceCode.ts +20 -0
  73. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +281 -3
  74. package/front_end/panels/accessibility/accessibilityAnnouncementRecordingView.css +85 -0
  75. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +5 -8
  76. package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
  77. package/front_end/panels/animation/AnimationTimeline.ts +1 -1
  78. package/front_end/panels/application/CrashReportContextView.ts +1 -1
  79. package/front_end/panels/application/IndexedDBViews.ts +1 -1
  80. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  81. package/front_end/panels/application/components/AdsView.ts +63 -1
  82. package/front_end/panels/application/components/adsView.css +11 -1
  83. package/front_end/{ui/comments → panels/common}/CommentThreadWidget.ts +5 -20
  84. package/front_end/{ui/comments → panels/common}/CommentsOverlayWidget.ts +39 -62
  85. package/front_end/{ui/comments → panels/common}/CommentsStatusBarPill.ts +5 -5
  86. package/front_end/panels/common/ExtensionServer.ts +2 -1
  87. package/front_end/{ui/comments → panels/common}/commentThreadWidget.css +0 -12
  88. package/front_end/{ui/comments → panels/common}/commentsOverlay.css +2 -1
  89. package/front_end/{ui/comments/comments-meta.ts → panels/common/common-meta.ts} +11 -11
  90. package/front_end/panels/common/common.ts +3 -0
  91. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +3 -3
  92. package/front_end/panels/elements/CSSRuleValidator.ts +1 -1
  93. package/front_end/panels/elements/ElementsPanel.ts +9 -5
  94. package/front_end/panels/elements/ElementsTreeElement.ts +11 -3
  95. package/front_end/panels/elements/ElementsTreeOutline.ts +69 -74
  96. package/front_end/panels/elements/PropertiesWidget.ts +11 -10
  97. package/front_end/panels/elements/PropertyRenderer.ts +29 -25
  98. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -6
  99. package/front_end/panels/elements/elementsTreeOutline.css +11 -5
  100. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
  101. package/front_end/panels/event_listeners/EventListenersView.ts +33 -44
  102. package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
  103. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +6 -7
  104. package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +5 -1
  105. package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -1
  106. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +1 -1
  107. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -1
  108. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +1 -1
  109. package/front_end/panels/recorder/StepView.ts +19 -4
  110. package/front_end/panels/recorder/TimelineSection.ts +1 -1
  111. package/front_end/panels/recorder/stepView.css +1 -0
  112. package/front_end/panels/security/SecurityPanel.ts +5 -5
  113. package/front_end/panels/security/SecurityPanelSidebar.ts +2 -11
  114. package/front_end/panels/settings/BackendLinkingSettingsTab.ts +2 -1
  115. package/front_end/panels/settings/EditFileSystemView.ts +1 -1
  116. package/front_end/panels/sources/CallStackSidebarPane.ts +1 -1
  117. package/front_end/panels/sources/DebuggerPlugin.ts +2 -2
  118. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
  119. package/front_end/panels/sources/sources-meta.ts +1 -1
  120. package/front_end/panels/timeline/components/DetailsView.ts +3 -3
  121. package/front_end/panels/timeline/components/OriginMap.ts +1 -1
  122. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -3
  123. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +0 -3
  124. package/front_end/third_party/chromium/README.chromium +1 -1
  125. package/front_end/ui/comments/CommentOverlayManager.ts +28 -110
  126. package/front_end/ui/comments/comments.ts +0 -6
  127. package/front_end/ui/components/buttons/Button.ts +19 -1
  128. package/front_end/ui/legacy/ContextMenu.ts +16 -1
  129. package/front_end/ui/legacy/PlusButton.ts +5 -6
  130. package/front_end/ui/legacy/Treeoutline.ts +6 -0
  131. package/front_end/ui/legacy/Widget.ts +33 -0
  132. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +3 -0
  133. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +14 -4
  134. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +36 -32
  135. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  136. package/package.json +1 -1
  137. package/.agents/skills/devtools-ci/SKILL.md +0 -65
  138. package/.agents/skills/evaluate-ai-css-completion/SKILL.md +0 -143
  139. package/.agents/skills/evaluate-ai-css-completion/scripts/evaluate.js +0 -104
  140. package/.agents/skills/fixing-skipped-tests/SKILL.md +0 -32
  141. package/.agents/skills/gerrit-cli/SKILL.md +0 -74
  142. package/.agents/skills/gerrit-cli/references/commands.md +0 -169
  143. package/.agents/skills/gerrit-cli/references/workflows.md +0 -63
  144. package/.agents/skills/gerrit-cli/scripts/import_upstream.py +0 -85
  145. package/front_end/models/issues_manager/descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +0 -4
@@ -20,6 +20,25 @@ description: "MANDATORY: Activate this skill ANY TIME you need to build the proj
20
20
  - `npm run lint` will execute ESLint and StyleLint. It will report any violations and automatically fix them where possible.
21
21
  - To run the linter on a specific file or directory, you can run `npm run lint -- <PATH>` where `PATH` is a path to a file or directory. This will also automatically fix violations where possible.
22
22
 
23
+ ## Fetching Tryjob Results, Failure Logs, & Screenshot Goldens
24
+
25
+ Use `scripts/tools/get_cl_test_results.py` to fetch all tryjob build statuses, per-test failure logs, Blink web test text diffs, and screenshot artifacts (`actual_image`, `expected_image`, `image_diff`) for a CL in one command:
26
+
27
+ ```bash
28
+ # Fetch all build statuses, failure logs, and artifacts for a CL into an output directory:
29
+ scripts/tools/get_cl_test_results.py --cl <CL_NUMBER> --output-dir <OUTPUT_DIR>
30
+
31
+ # Filter for specific failing tests (e.g. DOMTreeWidget) or specific builders:
32
+ scripts/tools/get_cl_test_results.py --cl <CL_NUMBER> --test-filter "DOMTreeWidget" --output-dir <OUTPUT_DIR>
33
+
34
+ # Also apply Linux actual_image screenshot artifacts directly to test/goldens/linux/...:
35
+ scripts/tools/get_cl_test_results.py --cl <CL_NUMBER> --output-dir <OUTPUT_DIR> --apply-goldens
36
+ ```
37
+
38
+ ### Screenshot Golden & Inspection Rules
39
+ - **Linux-only goldens**: Never generate, update, or commit golden PNGs from macOS. Screenshot tests in DevTools only use Linux goldens (`test/goldens/linux/...`) produced by Linux trybots (`dtf_linux_rel` / `dtf_linux_dbg`). Do not run screenshot tests locally on macOS to verify goldens.
40
+ - **Multimodal inspection only**: Always inspect `actual_image.png`, `expected_image.png`, and `image_diff.png` directly using your multimodal file viewer (`view_file`). Never write or run programmatic image comparison scripts.
41
+
23
42
  ## Best practices
24
43
 
25
44
  - Run tests often to verify your changes.
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: repro-flaky-tests
3
- description: Reproduce and investigate flakiness in a test.
2
+ name: fix-tests
3
+ description: Use this skill to reproduce and fix flaky and disabled tests.
4
4
  ---
5
5
 
6
6
  # Workflow
@@ -41,21 +41,25 @@ If CL B depends on CL A:
41
41
  2. Develop on branch B.
42
42
  3. When uploading B, Gerrit will show the dependency on A.
43
43
 
44
- ### Reparenting
45
- If you need to change the base of a branch (e.g., move CL B to be based on `main` instead of CL A):
44
+ ### Reparenting & Detaching Landed CLs
45
+ If you need to change the base of a branch back to the root branch (e.g., move CL B to be based on `origin/main` instead of CL A):
46
46
  ```bash
47
- git reparent-branch main
47
+ git reparent-branch --root
48
48
  ```
49
49
  Or to make it depend on another branch C:
50
50
  ```bash
51
51
  git reparent-branch <branch-C>
52
52
  ```
53
+ * **Detaching from landed CLs:** When parent CLs in a stack have landed on `main`, first run `git fetch` so `origin/main` includes the landed commits (otherwise reparenting will trigger merge conflicts). Then check out the first unlanded branch in the chain and run `git reparent-branch --root` **before** archiving the landed branches (so `depot_tools` can still resolve the old upstream tracking branch). After reparenting (which automatically runs `git rebase-update`), archive the landed branches (`git cl archive -f`) and run `gclient sync -Df`.
53
54
 
54
55
  ### Syncing with Upstream
55
- To update all your branches with the latest changes from `main` and their respective upstreams:
56
+ To update all your branches with the latest changes from `main` and their respective upstreams, and synchronize dependencies:
56
57
  ```bash
57
- git rebase-update
58
+ git rebase-update && gclient sync -Df
58
59
  ```
60
+ * **Always use `git rebase-update` for stacks:** Never write manual `git checkout && git rebase` loops across stacked branches. `git rebase-update` automatically rebases the entire dependency graph in order.
61
+ * **Clean up old branches first:** Before running `git rebase-update`, archive landed/closed branches (`git cl archive -f`) or mark dormant (`git config branch.<branch>.dormant true`) any obsolete branches so they do not trigger unnecessary rebase conflicts.
62
+ * **Always sync dependencies after rebase:** Always run `gclient sync -Df` after a `git rebase-update`. CIPD dependency updates do not show up in `git status`, so skipping `gclient sync -Df` risks leaving your checkout out of sync.
59
63
 
60
64
  ### Initial upload
61
65
  When a CL is ready, upload it with:
@@ -67,12 +71,14 @@ git cl upload -f -d --commit-description="<description>"
67
71
  * Keep line length below 72
68
72
  * Add a "Bug: <issue number>" or "Bug: None" trailer on a separate line.
69
73
  * Amend formatter/linter changes and fix linter issues.
74
+ * For a brand new stack of CLs, perform the initial upload on each branch individually in parent-to-child order so each CL receives its own commit description.
70
75
 
71
- ### Subsequent upload
76
+ ### Subsequent upload & Updating Stacks
72
77
  To upload an updated CL:
73
78
  ```bash
74
79
  git cl upload -f -d -t "<one sentence patch set description>"
75
80
  ```
81
+ * **Updating an existing stack of CLs:** Once all CLs in a stack have been initially created, **only run `git cl upload` from the leaf (latest) branch in the chain** for subsequent updates. Uploading from the leaf branch automatically runs presubmit checks and uploads new patchsets for all parent CLs in the stack simultaneously. Never upload intermediate CLs one by one when updating a stack.
76
82
 
77
83
  ## Release and Roll Status
78
84
 
@@ -87,12 +93,18 @@ To check whether a DevTools commit (`devtools/devtools-frontend`) has rolled int
87
93
  | Create new CL from main | `git new-branch <name>` |
88
94
  | Create stacked CL | `git new-branch --upstream_current <name>` |
89
95
  | Update current CL | `git commit --amend` |
90
- | Upload to Gerrit | `git cl upload -f` |
96
+ | Initial CL upload | `git cl upload -f -d --commit-description="<description>"` |
97
+ | Subsequent CL upload (or update stack from leaf) | `git cl upload -f -d -t "<message>"` |
98
+ | Reparent branch to root (`origin/main`) | `git reparent-branch --root` |
91
99
  | Change branch parent | `git reparent-branch <new-parent>` |
92
- | Sync all branches | `git rebase-update` |
100
+ | Archive landed/closed branches | `git cl archive -f` |
101
+ | Rebase all branches in stack | `git rebase-update` |
102
+ | Sync dependencies after rebase | `gclient sync -Df` |
93
103
  | Check release & roll status | Query `https://chromiumdash.appspot.com/fetch_commit?commit=<sha>` |
94
104
 
95
105
  ## Common Mistakes
96
106
  - **Multiple commits on one branch:** Gerrit expects one commit per CL. Always `commit --amend`.
97
107
  - **Using `git checkout -b`:** Does not set up tracking information correctly for `depot_tools`. Use `git new-branch`.
98
- - **Manual rebasing of stacked branches:** Can be complex. Use `git rebase-update` or `git reparent-branch` to let `depot_tools` handle the tracking updates.
108
+ - **Manual rebasing of stacked branches:** Never use manual `git rebase` loops. Always use `git rebase-update` or `git reparent-branch` to let `depot_tools` handle tracking updates.
109
+ - **Uploading intermediate branches when updating a stack:** When updating an existing stack of CLs, do not run `git cl upload` on each branch in a chain—uploading from the leaf branch uploads new patchsets for all parent CLs automatically (note: initial uploads must still be done per branch).
110
+ - **Archiving parent branches before reparenting:** Always run `git fetch` and `git reparent-branch --root` on the child branch before archiving a landed parent branch with `git cl archive -f`.
@@ -4,6 +4,18 @@
4
4
 
5
5
  import type * as Api from './api/api.js';
6
6
 
7
+ export type {
8
+ CacheEntry,
9
+ CacheStorageLike,
10
+ HostRuntime,
11
+ ScreenshotOptions,
12
+ Worker,
13
+ WorkerMessageEvent,
14
+ WorkerMessagePort,
15
+ WorkerScope,
16
+ WorkerTransferable,
17
+ } from './api/HostRuntime.js';
18
+
7
19
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
8
20
  // @ts-ignore 'process' is not available when type-checking against browser types.
9
21
  export const IS_NODE: boolean = typeof (process as unknown) !== 'undefined' && process.versions?.node !== null;
@@ -13,6 +13,16 @@ export interface ScreenshotOptions {
13
13
  };
14
14
  }
15
15
 
16
+ export interface CacheEntry {
17
+ put(url: string, response: Response): Promise<void>;
18
+ match(url: string): Promise<Response|undefined>;
19
+ }
20
+
21
+ export interface CacheStorageLike {
22
+ open(name: string): Promise<CacheEntry>;
23
+ delete(name: string): Promise<boolean>;
24
+ }
25
+
16
26
  /**
17
27
  * Provides abstractions for host features that require different implementations depending
18
28
  * on whether DevTools runs in the browser or Node.js
@@ -23,10 +33,13 @@ export interface HostRuntime {
23
33
  getOnLine(): boolean;
24
34
  getUserAgent(): string;
25
35
  getLocalStorage(): Storage|undefined;
36
+ getCacheStorage(): CacheStorageLike|undefined;
26
37
  getDevicePixelRatio(): number;
27
38
  saveScreenshot(options: ScreenshotOptions): Promise<void>;
28
39
  revokeLastScreenshotUrl(): void;
29
40
  loadTextFile(url: URL): Promise<string>;
41
+ evaluateCSS(dataValue: string|null, customExpr: string): string|null;
42
+ removeCSSEvaluationElement(): void;
30
43
  }
31
44
 
32
45
  /**
@@ -130,6 +130,8 @@ async function saveScreenshot(options: Api.HostRuntime.ScreenshotOptions): Promi
130
130
  link.click();
131
131
  }
132
132
 
133
+ let cssEvaluationElement: HTMLElement|null = null;
134
+
133
135
  export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
134
136
  createWorker(url: string): Api.HostRuntime.Worker {
135
137
  return new WebWorker(url);
@@ -145,6 +147,10 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
145
147
  undefined {
146
148
  return 'localStorage' in globalThis ? globalThis.localStorage : undefined;
147
149
  },
150
+ getCacheStorage(): Api.HostRuntime.CacheStorageLike |
151
+ undefined {
152
+ return 'caches' in globalThis ? globalThis.caches : undefined;
153
+ },
148
154
  getDevicePixelRatio(): number {
149
155
  return window.devicePixelRatio;
150
156
  },
@@ -154,4 +160,32 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
154
160
  const response = await fetch(url);
155
161
  return await response.text();
156
162
  },
163
+ evaluateCSS(dataValue: string|null, customExpr: string): string |
164
+ null {
165
+ if (!cssEvaluationElement || !cssEvaluationElement.isConnected) {
166
+ cssEvaluationElement = document.getElementById('css-evaluation-element');
167
+ if (!cssEvaluationElement) {
168
+ cssEvaluationElement = document.createElement('div');
169
+ cssEvaluationElement.id = 'css-evaluation-element';
170
+ cssEvaluationElement.setAttribute('style', 'hidden: true; --evaluation: attr(data-custom-expr type(*))');
171
+
172
+ document.body.appendChild(cssEvaluationElement);
173
+ }
174
+ }
175
+
176
+ if (dataValue !== null) {
177
+ cssEvaluationElement.setAttribute('data-value', dataValue);
178
+ } else {
179
+ cssEvaluationElement.removeAttribute('data-value');
180
+ }
181
+ cssEvaluationElement.setAttribute('data-custom-expr', customExpr);
182
+ return cssEvaluationElement.computedStyleMap().get('--evaluation')?.toString() ?? null;
183
+ },
184
+ removeCSSEvaluationElement(): void {
185
+ const element = cssEvaluationElement ?? document.getElementById('css-evaluation-element');
186
+ if (element) {
187
+ element.remove();
188
+ }
189
+ cssEvaluationElement = null;
190
+ },
157
191
  };
@@ -83,6 +83,37 @@ class NodeWorker implements Api.HostRuntime.Worker {
83
83
  }
84
84
  }
85
85
 
86
+ class NodeCacheEntry implements Api.HostRuntime.CacheEntry {
87
+ readonly #entries = new Map<string, Response>();
88
+
89
+ async put(url: string, response: Response): Promise<void> {
90
+ this.#entries.set(url, response.clone());
91
+ }
92
+
93
+ async match(url: string): Promise<Response|undefined> {
94
+ return this.#entries.get(url)?.clone();
95
+ }
96
+ }
97
+
98
+ class NodeCacheStorage implements Api.HostRuntime.CacheStorageLike {
99
+ readonly #caches = new Map<string, NodeCacheEntry>();
100
+
101
+ async open(name: string): Promise<Api.HostRuntime.CacheEntry> {
102
+ let cache = this.#caches.get(name);
103
+ if (!cache) {
104
+ cache = new NodeCacheEntry();
105
+ this.#caches.set(name, cache);
106
+ }
107
+ return cache;
108
+ }
109
+
110
+ async delete(name: string): Promise<boolean> {
111
+ return this.#caches.delete(name);
112
+ }
113
+ }
114
+
115
+ const nodeCacheStorage = new NodeCacheStorage();
116
+
86
117
  export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
87
118
  createWorker(url: string): Api.HostRuntime.Worker {
88
119
  return new NodeWorker(url);
@@ -98,6 +129,10 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
98
129
  undefined {
99
130
  return undefined;
100
131
  },
132
+ getCacheStorage(): Api.HostRuntime.CacheStorageLike |
133
+ undefined {
134
+ return nodeCacheStorage;
135
+ },
101
136
  getDevicePixelRatio(): number {
102
137
  return 1;
103
138
  },
@@ -106,4 +141,9 @@ export const HOST_RUNTIME: Api.HostRuntime.HostRuntime = {
106
141
  async loadTextFile(url: URL): Promise<string> {
107
142
  return await Fs.promises.readFile(Url.fileURLToPath(url), 'utf-8');
108
143
  },
144
+ evaluateCSS(_dataValue: string|null, _customExpr: string): string |
145
+ null {
146
+ return null;
147
+ },
148
+ removeCSSEvaluationElement(): void{},
109
149
  };
@@ -7,6 +7,16 @@ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
7
7
  import * as Protocol from '../../generated/protocol.js';
8
8
 
9
9
  import {DeferredDOMNode, type DOMNode} from './DOMModel.js';
10
+ import {
11
+ horizontalScrollRangeInPage,
12
+ removeScrollListenerInPage,
13
+ scrollLeftInPage,
14
+ scrollListenerInPage,
15
+ scrollTopInPage,
16
+ setScrollLeftInPage,
17
+ setScrollTopInPage,
18
+ verticalScrollRangeInPage,
19
+ } from './PageFunctions.js';
10
20
  import {RemoteObject} from './RemoteObject.js';
11
21
  import {Events as ResourceTreeModelEvents, ResourceTreeModel} from './ResourceTreeModel.js';
12
22
  import {Events as RuntimeModelEvents, type EventTypes as RuntimeModelEventTypes, RuntimeModel} from './RuntimeModel.js';
@@ -127,25 +137,6 @@ export class AnimationDOMNode {
127
137
  ].map(arg => RemoteObject.toCallArgument(arg)));
128
138
  object.release();
129
139
  return id;
130
-
131
- function scrollListenerInPage(
132
- this: HTMLElement|Document, id: number, reportScrollPositionBindingName: string,
133
- scrollListenerNameInPage: string): void {
134
- if ('scrollingElement' in this && !this.scrollingElement) {
135
- return;
136
- }
137
-
138
- const scrollingElement = ('scrollingElement' in this ? this.scrollingElement : this) as HTMLElement;
139
- // @ts-expect-error We're setting a custom field on `Element` or `Document` for retaining the function on the page.
140
- this[scrollListenerNameInPage] = () => {
141
- // @ts-expect-error `reportScrollPosition` binding is injected to the page before calling the function.
142
- globalThis[reportScrollPositionBindingName](
143
- JSON.stringify({scrollTop: scrollingElement.scrollTop, scrollLeft: scrollingElement.scrollLeft, id}));
144
- };
145
-
146
- // @ts-expect-error We've already defined the function used below.
147
- this.addEventListener('scroll', this[scrollListenerNameInPage], true);
148
- }
149
140
  }
150
141
 
151
142
  async removeScrollEventListener(id: number): Promise<void> {
@@ -154,8 +145,8 @@ export class AnimationDOMNode {
154
145
  return;
155
146
  }
156
147
 
157
- await object.callFunction(
158
- removeScrollListenerInPage, [getScrollListenerNameInPage(id)].map(arg => RemoteObject.toCallArgument(arg)));
148
+ await object.callFunction(removeScrollListenerInPage,
149
+ [getScrollListenerNameInPage(id)].map(arg => RemoteObject.toCallArgument(arg)));
159
150
  object.release();
160
151
 
161
152
  this.#scrollListenersById.delete(id);
@@ -164,107 +155,30 @@ export class AnimationDOMNode {
164
155
  if (this.#scrollListenersById.size === 0) {
165
156
  await this.#removeReportScrollPositionBinding();
166
157
  }
167
-
168
- function removeScrollListenerInPage(this: HTMLElement|Document, scrollListenerNameInPage: string): void {
169
- // @ts-expect-error We've already set this custom field while adding scroll listener.
170
- this.removeEventListener('scroll', this[scrollListenerNameInPage]);
171
- // @ts-expect-error We've already set this custom field while adding scroll listener.
172
- delete this[scrollListenerNameInPage];
173
- }
174
158
  }
175
159
 
176
160
  async scrollTop(): Promise<number|null> {
177
161
  return await this.#domNode.callFunction(scrollTopInPage).then(res => res?.value ?? null);
178
-
179
- function scrollTopInPage(this: Element|Document): number {
180
- if ('scrollingElement' in this) {
181
- if (!this.scrollingElement) {
182
- return 0;
183
- }
184
-
185
- return this.scrollingElement.scrollTop;
186
- }
187
- return this.scrollTop;
188
- }
189
162
  }
190
163
 
191
164
  async scrollLeft(): Promise<number|null> {
192
165
  return await this.#domNode.callFunction(scrollLeftInPage).then(res => res?.value ?? null);
193
-
194
- function scrollLeftInPage(this: Element|Document): number {
195
- if ('scrollingElement' in this) {
196
- if (!this.scrollingElement) {
197
- return 0;
198
- }
199
-
200
- return this.scrollingElement.scrollLeft;
201
- }
202
- return this.scrollLeft;
203
- }
204
166
  }
205
167
 
206
168
  async setScrollTop(offset: number): Promise<void> {
207
169
  await this.#domNode.callFunction(setScrollTopInPage, [offset]);
208
-
209
- function setScrollTopInPage(this: Element|Document, offsetInPage: number): void {
210
- if ('scrollingElement' in this) {
211
- if (!this.scrollingElement) {
212
- return;
213
- }
214
-
215
- this.scrollingElement.scrollTop = offsetInPage;
216
- } else {
217
- this.scrollTop = offsetInPage;
218
- }
219
- }
220
170
  }
221
171
 
222
172
  async setScrollLeft(offset: number): Promise<void> {
223
173
  await this.#domNode.callFunction(setScrollLeftInPage, [offset]);
224
-
225
- function setScrollLeftInPage(this: Element|Document, offsetInPage: number): void {
226
- if ('scrollingElement' in this) {
227
- if (!this.scrollingElement) {
228
- return;
229
- }
230
-
231
- this.scrollingElement.scrollLeft = offsetInPage;
232
- } else {
233
- this.scrollLeft = offsetInPage;
234
- }
235
- }
236
174
  }
237
175
 
238
176
  async verticalScrollRange(): Promise<number|null> {
239
177
  return await this.#domNode.callFunction(verticalScrollRangeInPage).then(res => res?.value ?? null);
240
-
241
- function verticalScrollRangeInPage(this: Element|Document): number {
242
- if ('scrollingElement' in this) {
243
- if (!this.scrollingElement) {
244
- return 0;
245
- }
246
-
247
- return this.scrollingElement.scrollHeight - this.scrollingElement.clientHeight;
248
- }
249
-
250
- return this.scrollHeight - this.clientHeight;
251
- }
252
178
  }
253
179
 
254
180
  async horizontalScrollRange(): Promise<number|null> {
255
181
  return await this.#domNode.callFunction(horizontalScrollRangeInPage).then(res => res?.value ?? null);
256
-
257
- function horizontalScrollRangeInPage(this: Element|Document): number {
258
- if ('scrollingElement' in this) {
259
- if (!this.scrollingElement) {
260
- return 0;
261
- }
262
-
263
- return this.scrollingElement.scrollWidth - this.scrollingElement.clientWidth;
264
- }
265
-
266
- return this.scrollWidth - this.clientWidth;
267
- }
268
182
  }
269
183
  }
270
184
 
@@ -27,6 +27,7 @@ import {
27
27
  } from './ResourceTreeModel.js';
28
28
  import {SDKModel} from './SDKModel.js';
29
29
  import {cssSourceMapsEnabledSettingDescriptor} from './SDKSettings.js';
30
+ import {SourceMapProvenance} from './SourceMap.js';
30
31
  import {SourceMapManager} from './SourceMapManager.js';
31
32
  import {Capability, type Target} from './Target.js';
32
33
 
@@ -784,7 +785,8 @@ export class CSSModel extends SDKModel<EventTypes> {
784
785
  }
785
786
  styleSheetIds.add(styleSheetHeader.id);
786
787
  }
787
- this.#sourceMapManager.attachSourceMap(styleSheetHeader, styleSheetHeader.sourceURL, styleSheetHeader.sourceMapURL);
788
+ this.#sourceMapManager.attachSourceMap(styleSheetHeader, styleSheetHeader.sourceURL, styleSheetHeader.sourceMapURL,
789
+ SourceMapProvenance.CDP);
788
790
  this.dispatchEventToListeners(Events.StyleSheetAdded, styleSheetHeader);
789
791
  }
790
792
 
@@ -846,7 +848,7 @@ export class CSSModel extends SDKModel<EventTypes> {
846
848
 
847
849
  this.#sourceMapManager.detachSourceMap(header);
848
850
  header.setSourceMapURL(sourceMapURL);
849
- this.#sourceMapManager.attachSourceMap(header, header.sourceURL, header.sourceMapURL);
851
+ this.#sourceMapManager.attachSourceMap(header, header.sourceURL, header.sourceMapURL, SourceMapProvenance.CDP);
850
852
  if (sourceMapURL === null) {
851
853
  return 'Error in CSS.setStyleSheetText';
852
854
  }
@@ -497,8 +497,10 @@ export class ComputedText {
497
497
  * ignored for the spacing requirement.
498
498
  **/
499
499
  export function requiresSpace(a: string, b: string): boolean;
500
- export function requiresSpace(a: Node[], b: Node[]): boolean;
501
- export function requiresSpace(a: Node[]|string|undefined, b: Node[]|string|undefined): boolean {
500
+ export function requiresSpace(a: Array<{textContent?: string | null}>,
501
+ b: Array<{textContent?: string | null}>): boolean;
502
+ export function requiresSpace(a: Array<{textContent?: string | null}>|string|undefined,
503
+ b: Array<{textContent?: string | null}>|string|undefined): boolean {
502
504
  const tail = Array.isArray(a) ? a.findLast(node => node.textContent)?.textContent : a;
503
505
  const head = Array.isArray(b) ? b.find(node => node.textContent)?.textContent : b;
504
506
  const trailingChar = tail ? tail[tail.length - 1] : '';
@@ -510,8 +512,6 @@ export function requiresSpace(a: Node[]|string|undefined, b: Node[]|string|undef
510
512
  !noSpaceBefore.includes(leadingChar);
511
513
  }
512
514
 
513
- export const CSSControlMap: MapConstructor = Map;
514
- export type CSSControlMap = Map<string, HTMLElement[]>;
515
515
  export namespace ASTUtils {
516
516
  export function siblings(node: CodeMirror.SyntaxNode|null): CodeMirror.SyntaxNode[] {
517
517
  const result = [];
@@ -1,10 +1,9 @@
1
1
  // Copyright 2023 The Chromium Authors
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
- /* eslint-disable @devtools/no-imperative-dom-api */
5
4
 
6
5
  import * as Common from '../../core/common/common.js';
7
- import type * as Platform from '../../core/platform/platform.js';
6
+ import * as Platform from '../../core/platform/platform.js';
8
7
  import type * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
9
8
 
10
9
  import type {CSSMatchedStyles, CSSValueSource, CSSVariableValue} from './CSSMatchedStyles.js';
@@ -212,33 +211,6 @@ export class AttributeMatch extends BaseVariableMatch {
212
211
  }
213
212
  }
214
213
 
215
- let cssEvaluationElement: HTMLElement|null = null;
216
- function getCssEvaluationElement(): HTMLElement {
217
- const id = 'css-evaluation-element';
218
- if (!cssEvaluationElement) {
219
- cssEvaluationElement = document.getElementById(id);
220
- if (!cssEvaluationElement) {
221
- cssEvaluationElement = document.createElement('div');
222
- cssEvaluationElement.setAttribute('id', id);
223
- cssEvaluationElement.setAttribute('style', 'hidden: true; --evaluation: attr(data-custom-expr type(*))');
224
- document.body.appendChild(cssEvaluationElement);
225
- }
226
- }
227
- return cssEvaluationElement;
228
- }
229
-
230
- /**
231
- * If a test calls localEvalCSS, an element is created on demand for this
232
- * purpose. This element is not removed from the DOM and will leak between tests
233
- * if not removed.
234
- */
235
- export function removeCSSEvaluationElement(): void {
236
- if (cssEvaluationElement) {
237
- document.body.removeChild(cssEvaluationElement);
238
- cssEvaluationElement = null;
239
- }
240
- }
241
-
242
214
  /**
243
215
  * These functions use an element in the frontend to evaluate CSS. The advantage
244
216
  * of this is that it is synchronous and doesn't require a CDP method. The
@@ -249,10 +221,7 @@ export function removeCSSEvaluationElement(): void {
249
221
  * substitutions (but not for actual evaluation) and for applying units.
250
222
  **/
251
223
  export function localEvalCSS(value: string, type: string): string|null {
252
- const element = getCssEvaluationElement();
253
- element.setAttribute('data-value', value);
254
- element.setAttribute('data-custom-expr', `attr(data-value ${type})`);
255
- return element.computedStyleMap().get('--evaluation')?.toString() ?? null;
224
+ return Platform.HostRuntime.HOST_RUNTIME.evaluateCSS(value, `attr(data-value ${type})`);
256
225
  }
257
226
 
258
227
  /**
@@ -261,15 +230,11 @@ export function localEvalCSS(value: string, type: string): string|null {
261
230
  * raw string, returning '' if the attribute is not set.
262
231
  **/
263
232
  export function isValidCSSType(type: string): boolean {
264
- const element = getCssEvaluationElement();
265
- element.setAttribute('data-custom-expr', `attr(data-nonexistent ${type}, "good")`);
266
- return '"good"' === (element.computedStyleMap().get('--evaluation')?.toString() ?? null);
233
+ return '"good"' === Platform.HostRuntime.HOST_RUNTIME.evaluateCSS(null, `attr(data-nonexistent ${type}, "good")`);
267
234
  }
268
235
 
269
236
  export function defaultValueForCSSType(type: string|null): string|null {
270
- const element = getCssEvaluationElement();
271
- element.setAttribute('data-custom-expr', `attr(data-nonexistent ${type ?? ''})`);
272
- return element.computedStyleMap().get('--evaluation')?.toString() ?? null;
237
+ return Platform.HostRuntime.HOST_RUNTIME.evaluateCSS(null, `attr(data-nonexistent ${type ?? ''})`);
273
238
  }
274
239
 
275
240
  export const RAW_STRING_TYPE = 'raw-string';
@@ -371,11 +336,6 @@ export class TextMatch implements Match {
371
336
  this.computedText = () => '';
372
337
  }
373
338
  }
374
- render(): Node[] {
375
- const span = document.createElement('span');
376
- span.appendChild(document.createTextNode(this.text));
377
- return [span];
378
- }
379
339
  }
380
340
 
381
341
  const TextMatcherBase: MatcherClass<TextMatch> = matcherBase(TextMatch);
@@ -16,6 +16,11 @@ const UIStrings = {
16
16
  * @description Text on the remote debugging window to indicate the connection is lost.
17
17
  */
18
18
  websocketDisconnected: 'WebSocket disconnected',
19
+ /**
20
+ * @description Text in the remote debugging terminated dialog when the WebSocket connection fails, instructing the user to check the --remote-allow-origins flag on the Chrome instance.
21
+ */
22
+ websocketConnectionFailed:
23
+ 'WebSocket disconnected. Make sure `--remote-allow-origins` on the Chrome instance allows the current origin.',
19
24
  } as const;
20
25
  const str_ = i18n.i18n.registerUIStrings('core/sdk/Connections.ts', UIStrings);
21
26
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -114,7 +119,7 @@ export class WebSocketTransport implements ProtocolClient.ConnectionTransport.Co
114
119
 
115
120
  private onError(): void {
116
121
  if (this.#onWebSocketDisconnect) {
117
- this.#onWebSocketDisconnect.call(null, i18nString(UIStrings.websocketDisconnected));
122
+ this.#onWebSocketDisconnect.call(null, i18nString(UIStrings.websocketConnectionFailed));
118
123
  }
119
124
  if (this.#onDisconnect) {
120
125
  // This is called if error occurred while connecting.
@@ -18,6 +18,7 @@ import {
18
18
  LOGPOINT_SOURCE_URL,
19
19
  } from './DebuggerModel.js';
20
20
  import {LogModel} from './LogModel.js';
21
+ import {saveVariable} from './PageFunctions.js';
21
22
  import {RemoteObject} from './RemoteObject.js';
22
23
  import {
23
24
  Events as ResourceTreeModelEvents,
@@ -458,18 +459,6 @@ export class ConsoleModel extends SDKModel<EventTypes> {
458
459
  if (callFunctionResult.object) {
459
460
  callFunctionResult.object.release();
460
461
  }
461
-
462
- function saveVariable(this: Window, value: Protocol.Runtime.CallArgument): string {
463
- const prefix = 'temp';
464
- let index = 1;
465
- while ((prefix + index) in this) {
466
- ++index;
467
- }
468
- const name = prefix + index;
469
- // @ts-expect-error Assignment to global object
470
- this[name] = value;
471
- return name;
472
- }
473
462
  }
474
463
  }
475
464