chrome-devtools-frontend 1.0.1030070 → 1.0.1031400

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 (81) hide show
  1. package/config/gni/devtools_grd_files.gni +3 -0
  2. package/config/gni/devtools_image_files.gni +2 -0
  3. package/docs/workflows.md +1 -1
  4. package/front_end/Images/src/file-sync_icon.svg +62 -0
  5. package/front_end/Images/src/file_icon.svg +52 -0
  6. package/front_end/Tests.js +0 -28
  7. package/front_end/core/host/UserMetrics.ts +2 -1
  8. package/front_end/core/i18n/locales/en-US.json +18 -9
  9. package/front_end/core/i18n/locales/en-XL.json +18 -9
  10. package/front_end/core/platform/string-utilities.ts +2 -5
  11. package/front_end/core/root/Runtime.ts +1 -0
  12. package/front_end/core/sdk/CSSStyleSheetHeader.ts +0 -4
  13. package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +0 -4
  14. package/front_end/core/sdk/NetworkRequest.ts +0 -4
  15. package/front_end/core/sdk/Resource.ts +0 -5
  16. package/front_end/core/sdk/Script.ts +71 -76
  17. package/front_end/core/sdk/Target.ts +4 -0
  18. package/front_end/entrypoints/inspector_main/InspectorMain.ts +4 -1
  19. package/front_end/entrypoints/main/MainImpl.ts +4 -0
  20. package/front_end/generated/InspectorBackendCommands.js +10 -8
  21. package/front_end/generated/protocol-mapping.d.ts +16 -2
  22. package/front_end/generated/protocol-proxy-api.d.ts +11 -1
  23. package/front_end/generated/protocol.ts +75 -1
  24. package/front_end/models/bindings/CompilerScriptMapping.ts +6 -3
  25. package/front_end/models/bindings/ContentProviderBasedProject.ts +2 -3
  26. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +1 -4
  27. package/front_end/models/bindings/IgnoreListManager.ts +10 -8
  28. package/front_end/models/bindings/ResourceMapping.ts +0 -4
  29. package/front_end/models/bindings/StylesSourceMapping.ts +0 -5
  30. package/front_end/models/extensions/ExtensionServer.ts +2 -3
  31. package/front_end/models/issues_manager/AttributionReportingIssue.ts +8 -0
  32. package/front_end/models/issues_manager/DeprecationIssue.ts +5 -1
  33. package/front_end/models/issues_manager/descriptions/arTooManyConcurrentRequests.md +5 -0
  34. package/front_end/models/javascript_metadata/NativeFunctions.js +6 -2
  35. package/front_end/models/persistence/NetworkPersistenceManager.ts +4 -6
  36. package/front_end/models/persistence/PersistenceActions.ts +5 -4
  37. package/front_end/models/text_utils/CodeMirrorUtils.ts +17 -4
  38. package/front_end/models/text_utils/ContentProvider.ts +0 -1
  39. package/front_end/models/text_utils/StaticContentProvider.ts +0 -4
  40. package/front_end/models/workspace/UISourceCode.ts +10 -5
  41. package/front_end/panels/application/components/StackTrace.ts +2 -2
  42. package/front_end/panels/elements/CSSRuleValidator.ts +382 -63
  43. package/front_end/panels/elements/CSSRuleValidatorHelper.ts +34 -0
  44. package/front_end/panels/elements/ElementsTreeOutline.ts +23 -7
  45. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  46. package/front_end/panels/elements/TopLayerContainer.ts +17 -28
  47. package/front_end/panels/elements/components/CSSHintDetailsView.ts +23 -20
  48. package/front_end/panels/elements/components/cssHintDetailsView.css +8 -2
  49. package/front_end/panels/elements/stylesSectionTree.css +1 -1
  50. package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +12 -0
  51. package/front_end/panels/network/components/RequestHeadersView.css +41 -8
  52. package/front_end/panels/network/components/RequestHeadersView.ts +102 -12
  53. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
  54. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +7 -0
  55. package/front_end/panels/sources/NavigatorView.ts +22 -0
  56. package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -3
  57. package/front_end/third_party/codemirror.next/bundle.ts +1 -1
  58. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  59. package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -2
  60. package/front_end/third_party/codemirror.next/chunk/java.js +1 -2
  61. package/front_end/third_party/codemirror.next/chunk/json.js +1 -2
  62. package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -2
  63. package/front_end/third_party/codemirror.next/chunk/php.js +1 -2
  64. package/front_end/third_party/codemirror.next/chunk/python.js +1 -2
  65. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -2
  66. package/front_end/third_party/codemirror.next/chunk/xml.js +1 -2
  67. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +1247 -116
  68. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -2
  69. package/front_end/ui/components/data_grid/DataGrid.ts +15 -10
  70. package/front_end/ui/components/data_grid/DataGridController.ts +7 -0
  71. package/front_end/ui/components/docs/building-ui-documentation/StylingComponents.md +64 -0
  72. package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspector.ts +2 -3
  73. package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorController.ts +97 -17
  74. package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorPane.ts +1 -1
  75. package/front_end/ui/components/linear_memory_inspector/LinearMemoryViewerUtils.ts +4 -0
  76. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +9 -7
  77. package/front_end/ui/legacy/components/source_frame/ImageView.ts +10 -11
  78. package/front_end/ui/legacy/components/source_frame/PreviewFactory.ts +1 -1
  79. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +49 -0
  80. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +18 -17
  81. package/package.json +6 -5
