chrome-devtools-frontend 1.0.1544076 → 1.0.1545096

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 (67) hide show
  1. package/config/typescript/tsconfig.eslint.json +1 -0
  2. package/front_end/core/common/ParsedURL.ts +1 -1
  3. package/front_end/core/common/common.ts +0 -2
  4. package/front_end/core/protocol_client/CDPConnection.ts +3 -3
  5. package/front_end/core/protocol_client/DevToolsCDPConnection.ts +2 -1
  6. package/front_end/core/sdk/CSSMetadata.ts +17 -5
  7. package/front_end/core/sdk/NetworkManager.ts +6 -8
  8. package/front_end/core/sdk/NetworkRequest.ts +4 -0
  9. package/front_end/core/sdk/SDKModel.ts +4 -2
  10. package/front_end/core/sdk/TargetManager.ts +14 -15
  11. package/front_end/generated/Deprecation.ts +4 -0
  12. package/front_end/generated/InspectorBackendCommands.ts +2 -5
  13. package/front_end/generated/SupportedCSSProperties.js +0 -23
  14. package/front_end/generated/protocol-mapping.d.ts +0 -15
  15. package/front_end/generated/protocol-proxy-api.d.ts +0 -11
  16. package/front_end/generated/protocol.ts +2 -34
  17. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -1
  18. package/front_end/panels/ai_assistance/components/UserActionRow.ts +2 -1
  19. package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -7
  20. package/front_end/panels/application/{components/FrameDetailsView.ts → FrameDetailsView.ts} +134 -165
  21. package/front_end/panels/application/{components/OriginTrialTreeView.ts → OriginTrialTreeView.ts} +9 -9
  22. package/front_end/panels/application/application.ts +4 -0
  23. package/front_end/panels/application/components/StackTrace.ts +5 -3
  24. package/front_end/panels/application/components/components.ts +2 -4
  25. package/front_end/panels/application/{components/frameDetailsReportView.css → frameDetailsReportView.css} +5 -1
  26. package/front_end/panels/common/BadgeNotification.ts +2 -1
  27. package/front_end/panels/common/DOMLinkifier.ts +7 -2
  28. package/front_end/panels/common/GdpSignUpDialog.ts +2 -1
  29. package/front_end/panels/elements/ElementStatePaneWidget.ts +2 -1
  30. package/front_end/panels/elements/StylePropertiesSection.ts +1 -1
  31. package/front_end/panels/elements/elements-meta.ts +0 -22
  32. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +3 -6
  33. package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +2 -1
  34. package/front_end/panels/settings/SettingsScreen.ts +3 -2
  35. package/front_end/panels/timeline/components/LiveMetricsView.ts +14 -5
  36. package/front_end/panels/timeline/components/MetricCard.ts +2 -2
  37. package/front_end/panels/timeline/components/insights/NodeLink.ts +2 -3
  38. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +2 -1
  39. package/front_end/panels/timeline/timeline-meta.ts +0 -10
  40. package/front_end/panels/timeline/timeline.ts +0 -2
  41. package/front_end/panels/whats_new/ReleaseNoteView.ts +2 -1
  42. package/front_end/panels/whats_new/WhatsNewImpl.ts +3 -2
  43. package/front_end/third_party/chromium/README.chromium +1 -1
  44. package/front_end/tsconfig.json +1 -0
  45. package/front_end/ui/components/buttons/Button.docs.ts +6 -5
  46. package/front_end/ui/components/snackbars/Snackbars.docs.ts +1 -1
  47. package/front_end/ui/components/spinners/Spinners.docs.ts +1 -1
  48. package/front_end/ui/components/survey_link/SurveyLink.docs.ts +2 -1
  49. package/front_end/ui/components/switch/Switch.docs.ts +1 -1
  50. package/front_end/ui/components/tooltips/Tooltip.docs.ts +3 -3
  51. package/front_end/ui/helpers/OpenInNewTab.ts +87 -0
  52. package/front_end/ui/helpers/helpers.ts +5 -0
  53. package/front_end/ui/legacy/ContextMenu.docs.ts +12 -11
  54. package/front_end/ui/legacy/RadioButton.docs.ts +1 -1
  55. package/front_end/ui/legacy/SelectMenu.docs.ts +1 -1
  56. package/front_end/ui/legacy/Slider.docs.ts +1 -1
  57. package/front_end/ui/legacy/UIUtils.ts +0 -33
  58. package/front_end/ui/legacy/XLink.ts +4 -4
  59. package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +2 -1
  60. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +144 -143
  61. package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -1
  62. package/mcp/tsconfig.json +16 -0
  63. package/package.json +2 -2
  64. package/front_end/core/common/Linkifier.ts +0 -55
  65. package/front_end/panels/timeline/CLSLinkifier.ts +0 -58
  66. /package/front_end/panels/application/{components/originTrialTokenRows.css → originTrialTokenRows.css} +0 -0
  67. /package/front_end/panels/application/{components/originTrialTreeView.css → originTrialTreeView.css} +0 -0
