chrome-devtools-frontend 1.0.1543082 → 1.0.1544076

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 (149) hide show
  1. package/AUTHORS +2 -0
  2. package/front_end/core/common/Gzip.ts +4 -4
  3. package/front_end/core/common/common.ts +0 -2
  4. package/front_end/core/host/AidaClient.ts +10 -7
  5. package/front_end/core/host/DispatchHttpRequestClient.ts +18 -3
  6. package/front_end/core/root/DevToolsContext.ts +60 -0
  7. package/front_end/core/root/Runtime.ts +8 -7
  8. package/front_end/core/root/root.ts +6 -1
  9. package/front_end/core/sdk/CPUThrottlingManager.ts +0 -4
  10. package/front_end/core/sdk/CSSMatchedStyles.ts +7 -9
  11. package/front_end/core/sdk/CSSModel.ts +1 -1
  12. package/front_end/core/sdk/CSSRule.ts +18 -6
  13. package/front_end/core/sdk/ChildTargetManager.ts +2 -2
  14. package/front_end/core/sdk/TargetManager.ts +5 -6
  15. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +2 -0
  16. package/front_end/entrypoints/inspector_main/InspectorMain.ts +1 -13
  17. package/front_end/entrypoints/main/MainImpl.ts +2 -20
  18. package/front_end/foundation/Universe.ts +24 -1
  19. package/front_end/models/ai_assistance/agents/AiAgent.ts +10 -8
  20. package/front_end/models/ai_assistance/agents/PatchAgent.ts +7 -1
  21. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +0 -5
  22. package/front_end/models/ai_assistance/agents/StylingAgent.ts +4 -8
  23. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +1 -1
  24. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +5 -3
  25. package/front_end/models/bindings/CSSWorkspaceBinding.ts +8 -7
  26. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +19 -15
  27. package/front_end/models/bindings/ResourceMapping.ts +57 -15
  28. package/front_end/models/live-metrics/LiveMetrics.ts +12 -20
  29. package/front_end/models/trace/handlers/SamplesHandler.ts +64 -6
  30. package/front_end/models/trace/types/TraceEvents.ts +16 -0
  31. package/front_end/models/workspace/IgnoreListManager.ts +10 -9
  32. package/front_end/models/workspace/WorkspaceImpl.ts +5 -10
  33. package/front_end/panels/accessibility/AccessibilityNodeView.ts +6 -2
  34. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -1
  35. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -4
  36. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +2 -1
  37. package/front_end/panels/animation/AnimationTimeline.ts +6 -6
  38. package/front_end/panels/application/ApplicationPanelSidebar.ts +0 -1
  39. package/front_end/panels/application/OpenedWindowDetailsView.ts +0 -2
  40. package/front_end/panels/application/ServiceWorkersView.ts +0 -2
  41. package/front_end/panels/application/StorageView.ts +0 -1
  42. package/front_end/panels/application/components/FrameDetailsView.ts +468 -447
  43. package/front_end/panels/application/components/ReportsGrid.ts +7 -2
  44. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +5 -3
  45. package/front_end/panels/application/components/TrustTokensView.ts +7 -1
  46. package/front_end/panels/application/preloading/PreloadingView.ts +10 -4
  47. package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +7 -11
  48. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +15 -3
  49. package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +12 -13
  50. package/front_end/panels/{elements → common}/DOMLinkifier.ts +6 -6
  51. package/front_end/panels/common/common.ts +1 -0
  52. package/front_end/panels/console/ConsoleView.ts +9 -7
  53. package/front_end/panels/console/ConsoleViewMessage.ts +23 -13
  54. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +2 -1
  55. package/front_end/panels/elements/ElementsTreeElement.ts +3 -1
  56. package/front_end/panels/elements/StylePropertiesSection.ts +52 -15
  57. package/front_end/panels/elements/StylePropertyTreeElement.ts +8 -3
  58. package/front_end/panels/elements/StylesSidebarPane.ts +24 -14
  59. package/front_end/panels/elements/elements-meta.ts +11 -2
  60. package/front_end/panels/elements/elements.ts +0 -3
  61. package/front_end/panels/explain/components/ConsoleInsight.ts +333 -318
  62. package/front_end/panels/issues/AffectedResourcesView.ts +2 -1
  63. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +2 -1
  64. package/front_end/panels/network/NetworkLogView.ts +1 -1
  65. package/front_end/panels/recorder/RecorderController.ts +7 -1
  66. package/front_end/panels/settings/SettingsScreen.ts +3 -6
  67. package/front_end/panels/settings/components/SyncSection.ts +218 -226
  68. package/front_end/panels/settings/components/syncSection.css +81 -80
  69. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +42 -294
  70. package/front_end/panels/sources/DebuggerPausedMessage.ts +3 -3
  71. package/front_end/panels/sources/DebuggerPlugin.ts +3 -1
  72. package/front_end/panels/sources/ResourceOriginPlugin.ts +7 -3
  73. package/front_end/panels/sources/SourcesPanel.ts +5 -1
  74. package/front_end/panels/timeline/TimelinePanel.ts +0 -21
  75. package/front_end/panels/timeline/TimelineUIUtils.ts +3 -2
  76. package/front_end/panels/timeline/components/LiveMetricsView.ts +7 -4
  77. package/front_end/panels/timeline/components/insights/NodeLink.ts +3 -2
  78. package/front_end/third_party/puppeteer/README.chromium +2 -2
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.d.ts +1 -0
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.js +4 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/HTTPRequest.js.map +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.d.ts +1 -0
  84. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.d.ts.map +1 -1
  85. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.js +8 -0
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkEventManager.js.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +22 -0
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +34 -6
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.d.ts +1 -0
  99. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.d.ts.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.js +4 -1
  101. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/HTTPRequest.js.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.d.ts +1 -0
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.d.ts.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.js +8 -0
  105. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkEventManager.js.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  107. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +22 -0
  108. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
  110. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
  111. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  114. package/front_end/third_party/puppeteer/package/package.json +2 -2
  115. package/front_end/third_party/puppeteer/package/src/cdp/HTTPRequest.ts +5 -1
  116. package/front_end/third_party/puppeteer/package/src/cdp/NetworkEventManager.ts +16 -1
  117. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +28 -0
  118. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  119. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  120. package/front_end/ui/components/docs/component_docs.ts +0 -4
  121. package/front_end/ui/components/report_view/ReportView.ts +4 -1
  122. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +8 -5
  123. package/front_end/ui/i18n/i18n.ts +16 -0
  124. package/front_end/ui/legacy/ReportView.ts +0 -5
  125. package/front_end/ui/legacy/TextPrompt.ts +65 -19
  126. package/front_end/ui/legacy/UIUtils.ts +1 -1
  127. package/front_end/ui/legacy/Widget.ts +56 -25
  128. package/front_end/ui/legacy/XLink.ts +0 -2
  129. package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +8 -4
  130. package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +3 -1
  131. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +239 -284
  132. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +114 -184
  133. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
  134. package/front_end/ui/legacy/inspectorCommon.css +0 -4
  135. package/front_end/ui/{components/docs/theme_colors/basic.ts → legacy/theme_support/ThemeColors.docs.ts} +33 -23
  136. package/mcp/mcp.ts +1 -0
  137. package/package.json +1 -1
  138. package/front_end/core/common/QueryParamHandler.ts +0 -7
  139. package/front_end/ui/components/docs/input/basic.html +0 -31
  140. package/front_end/ui/components/docs/input/basic.ts +0 -12
  141. package/front_end/ui/components/docs/report/basic.html +0 -27
  142. package/front_end/ui/components/docs/report/basic.ts +0 -48
  143. package/front_end/ui/components/docs/theme_colors/basic.html +0 -56
  144. package/front_end/ui/components/docs/toggle_dark_mode.ts +0 -36
  145. package/front_end/ui/components/docs/toggle_fonts.ts +0 -74
  146. package/front_end/ui/components/docs/user_agent_client_hints/basic.html +0 -25
  147. package/front_end/ui/components/docs/user_agent_client_hints/basic.ts +0 -26
  148. package/front_end/ui/components/expandable_list/ExpandableList.docs.ts +0 -30
  149. /package/front_end/panels/{elements → common}/domLinkifier.css +0 -0
