chrome-devtools-frontend 1.0.1009019 → 1.0.1010492

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 (28) hide show
  1. package/extension-api/ExtensionAPI.d.ts +8 -6
  2. package/front_end/core/host/UserMetrics.ts +3 -1
  3. package/front_end/core/i18n/locales/en-US.json +16 -4
  4. package/front_end/core/i18n/locales/en-XL.json +16 -4
  5. package/front_end/core/sdk/CSSProperty.ts +3 -3
  6. package/front_end/core/sdk/DebuggerModel.ts +12 -3
  7. package/front_end/core/sdk/EmulationModel.ts +9 -3
  8. package/front_end/core/sdk/Script.ts +3 -2
  9. package/front_end/models/bindings/BreakpointManager.ts +58 -22
  10. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +72 -65
  11. package/front_end/models/bindings/ResourceMapping.ts +43 -10
  12. package/front_end/models/bindings/ResourceScriptMapping.ts +13 -1
  13. package/front_end/models/extensions/ExtensionAPI.ts +15 -4
  14. package/front_end/models/extensions/ExtensionServer.ts +3 -3
  15. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +18 -1
  16. package/front_end/models/persistence/Automapping.ts +18 -12
  17. package/front_end/models/persistence/PersistenceImpl.ts +10 -2
  18. package/front_end/models/workspace/WorkspaceImpl.ts +16 -9
  19. package/front_end/panels/application/DOMStorageItemsView.ts +6 -0
  20. package/front_end/panels/console/ConsoleViewMessage.ts +2 -1
  21. package/front_end/panels/sources/CallStackSidebarPane.ts +11 -4
  22. package/front_end/panels/sources/DebuggerPlugin.ts +51 -1
  23. package/front_end/ui/components/data_grid/DataGrid.ts +5 -0
  24. package/front_end/ui/components/data_grid/DataGridController.ts +5 -0
  25. package/front_end/ui/legacy/Infobar.ts +1 -0
  26. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +1 -1
  27. package/front_end/ui/legacy/infobar.css +17 -0
  28. package/package.json +1 -1
@@ -172,7 +172,8 @@ export namespace Chrome {
172
172
  }
173
173
 
174
174
  export interface RecorderExtensionPlugin {
175
- stringify(obj: Record<string, any>): Promise<string>;
175
+ stringify(recording: Record<string, any>): Promise<string>;
176
+ stringifyStep(step: Record<string, any>): Promise<string>;
176
177
  }
177
178
 