@@ -40,7 +40,6 @@ import * as Common from '../../core/common/common.js';
40
40
  import * as Host from '../../core/host/host.js';
41
41
  import * as i18n from '../../core/i18n/i18n.js';
42
42
  import * as Platform from '../../core/platform/platform.js';
43
- import * as Root from '../../core/root/root.js';
44
43
  import * as Geometry from '../../models/geometry/geometry.js';
45
44
  import * as TextUtils from '../../models/text_utils/text_utils.js';
46
45
  import * as Buttons from '../components/buttons/buttons.js';
@@ -1989,38 +1988,6 @@ export function measuredScrollbarWidth(document?: Document|null): number {
1989
1988
  return cachedMeasuredScrollbarWidth;
1990
1989
  }
1991
1990
 
1992
- /**
1993
- * Opens the given `url` in a new Chrome tab.
1994
- *
1995
- * If the `url` is a Google owned documentation page (currently that includes
1996
- * `web.dev`, `developers.google.com`, and `developer.chrome.com`), the `url`
1997
- * will also be checked for UTM parameters:
1998
- *
1999
- * - If no `utm_source` search parameter is present, this method will add a new
2000
- * search parameter `utm_source=devtools` to `url`.
2001
- * - If no `utm_campaign` search parameter is present, and DevTools is running
2002
- * within a branded build, this method will add `utm_campaign=<channel>` to
2003
- * the search parameters, with `<channel>` being the release channel of
2004
- * Chrome ("stable", "beta", "dev", or "canary").
2005
- *
2006
- * @param url the URL to open in a new tab.
2007
- * @throws TypeError if `url` is not a valid URL.
2008
- * @see https://en.wikipedia.org/wiki/UTM_parameters
2009
- */
2010
- export function openInNewTab(url: URL|string): void {
2011
- url = new URL(`${url}`);
2012
- if (['developer.chrome.com', 'developers.google.com', 'web.dev'].includes(url.hostname)) {
2013
- if (!url.searchParams.has('utm_source')) {
2014
- url.searchParams.append('utm_source', 'devtools');
2015
- }
2016
- const {channel} = Root.Runtime.hostConfig;
2017
- if (!url.searchParams.has('utm_campaign') && typeof channel === 'string') {
2018
- url.searchParams.append('utm_campaign', channel);
2019
- }
2020
- }
2021
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.openInNewTab(Platform.DevToolsPath.urlString`${url}`);
2022
- }
2023
-
2024
1991
  export interface PromotionDisplayState {
2025
1992
  displayCount: number;
2026
1993
  firstRegistered: number;
@@ -4,6 +4,7 @@
4
4
 
5
5
  import * as Host from '../../core/host/host.js';
6
6
  import * as Platform from '../../core/platform/platform.js';
7
+ import * as UIHelpers from '../helpers/helpers.js';
7
8
  import * as VisualLogging from '../visual_logging/visual_logging.js';
8
9
 
9
10
  import * as ARIAUtils from './ARIAUtils.js';
@@ -13,7 +14,6 @@ import {Tooltip} from './Tooltip.js';
13
14
  import {
14
15
  copyLinkAddressLabel,
15
16
  MaxLengthForDisplayedURLs,
16
- openInNewTab,
17
17
  openLinkExternallyLabel,
18
18
  } from './UIUtils.js';
19
19
  import {XElement} from './XElement.js';
@@ -54,14 +54,14 @@ export class XLink extends XElement {
54
54
  this.onClick = (event: Event) => {
55
55
  event.consume(true);
56
56
  if (this.#href) {
57
- openInNewTab(this.#href);
57
+ UIHelpers.openInNewTab(this.#href);
58
58
  }
59
59
  };
60
60
  this.onKeyDown = (event: KeyboardEvent) => {
61
61
  if (Platform.KeyboardUtilities.isEnterOrSpaceKey(event)) {
62
62
  event.consume(true);
63
63
  if (this.#href) {
64
- openInNewTab(this.#href);
64
+ UIHelpers.openInNewTab(this.#href);
65
65
  }
66
66
  }
67
67
  };
@@ -140,7 +140,7 @@ export class ContextMenuProvider implements Provider<Node> {
140
140
  const node: XLink = targetNode;
141
141
  contextMenu.revealSection().appendItem(openLinkExternallyLabel(), () => {
142
142
  if (node.href) {
143
- openInNewTab(node.href);
143
+ UIHelpers.openInNewTab(node.href);
144
144
  }
145
145
  }, {jslogContext: 'open-in-new-tab'});
146
146
  contextMenu.revealSection().appendItem(copyLinkAddressLabel(), () => {
@@ -11,6 +11,7 @@ import * as i18n from '../../../../core/i18n/i18n.js';
11
11
  import * as Platform from '../../../../core/platform/platform.js';
12
12
  import * as Root from '../../../../core/root/root.js';
13
13
  import * as IconButton from '../../../../ui/components/icon_button/icon_button.js';
14
+ import * as UIHelpers from '../../../helpers/helpers.js';
14
15
  import * as UI from '../../legacy.js';
15
16
 
16
17
  import {type ContrastInfo, Events as ContrastInfoEvents} from './ContrastInfo.js';
@@ -363,7 +364,7 @@ export class ContrastDetails extends Common.ObjectWrapper.ObjectWrapper<EventTyp
363
364
  }
364
365
 
365
366
  private static showHelp(): void {
366
- UI.UIUtils.openInNewTab('https://web.dev/color-and-contrast-accessibility/');
367
+ UIHelpers.openInNewTab('https://web.dev/color-and-contrast-accessibility/');
367
368
  }
368
369
 
369
370
  setVisible(visible: boolean): void {
@@ -49,7 +49,7 @@ import objectPropertiesSectionStyles from './objectPropertiesSection.css.js';
49
49
  import objectValueStyles from './objectValue.css.js';
50
50
  import {RemoteObjectPreviewFormatter, renderNodeTitle} from './RemoteObjectPreviewFormatter.js';
51
51
 
52
- const {repeat, ifDefined} = Directives;
52
+ const {ref, repeat, ifDefined, classMap} = Directives;
53
53
  const UIStrings = {
54
54
  /**
55
55
  * @description Text in Object Properties Section
@@ -874,45 +874,116 @@ export class RootElement extends UI.TreeOutline.TreeElement {
874
874
  export const InitialVisibleChildrenLimit = 200;
875
875
 
876
876
  export interface TreeElementViewInput {
877
+ startEditing(): unknown;
878
+ invokeGetter(getter: SDK.RemoteObject.RemoteObject): unknown;
877
879
  onAutoComplete(expression: string, filter: string, force: boolean): unknown;
880
+ linkifier: Components.Linkifier.Linkifier|undefined;
878
881
  completions: string[];
879
- expandedValueElement: HTMLElement|undefined;
880
882
  expanded: boolean;
881
883
  editing: boolean;
882
884
  editingEnded(): unknown;
883
885
  editingCommitted(detail: string): unknown;
884
886
  node: ObjectTreeNode;
885
- nameElement: HTMLElement;
886
- valueElement: HTMLElement;
887
887
  }
888
- type TreeElementView = (input: TreeElementViewInput, output: object, target: HTMLElement) => void;
888
+ interface TreeElementViewOutput {
889
+ valueElement: Element|undefined;
890
+ nameElement: Element|undefined;
891
+ }
892
+ type TreeElementView = (input: TreeElementViewInput, output: TreeElementViewOutput, target: HTMLElement) => void;
889
893
  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
- }
894
+ const {property} = input.node;
895
+ const isInternalEntries = property.synthetic && input.node.name === '[[Entries]]';
896
+ const completionsId = `completions-${input.node.parent?.object?.objectId?.replaceAll('.', '-')}-${input.node.name}`;
897
+ const onAutoComplete = async(e: UI.TextPrompt.TextPromptElement.BeforeAutoCompleteEvent): Promise<void> => {
898
+ if (!(e.target instanceof UI.TextPrompt.TextPromptElement)) {
899
+ return;
900
+ }
901
+ input.onAutoComplete(e.detail.expression, e.detail.filter, e.detail.force);
902
+ };
903
+ const nameClasses = classMap({
904
+ name: true,
905
+ 'object-properties-section-dimmed': !property.enumerable,
906
+ 'own-property': property.isOwn,
907
+ 'synthetic-property': property.synthetic,
908
+ });
909
+ const quotedName =
910
+ /^\s|\s$|^$|\n/.test(property.name) ? `"${property.name.replace(/\n/g, '\u21B5')}"` : property.name;
911
+ const isExpandable = !isInternalEntries && property.value && !property.wasThrown && property.value.hasChildren &&
912
+ !property.value.customPreview() && property.value.subtype !== 'node' && property.value.type !== 'function' &&
913
+ (property.value.type !== 'object' || property.value.preview);
914
+
915
+ const value = (): LitTemplate|HTMLElement => {
916
+ const valueRef = ref(e => {
917
+ output.valueElement = e;
918
+ });
919
+ if (isInternalEntries) {
920
+ return html`<span ${valueRef} class=value></span>`;
921
+ }
922
+ if (property.value) {
923
+ const showPreview = property.name !== '[[Prototype]]';
924
+ const value = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
925
+ property.value, property.wasThrown, showPreview, input.linkifier, property.synthetic,
926
+ input.node.path /* variableName */);
927
+ output.valueElement = value;
928
+ return value;
929
+ }
930
+ if (property.getter) {
931
+ const getter = property.getter;
932
+ const invokeGetter = (event: Event): void => {
933
+ event.consume();
934
+ input.invokeGetter(getter);
935
+ };
936
+ return html`<span ${valueRef}><span
937
+ class=object-value-calculate-value-button
938
+ title=${i18nString(UIStrings.invokePropertyGetter)}
939
+ @click=${invokeGetter}
940
+ >${i18nString(UIStrings.dots)}</span></span>`;
941
+ }
942
+ return html`<span ${valueRef}
943
+ class=object-value-unavailable
944
+ title=${i18nString(UIStrings.valueNotAccessibleToTheDebugger)}>${
945
+ i18nString(UIStrings.valueUnavailable)}</span>`;
946
+ };
947
+
948
+ const onDblClick = (event: Event): void => {
949
+ event.consume(true);
950
+ if (property.value && !property.value.customPreview() && (property.writable || property.setter)) {
951
+ input.startEditing();
952
+ }
953
+ };
954
+
955
+ // clang-format off
956
+ render(
957
+ html`<span class=name-and-value><span
958
+ ${ref(e => { output.nameElement = e; })}
959
+ class=${nameClasses}
960
+ title=${input.node.path}>${property.private ?
961
+ html`<span class="private-property-hash">${property.name[0]}</span>${
962
+ property.name.substring(1)}</span>` : quotedName}</span>${
963
+ isInternalEntries ? nothing :
964
+ html`<span class='separator'>: </span><devtools-prompt
965
+ @commit=${(e: UI.TextPrompt.TextPromptElement.CommitEvent) => input.editingCommitted(e.detail)}
966
+ @cancel=${() => input.editingEnded()}
967
+ @beforeautocomplete=${onAutoComplete}
968
+ @dblclick=${onDblClick}
969
+ completions=${completionsId}
970
+ placeholder=${i18nString(UIStrings.stringIsTooLargeToEdit)}
971
+ ?editing=${input.editing}>
972
+ ${input.expanded && isExpandable && property.value ?
973
+ html`<span
974
+ class="value object-value-${property.value.subtype || property.value.type}"
975
+ title=${ifDefined(property.value.description)}>${
976
+ property.value.description === 'Object' ? '' :
977
+ Platform.StringUtilities.trimMiddle(property.value.description ?? '',
978
+ maxRenderableStringLength)}${
979
+ property.synthetic ? nothing :
980
+ ObjectPropertiesSection.getMemoryIcon(property.value)}</span>` :
981
+ value()
982
+ }
983
+ <datalist id=${completionsId}>${repeat(input.completions, c => html`<option>${c}</option>`)}</datalist>
984
+ </devtools-prompt></span>`}</span>`,
985
+ target);
986
+ // clang-format on
916
987
  };
917
988
  export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
918
989
  property: ObjectTreeNode;
@@ -920,15 +991,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
920
991
  private highlightChanges: UI.UIUtils.HighlightChange[];
921
992
  private linkifier: Components.Linkifier.Linkifier|undefined;
922
993
  private readonly maxNumPropertiesToShow: number;
923
- nameElement!: HTMLElement;
924
- valueElement!: HTMLElement;
925
994
  readOnly!: boolean;
926
995
  private prompt!: ObjectPropertyPrompt|undefined;
927
- private editableDiv!: HTMLElement;
928
- expandedValueElement?: HTMLElement;
929
996
  #editing = false;
930
997
  readonly #view: TreeElementView;
931
998
  #completions: string[] = [];
999
+ #nameElement: Element|undefined;
1000
+ #valueElement: Element|undefined;
932
1001
  constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier, view = TREE_ELEMENT_DEFAULT_VIEW) {
933
1002
  // Pass an empty title, the title gets made later in onattach.
934
1003
  super();
@@ -1071,6 +1140,10 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1071
1140
  return rootElement;
1072
1141
  }
1073
1142
 
1143
+ get nameElement(): Element|undefined {
1144
+ return this.#nameElement;
1145
+ }
1146
+
1074
1147
  setSearchRegex(regex: RegExp, additionalCssClassName?: string): boolean {
1075
1148
  let cssClasses = UI.UIUtils.highlightedSearchResultClassName;
1076
1149
  if (additionalCssClassName) {
@@ -1078,11 +1151,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1078
1151
  }
1079
1152
  this.revertHighlightChanges();
1080
1153
 
1081
- this.applySearch(regex, this.nameElement, cssClasses);
1154
+ if (this.#nameElement) {
1155
+ this.applySearch(regex, this.#nameElement, cssClasses);
1156
+ }
1082
1157
  if (this.property.object) {
1083
1158
  const valueType = this.property.object.type;
1084
- if (valueType !== 'object') {
1085
- this.applySearch(regex, this.valueElement, cssClasses);
1159
+ if (valueType !== 'object' && this.#valueElement) {
1160
+ this.applySearch(regex, this.#valueElement, cssClasses);
1086
1161
  }
1087
1162
  }
1088
1163
 
@@ -1144,17 +1219,6 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1144
1219
  }
1145
1220
  }
1146
1221
 
1147
- override ondblclick(event: Event): boolean {
1148
- const target = (event.target as HTMLElement);
1149
- const inEditableElement = target.isSelfOrDescendant(this.valueElement) ||
1150
- (this.expandedValueElement && target.isSelfOrDescendant(this.expandedValueElement));
1151
- if (this.property.object && !this.property.object.customPreview() && inEditableElement &&
1152
- (this.property.property.writable || this.property.property.setter)) {
1153
- this.startEditing();
1154
- }
1155
- return false;
1156
- }
1157
-
1158
1222
  override onenter(): boolean {
1159
1223
  if (this.property.object && !this.property.object.customPreview() &&
1160
1224
  (this.property.property.writable || this.property.property.setter)) {
@@ -1165,7 +1229,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1165
1229
  }
1166
1230
 
1167
1231
  override onattach(): void {
1168
- this.update();
1232
+ this.performUpdate();
1169
1233
  this.updateExpandable();
1170
1234
  }
1171
1235
 
@@ -1177,87 +1241,6 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1177
1241
  this.performUpdate();
1178
1242
  }
1179
1243
 
1180
- private createExpandedValueElement(value: SDK.RemoteObject.RemoteObject, isSyntheticProperty: boolean): HTMLElement
1181
- |undefined {
1182
- const needsAlternateValue = value.hasChildren && !value.customPreview() && value.subtype !== 'node' &&
1183
- value.type !== 'function' && (value.type !== 'object' || value.preview);
1184
- if (!needsAlternateValue) {
1185
- return undefined;
1186
- }
1187
-
1188
- const valueElement = document.createElement('span');
1189
- valueElement.classList.add('value');
1190
- if (value.description === 'Object') {
1191
- valueElement.textContent = '';
1192
- } else {
1193
- valueElement.setTextContentTruncatedIfNeeded(value.description || '');
1194
- }
1195
- valueElement.classList.add('object-value-' + (value.subtype || value.type));
1196
- UI.Tooltip.Tooltip.install(valueElement, value.description || '');
1197
- if (!isSyntheticProperty) {
1198
- ObjectPropertiesSection.appendMemoryIcon(valueElement, value);
1199
- }
1200
- return valueElement;
1201
- }
1202
-
1203
- update(): void {
1204
- this.nameElement =
1205
- (ObjectPropertiesSection.createNameElement(this.property.name, this.property.property.private) as HTMLElement);
1206
- if (!this.property.property.enumerable) {
1207
- this.nameElement.classList.add('object-properties-section-dimmed');
1208
- }
1209
- if (this.property.property.isOwn) {
1210
- this.nameElement.classList.add('own-property');
1211
- }
1212
- if (this.property.property.synthetic) {
1213
- this.nameElement.classList.add('synthetic-property');
1214
- }
1215
- this.nameElement.title = this.property.path;
1216
-
1217
- const isInternalEntries = this.property.property.synthetic && this.property.name === '[[Entries]]';
1218
- if (isInternalEntries) {
1219
- this.valueElement = document.createElement('span');
1220
- this.valueElement.classList.add('value');
1221
- } else if (this.property.object) {
1222
- const showPreview = this.property.name !== '[[Prototype]]';
1223
- this.valueElement = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
1224
- this.property.object, this.property.property.wasThrown, showPreview, this.linkifier,
1225
- this.property.property.synthetic, this.property.path /* variableName */);
1226
- } else if (this.property.property.getter) {
1227
- this.valueElement = document.createElement('span');
1228
- const element = this.valueElement.createChild('span');
1229
- element.textContent = i18nString(UIStrings.dots);
1230
- element.classList.add('object-value-calculate-value-button');
1231
- UI.Tooltip.Tooltip.install(element, i18nString(UIStrings.invokePropertyGetter));
1232
- const getter = this.property.property.getter;
1233
- element.addEventListener('click', (event: Event) => {
1234
- event.consume();
1235
- const invokeGetter = `
1236
- function invokeGetter(getter) {
1237
- return Reflect.apply(getter, this, []);
1238
- }`;
1239
- // Also passing a string instead of a Function to avoid coverage implementation messing with it.
1240
- void this.property.parent
1241
- ?.object
1242
- // @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
1243
- ?.callFunction(invokeGetter, [SDK.RemoteObject.RemoteObject.toCallArgument(getter)])
1244
- .then(this.onInvokeGetterClick.bind(this));
1245
- }, false);
1246
- } else {
1247
- this.valueElement = document.createElement('span');
1248
- this.valueElement.classList.add('object-value-unavailable');
1249
- this.valueElement.textContent = i18nString(UIStrings.valueUnavailable);
1250
- UI.Tooltip.Tooltip.install(this.valueElement, i18nString(UIStrings.valueNotAccessibleToTheDebugger));
1251
- }
1252
-
1253
- const valueText = this.valueElement.textContent;
1254
- if (this.property.object && valueText && !this.property.property.wasThrown) {
1255
- this.expandedValueElement =
1256
- this.createExpandedValueElement(this.property.object, this.property.property.synthetic);
1257
- }
1258
- this.performUpdate();
1259
- }
1260
-
1261
1244
  async #updateCompletions(expression: string, filter: string, force: boolean): Promise<void> {
1262
1245
  const suggestions = await TextEditor.JavaScript.completeInContext(expression, filter, force);
1263
1246
  this.#completions = suggestions.map(v => v.text);
@@ -1266,18 +1249,27 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1266
1249
 
1267
1250
  performUpdate(): void {
1268
1251
  const input: TreeElementViewInput = {
1269
- expandedValueElement: this.expandedValueElement,
1270
1252
  expanded: this.expanded,
1271
1253
  editing: this.#editing,
1272
1254
  editingEnded: this.editingEnded.bind(this),
1273
1255
  editingCommitted: this.editingCommitted.bind(this),
1274
1256
  node: this.property,
1275
- nameElement: this.nameElement,
1276
- valueElement: this.valueElement,
1257
+ linkifier: this.linkifier,
1277
1258
  completions: this.#editing ? this.#completions : [],
1278
1259
  onAutoComplete: this.#updateCompletions.bind(this),
1260
+ invokeGetter: this.onInvokeGetterClick.bind(this),
1261
+ startEditing: this.startEditing.bind(this),
1279
1262
  };
1280
- this.#view(input, {}, this.listItemElement);
1263
+ const that = this;
1264
+ const output: TreeElementViewOutput = {
1265
+ set nameElement(e: Element|undefined) {
1266
+ that.#nameElement = e;
1267
+ },
1268
+ set valueElement(e: Element|undefined) {
1269
+ that.#valueElement = e;
1270
+ },
1271
+ };
1272
+ this.#view(input, output, this.listItemElement);
1281
1273
  }
1282
1274
 
1283
1275
  getContextMenu(event: Event): UI.ContextMenu.ContextMenu {
@@ -1299,9 +1291,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1299
1291
  i18nString(UIStrings.copyValue), copyValueHandler, {jslogContext: 'copy-value'});
1300
1292
  }
1301
1293
  }
1302
- if (!this.property.property.synthetic && this.nameElement?.title) {
1294
+ if (!this.property.property.synthetic && this.property.path) {
1303
1295
  const copyPathHandler = Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText.bind(
1304
- Host.InspectorFrontendHost.InspectorFrontendHostInstance, this.nameElement.title);
1296
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance, this.property.path);
1305
1297
  contextMenu.clipboardSection().appendItem(
1306
1298
  i18nString(UIStrings.copyPropertyPath), copyPathHandler, {jslogContext: 'copy-property-path'});
1307
1299
  }
@@ -1375,7 +1367,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1375
1367
  void parent.onpopulate();
1376
1368
  }
1377
1369
  } else {
1378
- this.update();
1370
+ this.performUpdate();
1379
1371
  }
1380
1372
  return;
1381
1373
  }
@@ -1385,7 +1377,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1385
1377
  expression ? parentObject.setPropertyValue(property, expression) : parentObject.deleteProperty(property);
1386
1378
  const error = await errorPromise;
1387
1379
  if (error) {
1388
- this.update();
1380
+ this.performUpdate();
1389
1381
  return;
1390
1382
  }
1391
1383
 
@@ -1409,14 +1401,23 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1409
1401
  this.property.removeChildren();
1410
1402
  }