@@ -37,9 +37,8 @@ import * as SDK from '../../../../core/sdk/sdk.js';
37
37
  import type * as Protocol from '../../../../generated/protocol.js';
38
38
  import * as TextUtils from '../../../../models/text_utils/text_utils.js';
39
39
  import * as uiI18n from '../../../../ui/i18n/i18n.js';
40
- import * as IconButton from '../../../components/icon_button/icon_button.js';
41
40
  import * as TextEditor from '../../../components/text_editor/text_editor.js';
42
- import {Directives, html, render} from '../../../lit/lit.js';
41
+ import {Directives, html, type LitTemplate, nothing, render} from '../../../lit/lit.js';
43
42
  import * as VisualLogging from '../../../visual_logging/visual_logging.js';
44
43
  import * as UI from '../../legacy.js';
45
44
  import type * as Components from '../utils/utils.js';
@@ -48,9 +47,9 @@ import {CustomPreviewComponent} from './CustomPreviewComponent.js';
48
47
  import {JavaScriptREPL} from './JavaScriptREPL.js';
49
48
  import objectPropertiesSectionStyles from './objectPropertiesSection.css.js';
50
49
  import objectValueStyles from './objectValue.css.js';
51
- import {createSpansForNodeTitle, RemoteObjectPreviewFormatter} from './RemoteObjectPreviewFormatter.js';
50
+ import {RemoteObjectPreviewFormatter, renderNodeTitle} from './RemoteObjectPreviewFormatter.js';
52
51
 