178
179
  export interface LanguageExtensionPlugin {
@@ -180,7 +181,8 @@ export namespace Chrome {
180
181
  * A new raw module has been loaded. If the raw wasm module references an external debug info module, its URL will be
181
182
  * passed as symbolsURL.
182
183
  */
183
- addRawModule(rawModuleId: string, symbolsURL: string|undefined, rawModule: RawModule): Promise<string[]>;
184
+ addRawModule(rawModuleId: string, symbolsURL: string|undefined, rawModule: RawModule):
185
+ Promise<string[]|{missingSymbolFiles: string[]}>;
184
186
 
185
187
  /**
186
188
  * Find locations in raw modules from a location in a source file.
@@ -241,9 +243,8 @@ export namespace Chrome {
241
243
  /**
242
244
  * Find locations in source files from a location in a raw module
243
245
  */
244
- getFunctionInfo(rawLocation: RawLocation): Promise<{
245
- frames: Array<FunctionInfo>,
246
- }>;
246
+ getFunctionInfo(rawLocation: RawLocation):
247
+ Promise<{frames: Array<FunctionInfo>}|{missingSymbolFiles: Array<string>}>;
247
248
 
248
249
  /**
249
250
  * Find locations in raw modules corresponding to the inline function
@@ -278,7 +279,8 @@ export namespace Chrome {
278
279
  }
279
280
 
280
281
  export interface RecorderExtensions {
281
- registerRecorderExtensionPlugin(plugin: RecorderExtensionPlugin, pluginName: string): Promise<void>;
282
+ registerRecorderExtensionPlugin(plugin: RecorderExtensionPlugin, pluginName: string, mediaType: string):
283
+ Promise<void>;
282
284
  unregisterRecorderExtensionPlugin(plugin: RecorderExtensionPlugin): Promise<void>;
283
285
  }
284
286
 
@@ -939,7 +939,9 @@ export enum RecordingEdited {
939
939
  export enum RecordingExported {
940
940
  ToPuppeteer = 1,
941
941
  ToJSON = 2,
942
- MaxValue = 3,
942
+ ToPuppeteerReplay = 3,
943
+ ToExtension = 4,
944
+ MaxValue = 5,
943
945
  }
944
946
 
945
947
  /* eslint-disable @typescript-eslint/naming-convention */
@@ -1241,6 +1241,9 @@
1241
1241
  "models/bindings/ContentProviderBasedProject.ts | unknownErrorLoadingFile": {
1242
1242
  "message": "Unknown error loading file"
1243
1243
  },
1244
+ "models/bindings/DebuggerLanguagePlugins.ts | debugSymbolsIncomplete": {
1245
+ "message": "The debug information for function {PH1} is incomplete"
1246
+ },
1244
1247
  "models/bindings/DebuggerLanguagePlugins.ts | errorInDebuggerLanguagePlugin": {
1245
1248
  "message": "Error in debugger language plugin: {PH1}"
1246
1249
  },
@@ -1248,7 +1251,7 @@
1248
1251
  "message": "[{PH1}] Failed to load debug symbols for {PH2} ({PH3})"
1249
1252
  },
1250
1253
  "models/bindings/DebuggerLanguagePlugins.ts | failedToLoadDebugSymbolsForFunction": {
1251
- "message": "Missing debug symbols for function \"{PH1}\""
1254
+ "message": "No debug information for function \"{PH1}\""
1252
1255
  },
1253
1256
  "models/bindings/DebuggerLanguagePlugins.ts | loadedDebugSymbolsForButDidnt": {
1254
1257
  "message": "[{PH1}] Loaded debug symbols for {PH2}, but didn't find any source files"
@@ -1262,9 +1265,6 @@
1262
1265
  "models/bindings/DebuggerLanguagePlugins.ts | loadingDebugSymbolsForVia": {
1263
1266
  "message": "[{PH1}] Loading debug symbols for {PH2} (via {PH3})..."
1264
1267
  },
1265
- "models/bindings/DebuggerLanguagePlugins.ts | symbolFileNotFound": {
1266
- "message": "Symbol file \"{PH1}\" not found"
1267
- },
1268
1268
  "models/bindings/ResourceScriptMapping.ts | liveEditCompileFailed": {
1269
1269
  "message": "LiveEdit compile failed: {PH1}"
1270
1270
  },
@@ -3293,6 +3293,9 @@
3293
3293
  "panels/application/DOMStorageItemsView.ts | domStorageItems": {
3294
3294
  "message": "DOM Storage Items"
3295
3295
  },
3296
+ "panels/application/DOMStorageItemsView.ts | domStorageItemsCleared": {
3297
+ "message": "{PH1} cleared"
3298
+ },
3296
3299
  "panels/application/DOMStorageItemsView.ts | domStorageNumberEntries": {
3297
3300
  "message": "Number of entries shown in table: {PH1}"
3298
3301
  },
@@ -9515,6 +9518,9 @@
9515
9518
  "panels/sources/CallStackSidebarPane.ts | copyStackTrace": {
9516
9519
  "message": "Copy stack trace"
9517
9520
  },
9521
+ "panels/sources/CallStackSidebarPane.ts | debugFileNotFound": {
9522
+ "message": "Failed to load debug file \"{PH1}\"."
9523
+ },
9518
9524
  "panels/sources/CallStackSidebarPane.ts | notPaused": {
9519
9525
  "message": "Not paused"
9520
9526
  },
@@ -9650,6 +9656,12 @@
9650
9656
  "panels/sources/DebuggerPlugin.ts | configure": {
9651
9657
  "message": "Configure"
9652
9658
  },
9659
+ "panels/sources/DebuggerPlugin.ts | debugFileNotFound": {
9660
+ "message": "Failed to load debug file \"{PH1}\"."
9661
+ },
9662
+ "panels/sources/DebuggerPlugin.ts | debugInfoNotFound": {
9663
+ "message": "Failed to load any debug info for {PH1}."
9664
+ },
9653
9665
  "panels/sources/DebuggerPlugin.ts | disableBreakpoint": {
9654
9666
  "message": "{n, plural, =1 {Disable breakpoint} other {Disable all breakpoints in line}}"
9655
9667
  },
@@ -1241,6 +1241,9 @@
1241
1241
  "models/bindings/ContentProviderBasedProject.ts | unknownErrorLoadingFile": {
1242
1242
  "message": "Ûńk̂ńôẃn̂ ér̂ŕôŕ l̂óâd́îńĝ f́îĺê"
1243
1243
  },
1244
+ "models/bindings/DebuggerLanguagePlugins.ts | debugSymbolsIncomplete": {
1245
+ "message": "T̂h́ê d́êb́ûǵ îńf̂ór̂ḿât́îón̂ f́ôŕ f̂ún̂ćt̂íôń {PH1} îś îńĉóm̂ṕl̂ét̂é"
1246
+ },
1244
1247
  "models/bindings/DebuggerLanguagePlugins.ts | errorInDebuggerLanguagePlugin": {
1245
1248
  "message": "Êŕr̂ór̂ ín̂ d́êb́ûǵĝér̂ ĺâńĝúâǵê ṕl̂úĝín̂: {PH1}"
1246
1249
  },
@@ -1248,7 +1251,7 @@
1248
1251
  "message": "[{PH1}] F̂áîĺêd́ t̂ó l̂óâd́ d̂éb̂úĝ śŷḿb̂ól̂ś f̂ór̂ {PH2} ({PH3})"
1249
1252
  },
1250
1253
  "models/bindings/DebuggerLanguagePlugins.ts | failedToLoadDebugSymbolsForFunction": {
1251
- "message": "M̂íŝśîńĝ d́êb́ûǵ ŝým̂b́ôĺôún̂ćt̂íô \"{PH1}\""
1254
+ "message": "N̂ó d̂éb̂úĝ ín̂f́ôŕm̂át̂íôń f̂ór̂ f́ûńĉt́îón̂ \"{PH1}\""
1252
1255
  },
1253
1256
  "models/bindings/DebuggerLanguagePlugins.ts | loadedDebugSymbolsForButDidnt": {
1254
1257
  "message": "[{PH1}] L̂óâd́êd́ d̂éb̂úĝ śŷḿb̂ól̂ś f̂ór̂ {PH2}, b́ût́ d̂íd̂ń't̂ f́îńd̂ án̂ý ŝóûŕĉé f̂íl̂éŝ"
@@ -1262,9 +1265,6 @@
1262
1265
  "models/bindings/DebuggerLanguagePlugins.ts | loadingDebugSymbolsForVia": {
1263
1266
  "message": "[{PH1}] L̂óâd́îńĝ d́êb́ûǵ ŝým̂b́ôĺŝ f́ôŕ {PH2} (v̂íâ {PH3})..."
1264
1267
  },
1265
- "models/bindings/DebuggerLanguagePlugins.ts | symbolFileNotFound": {
1266
- "message": "Ŝým̂b́ôĺ f̂íl̂é \"{PH1}\" n̂ót̂ f́ôún̂d́"
1267
- },
1268
1268
  "models/bindings/ResourceScriptMapping.ts | liveEditCompileFailed": {
1269
1269
  "message": "LiveEdit ĉóm̂ṕîĺê f́âíl̂éd̂: {PH1}"
1270
1270
  },
@@ -3293,6 +3293,9 @@
3293
3293
  "panels/application/DOMStorageItemsView.ts | domStorageItems": {
3294
3294
  "message": "D̂ÓM̂ Śt̂ór̂áĝé Ît́êḿŝ"
3295
3295
  },
3296
+ "panels/application/DOMStorageItemsView.ts | domStorageItemsCleared": {
3297
+ "message": "{PH1} ĉĺêár̂éd̂"
3298
+ },
3296
3299
  "panels/application/DOMStorageItemsView.ts | domStorageNumberEntries": {
3297
3300
  "message": "N̂úm̂b́êŕ ôf́ êńt̂ŕîéŝ śĥóŵń îń t̂áb̂ĺê: {PH1}"
3298
3301
  },
@@ -9515,6 +9518,9 @@
9515
9518
  "panels/sources/CallStackSidebarPane.ts | copyStackTrace": {
9516
9519
  "message": "Ĉóp̂ý ŝt́âćk̂ t́r̂áĉé"
9517
9520
  },
9521
+ "panels/sources/CallStackSidebarPane.ts | debugFileNotFound": {
9522
+ "message": "F̂áîĺêd́ t̂ó l̂óâd́ d̂éb̂úĝ f́îĺê \"{PH1}\"."
9523
+ },
9518
9524
  "panels/sources/CallStackSidebarPane.ts | notPaused": {
9519
9525
  "message": "N̂ót̂ ṕâúŝéd̂"
9520
9526
  },
@@ -9650,6 +9656,12 @@
9650
9656
  "panels/sources/DebuggerPlugin.ts | configure": {
9651
9657
  "message": "Ĉón̂f́îǵûŕê"
9652
9658
  },
9659
+ "panels/sources/DebuggerPlugin.ts | debugFileNotFound": {
9660
+ "message": "F̂áîĺêd́ t̂ó l̂óâd́ d̂éb̂úĝ f́îĺê \"{PH1}\"."
9661
+ },
9662
+ "panels/sources/DebuggerPlugin.ts | debugInfoNotFound": {
9663
+ "message": "F̂áîĺêd́ t̂ó l̂óâd́ âńŷ d́êb́ûǵ îńf̂ó f̂ór̂ {PH1}."
9664
+ },
9653
9665
  "panels/sources/DebuggerPlugin.ts | disableBreakpoint": {
9654
9666
  "message": "{n, plural, =1 {D̂íŝáb̂ĺê b́r̂éâḱp̂óîńt̂} other {D́îśâb́l̂é âĺl̂ b́r̂éâḱp̂óîńt̂ś îń l̂ín̂é}}"
9655
9667
  },
@@ -188,7 +188,7 @@ export class CSSProperty {
188
188
  if (insideProperty) {
189
189
  result += propertyText;
190
190
  }
191
- result = result.substring(2, result.length - 1).trimRight();
191
+ result = result.substring(2, result.length - 1).trimEnd();
192
192
  return result + (indentation ? '\n' + endIndentation : '');
193
193
 
194
194
  function processToken(token: string, tokenType: string|null): void {
@@ -230,8 +230,8 @@ export class CSSProperty {
230
230
  }
231
231
  if (cssMetadata().isGridAreaDefiningProperty(propertyName)) {
232
232
  const rowResult = GridAreaRowRegex.exec(token);
233
- if (rowResult && rowResult.index === 0 && !propertyText.trimRight().endsWith(']')) {
234
- propertyText = propertyText.trimRight() + '\n' + doubleIndent;
233
+ if (rowResult && rowResult.index === 0 && !propertyText.trimEnd().endsWith(']')) {
234
+ propertyText = propertyText.trimEnd() + '\n' + doubleIndent;
235
235
  }
236
236
  }
237
237
  if (!propertyName && token === ':') {
@@ -1242,6 +1242,11 @@ export class BreakLocation extends Location {
1242
1242
  }
1243
1243
  }
1244
1244
 
1245
+ export interface MissingDebugInfoDetails {
1246
+ details: string;
1247
+ resources: string[];
1248
+ }
1249
+
1245
1250
  export class CallFrame {
1246
1251
  debuggerModel: DebuggerModel;
1247
1252
  readonly #scriptInternal: Script;
@@ -1253,7 +1258,7 @@ export class CallFrame {
1253
1258
  readonly #functionNameInternal: string;
1254
1259
  readonly #functionLocationInternal: Location|undefined;
1255
1260
  #returnValueInternal: RemoteObject|null;
1256
- readonly warnings: string[] = [];
1261
+ #missingDebugInfoDetails: MissingDebugInfoDetails|null = null;
1257
1262
 
1258
1263
  readonly canBeRestarted: boolean;
1259
1264
 
@@ -1299,8 +1304,12 @@ export class CallFrame {
1299
1304
  return new CallFrame(this.debuggerModel, this.#scriptInternal, this.payload, inlineFrameIndex, name);
1300
1305
  }
1301
1306
 
1302
- addWarning(warning: string): void {
1303
- this.warnings.push(warning);
1307
+ setMissingDebugInfoDetails(details: MissingDebugInfoDetails): void {
1308
+ this.#missingDebugInfoDetails = details;
1309
+ }
1310
+
1311
+ get missingDebugInfoDetails(): MissingDebugInfoDetails|null {
1312
+ return this.#missingDebugInfoDetails;
1304
1313
  }
1305
1314
 
1306
1315
  get script(): Script {
@@ -21,6 +21,7 @@ export class EmulationModel extends SDKModel<void> {
21
21
  readonly #mediaConfiguration: Map<string, string>;
22
22
  #touchEnabled: boolean;
23
23
  #touchMobile: boolean;
24
+ #touchEmulationAllowed: boolean;
24
25
  #customTouchEnabled: boolean;
25
26
  #touchConfiguration: {
26
27
  enabled: boolean,
@@ -176,6 +177,7 @@ export class EmulationModel extends SDKModel<void> {
176
177
  updateDisabledImageFormats();
177
178
  }
178
179
 
180
+ this.#touchEmulationAllowed = true;
179
181
  this.#touchEnabled = false;
180
182
  this.#touchMobile = false;
181
183
  this.#customTouchEnabled = false;
@@ -185,6 +187,10 @@ export class EmulationModel extends SDKModel<void> {
185
187
  };
186
188
  }
187
189
 
190
+ setTouchEmulationAllowed(touchEmulationAllowed: boolean): void {
191
+ this.#touchEmulationAllowed = touchEmulationAllowed;
192
+ }
193
+
188
194
  supportsDeviceEmulation(): boolean {
189
195
  return this.target().hasAllCapabilities(Capability.DeviceEmulation);
190
196
  }
@@ -322,13 +328,13 @@ export class EmulationModel extends SDKModel<void> {
322
328
  }
323
329
 
324
330
  async emulateTouch(enabled: boolean, mobile: boolean): Promise<void> {
325
- this.#touchEnabled = enabled;
326
- this.#touchMobile = mobile;
331
+ this.#touchEnabled = enabled && this.#touchEmulationAllowed;
332
+ this.#touchMobile = mobile && this.#touchEmulationAllowed;
327
333
  await this.updateTouch();
328
334
  }
329
335
 
330
336
  async overrideEmulateTouch(enabled: boolean): Promise<void> {
331
- this.#customTouchEnabled = enabled;
337
+ this.#customTouchEnabled = enabled && this.#touchEmulationAllowed;
332
338
  await this.updateTouch();
333
339
  }
334
340
 
@@ -192,7 +192,6 @@ export class Script implements TextUtils.ContentProvider.ContentProvider, FrameA
192
192
 
193
193
  originalContentProvider(): TextUtils.ContentProvider.ContentProvider {
194
194
  if (!this.#originalContentProviderInternal) {
195
- /* } */
196
195
  let lazyContentPromise: Promise<TextUtils.ContentProvider.DeferredContent>|null;
197
196
  this.#originalContentProviderInternal =
198
197
  new TextUtils.StaticContentProvider.StaticContentProvider(this.contentURL(), this.contentType(), () => {
@@ -220,7 +219,9 @@ export class Script implements TextUtils.ContentProvider.ContentProvider, FrameA
220
219
  return {content: bytecode, isEncoded: true};
221
220
  }
222
221
  let content: string = scriptSource || '';
223
- if (this.hasSourceURL) {
222
+ if (this.hasSourceURL && this.sourceURL.startsWith('snippet://')) {
223
+ // TODO(crbug.com/1330846): Find a better way to establish the snippet automapping binding then adding
224
+ // a sourceURL comment before evaluation and removing it here.
224
225
  content = Script.trimSourceURLComment(content);
225
226
  }
226
227
  return {content, isEncoded: false};
@@ -51,6 +51,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
51
51
  readonly debuggerWorkspaceBinding: DebuggerWorkspaceBinding;
52
52
  readonly #breakpointsForUISourceCode: Map<Workspace.UISourceCode.UISourceCode, Map<string, BreakpointLocation>>;
53
53
  readonly #breakpointByStorageId: Map<string, Breakpoint>;
54
+ #updateBindingsCallbacks: ((uiSourceCode: Workspace.UISourceCode.UISourceCode) => Promise<void>)[];
54
55
 
55
56
  private constructor(
56
57
  targetManager: SDK.TargetManager.TargetManager, workspace: Workspace.Workspace.WorkspaceImpl,
@@ -69,6 +70,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
69
70
  this.#workspace.addEventListener(Workspace.Workspace.Events.ProjectRemoved, this.projectRemoved, this);
70
71
 
71
72
  this.targetManager.observeModels(SDK.DebuggerModel.DebuggerModel, this);
73
+ this.#updateBindingsCallbacks = [];
72
74
  }
73
75
 
74
76
  static instance(opts: {
@@ -108,6 +110,10 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
108
110
  debuggerModel.setSynchronizeBreakpointsCallback(null);
109
111
  }
110
112
 
113
+ addUpdateBindingsCallback(callback: ((uiSourceCode: Workspace.UISourceCode.UISourceCode) => Promise<void>)): void {
114
+ this.#updateBindingsCallbacks.push(callback);
115
+ }
116
+
111
117
  async copyBreakpoints(fromURL: Platform.DevToolsPath.UrlString, toSourceCode: Workspace.UISourceCode.UISourceCode):
112
118
  Promise<void> {
113
119
  const breakpointItems = this.storage.breakpointItems(fromURL);
@@ -122,15 +128,13 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
122
128
  if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.INSTRUMENTATION_BREAKPOINTS)) {
123
129
  return;
124
130
  }
131
+ if (!script.sourceURL) {
132
+ return;
133
+ }
134
+
125
135
  const debuggerModel = script.debuggerModel;
136
+ const uiSourceCode = await this.getUpdatedUISourceCode(script);
126
137
  if (this.#hasBreakpointsForUrl(script.sourceURL)) {
127
- // Handle inline scripts without sourceURL comment separately:
128
- // The UISourceCode of inline scripts without sourceURLs will not be availabe
129
- // until a later point. Use the v8 script for setting the breakpoint.
130
- const isInlineScriptWithoutSourceURL = script.isInlineScript() && !script.hasSourceURL;
131
- const sourceURL =
132
- isInlineScriptWithoutSourceURL ? DefaultScriptMapping.createV8ScriptURL(script) : script.sourceURL;
133
- const uiSourceCode = await Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURLPromise(sourceURL);
134
138
  await this.#restoreBreakpointsForUrl(uiSourceCode);
135
139
  }
136
140
 
@@ -149,7 +153,7 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
149
153
  const {pluginManager} = this.debuggerWorkspaceBinding;
150
154
  if (pluginManager) {
151
155
  const sourceUrls = await pluginManager.getSourcesForScript(script);
152
- if (sourceUrls) {
156
+ if (Array.isArray(sourceUrls)) {
153
157
  for (const sourceURL of sourceUrls) {
154
158
  if (this.#hasBreakpointsForUrl(sourceURL)) {
155
159
  const uiSourceCode =
@@ -161,6 +165,34 @@ export class BreakpointManager extends Common.ObjectWrapper.ObjectWrapper<EventT
161
165
  }
162
166
  }
163
167
 
168
+ async getUpdatedUISourceCode(script: SDK.Script.Script): Promise<Workspace.UISourceCode.UISourceCode> {
169
+ const isSnippet = script.sourceURL.startsWith('snippet://');
170
+ const projectType = isSnippet ? Workspace.Workspace.projectTypes.Network : undefined;
171
+
172
+ // Handle inline scripts without sourceURL comment separately:
173
+ // The UISourceCode of inline scripts without sourceURLs will not be availabe
174
+ // until a later point. Use the v8 script for setting the breakpoint.
175
+ const isInlineScriptWithoutSourceURL = script.isInlineScript() && !script.hasSourceURL;
176
+ const sourceURL =
177
+ isInlineScriptWithoutSourceURL ? DefaultScriptMapping.createV8ScriptURL(script) : script.sourceURL;
178
+ const uiSourceCode =
179
+ await Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURLPromise(sourceURL, projectType);
180
+
181
+ if (this.#updateBindingsCallbacks.length > 0) {
182
+ // It's possible to set breakpoints on files on the file system, and to have them
183
+ // hit whenever we navigate to a page that serves that file.
184
+ // To make sure that we have all breakpoint information moved from the file system
185
+ // to the served file, we need to update the bindings and await it. This will
186
+ // move the breakpoints from the FileSystem UISourceCode to the Network UiSourceCode.
187
+ const promises = [];
188
+ for (const callback of this.#updateBindingsCallbacks) {
189
+ promises.push(callback(uiSourceCode));
190
+ }
191
+ await Promise.all(promises);
192
+ }
193
+ return uiSourceCode;
194
+ }
195
+
164
196
  async #restoreBreakpointsForUrl(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise<void> {
165
197
  this.restoreBreakpoints(uiSourceCode);
166
198
  const breakpoints = this.#breakpointByStorageId.values();
@@ -713,20 +745,24 @@ export class ModelBreakpoint {
713
745
  };
714
746
  });
715
747
  newState = new Breakpoint.State(positions, condition);
716
- } else if (this.#breakpoint.currentState) {
717
- newState = new Breakpoint.State(this.#breakpoint.currentState.positions, condition);
718
- } else {
719
- // TODO(bmeurer): This fallback doesn't make a whole lot of sense, we should
720
- // at least signal a warning to the developer that this #breakpoint wasn't
721
- // really resolved.
722
- const position = {
723
- url: this.#breakpoint.url(),
724
- scriptId: '' as Protocol.Runtime.ScriptId,
725
- scriptHash: '',
726
- lineNumber,
727
- columnNumber,
728
- };
729
- newState = new Breakpoint.State([position], condition);
748
+ } else if (!Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.INSTRUMENTATION_BREAKPOINTS)) {
749
+ // Use this fallback if we do not have instrumentation breakpoints enabled yet. This currently makes
750
+ // sure that v8 knows about the breakpoint and is able to restore it whenever the script is parsed.
751
+ if (this.#breakpoint.currentState) {
752
+ newState = new Breakpoint.State(this.#breakpoint.currentState.positions, condition);
753
+ } else {
754
+ // TODO(bmeurer): This fallback doesn't make a whole lot of sense, we should
755
+ // at least signal a warning to the developer that this #breakpoint wasn't
756
+ // really resolved.
757
+ const position = {
758
+ url: this.#breakpoint.url(),
759
+ scriptId: '' as Protocol.Runtime.ScriptId,
760
+ scriptHash: '',
761
+ lineNumber,
762
+ columnNumber,
763
+ };
764
+ newState = new Breakpoint.State([position], condition);
765
+ }
730
766
  }
731
767
  }
732
768
 
@@ -59,12 +59,12 @@ const UIStrings = {
59
59
  *@description Error message that is displayed in UI debugging information cannot be found for a call frame
60
60
  *@example {main} PH1
61
61
  */
62
- failedToLoadDebugSymbolsForFunction: 'Missing debug symbols for function "{PH1}"',
62
+ failedToLoadDebugSymbolsForFunction: 'No debug information for function "{PH1}"',
63
63
  /**
64
64
  *@description Error message that is displayed in UI when a file needed for debugging information for a call frame is missing
65
- *@example {src/myapp.debug.wasm.dwp} PH1
65
+ *@example {mainp.debug.wasm.dwp} PH1
66
66
  */
67
- symbolFileNotFound: 'Symbol file "{PH1}" not found',
67
+ debugSymbolsIncomplete: 'The debug information for function {PH1} is incomplete',
68
68
  };
69
69
  const str_ = i18n.i18n.registerUIStrings('models/bindings/DebuggerLanguagePlugins.ts', UIStrings);
70
70
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -766,7 +766,7 @@ export class DebuggerLanguagePluginManager implements
766
766
  rawModuleId: string,
767
767
  plugin: DebuggerLanguagePlugin,
768
768
  scripts: Array<SDK.Script.Script>,
769
- addRawModulePromise: Promise<Array<Platform.DevToolsPath.UrlString>>,
769
+ addRawModulePromise: Promise<Array<Platform.DevToolsPath.UrlString>|{missingSymbolFiles: string[]}>,
770
770
  }>;
771
771
 
772
772
  constructor(
@@ -819,17 +819,19 @@ export class DebuggerLanguagePluginManager implements
819
819
  .all(callFrames.map(async callFrame => {
820
820
  const functionInfo = await this.getFunctionInfo(callFrame.script, callFrame.location());
821
821
  if (functionInfo) {
822
- const {frames, missingSymbolFiles} = functionInfo;
823
- if (frames.length) {
824
- return frames.map(({name}, index) => callFrame.createVirtualCallFrame(index, name));
822
+ if ('frames' in functionInfo && functionInfo.frames.length) {
823
+ return functionInfo.frames.map(({name}, index) => callFrame.createVirtualCallFrame(index, name));
825
824
  }
826
- if (missingSymbolFiles && missingSymbolFiles.length) {
827
- for (const file of missingSymbolFiles) {
828
- callFrame.addWarning(i18nString(UIStrings.symbolFileNotFound, {PH1: file}));
829
- }
825
+ if ('missingSymbolFiles' in functionInfo && functionInfo.missingSymbolFiles.length) {
826
+ const resources = functionInfo.missingSymbolFiles;
827
+ const details = i18nString(UIStrings.debugSymbolsIncomplete, {PH1: callFrame.functionName});
828
+ callFrame.setMissingDebugInfoDetails({details, resources});
829
+ } else {
830
+ callFrame.setMissingDebugInfoDetails({
831
+ resources: [],
832
+ details: i18nString(UIStrings.failedToLoadDebugSymbolsForFunction, {PH1: callFrame.functionName}),
833
+ });
830
834
  }
831
- callFrame.addWarning(
832
- i18nString(UIStrings.failedToLoadDebugSymbolsForFunction, {PH1: callFrame.functionName}));
833
835
  }
834
836
  return callFrame;
835
837
  }))
@@ -1069,40 +1071,45 @@ export class DebuggerLanguagePluginManager implements
1069
1071
  const rawModuleId = rawModuleIdForScript(script);
1070
1072
  let rawModuleHandle = this.#rawModuleHandles.get(rawModuleId);
1071
1073
  if (!rawModuleHandle) {
1072
- const sourceFileURLsPromise = (async(): Promise<Platform.DevToolsPath.UrlString[]> => {
1073
- const console = Common.Console.Console.instance();
1074
- const url = script.sourceURL;
1075
- const symbolsUrl = (script.debugSymbols && script.debugSymbols.externalURL) || '';
1076
- if (symbolsUrl) {
1077
- console.log(i18nString(UIStrings.loadingDebugSymbolsForVia, {PH1: plugin.name, PH2: url, PH3: symbolsUrl}));
1078
- } else {
1079
- console.log(i18nString(UIStrings.loadingDebugSymbolsFor, {PH1: plugin.name, PH2: url}));
1080
- }
1081
- try {
1082
- const code = (!symbolsUrl && url.startsWith('wasm://')) ? await script.getWasmBytecode() : undefined;
1083
- const sourceFileURLs =
1084
- await plugin.addRawModule(rawModuleId, symbolsUrl, {url, code}) as Platform.DevToolsPath.UrlString[];
1085
- // Check that the handle isn't stale by now. This works because the code that assigns to
1086
- // `rawModuleHandle` below will run before this code because of the `await` in the preceding
1087
- // line. This is primarily to avoid logging the message below, which would give the developer
1088
- // the misleading information that we're done, while in reality it was a stale call that finished.
1089
- if (rawModuleHandle !== this.#rawModuleHandles.get(rawModuleId)) {
1090
- return [];
1091
- }
1092
- if (sourceFileURLs.length === 0) {
1093
- console.warn(i18nString(UIStrings.loadedDebugSymbolsForButDidnt, {PH1: plugin.name, PH2: url}));
1094
- } else {
1095
- console.log(i18nString(
1096
- UIStrings.loadedDebugSymbolsForFound, {PH1: plugin.name, PH2: url, PH3: sourceFileURLs.length}));
1097
- }
1098
- return sourceFileURLs;
1099
- } catch (error) {
1100
- console.error(
1101
- i18nString(UIStrings.failedToLoadDebugSymbolsFor, {PH1: plugin.name, PH2: url, PH3: error.message}));
1102
- this.#rawModuleHandles.delete(rawModuleId);
1103
- return [];
1104
- }
1105
- })();
1074
+ const sourceFileURLsPromise =
1075
+ (async(): Promise<Platform.DevToolsPath.UrlString[]|{missingSymbolFiles: string[]}> => {
1076
+ const console = Common.Console.Console.instance();
1077
+ const url = script.sourceURL;
1078
+ const symbolsUrl = (script.debugSymbols && script.debugSymbols.externalURL) || '';
1079
+ if (symbolsUrl) {
1080
+ console.log(
1081
+ i18nString(UIStrings.loadingDebugSymbolsForVia, {PH1: plugin.name, PH2: url, PH3: symbolsUrl}));
1082
+ } else {
1083
+ console.log(i18nString(UIStrings.loadingDebugSymbolsFor, {PH1: plugin.name, PH2: url}));
1084
+ }
1085
+ try {
1086
+ const code = (!symbolsUrl && url.startsWith('wasm://')) ? await script.getWasmBytecode() : undefined;
1087
+ const addModuleResult = await plugin.addRawModule(rawModuleId, symbolsUrl, {url, code});
1088
+ // Check that the handle isn't stale by now. This works because the code that assigns to
1089
+ // `rawModuleHandle` below will run before this code because of the `await` in the preceding
1090
+ // line. This is primarily to avoid logging the message below, which would give the developer
1091
+ // the misleading information that we're done, while in reality it was a stale call that finished.
1092
+ if (rawModuleHandle !== this.#rawModuleHandles.get(rawModuleId)) {
1093
+ return [];
1094
+ }
1095
+ if ('missingSymbolFiles' in addModuleResult) {
1096
+ return {missingSymbolFiles: addModuleResult.missingSymbolFiles};
1097
+ }
1098
+ const sourceFileURLs = addModuleResult as Platform.DevToolsPath.UrlString[];
1099
+ if (sourceFileURLs.length === 0) {
1100
+ console.warn(i18nString(UIStrings.loadedDebugSymbolsForButDidnt, {PH1: plugin.name, PH2: url}));
1101
+ } else {
1102
+ console.log(i18nString(
1103
+ UIStrings.loadedDebugSymbolsForFound, {PH1: plugin.name, PH2: url, PH3: sourceFileURLs.length}));
1104
+ }
1105
+ return sourceFileURLs;
1106
+ } catch (error) {
1107
+ console.error(i18nString(
1108
+ UIStrings.failedToLoadDebugSymbolsFor, {PH1: plugin.name, PH2: url, PH3: error.message}));
1109
+ this.#rawModuleHandles.delete(rawModuleId);
1110
+ return [];
1111
+ }
1112
+ })();
1106
1113
  rawModuleHandle = {rawModuleId, plugin, scripts: [script], addRawModulePromise: sourceFileURLsPromise};
1107
1114
  this.#rawModuleHandles.set(rawModuleId, rawModuleHandle);
1108
1115
  } else {
@@ -1114,12 +1121,14 @@ export class DebuggerLanguagePluginManager implements
1114
1121
  // for the DebuggerModel again, which may disappear
1115
1122
  // in the meantime...
1116
1123
  void rawModuleHandle.addRawModulePromise.then(sourceFileURLs => {
1117
- // The script might have disappeared meanwhile...
1118
- if (script.debuggerModel.scriptForId(script.scriptId) === script) {
1119
- const modelData = this.#debuggerModelToData.get(script.debuggerModel);
1120
- if (modelData) { // The DebuggerModel could have disappeared meanwhile...
1121
- modelData.addSourceFiles(script, sourceFileURLs);
1122
- void this.#debuggerWorkspaceBinding.updateLocations(script);
1124
+ if (!('missingSymbolFiles' in sourceFileURLs)) {
1125
+ // The script might have disappeared meanwhile...
1126
+ if (script.debuggerModel.scriptForId(script.scriptId) === script) {
1127
+ const modelData = this.#debuggerModelToData.get(script.debuggerModel);
1128
+ if (modelData) { // The DebuggerModel could have disappeared meanwhile...
1129
+ modelData.addSourceFiles(script, sourceFileURLs);
1130
+ void this.#debuggerWorkspaceBinding.updateLocations(script);
1131
+ }
1123
1132
  }
1124
1133
  }
1125
1134
  });
@@ -1127,7 +1136,8 @@ export class DebuggerLanguagePluginManager implements
1127
1136
  }
1128
1137
  }
1129
1138
 
1130
- getSourcesForScript(script: SDK.Script.Script): Promise<Array<Platform.DevToolsPath.UrlString>|undefined> {
1139
+ getSourcesForScript(script: SDK.Script.Script):
1140
+ Promise<Array<Platform.DevToolsPath.UrlString>|{missingSymbolFiles: string[]}|undefined> {
1131
1141
  const rawModuleId = rawModuleIdForScript(script);
1132
1142
  const rawModuleHandle = this.#rawModuleHandles.get(rawModuleId);
1133
1143
  if (rawModuleHandle) {
@@ -1173,10 +1183,8 @@ export class DebuggerLanguagePluginManager implements
1173
1183
  }
1174
1184
  }
1175
1185
 
1176
- async getFunctionInfo(script: SDK.Script.Script, location: SDK.DebuggerModel.Location): Promise<{
1177
- frames: Array<Chrome.DevTools.FunctionInfo>,
1178
- missingSymbolFiles?: Array<string>,
1179
- }|null> {
1186
+ async getFunctionInfo(script: SDK.Script.Script, location: SDK.DebuggerModel.Location):
1187
+ Promise<{frames: Array<Chrome.DevTools.FunctionInfo>}|{missingSymbolFiles: string[]}|null> {
1180
1188
  const {rawModuleId, plugin} = await this.rawModuleIdAndPluginForScript(script);
1181
1189
  if (!plugin) {
1182
1190
  return null;
@@ -1189,7 +1197,8 @@ export class DebuggerLanguagePluginManager implements
1189
1197
  };
1190
1198
 
1191
1199
  try {
1192
- return await plugin.getFunctionInfo(rawLocation);
1200
+ const functionInfo = await plugin.getFunctionInfo(rawLocation);
1201
+ return functionInfo;
1193
1202
  } catch (error) {
1194
1203
  Common.Console.Console.instance().warn(i18nString(UIStrings.errorInDebuggerLanguagePlugin, {PH1: error.message}));
1195
1204
  return {frames: []};
@@ -1362,7 +1371,7 @@ class ModelData {
1362
1371
  }
1363
1372
  }
1364
1373
 
1365
- export class DebuggerLanguagePlugin {
1374
+ export class DebuggerLanguagePlugin implements Chrome.DevTools.LanguageExtensionPlugin {
1366
1375
  name: string;
1367
1376
  constructor(name: string) {
1368
1377
  this.name = name;
@@ -1378,7 +1387,7 @@ export class DebuggerLanguagePlugin {
1378
1387
  /** Notify the #plugin about a new script
1379
1388
  */
1380
1389
  async addRawModule(_rawModuleId: string, _symbolsURL: string, _rawModule: Chrome.DevTools.RawModule):
1381
- Promise<string[]> {
1390
+ Promise<string[]|{missingSymbolFiles: string[]}> {
1382
1391
  throw new Error('Not implemented yet');
1383
1392
  }
1384
1393
 
@@ -1445,10 +1454,8 @@ export class DebuggerLanguagePlugin {
1445
1454
  /**
1446
1455
  * Find #locations in source files from a #location in a raw module
1447
1456
  */
1448
- async getFunctionInfo(_rawLocation: Chrome.DevTools.RawLocation): Promise<{
1449
- frames: Array<Chrome.DevTools.FunctionInfo>,
1450
- missingSymbolFiles?: Array<string>,
1451
- }> {
1457
+ async getFunctionInfo(_rawLocation: Chrome.DevTools.RawLocation):
1458
+ Promise<{frames: Array<Chrome.DevTools.FunctionInfo>}|{missingSymbolFiles: string[]}> {
1452
1459
  throw new Error('Not implemented yet');
1453
1460
  }
1454
1461