1411
1403
 
1412
- private onInvokeGetterClick(result: SDK.RemoteObject.CallFunctionResult): void {
1413
- if (!result.object) {
1404
+ async onInvokeGetterClick(getter: SDK.RemoteObject.RemoteObject): Promise<void> {
1405
+ const invokeGetter = `
1406
+ function invokeGetter(getter) {
1407
+ return Reflect.apply(getter, this, []);
1408
+ }`;
1409
+ // Also passing a string instead of a Function to avoid coverage implementation messing with it.
1410
+ const result = await this.property.parent
1411
+ ?.object
1412
+ // @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
1413
+ ?.callFunction(invokeGetter, [SDK.RemoteObject.RemoteObject.toCallArgument(getter)]);
1414
+ if (!result?.object) {
1414
1415
  return;
1415
1416
  }
1416
1417
  this.property.property.value = result.object;
1417
1418
  this.property.property.wasThrown = result.wasThrown || false;
1418
1419
 
1419
- this.update();
1420
+ this.performUpdate();
1420
1421
  this.invalidateChildren();
1421
1422
  this.updateExpandable();
1422
1423
  }
@@ -1432,7 +1433,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1432
1433
  }
1433
1434
 
1434
1435
  path(): string {
1435
- return this.nameElement.title;
1436
+ return this.property.path;
1436
1437
  }
1437
1438
  }
