chrome-devtools-frontend 1.0.1699061 → 1.0.1701636

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 (157) hide show
  1. package/front_end/core/root/Runtime.ts +5 -0
  2. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +16 -11
  3. package/front_end/core/sdk/NetworkManager.ts +7 -0
  4. package/front_end/core/sdk/SecurityOrigin.ts +1 -0
  5. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +3 -0
  6. package/front_end/core/sdk/SourceMap.ts +12 -1
  7. package/front_end/core/sdk/SourceMapCache.ts +12 -0
  8. package/front_end/core/sdk/SourceMapManager.ts +17 -8
  9. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +2 -19
  10. package/front_end/core/sdk/SourceMapScopesInfo.ts +21 -0
  11. package/front_end/core/sdk/StorageBucketsModel.ts +2 -0
  12. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +7 -3
  13. package/front_end/entrypoints/formatter_worker/Substitute.ts +90 -26
  14. package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
  15. package/front_end/entrypoints/main/ExecutionContextSelector.ts +17 -4
  16. package/front_end/entrypoints/main/GlobalAiButton.ts +2 -6
  17. package/front_end/entrypoints/main/MainImpl.ts +8 -1
  18. package/front_end/generated/InspectorBackendCommands.ts +13 -5
  19. package/front_end/generated/SupportedCSSProperties.ts +14 -0
  20. package/front_end/generated/protocol-mapping.d.ts +48 -9
  21. package/front_end/generated/protocol-proxy-api.d.ts +37 -7
  22. package/front_end/generated/protocol.ts +135 -22
  23. package/front_end/models/ai_assistance/debug.ts +10 -2
  24. package/front_end/models/bindings/NetworkProject.ts +30 -0
  25. package/front_end/models/bindings/ResourceScriptMapping.ts +62 -0
  26. package/front_end/models/change_tracker/ChangeTracker.ts +1 -1
  27. package/front_end/models/comment_manager/CD4ABridge.ts +4 -4
  28. package/front_end/models/comment_manager/CommentManager.ts +21 -0
  29. package/front_end/models/extensions/ExtensionAPI.ts +4 -2
  30. package/front_end/models/formatter/FormatterWorkerPool.ts +2 -2
  31. package/front_end/models/issues_manager/CookieIssue.ts +0 -2
  32. package/front_end/models/javascript_metadata/NativeFunctions.ts +7 -2
  33. package/front_end/models/persistence/NetworkPersistenceManager.ts +29 -4
  34. package/front_end/models/source_map_scopes/NamesResolver.ts +65 -40
  35. package/front_end/models/source_map_scopes/ScopeChainModel.ts +21 -1
  36. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +70 -1
  37. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +5 -8
  38. package/front_end/panels/ai_assistance/components/ChatMessage.ts +1 -1
  39. package/front_end/panels/application/AppManifestView.ts +128 -134
  40. package/front_end/panels/application/CrashReportContextView.ts +5 -5
  41. package/front_end/panels/application/DeviceBoundSessionsTreeElement.ts +17 -17
  42. package/front_end/panels/application/DeviceBoundSessionsView.ts +136 -137
  43. package/front_end/panels/application/IndexedDBModel.ts +3 -0
  44. package/front_end/panels/application/OriginTrialTreeView.ts +18 -23
  45. package/front_end/panels/application/ReportingApiTreeElement.ts +3 -3
  46. package/front_end/panels/application/ReportingApiView.ts +6 -14
  47. package/front_end/panels/application/application-meta.ts +7 -7
  48. package/front_end/panels/common/CommentThreadWidget.ts +19 -6
  49. package/front_end/panels/common/CommentsOverlayWidget.ts +143 -10
  50. package/front_end/panels/common/CommentsStatusBarPill.ts +13 -1
  51. package/front_end/panels/common/ExtensionServer.ts +61 -42
  52. package/front_end/panels/common/GeminiRebrandPromoDialog.ts +1 -1
  53. package/front_end/panels/common/commentThreadWidget.css +18 -0
  54. package/front_end/panels/common/common-meta.ts +4 -1
  55. package/front_end/panels/console/ConsolePrompt.ts +1 -1
  56. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  57. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -1
  58. package/front_end/panels/elements/DOMTreeContextMenu.ts +1 -1
  59. package/front_end/panels/elements/{ElementsTreeOutline.ts → DOMTreeWidget.ts} +45 -31
  60. package/front_end/panels/elements/ElementsPanel.ts +1 -1
  61. package/front_end/panels/elements/ElementsTreeElement.ts +3 -1
  62. package/front_end/panels/elements/ShortcutTreeElement.ts +1 -1
  63. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  64. package/front_end/panels/elements/StylesSidebarPane.ts +4 -6
  65. package/front_end/panels/elements/TopLayerContainer.ts +1 -1
  66. package/front_end/panels/elements/elements.ts +4 -3
  67. package/front_end/panels/elements/elementsTreeOutline.css +4 -0
  68. package/front_end/panels/event_listeners/EventListenersView.ts +9 -4
  69. package/front_end/panels/issues/IssuesPane.ts +34 -22
  70. package/front_end/panels/network/RequestPayloadView.ts +17 -15
  71. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +1 -1
  72. package/front_end/panels/profiler/HeapProfileView.ts +8 -6
  73. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +8 -1
  74. package/front_end/panels/profiler/HeapSnapshotView.ts +6 -4
  75. package/front_end/panels/recorder/RecordingView.ts +32 -53
  76. package/front_end/panels/recorder/controlButton.css +6 -0
  77. package/front_end/panels/recorder/recordingView.css +11 -2
  78. package/front_end/panels/security/SecurityPanel.ts +87 -99
  79. package/front_end/panels/sensors/SensorsView.ts +87 -0
  80. package/front_end/panels/sensors/sensors-meta.ts +69 -1
  81. package/front_end/panels/settings/keybindsSettingsTab.css +1 -1
  82. package/front_end/panels/sources/DebuggerPlugin.ts +136 -55
  83. package/front_end/panels/sources/ScopeChainSidebarPane.ts +17 -15
  84. package/front_end/panels/timeline/components/IgnoreListSetting.ts +0 -2
  85. package/front_end/panels/timeline/components/LiveMetricsView.ts +59 -64
  86. package/front_end/panels/timeline/components/liveMetricsView.css +1 -0
  87. package/front_end/third_party/chromium/README.chromium +1 -1
  88. package/front_end/third_party/lighthouse/README.chromium +2 -2
  89. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1580 -1524
  90. package/front_end/third_party/lighthouse/locales/ar-XB.json +111 -72
  91. package/front_end/third_party/lighthouse/locales/ar.json +113 -74
  92. package/front_end/third_party/lighthouse/locales/bg.json +112 -73
  93. package/front_end/third_party/lighthouse/locales/ca.json +112 -73
  94. package/front_end/third_party/lighthouse/locales/cs.json +112 -73
  95. package/front_end/third_party/lighthouse/locales/da.json +112 -73
  96. package/front_end/third_party/lighthouse/locales/de.json +112 -73
  97. package/front_end/third_party/lighthouse/locales/el.json +112 -73
  98. package/front_end/third_party/lighthouse/locales/en-GB.json +111 -72
  99. package/front_end/third_party/lighthouse/locales/en-US.json +102 -66
  100. package/front_end/third_party/lighthouse/locales/en-XA.json +111 -72
  101. package/front_end/third_party/lighthouse/locales/en-XL.json +102 -66
  102. package/front_end/third_party/lighthouse/locales/es-419.json +112 -73
  103. package/front_end/third_party/lighthouse/locales/es.json +112 -73
  104. package/front_end/third_party/lighthouse/locales/fi.json +112 -73
  105. package/front_end/third_party/lighthouse/locales/fil.json +112 -73
  106. package/front_end/third_party/lighthouse/locales/fr.json +112 -73
  107. package/front_end/third_party/lighthouse/locales/he.json +112 -73
  108. package/front_end/third_party/lighthouse/locales/hi.json +112 -73
  109. package/front_end/third_party/lighthouse/locales/hr.json +112 -73
  110. package/front_end/third_party/lighthouse/locales/hu.json +112 -73
  111. package/front_end/third_party/lighthouse/locales/id.json +112 -73
  112. package/front_end/third_party/lighthouse/locales/it.json +113 -74
  113. package/front_end/third_party/lighthouse/locales/ja.json +112 -73
  114. package/front_end/third_party/lighthouse/locales/ko.json +112 -73
  115. package/front_end/third_party/lighthouse/locales/lt.json +112 -73
  116. package/front_end/third_party/lighthouse/locales/lv.json +112 -73
  117. package/front_end/third_party/lighthouse/locales/nl.json +112 -73
  118. package/front_end/third_party/lighthouse/locales/no.json +112 -73
  119. package/front_end/third_party/lighthouse/locales/pl.json +112 -73
  120. package/front_end/third_party/lighthouse/locales/pt-PT.json +112 -73
  121. package/front_end/third_party/lighthouse/locales/pt.json +112 -73
  122. package/front_end/third_party/lighthouse/locales/ro.json +112 -73
  123. package/front_end/third_party/lighthouse/locales/ru.json +112 -73
  124. package/front_end/third_party/lighthouse/locales/sk.json +112 -73
  125. package/front_end/third_party/lighthouse/locales/sl.json +112 -73
  126. package/front_end/third_party/lighthouse/locales/sr-Latn.json +112 -73
  127. package/front_end/third_party/lighthouse/locales/sr.json +112 -73
  128. package/front_end/third_party/lighthouse/locales/sv.json +124 -85
  129. package/front_end/third_party/lighthouse/locales/ta.json +112 -73
  130. package/front_end/third_party/lighthouse/locales/te.json +112 -73
  131. package/front_end/third_party/lighthouse/locales/th.json +112 -73
  132. package/front_end/third_party/lighthouse/locales/tr.json +113 -74
  133. package/front_end/third_party/lighthouse/locales/uk.json +112 -73
  134. package/front_end/third_party/lighthouse/locales/vi.json +112 -73
  135. package/front_end/third_party/lighthouse/locales/zh-HK.json +112 -73
  136. package/front_end/third_party/lighthouse/locales/zh-TW.json +113 -74
  137. package/front_end/third_party/lighthouse/locales/zh.json +113 -74
  138. package/front_end/third_party/lighthouse/report/bundle.d.ts +4 -4
  139. package/front_end/third_party/lighthouse/report/bundle.js +10 -3
  140. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +2 -2
  141. package/front_end/third_party/lit/lit.ts +3 -0
  142. package/front_end/third_party/lit/package.json +3 -0
  143. package/front_end/third_party/lit/rebuild.sh +3 -2
  144. package/front_end/ui/comments/CommentAnchorResolver.ts +8 -2
  145. package/front_end/ui/comments/CommentOverlayManager.ts +2 -1
  146. package/front_end/ui/legacy/InspectorView.ts +4 -3
  147. package/front_end/ui/legacy/TabbedPane.ts +121 -80
  148. package/front_end/ui/legacy/Treeoutline.ts +37 -7
  149. package/front_end/ui/legacy/UIUtils.ts +7 -0
  150. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +1 -1
  151. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +135 -146
  152. package/front_end/ui/legacy/treeoutline.css +2 -2
  153. package/front_end/ui/lit/lit.ts +1 -1
  154. package/front_end/ui/visual_logging/KnownContextValues.ts +11 -0
  155. package/inspector_overlay/highlight_anchor.ts +197 -0
  156. package/inspector_overlay/tool_highlight.ts +8 -0
  157. package/package.json +1 -1