@@ -1,2 +1 @@
1
- export{$ as cursorMatchingBracket,_ as closeBracketsKeymap,A as cpp,a$ as gutters,a0 as cursorSubwordBackward,a1 as cursorSubwordForward,a2 as indentLess,a3 as indentMore,a4 as insertNewlineAndIndent,a5 as selectMatchingBracket,a6 as selectSubwordBackward,a7 as selectSubwordForward,a8 as standardKeymap,a9 as toggleComment,a_ as GutterMarker,aA as Compartment,aa as history,aB as EditorState,ab as historyKeymap,aC as Facet,ac as redo,aD as MapMode,ad as redoSelection,aE as SelectionRange,ae as undo,aF as StateEffect,af as undoSelection,aG as StateEffectType,ag as css,aH as StateField,ah as html,aI as Transaction,ai as javascript,aJ as Range,aj as ensureSyntaxTree,aK as RangeSet,ak as indentOnInput,aL as RangeSetBuilder,al as indentUnit,aM as Line,am as codeFolding,aN as Text,an as foldGutter,aO as Decoration,ao as foldKeymap,ap as HighlightStyle,aP as drawSelection,aQ as EditorView,aq as syntaxHighlighting,ar as bracketMatching,aR as highlightSpecialChars,aS as MatchDecorator,as as StreamLanguage,at as StringStream,aT as placeholder,au as highlightSelectionMatches,aU as scrollPastEnd,aV as ViewPlugin,av as selectNextOccurrence,aw as Annotation,aW as ViewUpdate,ax as AnnotationType,aX as WidgetType,ay as ChangeDesc,aY as showPanel,az as ChangeSet,aZ as gutter,B as java,b0 as lineNumberMarkers,b1 as lineNumbers,b2 as repositionTooltips,b3 as showTooltip,b4 as tooltips,b5 as TreeCursor,b6 as highlightTree,b7 as StyleModule,D as json,e as LanguageSupport,F as markdown,g as NodeProp,G as php,h as NodeSet,H as python,I as shell,j as Tree,J as cssStreamParser,k as Language,K as wast,L as LRParser,l as syntaxTree,m as EditorSelection,M as xml,N as NodeType,n as Prec,O as acceptCompletion,o as keymap,P as Parser,Q as autocompletion,R as closeCompletion,S as completeAnyWord,T as Tag,t as tags,U as CompletionContext,V as currentCompletions,W as ifNotIn,X as selectedCompletion,y as clojure,Y as startCompletion,Z as closeBrackets,z as coffeescript}from"./chunk/codemirror.js";
2
-
1
+ export{aw as Annotation,ax as AnnotationType,ay as ChangeDesc,az as ChangeSet,aA as Compartment,W as CompletionContext,aO as Decoration,m as EditorSelection,aB as EditorState,aQ as EditorView,aC as Facet,aS as GutterMarker,ao as HighlightStyle,L as LRParser,k as Language,e as LanguageSupport,aD as Line,aE as MapMode,aX as MatchDecorator,g as NodeProp,h as NodeSet,N as NodeType,P as Parser,n as Prec,aF as Range,aG as RangeSet,aH as RangeSetBuilder,aI as SelectionRange,aJ as StateEffect,aK as StateEffectType,aL as StateField,ar as StreamLanguage,as as StringStream,b7 as StyleModule,T as Tag,aM as Text,aN as Transaction,j as Tree,b5 as TreeCursor,b2 as ViewPlugin,b3 as ViewUpdate,b4 as WidgetType,O as acceptCompletion,Q as autocompletion,aj as bracketMatching,y as clojure,R as closeBrackets,S as closeBracketsKeymap,U as closeCompletion,ak as codeFolding,z as coffeescript,V as completeAnyWord,A as cpp,ag as css,J as cssStreamParser,X as currentCompletions,$ as cursorMatchingBracket,a0 as cursorSubwordBackward,a1 as cursorSubwordForward,aP as drawSelection,al as ensureSyntaxTree,am as foldGutter,an as foldKeymap,aR as gutter,aT as gutters,au as highlightSelectionMatches,aU as highlightSpecialChars,b6 as highlightTree,a2 as history,a3 as historyKeymap,ah as html,Y as ifNotIn,a4 as indentLess,a5 as indentMore,ap as indentOnInput,aq as indentUnit,a6 as insertNewlineAndIndent,B as java,ai as javascript,D as json,o as keymap,aV as lineNumberMarkers,aW as lineNumbers,F as markdown,G as php,aY as placeholder,H as python,a7 as redo,a8 as redoSelection,aZ as repositionTooltips,a_ as scrollPastEnd,a9 as selectMatchingBracket,av as selectNextOccurrence,aa as selectSubwordBackward,ab as selectSubwordForward,Z as selectedCompletion,I as shell,a$ as showPanel,b0 as showTooltip,ac as standardKeymap,_ as startCompletion,at as syntaxHighlighting,l as syntaxTree,t as tags,ad as toggleComment,b1 as tooltips,ae as undo,af as undoSelection,K as wast,M as xml}from"./chunk/codemirror.js";
@@ -58,6 +58,7 @@ export interface DataGridData {
58
58
  activeSort: SortState|null;
59
59
  contextMenus?: DataGridContextMenusConfiguration;
60
60
  label?: string;
61
+ paddingRowsCount?: number;
61
62
  }