1438
1439
 
@@ -17,6 +17,7 @@ import * as TextUtils from '../../../../models/text_utils/text_utils.js';
17
17
  import type * as Trace from '../../../../models/trace/trace.js';
18
18
  import * as Workspace from '../../../../models/workspace/workspace.js';
19
19
  import type * as IconButton from '../../../components/icon_button/icon_button.js';
20
+ import * as UIHelpers from '../../../helpers/helpers.js';
20
21
  import {html, render} from '../../../lit/lit.js';
21
22
  import * as VisualLogging from '../../../visual_logging/visual_logging.js';
22
23
  import * as UI from '../../legacy.js';
@@ -920,7 +921,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
920
921
  section: 'reveal',
921
922
  title: UI.UIUtils.openLinkExternallyLabel(),
922
923
  jslogContext: 'open-in-new-tab',
923
- handler: () => UI.UIUtils.openInNewTab(url),
924
+ handler: () => UIHelpers.openInNewTab(url),
924
925
  });
925
926
  result.push({
926
927
  section: 'clipboard',
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../config/typescript/tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "allowUmdGlobalAccess": true,
5
+ "outDir": "ignored",
6
+ "target": "ES2023",
7
+ "lib": [
8
+ "ES2023",
9
+ "ES2024.Promise",
10
+ "ESNext.Iterator",
11
+ "ESNext.Collection",
12
+ "ESNext.Array"
13
+ ]
14
+ },
15
+ "references": [{ "path": "../front_end/tsconfig.json" }]
16
+ }
package/package.json CHANGED
@@ -46,7 +46,7 @@
46
46
  "@types/glob": "7.2.0",