53
- const {ifDefined} = Directives;
52
+ const {repeat, ifDefined} = Directives;
54
53
  const UIStrings = {
55
54
  /**
56
55
  * @description Text in Object Properties Section
@@ -504,86 +503,82 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
504
503
  return UI.Fragment.html`<span class="name">${name}</span>`;
505
504
  }
506
505
 
507
- static valueElementForFunctionDescription(description?: string, includePreview?: boolean, defaultName?: string):
508
- HTMLElement {
509
- const valueElement = document.createElement('span');
510
- valueElement.classList.add('object-value-function');
511
- description = description || '';
512
- const text = description.replace(/^function [gs]et /, 'function ')
513
- .replace(/^function [gs]et\(/, 'function\(')
514
- .replace(/^[gs]et /, '');
515
- defaultName = defaultName || '';
516
-
517
- // This set of best-effort regular expressions captures common function descriptions.
518
- // Ideally, some parser would provide prefix, arguments, function body text separately.
519
- const asyncMatch = text.match(/^(async\s+function)/);
520
- const isGenerator = text.startsWith('function*');
521
- const isGeneratorShorthand = text.startsWith('*');
522
- const isBasic = !isGenerator && text.startsWith('function');
523
- const isClass = text.startsWith('class ') || text.startsWith('class{');
524
- const firstArrowIndex = text.indexOf('=>');
525
- const isArrow = !asyncMatch && !isGenerator && !isBasic && !isClass && firstArrowIndex > 0;
526
-
527
- let textAfterPrefix;
528
- if (isClass) {
529
- textAfterPrefix = text.substring('class'.length);
530
- const classNameMatch = /^[^{\s]+/.exec(textAfterPrefix.trim());
531
- let className: string = defaultName;
532
- if (classNameMatch) {
533
- className = classNameMatch[0].trim() || defaultName;
534
- }
535
- addElements('class', textAfterPrefix, className);
536
- } else if (asyncMatch) {
537
- textAfterPrefix = text.substring(asyncMatch[1].length);
538
- addElements('async \u0192', textAfterPrefix, nameAndArguments(textAfterPrefix));
539
- } else if (isGenerator) {
540
- textAfterPrefix = text.substring('function*'.length);
541
- addElements('\u0192*', textAfterPrefix, nameAndArguments(textAfterPrefix));
542
- } else if (isGeneratorShorthand) {
543
- textAfterPrefix = text.substring('*'.length);
544
- addElements('\u0192*', textAfterPrefix, nameAndArguments(textAfterPrefix));
545
- } else if (isBasic) {
546
- textAfterPrefix = text.substring('function'.length);
547
- addElements('\u0192', textAfterPrefix, nameAndArguments(textAfterPrefix));
548
- } else if (isArrow) {
549
- const maxArrowFunctionCharacterLength = 60;
550
- let abbreviation: string = text;
551
- if (defaultName) {
552
- abbreviation = defaultName + '()';
553
- } else if (text.length > maxArrowFunctionCharacterLength) {
554
- abbreviation = text.substring(0, firstArrowIndex + 2) + ' {…}';
555
- }
556
- addElements('', text, abbreviation);
557
- } else {
558
- addElements('\u0192', text, nameAndArguments(text));
559
- }
560
- UI.Tooltip.Tooltip.install(valueElement, Platform.StringUtilities.trimEndWithMaxLength(description, 500));
561
- return valueElement;
506
+ static valueElementForFunctionDescription(
507
+ description?: string, includePreview?: boolean, defaultName?: string, className?: string): LitTemplate {
508
+ const contents =
509
+ (description: string, defaultName: string): {prefix: string, abbreviation: string, body: string} => {
510
+ const text = description.replace(/^function [gs]et /, 'function ')
511
+ .replace(/^function [gs]et\(/, 'function\(')
512
+ .replace(/^[gs]et /, '');
513
+
514
+ // This set of best-effort regular expressions captures common function descriptions.
515
+ // Ideally, some parser would provide prefix, arguments, function body text separately.
516
+ const asyncMatch = text.match(/^(async\s+function)/);
517
+ const isGenerator = text.startsWith('function*');
518
+ const isGeneratorShorthand = text.startsWith('*');
519
+ const isBasic = !isGenerator && text.startsWith('function');
520
+ const isClass = text.startsWith('class ') || text.startsWith('class{');
521
+ const firstArrowIndex = text.indexOf('=>');
522
+ const isArrow = !asyncMatch && !isGenerator && !isBasic && !isClass && firstArrowIndex > 0;
523
+
524
+ if (isClass) {
525
+ const body = text.substring('class'.length);
526
+ const classNameMatch = /^[^{\s]+/.exec(body.trim());
527
+ let className: string = defaultName;
528
+ if (classNameMatch) {
529
+ className = classNameMatch[0].trim() || defaultName;
530
+ }
531
+ return {prefix: 'class', body, abbreviation: className};
532
+ }
533
+ if (asyncMatch) {
534
+ const body = text.substring(asyncMatch[1].length);
535
+ return {prefix: 'async \u0192', body, abbreviation: nameAndArguments(body)};
536
+ }
537
+ if (isGenerator) {
538
+ const body = text.substring('function*'.length);
539
+ return {prefix: '\u0192*', body, abbreviation: nameAndArguments(body)};
540
+ }
541
+ if (isGeneratorShorthand) {
542
+ const body = text.substring('*'.length);
543
+ return {prefix: '\u0192*', body, abbreviation: nameAndArguments(body)};
544
+ }
545
+ if (isBasic) {
546
+ const body = text.substring('function'.length);
547
+ return {prefix: '\u0192', body, abbreviation: nameAndArguments(body)};
548
+ }
549
+ if (isArrow) {
550
+ const maxArrowFunctionCharacterLength = 60;
551
+ let abbreviation: string = text;
552
+ if (defaultName) {
553
+ abbreviation = defaultName + '()';
554
+ } else if (text.length > maxArrowFunctionCharacterLength) {
555
+ abbreviation = text.substring(0, firstArrowIndex + 2) + ' {…}';
556
+ }
557
+ return {prefix: '', body: text, abbreviation};
558
+ }
559
+ return {prefix: '\u0192', body: text, abbreviation: nameAndArguments(text)};
560
+ };
561
+
562
+ const {prefix, body, abbreviation} = contents(description ?? '', defaultName ?? '');
563
+ const maxFunctionBodyLength = 200;
564
+ return html`<span
565
+ class="object-value-function ${className ?? ''}"
566
+ title=${Platform.StringUtilities.trimEndWithMaxLength(description ?? '', 500)}>${
567
+ prefix && html`<span class=object-value-function-prefix>${prefix} </span>`}${
568
+ includePreview ? Platform.StringUtilities.trimEndWithMaxLength(body.trim(), maxFunctionBodyLength) :
569
+ abbreviation.replace(/\n/g, ' ')}</span>`;
562
570
 
563
571
  function nameAndArguments(contents: string): string {
564
572
  const startOfArgumentsIndex = contents.indexOf('(');
565
573
  const endOfArgumentsMatch = contents.match(/\)\s*{/);
566
574
  if (startOfArgumentsIndex !== -1 && endOfArgumentsMatch?.index !== undefined &&
567
575
  endOfArgumentsMatch.index > startOfArgumentsIndex) {
568
- const name = contents.substring(0, startOfArgumentsIndex).trim() || defaultName;
576
+ const name = contents.substring(0, startOfArgumentsIndex).trim() || (defaultName ?? '');
569
577
  const args = contents.substring(startOfArgumentsIndex, endOfArgumentsMatch.index + 1);
570
578
  return name + args;
571
579
  }
572
580
  return defaultName + '()';
573
581
  }
574
-
575
- function addElements(prefix: string, body: string, abbreviation: string): void {
576
- const maxFunctionBodyLength = 200;
577
- if (prefix.length) {
578
- valueElement.createChild('span', 'object-value-function-prefix').textContent = prefix + ' ';
579
- }
580
- if (includePreview) {
581
- UI.UIUtils.createTextChild(
582
- valueElement, Platform.StringUtilities.trimEndWithMaxLength(body.trim(), maxFunctionBodyLength));
583
- } else {
584
- UI.UIUtils.createTextChild(valueElement, abbreviation.replace(/\n/g, ' '));
585
- }
586
- }
587
582
  }
588
583
 
589
584
  static createPropertyValueWithCustomSupport(
@@ -598,139 +593,100 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
598
593
  value, wasThrown, showPreview, linkifier, isSyntheticProperty, variableName);
599
594
  }
600
595
 
601
- static appendMemoryIcon(element: Element, object: SDK.RemoteObject.RemoteObject, expression?: string): void {
602
- if (!object.isLinearMemoryInspectable()) {
603
- return;
604
- }
605
-
606
- const memoryIcon = new IconButton.Icon.Icon();
607
- memoryIcon.name = 'memory';
608
- memoryIcon.style.width = 'var(--sys-size-8)';
609
- memoryIcon.style.height = '13px';
610
- memoryIcon.addEventListener('click', event => {
611
- event.consume();
612
- void Common.Revealer.reveal(new SDK.RemoteObject.LinearMemoryInspectable(object, expression));
613
- });
614
- memoryIcon.setAttribute('jslog', `${VisualLogging.action('open-memory-inspector').track({click: true})}`);
615
-
616
- const revealText = i18nString(UIStrings.openInMemoryInpector);
617
- UI.Tooltip.Tooltip.install(memoryIcon, revealText);
618
- UI.ARIAUtils.setLabel(memoryIcon, revealText);
619
-
620
- // Directly set property on memory icon, so that the memory icon is also
596
+ static getMemoryIcon(object: SDK.RemoteObject.RemoteObject, expression?: string): LitTemplate {
597
+ // Directly set styles on memory icon, so that the memory icon is also
621
598
  // styled within the context of code mirror.
622
- memoryIcon.style.setProperty('vertical-align', 'sub');
623
- memoryIcon.style.setProperty('cursor', 'pointer');
599
+ // clang-format off
600
+ return !object.isLinearMemoryInspectable() ? nothing : html`<devtools-icon
601
+ name=memory
602
+ style="width: var(--sys-size-8); height: 13px; vertical-align: sub; cursor: pointer;"
603
+ @click=${(event: Event) => {
604
+ event.consume();
605
+ void Common.Revealer.reveal(new SDK.RemoteObject.LinearMemoryInspectable(object, expression));
606
+ }}
607
+ jslog=${VisualLogging.action('open-memory-inspector').track({click: true})}
608
+ title=${i18nString(UIStrings.openInMemoryInpector)}
609
+ aria-label=${i18nString(UIStrings.openInMemoryInpector)}></devtools-icon>`;
610
+ // clang-format on
611
+ }
624
612
 
625
- element.appendChild(memoryIcon);
613
+ static appendMemoryIcon(element: Element, object: SDK.RemoteObject.RemoteObject, expression?: string): void {
614
+ const fragment = document.createDocumentFragment();
615
+ // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
616
+ render(ObjectPropertiesSection.getMemoryIcon(object, expression), fragment);
617
+ element.appendChild(fragment);
626
618
  }
627
619
 
628
620
  static createPropertyValue(
629
621
  value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
630
622
  linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false, variableName?: string): HTMLElement {
631
- let propertyValue: HTMLElement;
623
+ const propertyValue = document.createDocumentFragment();
632
624
  const type = value.type;
633
625
  const subtype = value.subtype;
634
626
  const description = value.description || '';
635
627
  const className = value.className;
636
- if (type === 'object' && subtype === 'internal#location') {
637
- const rawLocation = value.debuggerModel().createRawLocationByScriptId(
638
- value.value.scriptId, value.value.lineNumber, value.value.columnNumber);
639
- if (rawLocation && linkifier) {
640
- return linkifier.linkifyRawLocation(rawLocation, Platform.DevToolsPath.EmptyUrlString);
628
+
629
+ const contents = (): LitTemplate => {
630
+ if (type === 'object' && subtype === 'internal#location') {
631
+ const rawLocation = value.debuggerModel().createRawLocationByScriptId(
632
+ value.value.scriptId, value.value.lineNumber, value.value.columnNumber);
633
+ if (rawLocation && linkifier) {
634
+ return html`${linkifier.linkifyRawLocation(rawLocation, Platform.DevToolsPath.EmptyUrlString, 'value')}`;
635
+ }
636
+ return html`<span class=value title=${description}>${'<' + i18nString(UIStrings.unknown) + '>'}</span>`;
641
637
  }
642
- propertyValue = createUnknownInternalLocationElement();
643
- } else if (type === 'string' && typeof description === 'string') {
644
- propertyValue = createStringElement();
645
- } else if (type === 'object' && subtype === 'trustedtype') {
646
- propertyValue = createTrustedTypeElement();
647
- } else if (type === 'function') {
648
- propertyValue = ObjectPropertiesSection.valueElementForFunctionDescription(description);
649
- } else if (type === 'object' && subtype === 'node' && description) {
650
- propertyValue = createNodeElement();
651
- } else {
652
- const valueElement = document.createElement('span');
653
- valueElement.classList.add('object-value-' + (subtype || type));
654
- if (value.preview && showPreview) {
655
- const previewFormatter = new RemoteObjectPreviewFormatter();
656
- previewFormatter.appendObjectPreview(valueElement, value.preview, false /* isEntry */);
657
- propertyValue = valueElement;
658
- UI.Tooltip.Tooltip.install(propertyValue as HTMLElement, description || '');
659
- } else if (description.length > maxRenderableStringLength) {
660
- propertyValue = new ExpandableTextPropertyValue(valueElement, description, EXPANDABLE_MAX_LENGTH).element;
661
- } else {
662
- propertyValue = valueElement;
663
- propertyValue.textContent = description;
664
- UI.Tooltip.Tooltip.install(propertyValue as HTMLElement, description);
638
+ if (type === 'string' && typeof description === 'string') {
639
+ const text = JSON.stringify(description);
640
+ const tooLong = description.length > maxRenderableStringLength;
641
+ return html`<span class="value object-value-string" title=${ifDefined(tooLong ? undefined : description)}>${
642
+ tooLong ? new ExpandableTextPropertyValue(text, EXPANDABLE_MAX_LENGTH).element : text}</span>`;
665
643
  }
666
- if (!isSyntheticProperty) {
667
- this.appendMemoryIcon(valueElement, value, variableName);
644
+ if (type === 'object' && subtype === 'trustedtype') {
645
+ const text = `${className} '${description}'`;
646
+ const tooLong = text.length > maxRenderableStringLength;
647
+ return html`<span class="value object-value-trustedtype" title=${ifDefined(tooLong ? undefined : text)}>${
648
+ tooLong ? new ExpandableTextPropertyValue(text, EXPANDABLE_MAX_LENGTH).element :
649
+ html`${className} <span class=object-value-string title=${description}>${
650
+ JSON.stringify(description)}</span>`}</span>`;
668
651
  }
669
- }
670
-
671
- if (wasThrown) {
672
- const wrapperElement = document.createElement('span');
673
- wrapperElement.classList.add('error');
674
- wrapperElement.classList.add('value');
675
- wrapperElement.appendChild(uiI18n.getFormatLocalizedString(str_, UIStrings.exceptionS, {PH1: propertyValue}));
676
- propertyValue = wrapperElement;
677
- }
678
- propertyValue.classList.add('value');
679
- return propertyValue;
680
-
681
- function createUnknownInternalLocationElement(): HTMLElement {
682
- const valueElement = document.createElement('span');
683
- valueElement.textContent = '<' + i18nString(UIStrings.unknown) + '>';
684
- UI.Tooltip.Tooltip.install(valueElement, description || '');
685
- return valueElement;
686
- }
687
-
688
- function createStringElement(): HTMLElement {
689
- const valueElement = document.createElement('span');
690
- valueElement.classList.add('object-value-string');
691
- const text = JSON.stringify(description);
692
- let propertyValue: HTMLElement;
693
- if (description.length > maxRenderableStringLength) {
694
- propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH).element;
695
- } else {
696
- UI.UIUtils.createTextChild(valueElement, text);
697
- propertyValue = valueElement;
698
- UI.Tooltip.Tooltip.install(valueElement, description);
652
+ if (type === 'function') {
653
+ return ObjectPropertiesSection.valueElementForFunctionDescription(description, undefined, undefined, 'value');
699
654
  }
700
- return propertyValue;
701
- }
702
-
703
- function createTrustedTypeElement(): HTMLElement {
704
- const valueElement = document.createElement('span');
705
- valueElement.classList.add('object-value-trustedtype');
706
- const text = `${className} "${description}"`;
707
- let propertyValue;
708
- if (text.length > maxRenderableStringLength) {
709
- propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH).element;
710
- } else {
711
- const contentString = createStringElement();
712
- UI.UIUtils.createTextChild(valueElement, `${className} `);
713
- valueElement.appendChild(contentString);
714
- propertyValue = valueElement;
715
- UI.Tooltip.Tooltip.install(valueElement, text);
655
+ if (type === 'object' && subtype === 'node' && description) {
656
+ return html`<span class="value object-value-node"
657
+ @click=${(event: Event) => {
658
+ void Common.Revealer.reveal(value);
659
+ event.consume(true);
660
+ }}
661
+ @mousemove=${() => SDK.OverlayModel.OverlayModel.highlightObjectAsDOMNode(value)}
662
+ @mouseleave=${() => SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight()}
663
+ >${renderNodeTitle(description)}</span>`;
664
+ }
665
+ if (description.length > maxRenderableStringLength) {
666
+ return html`<span class="value object-value-${subtype || type}" title=${description}>${
667
+ new ExpandableTextPropertyValue(description, EXPANDABLE_MAX_LENGTH).element}</span>`;
716
668
  }
669
+ const hasPreview = value.preview && showPreview;
670
+ return html`<span class="value object-value-${subtype || type}" title=${description}>${
671
+ hasPreview ? new RemoteObjectPreviewFormatter().renderObjectPreview(value.preview) :
672
+ description}${isSyntheticProperty ? nothing : this.getMemoryIcon(value, variableName)}</span>`;
673
+ };
717
674
 
718
- return propertyValue;
675
+ if (wasThrown) {
676
+ // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
677
+ render(
678
+ html`<span class="error value">${
679
+ uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.exceptionS, {PH1: contents()})}</span>`,
680
+ propertyValue);
681
+ } else {
682
+ // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
683
+ render(contents(), propertyValue);
719
684
  }
720
-
721
- function createNodeElement(): HTMLElement {
722
- const valueElement = document.createElement('span');
723
- valueElement.classList.add('object-value-node');
724
- createSpansForNodeTitle(valueElement, (description));
725
- valueElement.addEventListener('click', event => {
726
- void Common.Revealer.reveal(value);
727
- event.consume(true);
728
- }, false);
729
- valueElement.addEventListener(
730
- 'mousemove', () => SDK.OverlayModel.OverlayModel.highlightObjectAsDOMNode(value), false);
731
- valueElement.addEventListener('mouseleave', () => SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight(), false);
732
- return valueElement;
685
+ const child = propertyValue.firstElementChild;
686
+ if (!(child instanceof HTMLElement)) {
687
+ throw new Error('Expected an HTML element');
733
688
  }
689
+ return child;
734
690
  }
735
691
 
736
692
  static formatObjectAsFunction(
@@ -752,8 +708,11 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
752
708
  if (response?.functionName) {
753
709
  defaultName = response.functionName;
754
710
  }
755
- const valueElement =
756
- ObjectPropertiesSection.valueElementForFunctionDescription(func.description, includePreview, defaultName);
711
+ const valueElement = document.createDocumentFragment();
712
+ // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
713
+ render(
714
+ ObjectPropertiesSection.valueElementForFunctionDescription(func.description, includePreview, defaultName),
715
+ valueElement);
757
716
  element.appendChild(valueElement);
758
717
  }
759
718
  }