62
63
 
63
64
  const enum UserScrollState {
@@ -69,7 +70,6 @@ const enum UserScrollState {
69
70
  const KEYS_TREATED_AS_CLICKS = new Set([' ', 'Enter']);
70
71
 
71
72
  const ROW_HEIGHT_PIXELS = 18;
72
- const PADDING_ROWS_COUNT = 10;
73
73
 
74
74
  export class DataGrid extends HTMLElement {
75
75
  static readonly litTagName = LitHtml.literal`devtools-data-grid`;
@@ -82,6 +82,7 @@ export class DataGrid extends HTMLElement {
82
82
  #userScrollState: UserScrollState = UserScrollState.NOT_SCROLLED;
83
83
  #contextMenus?: DataGridContextMenusConfiguration = undefined;
84
84
  #label?: string = undefined;
85
+ #paddingRowsCount = 10;
85
86
  #currentResize: {
86
87
  rightCellCol: HTMLTableColElement,
87
88
  leftCellCol: HTMLTableColElement,
@@ -139,6 +140,7 @@ export class DataGrid extends HTMLElement {
139
140
  activeSort: this.#sortState,
140
141
  contextMenus: this.#contextMenus,
141
142
  label: this.#label,
143
+ paddingRowsCount: this.#paddingRowsCount,
142
144
  };
143
145
  }
144
146
 
@@ -171,6 +173,10 @@ export class DataGrid extends HTMLElement {
171
173
  this.#cellToFocusIfUserTabsIn = calculateFirstFocusableCell({columns: this.#columns, rows: this.#rows});
172
174
  }
173
175
 
176
+ if (data.paddingRowsCount !== undefined) {
177
+ this.#paddingRowsCount = data.paddingRowsCount;
178
+ }
179
+
174
180
  if (this.#hasRenderedAtLeastOnce && this.#userHasCellFocused()) {
175
181
  const [selectedColIndex, selectedRowIndex] = this.#tabbableCell();
176
182
  const columnOutOfBounds = selectedColIndex > this.#columns.length;
@@ -220,15 +226,14 @@ export class DataGrid extends HTMLElement {
220
226
  return;
221
227
  }
222
228
 
223
- void coordinator.read(() => {
224
- const wrapper = this.#shadow.querySelector('.wrapping-container');
225
- if (!wrapper) {
226
- return;
227
- }
229
+ const wrapper = this.#shadow.querySelector('.wrapping-container');
230
+ if (!wrapper) {
231
+ return;
232
+ }
233
+
234
+ void coordinator.scroll(() => {
228
235
  const scrollHeight = wrapper.scrollHeight;
229
- void coordinator.scroll(() => {
230
- wrapper.scrollTo(0, scrollHeight);
231
- });
236
+ wrapper.scrollTo(0, scrollHeight);
232
237
  });
233
238
  }
234
239
 
@@ -643,7 +648,7 @@ export class DataGrid extends HTMLElement {
643
648
  scrollTop = wrapper.scrollTop;
644
649
  clientHeight = wrapper.clientHeight;
645
650
  }
646
- const padding = ROW_HEIGHT_PIXELS * PADDING_ROWS_COUNT;
651
+ const padding = ROW_HEIGHT_PIXELS * this.#paddingRowsCount;
647
652
  let topVisibleRow = Math.floor((scrollTop - padding) / ROW_HEIGHT_PIXELS);
648
653
  let bottomVisibleRow = Math.ceil((scrollTop + clientHeight + padding) / ROW_HEIGHT_PIXELS);
649
654
 
@@ -31,6 +31,7 @@ export interface DataGridControllerData {
31
31
  initialSort?: SortState;
32
32
  contextMenus?: DataGridContextMenusConfiguration;
33
33
  label?: string;
34
+ paddingRowsCount?: number;
34
35
  }
35
36
 
36
37
  export class DataGridController extends HTMLElement {
@@ -55,6 +56,8 @@ export class DataGridController extends HTMLElement {
55
56
  #sortState: Readonly<SortState>|null = null;
56
57
  #filters: readonly TextUtils.TextUtils.ParsedFilter[] = [];
57
58
 
59
+ #paddingRowsCount?: number;
60
+
58
61
  connectedCallback(): void {
59
62
  this.#shadow.adoptedStyleSheets = [dataGridControllerStyles];
60
63
  }
@@ -66,6 +69,7 @@ export class DataGridController extends HTMLElement {
66
69
  filters: this.#filters,
67
70
  contextMenus: this.#contextMenus,
68
71
  label: this.#label,
72
+ paddingRowsCount: this.#paddingRowsCount,
69
73
  };
70
74
  }
71
75
 
@@ -88,6 +92,8 @@ export class DataGridController extends HTMLElement {
88
92
  this.#sortRows(this.#sortState);
89
93
  }
90
94
 
95
+ this.#paddingRowsCount = data.paddingRowsCount;
96
+
91
97
  this.#render();
92
98
  }
93
99
 
@@ -222,6 +228,7 @@ export class DataGridController extends HTMLElement {
222
228
  activeSort: this.#sortState,
223
229
  contextMenus: this.#contextMenus,
224
230
  label: this.#label,
231
+ paddingRowsCount: this.#paddingRowsCount,
225
232
  } as DataGridData}
226
233
  @columnheaderclick=${this.#onColumnHeaderClick}
227
234
  @contextmenucolumnsortclick=${this.#onContextMenuColumnSortClick}
@@ -0,0 +1,64 @@
1
+ # Styling Components
2
+
3
+ Components are styled by a CSS file that is co-located next to the TypeScript source file. The only difference in file name is the extension and that for CSS files, the first letter is lowercase:
4
+
5
+ ```
6
+ - ElementsBreadcrumbs.ts
7
+ - elementsBreadcrumbs.css
8
+ ```
9
+
10
+ To import this file you use a regular `import` statement, and import the filename with `.js` appended:
11
+
12
+ ```ts
13
+ import elementsBreadcrumbsStyles from './elementsBreadcrumbs.css.js';
14
+ ```
15
+
16
+ As part of the build tool step, each CSS file is converted into a JS file that exports a `CSSStyleSheet` instance. This is done by Rollup in [`generate_css_js_files`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/devtools-frontend/src/scripts/build/generate_css_js_files.js;l=1;drc=28af9fbe783d82aa64bfa5f9b9509572dc2b3efe).
17
+
18
+ ## `BUILD.gn` changes
19
+
20
+ Use the `generate_css` action (`scripts/build/ninja/generate_css.gni`) to declare stylesheets:
21
+
22
+ ```gn
23
+ import("scripts/build/ninja/generate_css.gni") // Edit path correctly: this must be relative
24
+
25
+ generate_css("css_files") {
26
+ sources = [ "elementsBreadcrumbs.css"]
27
+ }
28
+ ```
29
+
30
+ And then add `:css_files` as a dependency to the `devtools_entrypoint`:
31
+
32
+ ```gn
33
+ devtools_entrypoint("bundle") {
34
+ deps = [ ":css_files" , "..."]
35
+ }
36
+ ```
37
+
38
+ ## Adopting the stylesheet
39
+
40
+ Importing the stylesheet is not enough to have it apply to the component's ShadowDOM, it must be adopted. The `connectedCallback` method is the best place for this:
41
+
42
+ ```ts
43
+ connectedCallback() {
44
+ this.#shadow.adoptedStyleSheets = [elementsBreadcrumbs];
45
+ }
46
+ ```
47
+
48
+ ## Tips for writing CSS.
49
+
50
+ Use `:host` to style the component itself. By default elements are `display: inline`. Often it can be useful to set `display: block`.
51
+
52
+ Remember to use theme colors (`var(--color-text-primary)`) when styling elements to ensure consistency across DevTools.
53
+
54
+ If you want your component to have its colors configurable by users, consider defining `--override` variables. In your component's CSS, you would have something like:
55
+
56
+ ```css
57
+ :host {
58
+ color: var(--override-custom-color, var(--color-text-primary));
59
+ }
60
+ ```
61
+
62
+ This allows someone to define that `--override-custom-color` variable, but also ensures if it isn't defined that the default `color-text-primary` will be used. **Be careful with this!** We try to ensure consistent colors across DevTools; so most of the time you shouldn't allow configurable colors and should use the correct theme variables.
63
+
64
+
@@ -160,12 +160,11 @@ export class LinearMemoryInspector extends HTMLElement {
160
160
  throw new Error('Memory offset has to be greater or equal to zero.');
161
161
  }
162
162
 
163
- if (data.highlightInfo !== undefined) {
163
+ if (data.highlightInfo) {
164
164
  if (data.highlightInfo.size < 0) {
165
165
  throw new Error('Object size has to be greater than or equal to zero');
166
166
  }
167
- if (data.highlightInfo.startAddress > data.memoryOffset + data.memory.length ||
168
- data.highlightInfo.startAddress < 0) {
167
+ if (data.highlightInfo.startAddress < 0 || data.highlightInfo.startAddress >= data.outerMemoryLength) {
169
168
  throw new Error('Object start address is out of bounds.');
170
169
  }
171
170
  }
@@ -164,6 +164,21 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
164
164
  return await memoryWrapper.getRange(start, chunkEnd);
165
165
  }
166
166
 
167
+ async evaluateExpression(callFrame: SDK.DebuggerModel.CallFrame, expressionName: string):
168
+ Promise<SDK.RemoteObject.RemoteObject|undefined> {
169
+ const result = await callFrame.evaluate({expression: expressionName});
170
+ if ('error' in result) {
171
+ console.error(`Tried to evaluate the expression '${expressionName}' but got an error: ${result.error}`);
172
+ return undefined;
173
+ }
174
+ if ('exceptionDetails' in result && result?.exceptionDetails?.text) {
175
+ console.error(
176
+ `Tried to evaluate the expression '${expressionName}' but got an exception: ${result.exceptionDetails.text}`);
177
+ return undefined;
178
+ }
179
+ return result.object;
180
+ }
181
+
167
182
  saveSettings(data: Settings): void {
168
183
  const valueTypes = Array.from(data.valueTypes);
169
184
  const modes = [...data.modes];
@@ -233,14 +248,15 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
233
248
  // This function returns the size of the source language value represented
234
249
  // by the ValueNode. If the value is a pointer, the function returns the size of
235
250
  // the pointed-to value. If the pointed-to value is also a pointer, it returns
236
- // the size of the pointer (usually 4 bytes) to stay consistent with the DWARF extension.
251
+ // the size of the pointer (usually 4 bytes). This is the convention taken
252
+ // by the DWARF extension.
237
253
  // > double x = 42.0;
238
254
  // > double *ptr = &x;
239
255
  // > double **dblptr = &ptr;
240
256
  //
241
257
  // retrieveObjectSize(ptr_ValueNode) -> 8, the size of a double
242
258
  // retrieveObjectSize(dblptr_ValueNode) -> 4, the size of a pointer
243
- static retrieveObjectSize(obj: Bindings.DebuggerLanguagePlugins.ValueNode): number {
259
+ static extractObjectSize(obj: Bindings.DebuggerLanguagePlugins.ValueNode): number {
244
260
  let typeInfo = obj.sourceType.typeInfo;
245
261
  const pointerMembers = typeInfo.members.filter(member => member.name === '*');
246
262
  if (pointerMembers.length === 1) {
@@ -257,7 +273,34 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
257
273
  return typeInfo.size;
258
274
  }
259
275
 
260
- async openInspectorView(obj: SDK.RemoteObject.RemoteObject, address?: number): Promise<void> {
276
+ // The object type description corresponds to the type of the highlighted memory
277
+ // that the user sees in the memory inspector. For pointers, we highlight the pointed to object.
278
+ //
279
+ // Example: The variable `x` has the type `int *`. Assume that `x` points to the value 3.
280
+ // -> The memory inspector will jump to the address where 3 is stored.
281
+ // -> The memory inspector will highlight the bytes that represent the 3.
282
+ // -> The object type description of what we show will thus be `int` and not `int *`.
283
+ static extractObjectTypeDescription(obj: Bindings.DebuggerLanguagePlugins.ValueNode): string {
284
+ const objType = obj.description;
285
+ if (!objType) {
286
+ return '';
287
+ }
288
+ const lastChar = objType.charAt(objType.length - 1);
289
+ const secondToLastChar = objType.charAt(objType.length - 2);
290
+ const isPointerType = lastChar === '*' || lastChar === '&';
291
+ const isOneLevelPointer = secondToLastChar === ' ';
292
+ if (!isPointerType) {
293
+ return objType;
294
+ }
295
+ if (isOneLevelPointer) {
296
+ // For example, 'int *'and 'int &' become 'int'.
297
+ return objType.slice(0, objType.length - 2);
298
+ }
299
+ // For example, 'int **' becomes 'int *'.
300
+ return objType.slice(0, objType.length - 1);
301
+ }
302
+
303
+ async openInspectorView(obj: SDK.RemoteObject.RemoteObject, address?: number, expression?: string): Promise<void> {
261
304
  const response = await LinearMemoryInspectorController.retrieveDWARFMemoryObjectAndAddress(obj);
262
305
  let memoryObj = obj;
263
306
  let memoryAddress = address;
@@ -288,8 +331,8 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
288
331
  }
289
332
  const memoryProperty = internalProperties?.find(({name}) => name === '[[WebAssemblyMemory]]');
290
333
  const memory = memoryProperty?.value;
291
- const highlightInfo = LinearMemoryInspectorController.extractHighlightInfo(obj, memoryAddress);
292
- if (highlightInfo !== undefined) {
334
+ const highlightInfo = LinearMemoryInspectorController.extractHighlightInfo(obj, expression);
335
+ if (highlightInfo) {
293
336
  this.#setHighlightInfo(id, highlightInfo);
294
337
  } else {
295
338
  this.#resetHighlightInfo(id);
@@ -308,17 +351,21 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
308
351
  void UI.ViewManager.ViewManager.instance().showView('linear-memory-inspector');
309
352
  }
310
353
 
311
- static extractHighlightInfo(obj: SDK.RemoteObject.RemoteObject, memoryAddress?: number): HighlightInfo|undefined {
354
+ static extractHighlightInfo(obj: SDK.RemoteObject.RemoteObject, expression?: string): HighlightInfo|undefined {
355
+ if (!(obj instanceof Bindings.DebuggerLanguagePlugins.ValueNode)) {
356
+ return undefined;
357
+ }
358
+
312
359
  let highlightInfo;
313
- if (obj instanceof Bindings.DebuggerLanguagePlugins.ValueNode) {
314
- try {
315
- highlightInfo = {
316
- startAddress: memoryAddress || 0,
317
- size: LinearMemoryInspectorController.retrieveObjectSize(obj),
318
- };
319
- } catch (err) {
320
- highlightInfo = undefined;
321
- }
360
+ try {
361
+ highlightInfo = {
362
+ startAddress: obj.inspectableAddress || 0,
363
+ size: LinearMemoryInspectorController.extractObjectSize(obj),
364
+ name: expression,
365
+ type: LinearMemoryInspectorController.extractObjectTypeDescription(obj),
366
+ };
367
+ } catch (err) {
368
+ highlightInfo = undefined;
322
369
  }
323
370
  return highlightInfo;
324
371
  }
@@ -337,8 +384,16 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
337
384
  const debuggerModel = event.data;
338
385
  for (const [bufferId, remoteObject] of this.#bufferIdToRemoteObject) {
339
386
  if (debuggerModel.runtimeModel() === remoteObject.runtimeModel()) {
340
- this.#resetHighlightInfo(bufferId);
341
- this.#paneInstance.refreshView(bufferId);
387
+ const topCallFrame = debuggerModel.debuggerPausedDetails()?.callFrames[0];
388
+ if (topCallFrame) {
389
+ void this
390
+ .updateHighlightedMemory(bufferId, topCallFrame)
391
+ // Need to call refreshView in the callback to trigger re-render.
392
+ .then(() => this.#paneInstance.refreshView(bufferId));
393
+ } else {
394
+ this.#resetHighlightInfo(bufferId);
395
+ this.#paneInstance.refreshView(bufferId);
396
+ }
342
397
  }
343
398
  }
344
399
  }
@@ -355,4 +410,29 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
355
410
  this.#bufferIdToRemoteObject.delete(bufferId);
356
411
  this.#resetHighlightInfo(bufferId);
357
412
  }
413
+
414
+ async updateHighlightedMemory(bufferId: string, callFrame: SDK.DebuggerModel.CallFrame): Promise<void> {
415
+ const oldHighlightInfo = this.getHighlightInfo(bufferId);
416
+ const expressionName = oldHighlightInfo?.name;
417
+ if (!oldHighlightInfo || !expressionName) {
418
+ this.#resetHighlightInfo(bufferId);
419
+ return;
420
+ }
421
+ const obj = await this.evaluateExpression(callFrame, expressionName);
422
+ if (!obj) {
423
+ this.#resetHighlightInfo(bufferId);
424
+ return;
425
+ }
426
+
427
+ const newHighlightInfo = LinearMemoryInspectorController.extractHighlightInfo(obj, expressionName);
428
+ if (!newHighlightInfo || !this.#pointToSameMemoryObject(newHighlightInfo, oldHighlightInfo)) {
429
+ this.#resetHighlightInfo(bufferId);
430
+ } else {
431
+ this.#setHighlightInfo(bufferId, newHighlightInfo);
432
+ }
433
+ }
434
+
435
+ #pointToSameMemoryObject(highlightInfoA: HighlightInfo, highlightInfoB: HighlightInfo): boolean {
436
+ return highlightInfoA.type === highlightInfoB.type && highlightInfoA.startAddress === highlightInfoB.startAddress;
437
+ }
358
438
  }
@@ -226,7 +226,7 @@ class LinearMemoryInspectorView extends UI.Widget.VBox {
226
226
  const highlightInfo = LinearMemoryInspectorController.instance().getHighlightInfo(this.#tabId);
227
227
  if (highlightInfo !== undefined) {
228
228
  if (highlightInfo.startAddress < 0 || highlightInfo.startAddress >= this.#memoryWrapper.length()) {
229
- throw new Error('Highlight info start address is out of bounds.');
229
+ throw new Error('HighlightInfo start address is out of bounds.');
230
230
  }
231
231
  if (highlightInfo.size <= 0) {
232
232
  throw new Error('Highlight size must be a positive number.');
@@ -5,4 +5,8 @@
5
5
  export interface HighlightInfo {
6
6
  startAddress: number;
7
7
  size: number;
8
+ // If the inspector is opened from a different UI location
9
+ // than the scope view, we don't have guaranteed access to the name.
10
+ name?: string;
11
+ type: string;
8
12
  }
@@ -386,16 +386,17 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
386
386
 
387
387
  static createPropertyValueWithCustomSupport(
388
388
  value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean, parentElement?: Element,
389
- linkifier?: Components.Linkifier.Linkifier): ObjectPropertyValue {
389
+ linkifier?: Components.Linkifier.Linkifier, variableName?: string): ObjectPropertyValue {
390
390
  if (value.customPreview()) {
391
391
  const result = (new CustomPreviewComponent(value)).element;
392
392
  result.classList.add('object-properties-section-custom-section');
393
393
  return new ObjectPropertyValue(result);
394
394
  }
395
- return ObjectPropertiesSection.createPropertyValue(value, wasThrown, showPreview, parentElement, linkifier);
395
+ return ObjectPropertiesSection.createPropertyValue(
396
+ value, wasThrown, showPreview, parentElement, linkifier, variableName);
396
397
  }
397
398
 
398
- static appendMemoryIcon(element: Element, obj: SDK.RemoteObject.RemoteObject): void {
399
+ static appendMemoryIcon(element: Element, obj: SDK.RemoteObject.RemoteObject, variableName?: string): void {
399
400
  // We show the memory icon only on ArrayBuffer, WebAssembly.Memory and DWARF memory instances.
400
401
  // TypedArrays DataViews are also supported, but showing the icon next to their
401
402
  // previews is quite a significant visual overhead, and users can easily get to
@@ -418,7 +419,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
418
419
  const controller =
419
420
  LinearMemoryInspector.LinearMemoryInspectorController.LinearMemoryInspectorController.instance();
420
421
  Host.userMetrics.linearMemoryInspectorRevealedFrom(Host.UserMetrics.LinearMemoryInspectorRevealedFrom.MemoryIcon);
421
- void controller.openInspectorView(obj);
422
+ void controller.openInspectorView(obj, undefined /* address */, variableName);
422
423
  };
423
424
 
424
425
  UI.Tooltip.Tooltip.install(memoryIcon, 'Reveal in Memory Inspector panel');
@@ -428,7 +429,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
428
429
 
429
430
  static createPropertyValue(
430
431
  value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean, parentElement?: Element,
431
- linkifier?: Components.Linkifier.Linkifier): ObjectPropertyValue {
432
+ linkifier?: Components.Linkifier.Linkifier, variableName?: string): ObjectPropertyValue {
432
433
  let propertyValue;
433
434
  const type = value.type;
434
435
  const subtype = value.subtype;
@@ -464,7 +465,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
464
465
  propertyValue.element.textContent = description;
465
466
  UI.Tooltip.Tooltip.install(propertyValue.element as HTMLElement, description);
466
467
  }
467
- this.appendMemoryIcon(valueElement, value);
468
+ this.appendMemoryIcon(valueElement, value, variableName);
468
469
  }
469
470
 
470
471
  if (wasThrown) {
@@ -1090,7 +1091,8 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1090
1091
  } else if (this.property.value) {
1091
1092
  const showPreview = this.property.name !== '[[Prototype]]';
1092
1093
  this.propertyValue = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
1093
- this.property.value, this.property.wasThrown, showPreview, this.listItemElement, this.linkifier);
1094
+ this.property.value, this.property.wasThrown, showPreview, this.listItemElement, this.linkifier,
1095
+ this.path() /* variableName */);
1094
1096
  this.valueElement = (this.propertyValue.element as HTMLElement);
1095
1097
  } else if (this.property.getter) {
1096
1098
  this.valueElement = document.createElement('span');
@@ -95,7 +95,7 @@ export class ImageView extends UI.View.SimpleView {
95
95
  private readonly mimeTypeLabel: UI.Toolbar.ToolbarText;
96
96
  private readonly container: HTMLElement;
97
97
  private imagePreviewElement: HTMLImageElement;
98
- private cachedContent?: string|null;
98
+ private cachedContent?: TextUtils.ContentProvider.DeferredContent;
99
99
  constructor(mimeType: string, contentProvider: TextUtils.ContentProvider.ContentProvider) {
100
100
  super(i18nString(UIStrings.image));
101
101
  this.registerRequiredCSS(imageViewStyles);
@@ -153,20 +153,21 @@ export class ImageView extends UI.View.SimpleView {
153
153
  }
154
154
 
155
155
  private async updateContentIfNeeded(): Promise<void> {
156
- const {content} = await this.contentProvider.requestContent();
157
- if (this.cachedContent === content) {
156
+ const content = await this.contentProvider.requestContent();
157
+ if (this.cachedContent?.content === content.content) {
158
158
  return;
159
159
  }
160
160
 
161
- const contentEncoded = await this.contentProvider.contentEncoded();
162
161
  this.cachedContent = content;
163
- const imageSrc = TextUtils.ContentProvider.contentAsDataURL(content, this.mimeType, contentEncoded) || this.url;
162
+ const imageSrc =
163
+ TextUtils.ContentProvider.contentAsDataURL(content.content, this.mimeType, content.isEncoded) || this.url;
164
164
  const loadPromise = new Promise(x => {
165
165
  this.imagePreviewElement.onload = x;
166
166
  });
167
167
  this.imagePreviewElement.src = imageSrc;
168
168
  this.imagePreviewElement.alt = i18nString(UIStrings.imageFromS, {PH1: this.url});
169
- const size = content && !contentEncoded ? content.length : Platform.StringUtilities.base64ToSize(content);
169
+ const size = content.content && !content.isEncoded ? content.content.length :
170
+ Platform.StringUtilities.base64ToSize(content.content);
170
171
  this.sizeLabel.setText(Platform.NumberUtilities.bytesToString(size));
171
172
  await loadPromise;
172
173
  this.dimensionsLabel.setText(i18nString(
@@ -203,13 +204,11 @@ export class ImageView extends UI.View.SimpleView {
203
204
  }
204
205
 
205
206
  private async saveImage(): Promise<void> {
206
- const contentEncoded = await this.contentProvider.contentEncoded();
207
- if (!this.cachedContent) {
207
+ if (!this.cachedContent || !this.cachedContent.content) {
208
208
  return;
209
209
  }
210
- const cachedContent = this.cachedContent;
211
- const imageDataURL =
212
- TextUtils.ContentProvider.contentAsDataURL(cachedContent, this.mimeType, contentEncoded, '', false);
210
+ const imageDataURL = TextUtils.ContentProvider.contentAsDataURL(
211
+ this.cachedContent.content, this.mimeType, this.cachedContent.isEncoded, '', false);
213
212
 
214
213
  if (!imageDataURL) {
215
214
  return;
@@ -45,7 +45,7 @@ export class PreviewFactory {
45
45
  }
46
46
 
47
47
  let content: string = deferredContent.content;
48
- if (await provider.contentEncoded()) {
48
+ if (deferredContent.isEncoded) {
49
49
  content = window.atob(content);
50
50
  }
51
51
 
@@ -460,6 +460,55 @@ export class SourceFrameImpl extends Common.ObjectWrapper.eventMixin<EventTypes,
460
460
  }
461
461
  }
462
462
 
463
+ // If the input is wasm but v8-based wasm disassembly failed, fall back to wasmparser for backwards compatibility.
464
+ if (content && this.contentType === 'application/wasm' && !this.wasmDisassemblyInternal) {
465
+ const worker = Common.Worker.WorkerWrapper.fromURL(
466
+ new URL('../../../../entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.js', import.meta.url));
467
+ const promise = new Promise<{
468
+ lines: string[],
469
+ offsets: number[],
470
+ functionBodyOffsets: {
471
+ start: number,
472
+ end: number,
473
+ }[],
474
+ }>((resolve, reject) => {
475
+ worker.onmessage =
476
+ // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
477
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
478
+ ({data}: MessageEvent<any>): void => {
479
+ if ('event' in data) {
480
+ switch (data.event) {
481
+ case 'progress':
482
+ progressIndicator.setWorked(data.params.percentage);
483
+ break;
484
+ }
485
+ } else if ('method' in data) {
486
+ switch (data.method) {
487
+ case 'disassemble':
488
+ if ('error' in data) {
489
+ reject(data.error);
490
+ } else if ('result' in data) {
491
+ resolve(data.result);
492
+ }
493
+ break;
494
+ }
495
+ }
496
+ };
497
+ worker.onerror = reject;
498
+ });
499
+ worker.postMessage({method: 'disassemble', params: {content}});
500
+ try {
501
+ const {lines, offsets, functionBodyOffsets} = await promise;
502
+ this.rawContent = content = CodeMirror.Text.of(lines);
503
+ this.wasmDisassemblyInternal =
504
+ new Common.WasmDisassembly.WasmDisassembly(lines, offsets, functionBodyOffsets);
505
+ } catch (e) {
506
+ this.rawContent = content = error = e.message;
507
+ } finally {
508
+ worker.terminate();
509
+ }
510
+ }
511
+
463
512
  progressIndicator.setWorked(100);
464
513
  progressIndicator.done();
465
514