@@ -14,6 +14,19 @@ import {type DebuggerSourceMapping, DebuggerWorkspaceBinding} from './DebuggerWo
14
14
  import {NetworkProject} from './NetworkProject.js';
15
15
  import {metadataForURL} from './ResourceUtils.js';
16
16
 
17
+ /**
18
+ * The security origin of the URL that `target` (or its closest ancestor that has
19
+ * one) is inspecting, or `null` if none of them has an inspected URL yet.
20
+ */
21
+ function inspectedSecurityOrigin(target: SDK.Target.Target): SDK.SecurityOrigin.SecurityOrigin|null {
22
+ for (let current: SDK.Target.Target|null = target; current; current = current.parentTarget()) {
23
+ if (current.inspectedURL()) {
24
+ return current.inspectedSecurityOrigin();
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+
17
30
  export class ResourceScriptMapping implements DebuggerSourceMapping {
18
31
  readonly debuggerModel: SDK.DebuggerModel.DebuggerModel;
19
32
  #workspace: Workspace.Workspace.WorkspaceImpl;
@@ -197,6 +210,19 @@ export class ResourceScriptMapping implements DebuggerSourceMapping {
197
210
  // Try to resolve `//# sourceURL=` annotations relative to
198
211
  // the base URL, according to the sourcemap specification.
199
212
  url = SDK.SourceMapManager.SourceMapManager.resolveRelativeSourceURL(script.debuggerModel.target(), url);
213
+
214
+ // `//# sourceURL=` annotations are fully controlled by the page, so don't let
215
+ // them impersonate a resource of a different origin (b/553931271).
216
+ if (!this.#isTrustworthySourceURL(script, url)) {
217
+ return;
218
+ }
219
+
220
+ // Don't let a synthetic source evict the `UISourceCode` of a script that was
221
+ // actually fetched from the network under the same URL.
222
+ const previousUISourceCode = this.project(script).uiSourceCodeForURL(url);
223
+ if (previousUISourceCode && !NetworkProject.isSourceURLSynthesized(previousUISourceCode)) {
224
+ return;
225
+ }
200
226
  } else {
201
227
  // Ignore inline <script>s without `//# sourceURL` annotation here.
202
228
  if (script.isInlineScript()) {
@@ -225,6 +251,9 @@ export class ResourceScriptMapping implements DebuggerSourceMapping {
225
251
  // Create UISourceCode.
226
252
  const originalContentProvider = script.originalContentProvider();
227
253
  const uiSourceCode = project.createUISourceCode(url, originalContentProvider.contentType());
254
+ if (script.hasSourceURL) {
255
+ NetworkProject.setSourceURLSynthesized(uiSourceCode);
256
+ }
228
257
  NetworkProject.setInitialFrameAttribution(uiSourceCode, script.frameId);
229
258
  const metadata = metadataForURL(this.debuggerModel.target(), script.frameId, url);
230
259
 
@@ -238,6 +267,39 @@ export class ResourceScriptMapping implements DebuggerSourceMapping {
238
267
  void this.debuggerWorkspaceBinding.updateLocations(script);
239
268
  }
240
269
 
270
+ /**
271
+ * Whether the (already resolved) `//# sourceURL=` annotation `url` of `script` may
272
+ * be used as-is.
273
+ *
274
+ * Only `http(s)` URLs can collide with genuine network resources, so an origin is
275
+ * only enforced for those. Annotations using other schemes (e.g. `webpack-internal://`,
276
+ * `snippet://` or `chrome-extension://` for content scripts) cannot impersonate a
277
+ * network resource and are always accepted.
278
+ *
279
+ * The origin of the script's frame is authoritative. For targets that don't have a
280
+ * frame (e.g. workers) we fall back to the inspected URL of the target (or of its
281
+ * closest ancestor that has one). If no origin can be established at all, the
282
+ * annotation is rejected, since we cannot rule out that it spoofs another origin.
283
+ */
284
+ #isTrustworthySourceURL(script: SDK.Script.Script, url: Platform.DevToolsPath.UrlString): boolean {
285
+ if (script.isContentScript()) {
286
+ return true;
287
+ }
288
+ const parsedURL = Common.ParsedURL.ParsedURL.fromString(url);
289
+ if (!parsedURL || !['http', 'https'].includes(parsedURL.scheme)) {
290
+ return true;
291
+ }
292
+ const target = script.debuggerModel.target();
293
+ const frame = script.frameId ?
294
+ target.model(SDK.ResourceTreeModel.ResourceTreeModel)?.frameForId(script.frameId) ?? null :
295
+ null;
296
+ const securityOrigin = frame ? frame.securityOrigin() : inspectedSecurityOrigin(target);
297
+ if (!securityOrigin) {
298
+ return false;
299
+ }
300
+ return SDK.SecurityOrigin.SecurityOrigin.create(url).isSameOriginWith(securityOrigin);
301
+ }
302
+
241
303
  scriptFile(uiSourceCode: Workspace.UISourceCode.UISourceCode): ResourceScriptFile|null {
242
304
  return this.#uiSourceCodeToScriptFile.get(uiSourceCode) || null;
243
305
  }
@@ -25,7 +25,7 @@ export class ChangeTracker {
25
25
  }
26
26
 
27
27
  get isTracking(): boolean {
28
- return Boolean(Root.Runtime.hostConfig.devToolsComments?.enabled);
28
+ return Boolean(Root.Runtime.hostConfig.devToolsComments?.enabled) && this.#commentManager.isAgentAttached();
29
29
  }
30
30
 
31
31
  trackChange(
@@ -72,7 +72,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
72
72
  if (!this.#targetManager) {
73
73
  return undefined;
74
74
  }
75
- const target = this.#targetManager.targetById(nodeSignature.targetId) ?? this.#targetManager.primaryPageTarget();
75
+ const target = this.#targetManager.targetById(nodeSignature.targetId);
76
76
  const domModel = target?.model(SDK.DOMModel.DOMModel);
77
77
  if (!domModel) {
78
78
  return undefined;
@@ -132,8 +132,8 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
132
132
  });
133
133
  }
134
134
 
135
- takeComments(): CommentThread[] {
136
- return this.getCommentThreads();
135
+ setAgentAttached(value: boolean): void {
136
+ this.#commentManager.setAgentAttached(value);
137
137
  }
138
138
 
139
139
  resolveCommentThread(threadId: string, replyText?: string): boolean {
@@ -156,7 +156,7 @@ export class CD4ABridge extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
156
156
  }
157
157
 
158
158
  if (target?.node && this.#targetManager) {
159
- const sdkTarget = this.#targetManager.targetById(target.node.targetId) ?? this.#targetManager.primaryPageTarget();
159
+ const sdkTarget = this.#targetManager.targetById(target.node.targetId);
160
160
  const domModel = sdkTarget?.model(SDK.DOMModel.DOMModel);
161
161
  if (domModel) {
162
162
  const cdpNodeId = target.node.backendNodeId as Protocol.DOM.BackendNodeId;
@@ -32,11 +32,13 @@ export {
32
32
  export const enum Events {
33
33
  COMMENT_THREADS_CHANGED = 'CommentThreadsChanged',
34
34
  COMMENT_MODE_CHANGED = 'CommentModeChanged',
35
+ AGENT_ATTACHED_CHANGED = 'AgentAttachedChanged',
35
36
  }
36
37
 
37
38
  export interface EventTypes {
38
39
  [Events.COMMENT_THREADS_CHANGED]: CommentThread[];
39
40
  [Events.COMMENT_MODE_CHANGED]: boolean;
41
+ [Events.AGENT_ATTACHED_CHANGED]: boolean;
40
42
  }
41
43
 
42
44
  /**
@@ -45,6 +47,7 @@ export interface EventTypes {
45
47
  export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
46
48
  readonly #commentThreads = new Map<string, CommentThread>();
47
49
  #commentMode = false;
50
+ #agentAttached = false;
48
51
 
49
52
  constructor() {
50
53
  super();
@@ -55,7 +58,25 @@ export class CommentManager extends Common.ObjectWrapper.ObjectWrapper<EventType
55
58
  this.dispatchEventToListeners(Events.COMMENT_THREADS_CHANGED, this.getCommentThreads());
56
59
  }
57
60
 
61
+ setAgentAttached(value: boolean): void {
62
+ if (this.#agentAttached === value) {
63
+ return;
64
+ }
65
+ this.#agentAttached = value;
66
+ if (!value) {
67
+ this.setCommentMode(false);
68
+ }
69
+ this.dispatchEventToListeners(Events.AGENT_ATTACHED_CHANGED, value);
70
+ }
71
+
72
+ isAgentAttached(): boolean {
73
+ return this.#agentAttached;
74
+ }
75
+
58
76
  setCommentMode(active: boolean): void {
77
+ if (active && !this.#agentAttached) {
78
+ return;
79
+ }
59
80
  if (this.#commentMode === active) {
60
81
  return;
61
82
  }
@@ -1586,8 +1586,10 @@ globalThis.injectedExtensionAPI = function(
1586
1586
  const targetDocument = targetWindowForTest?.document ?? document;
1587
1587
  const focused = targetDocument.activeElement;
1588
1588
  if (focused) {
1589
- const isInput =
1590
- focused.nodeName === 'INPUT' || focused.nodeName === 'TEXTAREA' || (focused as HTMLElement).isContentEditable;
1589
+ // Elements made editable through the EditContext API are not reported as contentEditable.
1590
+ const hasEditContext = 'editContext' in focused && Boolean(focused.editContext);
1591
+ const isInput = focused.nodeName === 'INPUT' || focused.nodeName === 'TEXTAREA' ||
1592
+ (focused as HTMLElement).isContentEditable || hasEditContext;
1591
1593
  if (isInput && !(requestPayload.ctrlKey || requestPayload.altKey || requestPayload.metaKey)) {
1592
1594
  return;
1593
1595
  }
@@ -134,8 +134,8 @@ export class FormatterWorkerPool {
134
134
  return this.runTask(FormatterActions.FormatterActions.FORMAT, parameters) as Promise<FormatterActions.FormatResult>;
135
135
  }
136
136
 
137
- javaScriptSubstitute(expression: string, mapping: Map<string, string|null>): Promise<string> {
138
- if (mapping.size === 0) {
137
+ javaScriptSubstitute(expression: string, mapping: Array<Map<string, string|null>>): Promise<string> {
138
+ if (mapping.every(m => m.size === 0)) {
139
139
  return Promise.resolve(expression);
140
140
  }
141
141
  return this.runTask(FormatterActions.FormatterActions.JAVASCRIPT_SUBSTITUTE, {content: expression, mapping})
@@ -306,8 +306,6 @@ export function isCausedByThirdParty(
306
306
  // site. Only cookies that have their domain also set to this third-party
307
307
  // are included in the request. We assume that the cookie was set by the same
308
308
  // third-party at some point, so we treat this as a third-party issue.
309
- //
310
- // TODO(crbug.com/1080589): Use "First-Party sets" instead of the sites registered domain.
311
309
  return !isSubdomainOf(parsedCookieUrl.domain(), outermostFrame.domainAndRegistry());
312
310
  }
313
311
 
@@ -1367,6 +1367,11 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
1367
1367
  signatures: [["message","?options"],["message","transfer"],["message","targetOrigin","?transfer"]],
1368
1368
  receivers: ["Window"]
1369
1369
  },
1370
+ {
1371
+ name: "postMessage",
1372
+ signatures: [["message","targetOrigin"],["message","?options"]],
1373
+ receivers: ["HTMLPersistentWidgetElement","PersistentWidgetOpener"]
1374
+ },
1370
1375
  {
1371
1376
  name: "deleteRule",
1372
1377
  signatures: [["index"]],
@@ -2050,7 +2055,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
2050
2055
  },
2051
2056
  {
2052
2057
  name: "write",
2053
- signatures: [["...text"],["text"],["text1","...text"]],
2058
+ signatures: [["...text"]],
2054
2059
  receivers: ["Document"]
2055
2060
  },
2056
2061
  {
@@ -2489,7 +2494,7 @@ export const NativeFunctions: readonly NativeFunctionValue[] = [
2489
2494
  },
2490
2495
  {
2491
2496
  name: "writeln",
2492
- signatures: [["...text"],["text"],["text1","...text"]]
2497
+ signatures: [["...text"]]
2493
2498
  },
2494
2499
  {
2495
2500
  name: "elementFromPoint",
@@ -9,6 +9,7 @@ import * as Root from '../../core/root/root.js';
9
9
  import * as SDK from '../../core/sdk/sdk.js';
10
10
  import * as TextUtils from '../../core/text_utils/text_utils.js';
11
11
  import * as Protocol from '../../generated/protocol.js';
12
+ import * as Bindings from '../bindings/bindings.js';
12
13
  import * as Breakpoints from '../breakpoints/breakpoints.js';
13
14
  import * as Workspace from '../workspace/workspace.js';
14
15
 
@@ -431,8 +432,32 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
431
432
  }
432
433
 
433
434
  isUISourceCodeOverridable(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
434
- return uiSourceCode.project().type() === Workspace.Workspace.projectTypes.Network &&
435
- !NetworkPersistenceManager.isForbiddenNetworkUrl(uiSourceCode.url());
435
+ if (uiSourceCode.project().type() !== Workspace.Workspace.projectTypes.Network) {
436
+ return false;
437
+ }
438
+ if (NetworkPersistenceManager.isForbiddenNetworkUrl(uiSourceCode.url())) {
439
+ return false;
440
+ }
441
+ // A `//# sourceURL=` annotation is fully controlled by the page and doesn't refer
442
+ // to an actual network resource, so there is nothing to override here. Persisting
443
+ // it would poison the overrides folder with a file that masquerades as a genuine
444
+ // resource (b/553931271).
445
+ if (Bindings.NetworkProject.NetworkProject.isSourceURLSynthesized(uiSourceCode)) {
446
+ return false;
447
+ }
448
+ return true;
449
+ }
450
+
451
+ /**
452
+ * Whether the contents of `uiSourceCode` may be written into the overrides folder.
453
+ *
454
+ * Sources that originate from a source map are overridable in the sense that the
455
+ * deployed resource they are mapped from can be overridden (see
456
+ * `PersistenceActions`), but their own URL and content are page controlled and
457
+ * must never be persisted themselves (b/553931271).
458
+ */
459
+ #canPersistUISourceCodeAsOverride(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
460
+ return this.isUISourceCodeOverridable(uiSourceCode) && !uiSourceCode.contentType().isFromSourceMap();
436
461
  }
437
462
 
438
463
  #isUISourceCodeAlreadyOverridden(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
@@ -445,12 +470,12 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
445
470
  }
446
471
 
447
472
  #canSaveUISourceCodeForOverrides(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
448
- return this.#active && this.isUISourceCodeOverridable(uiSourceCode) &&
473
+ return this.#active && this.#canPersistUISourceCodeAsOverride(uiSourceCode) &&
449
474
  !this.#isUISourceCodeAlreadyOverridden(uiSourceCode);
450
475
  }
451
476
 
452
477
  async setupAndStartLocalOverrides(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise<boolean> {
453
- if (!this.isUISourceCodeOverridable(uiSourceCode)) {
478
+ if (!this.#canPersistUISourceCodeAsOverride(uiSourceCode)) {
454
479
  return false;
455
480
  }
456
481
  // No overrides folder, set it up
@@ -15,7 +15,7 @@ interface CachedScopeMap {
15
15
  }
16
16
 
17
17
  const scopeToCachedIdentifiersMap = new WeakMap<Formatter.FormatterWorkerPool.ScopeTreeNode, CachedScopeMap>();
18
- const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Map<string, string|null>>();
18
+ const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Array<Map<string, string|null>>>();
19
19
 
20
20
  export async function getTextFor(contentProvider: TextUtils.ContentProvider.ContentProvider):
21
21
  Promise<TextUtils.Text.Text|null> {
@@ -401,56 +401,61 @@ export const resolveScopeChain =
401
401
  return scopes.map(scope => new ScopeWithSourceMappedVariables(scope, thisObject, debuggerWorkspaceBinding));
402
402
  };
403
403
 
404
+ function reverseScopeMapping(variableMapping: Map<string, string>): Map<string, string|null> {
405
+ const result = new Map<string, string|null>();
406
+ for (const [compiledName, originalName] of variableMapping) {
407
+ if (originalName && !result.has(originalName)) {
408
+ result.set(originalName, compiledName);
409
+ }
410
+ }
411
+ return result;
412
+ }
413
+
404
414
  /**
405
- * @returns A mapping from original name -> compiled name. If the orignal name is unavailable (e.g. because the compiled name was
406
- * shadowed) we set it to `null`.
415
+ * @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
407
416
  */
408
417
  export const allVariablesInCallFrame = async(
409
418
  callFrame: SDK.DebuggerModel.CallFrame,
410
419
  debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
411
- Promise<Map<string, string|null>> => {
420
+ Promise<Array<Map<string, string|null>>> => {
412
421
  if (!callFrame.debuggerModel.target()
413
422
  .targetManager()
414
423
  .settings.resolve(SDK.SDKSettings.jsSourceMapsEnabledSettingDescriptor)
415
424
  .get()) {
416
- return new Map<string, string|null>();
425
+ return [];
426
+ }
427
+ const cached = cachedMapByCallFrame.get(callFrame);
428
+ if (cached) {
429
+ return cached;
417
430
  }
418
- const cachedMap = cachedMapByCallFrame.get(callFrame);
419
- if (cachedMap) {
420
- return cachedMap;
431
+
432
+ if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
433
+ const sourceMap = callFrame.script.sourceMap() ??
434
+ await callFrame.debuggerModel.sourceMapManager().sourceMapForClientPromise(callFrame.script);
435
+ const mappedVariables =
436
+ sourceMap?.resolveMappedVariablesAtPosition(callFrame.location(), callFrame.returnValue() !== null);
437
+ if (mappedVariables) {
438
+ cachedMapByCallFrame.set(callFrame, mappedVariables);
439
+ return mappedVariables;
440
+ }
421
441
  }
422
442
 
423
443
  const scopeChain = callFrame.scopeChain().filter(scope => !scope.empty());
424
444
  const nameMappings =
425
445
  await Promise.all(scopeChain.map(scope => resolveDebuggerScope(scope, debuggerWorkspaceBinding)));
426
- const reverseMapping = new Map<string, string|null>();
427
- const compiledNames = new Set<string>();
428
- for (const {variableMapping} of nameMappings) {
429
- for (const [compiledName, originalName] of variableMapping) {
430
- if (!originalName) {
431
- continue;
432
- }
433
- if (!reverseMapping.has(originalName)) {
434
- // An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
435
- const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
436
- reverseMapping.set(originalName, compiledNameOrNull);
437
- }
438
- compiledNames.add(compiledName);
439
- }
440
- }
446
+ const reverseMapping = nameMappings.map(({variableMapping}) => reverseScopeMapping(variableMapping));
441
447
  cachedMapByCallFrame.set(callFrame, reverseMapping);
442
448
  return reverseMapping;
443
449
  };
444
450
 
445
451
  /**
446
- * @returns A mapping from original name -> compiled name. If the orignal name is unavailable (e.g. because the compiled name was
447
- * shadowed) we set it to `null`.
452
+ * @returns An array of mappings (from inner-most to outer-most scope) of original name -> compiled name or binding expression.
448
453
  */
449
454
  export const allVariablesAtPosition =
450
455
  async(location: SDK.DebuggerModel.Location,
451
456
  debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
452
- Promise<Map<string, string|null>> => {
453
- const reverseMapping = new Map<string, string|null>();
457
+ Promise<Array<Map<string, string|null>>> => {
458
+ const reverseMapping: Array<Map<string, string|null>> = [];
454
459
  const script = location.script();
455
460
  if (!script) {
456
461
  return reverseMapping;
@@ -462,6 +467,15 @@ export const allVariablesAtPosition =
462
467
  return reverseMapping;
463
468
  }
464
469
 
470
+ if (Root.Runtime.hostConfig.devToolsSourceMapScopesInSourcesPanel?.enabled) {
471
+ const sourceMap =
472
+ script.sourceMap() ?? await script.debuggerModel.sourceMapManager().sourceMapForClientPromise(script);
473
+ const mappedVariables = sourceMap?.resolveMappedVariablesAtPosition(location);
474
+ if (mappedVariables) {
475
+ return mappedVariables;
476
+ }
477
+ }
478
+
465
479
  const scopeTreeAndText = await computeScopeTree(script);
466
480
  if (!scopeTreeAndText) {
467
481
  return reverseMapping;
@@ -470,21 +484,10 @@ export const allVariablesAtPosition =
470
484
  const {scopeTree, text} = scopeTreeAndText;
471
485
  const locationOffset = text.offsetFromPosition(location.lineNumber, location.columnNumber);
472
486
  const scopeChain = findScopeChain(scopeTree, {start: locationOffset, end: locationOffset});
473
- const compiledNames = new Set<string>();
474
487
 
475
488
  while (scopeChain.length > 0) {
476
489
  const {variableMapping} = await resolveScope(script, scopeChain, debuggerWorkspaceBinding);
477
- for (const [compiledName, originalName] of variableMapping) {
478
- if (!originalName) {
479
- continue;
480
- }
481
- if (!reverseMapping.has(originalName)) {
482
- // An inner scope might have shadowed {compiledName}. Mark it as "unavailable" in that case.
483
- const compiledNameOrNull = compiledNames.has(compiledName) ? null : compiledName;
484
- reverseMapping.set(originalName, compiledNameOrNull);
485
- }
486
- compiledNames.add(compiledName);
487
- }
490
+ reverseMapping.push(reverseScopeMapping(variableMapping));
488
491
  scopeChain.pop();
489
492
  }
490
493
  return reverseMapping;
@@ -545,6 +548,7 @@ class ScopeWithSourceMappedVariables implements SDK.DebuggerModel.ScopeChainEntr
545
548
  /** The resolved `this` of the current call frame */
546
549
  readonly #thisObject: SDK.RemoteObject.RemoteObject|null;
547
550
  readonly #debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding;
551
+ #object?: SDK.RemoteObject.RemoteObject;
548
552
 
549
553
  constructor(scope: SDK.DebuggerModel.ScopeChainEntry, thisObject: SDK.RemoteObject.RemoteObject|null,
550
554
  debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding) {
@@ -574,7 +578,10 @@ class ScopeWithSourceMappedVariables implements SDK.DebuggerModel.ScopeChainEntr
574
578
  }
575
579
 
576
580
  object(): SDK.RemoteObject.RemoteObject {
577
- return resolveScopeInObject(this.#debuggerScope, this.#debuggerWorkspaceBinding);
581
+ if (!this.#object) {
582
+ this.#object = resolveScopeInObject(this.#debuggerScope, this.#debuggerWorkspaceBinding);
583
+ }
584
+ return this.#object;
578
585
  }
579
586
 
580
587
  description(): string {
@@ -599,6 +606,8 @@ export class RemoteObject extends SDK.RemoteObject.RemoteObject {
599
606
  private readonly scope: SDK.DebuggerModel.ScopeChainEntry;
600
607
  private readonly object: SDK.RemoteObject.RemoteObject;
601
608
  readonly #debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding;
609
+ #allPropertiesPromise?: Promise<SDK.RemoteObject.GetPropertiesResult>;
610
+ #cachedWithPreview = false;
602
611
 
603
612
  constructor(scope: SDK.DebuggerModel.ScopeChainEntry,
604
613
  debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding) {
@@ -650,6 +659,18 @@ export class RemoteObject extends SDK.RemoteObject.RemoteObject {
650
659
 
651
660
  override async getAllProperties(accessorPropertiesOnly: boolean, generatePreview: boolean):
652
661
  Promise<SDK.RemoteObject.GetPropertiesResult> {
662
+ if (accessorPropertiesOnly) {
663
+ return await this.#resolveAllProperties(true, generatePreview);
664
+ }
665
+ if (!this.#allPropertiesPromise || (generatePreview && !this.#cachedWithPreview)) {
666
+ this.#cachedWithPreview = generatePreview;
667
+ this.#allPropertiesPromise = this.#resolveAllProperties(false, generatePreview);
668
+ }
669
+ return await this.#allPropertiesPromise;
670
+ }
671
+
672
+ async #resolveAllProperties(accessorPropertiesOnly: boolean,
673
+ generatePreview: boolean): Promise<SDK.RemoteObject.GetPropertiesResult> {
653
674
  const allProperties = await this.object.getAllProperties(accessorPropertiesOnly, generatePreview);
654
675
  const {variableMapping} = await resolveDebuggerScope(this.scope, this.#debuggerWorkspaceBinding);
655
676
 
@@ -664,6 +685,8 @@ export class RemoteObject extends SDK.RemoteObject.RemoteObject {
664
685
 
665
686
  override async setPropertyValue(argumentName: string|Protocol.Runtime.CallArgument, value: string):
666
687
  Promise<string|undefined> {
688
+ this.#allPropertiesPromise = undefined;
689
+ this.#cachedWithPreview = false;
667
690
  const {variableMapping} = await resolveDebuggerScope(this.scope, this.#debuggerWorkspaceBinding);
668
691
 
669
692
  let name;
@@ -684,6 +707,8 @@ export class RemoteObject extends SDK.RemoteObject.RemoteObject {
684
707
  }
685
708
 
686
709
  override async deleteProperty(name: Protocol.Runtime.CallArgument): Promise<string|undefined> {
710
+ this.#allPropertiesPromise = undefined;
711
+ this.#cachedWithPreview = false;
687
712
  return await this.object.deleteProperty(name);
688
713
  }
689
714
 
@@ -21,6 +21,9 @@ import {resolveScopeChain} from './NamesResolver.js';
21
21
  * This class tracks all that and sends events with the latest scope chain for a specific call frame.
22
22
  */
23
23
  export class ScopeChainModel extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
24
+ static readonly #cachedScopeChainByCallFrame =
25
+ new WeakMap<SDK.DebuggerModel.CallFrame, Promise<SDK.DebuggerModel.ScopeChainEntry[]>>();
26
+
24
27
  readonly #callFrame: SDK.DebuggerModel.CallFrame;
25
28
  readonly #debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding;
26
29
 
@@ -53,13 +56,29 @@ export class ScopeChainModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
53
56
  this.listeners?.clear();
54
57
  }
55
58
 
59
+ static resolveScopeChain(callFrame: SDK.DebuggerModel.CallFrame,
60
+ debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding):
61
+ Promise<SDK.DebuggerModel.ScopeChainEntry[]> {
62
+ let cachedPromise = ScopeChainModel.#cachedScopeChainByCallFrame.get(callFrame);
63
+ if (!cachedPromise) {
64
+ cachedPromise = resolveScopeChain(callFrame, debuggerWorkspaceBinding);
65
+ ScopeChainModel.#cachedScopeChainByCallFrame.set(callFrame, cachedPromise);
66
+ }
67
+ return cachedPromise;
68
+ }
69
+
70
+ resolveScopeChain(): Promise<SDK.DebuggerModel.ScopeChainEntry[]> {
71
+ return ScopeChainModel.resolveScopeChain(this.#callFrame, this.#debuggerWorkspaceBinding);
72
+ }
73
+
56
74
  async #update(): Promise<void> {
57
- const scopeChain = await resolveScopeChain(this.#callFrame, this.#debuggerWorkspaceBinding);
75
+ const scopeChain = await this.resolveScopeChain();
58
76
  this.dispatchEventToListeners(Events.SCOPE_CHAIN_UPDATED, new ScopeChain(scopeChain));
59
77
  }
60
78
 
61
79
  #debugInfoAttached(event: Common.EventTarget.EventTargetEvent<SDK.Script.Script>): void {
62
80
  if (event.data === this.#callFrame.script) {
81
+ ScopeChainModel.#cachedScopeChainByCallFrame.delete(this.#callFrame);
63
82
  void this.#throttler.schedule(this.#boundUpdate);
64
83
  }
65
84
  }
@@ -67,6 +86,7 @@ export class ScopeChainModel extends Common.ObjectWrapper.ObjectWrapper<EventTyp
67
86
  #sourceMapChanged(event: Common.EventTarget
68
87
  .EventTargetEvent<{client: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap}>): void {
69
88
  if (event.data.client === this.#callFrame.script) {
89
+ ScopeChainModel.#cachedScopeChainByCallFrame.delete(this.#callFrame);
70
90
  void this.#throttler.schedule(this.#boundUpdate);
71
91
  }
72
92
  }