@@ -914,6 +873,47 @@ export class RootElement extends UI.TreeOutline.TreeElement {
914
873
  **/
915
874
  export const InitialVisibleChildrenLimit = 200;
916
875
 
876
+ export interface TreeElementViewInput {
877
+ onAutoComplete(expression: string, filter: string, force: boolean): unknown;
878
+ completions: string[];
879
+ expandedValueElement: HTMLElement|undefined;
880
+ expanded: boolean;
881
+ editing: boolean;
882
+ editingEnded(): unknown;
883
+ editingCommitted(detail: string): unknown;
884
+ node: ObjectTreeNode;
885
+ nameElement: HTMLElement;
886
+ valueElement: HTMLElement;
887
+ }
888
+ type TreeElementView = (input: TreeElementViewInput, output: object, target: HTMLElement) => void;
889
+ export const TREE_ELEMENT_DEFAULT_VIEW: TreeElementView = (input, output, target) => {
890
+ const isInternalEntries = input.node.property.synthetic && input.node.name === '[[Entries]]';
891
+ if (isInternalEntries) {
892
+ render(html`<span class=name-and-value>${input.nameElement}</span>`, target);
893
+ } else {
894
+ const completionsId = `completions-${input.node.parent?.object?.objectId?.replaceAll('.', '-')}-${input.node.name}`;
895
+ const onAutoComplete = async(e: UI.TextPrompt.TextPromptElement.BeforeAutoCompleteEvent): Promise<void> => {
896
+ if (!(e.target instanceof UI.TextPrompt.TextPromptElement)) {
897
+ return;
898
+ }
899
+ input.onAutoComplete(e.detail.expression, e.detail.filter, e.detail.force);
900
+ };
901
+ // clang-format off
902
+ render(
903
+ html`<span class=name-and-value>${input.nameElement}<span class='separator'>: </span><devtools-prompt
904
+ @commit=${(e: UI.TextPrompt.TextPromptElement.CommitEvent) => input.editingCommitted(e.detail)}
905
+ @cancel=${() => input.editingEnded()}
906
+ @beforeautocomplete=${onAutoComplete}
907
+ completions=${completionsId}
908
+ placeholder=${i18nString(UIStrings.stringIsTooLargeToEdit)}
909
+ ?editing=${input.editing}>
910
+ ${input.expanded && input.expandedValueElement || input.valueElement}
911
+ <datalist id=${completionsId}>${repeat(input.completions, c => html`<option>${c}</option>`)}</datalist>
912
+ </devtools-prompt></span><span>`,
913
+ target);
914
+ // clang-format on
915
+ }
916
+ };
917
917
  export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
918
918
  property: ObjectTreeNode;
919
919
  override toggleOnClick: boolean;
@@ -922,16 +922,18 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
922
922
  private readonly maxNumPropertiesToShow: number;
923
923
  nameElement!: HTMLElement;
924
924
  valueElement!: HTMLElement;
925
- private rowContainer!: HTMLElement;
926
925
  readOnly!: boolean;
927
926
  private prompt!: ObjectPropertyPrompt|undefined;
928
927
  private editableDiv!: HTMLElement;
929
- propertyValue?: HTMLElement;
930
- expandedValueElement?: Element|null;
931
- constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier) {
928
+ expandedValueElement?: HTMLElement;
929
+ #editing = false;
930
+ readonly #view: TreeElementView;
931
+ #completions: string[] = [];
932
+ constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier, view = TREE_ELEMENT_DEFAULT_VIEW) {
932
933
  // Pass an empty title, the title gets made later in onattach.
933
934
  super();
934
935
 
936
+ this.#view = view;
935
937
  this.property = property;
936
938
  this.toggleOnClick = true;
937
939
  this.highlightChanges = [];
@@ -1168,29 +1170,19 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1168
1170
  }