47
47
  "@types/karma-chai-sinon": "0.1.20",
48
48
  "@types/mocha": "10.0.10",
49
- "@types/node": "22.10.7",
49
+ "@types/node": "24.10.0",
50
50
  "@types/sinon": "17.0.4",
51
51
  "@types/webidl2": "24.4.3",
52
52
  "@types/yargs": "17.0.33",
@@ -103,5 +103,5 @@
103
103
  "flat-cache": "6.1.12"
104
104
  }
105
105
  },
106
- "version": "1.0.1544076"
106
+ "version": "1.0.1545096"
107
107
  }
@@ -1,55 +0,0 @@
1
- // Copyright 2019 The Chromium Authors
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import type * as Platform from '../platform/platform.js';
6
-
7
- export abstract class Linkifier {
8
- abstract linkify(object: Object, options?: Options): Node;
9
-
10
- static async linkify(object: Object|null, options?: Options): Promise<Node> {
11
- if (!object) {
12
- throw new Error('Can\'t linkify ' + object);
13
- }
14
- const linkifierRegistration = getApplicableRegisteredlinkifiers(object)[0];
15
- if (!linkifierRegistration) {
16
- throw new Error('No linkifiers registered for object ' + object);
17
- }
18
- const linkifier = await linkifierRegistration.loadLinkifier();
19
- return linkifier.linkify(object, options);
20
- }
21
- }
22
- export interface Options {
23
- tooltip?: string;
24
- preventKeyboardFocus?: boolean;
25
- textContent?: string;
26
- // Dynamic links include hyperlinks and anchorlinks -- links that navigate the content.
27
- isDynamicLink?: boolean;
28
- }
29
-
30
- const registeredLinkifiers: LinkifierRegistration[] = [];
31
-
32
- export function registerLinkifier(registration: LinkifierRegistration): void {
33
- registeredLinkifiers.push(registration);
34
- }
35
-
36
- export function getApplicableRegisteredlinkifiers(object: Object): LinkifierRegistration[] {
37
- return registeredLinkifiers.filter(isLinkifierApplicableToContextTypes);
38
-
39
- function isLinkifierApplicableToContextTypes(linkifierRegistration: LinkifierRegistration): boolean {
40
- if (!linkifierRegistration.contextTypes) {
41
- return true;
42
- }
43
- for (const contextType of linkifierRegistration.contextTypes()) {
44
- if (object instanceof contextType) {
45
- return true;
46
- }
47
- }
48
- return false;
49
- }
50
- }
51
-
52
- export interface LinkifierRegistration {
53
- loadLinkifier: () => Promise<Linkifier>;
54
- contextTypes?: () => Array<Platform.Constructor.Constructor<unknown>>;
55
- }