1169
1171
 
1170
1172
  override onexpand(): void {
1171
- this.showExpandedValueElement(true);
1173
+ this.performUpdate();
1172
1174
  }
1173
1175
 
1174
1176
  override oncollapse(): void {
1175
- this.showExpandedValueElement(false);
1177
+ this.performUpdate();
1176
1178
  }
1177
1179
 
1178
- private showExpandedValueElement(value: boolean): void {
1179
- if (!this.expandedValueElement) {
1180
- return;
1181
- }
1182
- if (value) {
1183
- this.rowContainer.replaceChild(this.expandedValueElement, this.valueElement);
1184
- } else {
1185
- this.rowContainer.replaceChild(this.valueElement, this.expandedValueElement);
1186
- }
1187
- }
1188
-
1189
- private createExpandedValueElement(value: SDK.RemoteObject.RemoteObject, isSyntheticProperty: boolean): Element|null {
1180
+ private createExpandedValueElement(value: SDK.RemoteObject.RemoteObject, isSyntheticProperty: boolean): HTMLElement
1181
+ |undefined {
1190
1182
  const needsAlternateValue = value.hasChildren && !value.customPreview() && value.subtype !== 'node' &&
1191
1183
  value.type !== 'function' && (value.type !== 'object' || value.preview);
1192
1184
  if (!needsAlternateValue) {
1193
- return null;
1185
+ return undefined;
1194
1186
  }
1195
1187
 
1196
1188
  const valueElement = document.createElement('span');
@@ -1228,10 +1220,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1228
1220
  this.valueElement.classList.add('value');
1229
1221
  } else if (this.property.object) {
1230
1222
  const showPreview = this.property.name !== '[[Prototype]]';
1231
- this.propertyValue = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
1223
+ this.valueElement = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
1232
1224
  this.property.object, this.property.property.wasThrown, showPreview, this.linkifier,
1233
1225
  this.property.property.synthetic, this.property.path /* variableName */);
1234
- this.valueElement = this.propertyValue;
1235
1226
  } else if (this.property.property.getter) {
1236
1227
  this.valueElement = document.createElement('span');
1237
1228
  const element = this.valueElement.createChild('span');
@@ -1264,24 +1255,29 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1264
1255
  this.expandedValueElement =
1265
1256
  this.createExpandedValueElement(this.property.object, this.property.property.synthetic);
1266
1257
  }
1258
+ this.performUpdate();
1259
+ }
1267
1260
 
1268
- const adorner: Element|string = '';
1269
- let container: Element;
1270
-
1271
- if (isInternalEntries) {
1272
- container = UI.Fragment.html`
1273
- <span class='name-and-value'>${adorner}${this.nameElement}</span>
1274
- `;
1275
- } else {
1276
- container = UI.Fragment.html`
1277
- <span class='name-and-value'>${adorner}${this.nameElement}<span class='separator'>: </span>${
1278
- this.valueElement}</span>
1279
- `;
1280
- }
1261
+ async #updateCompletions(expression: string, filter: string, force: boolean): Promise<void> {
1262
+ const suggestions = await TextEditor.JavaScript.completeInContext(expression, filter, force);
1263
+ this.#completions = suggestions.map(v => v.text);
1264
+ this.performUpdate();
1265
+ }
1281
1266
 
1282
- this.listItemElement.removeChildren();
1283
- this.rowContainer = (container as HTMLElement);
1284
- this.listItemElement.appendChild(this.rowContainer);
1267
+ performUpdate(): void {
1268
+ const input: TreeElementViewInput = {
1269
+ expandedValueElement: this.expandedValueElement,
1270
+ expanded: this.expanded,
1271
+ editing: this.#editing,
1272
+ editingEnded: this.editingEnded.bind(this),
1273
+ editingCommitted: this.editingCommitted.bind(this),
1274
+ node: this.property,
1275
+ nameElement: this.nameElement,
1276
+ valueElement: this.valueElement,
1277
+ completions: this.#editing ? this.#completions : [],
1278
+ onAutoComplete: this.#updateCompletions.bind(this),
1279
+ };
1280
+ this.#view(input, {}, this.listItemElement);
1285
1281
  }
1286
1282
 
1287
1283
  getContextMenu(event: Event): UI.ContextMenu.ContextMenu {
@@ -1325,69 +1321,28 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1325
1321
  void contextMenu.show();
1326
1322
  }
1327
1323
 
1328
- private startEditing(): void {
1329
- const treeOutline = (this.treeOutline as ObjectPropertiesSectionsTreeOutline | null);
1330
- if (this.prompt || !treeOutline || !treeOutline.editable || this.readOnly) {
1331
- return;
1332
- }
1333
- this.editableDiv = this.rowContainer.createChild('span', 'editable-div');
1334
-
1335
- if (this.property.object) {
1336
- let text: string|(string | undefined) = this.property.object.description;
1337
- if (this.property.object.type === 'string' && typeof text === 'string') {
1338
- text = `"${text}"`;
1339
- }
1340
-
1341
- this.editableDiv.setTextContentTruncatedIfNeeded(text, i18nString(UIStrings.stringIsTooLargeToEdit));
1342
- }
1343
-
1344
- const originalContent = this.editableDiv.textContent || '';
1345
-
1346
- // Lie about our children to prevent expanding on double click and to collapse subproperties.
1347
- this.setExpandable(false);
1348
- this.listItemElement.classList.add('editing-sub-part');
1349
- this.valueElement.classList.add('hidden');
1350
-
1351
- this.prompt = new ObjectPropertyPrompt();
1352
-
1353
- const proxyElement =
1354
- this.prompt.attachAndStartEditing(this.editableDiv, this.editingCommitted.bind(this, originalContent));
1355
- proxyElement.classList.add('property-prompt');
1356
-
1357
- const selection = this.listItemElement.getComponentSelection();
1324
+ get editing(): boolean {
1325
+ return this.#editing;
1326
+ }
1358
1327
 
1359
- if (selection) {
1360
- selection.selectAllChildren(this.editableDiv);
1328
+ private startEditing(): void {
1329
+ if (!this.readOnly) {
1330
+ this.#editing = true;
1331
+ this.performUpdate();
1361
1332
  }
1362
- proxyElement.addEventListener('keydown', this.promptKeyDown.bind(this, originalContent), false);
1363
1333
  }
1364
1334
 
1365
1335
  private editingEnded(): void {
1366
- if (this.prompt) {
1367
- this.prompt.detach();
1368
- delete this.prompt;
1369
- }
1370
- this.editableDiv.remove();
1336
+ this.#completions = [];
1337
+ this.#editing = false;
1338
+ this.performUpdate();
1371
1339
  this.updateExpandable();
1372
- this.listItemElement.scrollLeft = 0;
1373
- this.listItemElement.classList.remove('editing-sub-part');
1374
1340
  this.select();
1375
1341
  }
1376
1342
 
1377
- private editingCancelled(): void {
1378
- this.valueElement.classList.remove('hidden');
1379
- this.editingEnded();
1380
- }
1381
-
1382
- private async editingCommitted(originalContent: string): Promise<void> {
1383
- const userInput = this.prompt ? this.prompt.text() : '';
1384
- if (userInput === originalContent) {
1385
- this.editingCancelled(); // nothing changed, so cancel
1386
- return;
1387
- }
1388
-
1343
+ private async editingCommitted(newContent: string): Promise<void> {
1389
1344
  this.editingEnded();
1390
- await this.applyExpression(userInput);
1345
+ await this.applyExpression(newContent);
1391
1346
  }
1392
1347
 
1393
1348
  private promptKeyDown(originalContent: string, event: Event): void {
@@ -1399,7 +1354,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1399
1354
  }
1400
1355
  if (keyboardEvent.key === Platform.KeyboardUtilities.ESCAPE_KEY) {
1401
1356
  keyboardEvent.consume();
1402
- this.editingCancelled();
1357
+ this.editingEnded();
1403
1358
  return;
1404
1359
  }
1405
1360
  }
@@ -1790,10 +1745,10 @@ export class ExpandableTextPropertyValue {
1790
1745
  private readonly maxDisplayableTextLength: number;
1791
1746
  readonly #byteCount: number;
1792
1747
  #expanded = false;
1793
- #element: HTMLElement;
1748
+ #element: DocumentFragment;
1794
1749
 
1795
- constructor(element: HTMLElement, text: string, maxLength: number) {
1796
- this.#element = element;
1750
+ constructor(text: string, maxLength: number) {
1751
+ this.#element = document.createDocumentFragment();
1797
1752
  this.text = text;
1798
1753
  this.maxLength = maxLength;
1799
1754
  this.maxDisplayableTextLength = 10000000;
@@ -1801,7 +1756,7 @@ export class ExpandableTextPropertyValue {
1801
1756
  this.#render();
1802
1757
  }
1803
1758
 
1804
- get element(): HTMLElement {
1759
+ get element(): DocumentFragment {
1805
1760
  return this.#element;
1806
1761
  }
1807
1762