chrome-devtools-frontend 1.0.1662289 → 1.0.1662965

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/.agents/skills/devtools-unicode-escaping/SKILL.md +64 -0
  2. package/.agents/skills/migrate-chromium-test/SKILL.md +29 -4
  3. package/front_end/core/common/SettingRegistration.ts +0 -5
  4. package/front_end/core/common/Settings.ts +69 -3
  5. package/front_end/core/platform/StringUtilities.ts +38 -6
  6. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +0 -10
  7. package/front_end/core/sdk/StorageBucketsModel.ts +0 -10
  8. package/front_end/core/sdk/sdk-meta.ts +0 -1
  9. package/front_end/entrypoints/inspector_main/OutermostTargetSelector.ts +0 -13
  10. package/front_end/entrypoints/inspector_main/RenderingOptions.ts +8 -3
  11. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +3 -3
  12. package/front_end/entrypoints/main/MainImpl.ts +7 -2
  13. package/front_end/foundation/Universe.ts +16 -0
  14. package/front_end/generated/InspectorBackendCommands.ts +2 -14
  15. package/front_end/generated/protocol-mapping.d.ts +0 -53
  16. package/front_end/generated/protocol-proxy-api.d.ts +0 -46
  17. package/front_end/generated/protocol.ts +0 -148
  18. package/front_end/models/ai_assistance/AiAgent2.ts +3 -3
  19. package/front_end/models/ai_assistance/AiConversation.ts +21 -10
  20. package/front_end/models/ai_assistance/AiHistoryStorage.ts +21 -10
  21. package/front_end/models/ai_assistance/ChangeManager.ts +2 -2
  22. package/front_end/models/ai_assistance/ExtensionScope.ts +6 -2
  23. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +1 -1
  24. package/front_end/models/ai_assistance/agents/AiAgent.ts +8 -1
  25. package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
  26. package/front_end/models/badges/UserBadges.ts +31 -17
  27. package/front_end/models/bindings/NetworkProject.ts +16 -4
  28. package/front_end/models/emulation/DeviceModeModel.ts +67 -5
  29. package/front_end/models/extensions/RecorderPluginManager.ts +10 -6
  30. package/front_end/models/har/Log.snapshot.txt +193 -0
  31. package/front_end/models/har/Log.ts +3 -2
  32. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +7 -5
  33. package/front_end/models/source_map_scopes/NamesResolver.ts +36 -30
  34. package/front_end/models/stack_trace/StackTrace.ts +17 -0
  35. package/front_end/panels/application/IndexedDBModel.ts +0 -10
  36. package/front_end/panels/application/IndexedDBViews.ts +240 -164
  37. package/front_end/panels/application/SharedStorageModel.ts +0 -10
  38. package/front_end/panels/application/components/AdsView.ts +23 -0
  39. package/front_end/panels/application/components/SharedStorageAccessGrid.ts +1 -1
  40. package/front_end/panels/application/components/adsView.css +21 -1
  41. package/front_end/panels/application/indexedDBViews.css +1 -1
  42. package/front_end/panels/network/NetworkDataGridNode.ts +43 -1
  43. package/front_end/panels/network/RequestInitiatorView.ts +24 -2
  44. package/front_end/panels/network/networkLogView.css +5 -0
  45. package/front_end/panels/network/requestInitiatorViewTree.css +5 -0
  46. package/front_end/panels/profiler/HeapProfileView.ts +198 -79
  47. package/front_end/panels/recorder/README.md +1 -2
  48. package/front_end/panels/recorder/RecorderPanel.ts +1749 -17
  49. package/front_end/panels/recorder/recorder.ts +0 -2
  50. package/front_end/panels/settings/AISettingsTab.ts +13 -0
  51. package/front_end/third_party/chromium/README.chromium +1 -1
  52. package/front_end/ui/components/spinners/Spinner.ts +29 -32
  53. package/front_end/ui/components/spinners/spinner.css +32 -84
  54. package/front_end/ui/legacy/Treeoutline.ts +14 -6
  55. package/front_end/ui/legacy/UIUtils.ts +25 -10
  56. package/front_end/ui/legacy/Widget.ts +17 -10
  57. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +36 -7
  58. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +63 -68
  59. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +1 -1
  60. package/front_end/ui/legacy/components/object_ui/objectValue.css +2 -1
  61. package/front_end/ui/legacy/inspectorCommon.css +4 -4
  62. package/front_end/ui/lit/lit.ts +1 -0
  63. package/front_end/ui/lit/render.ts +44 -10
  64. package/front_end/ui/lit/strip-whitespace.ts +23 -2
  65. package/package.json +1 -1
  66. package/front_end/panels/recorder/RecorderController.ts +0 -1759
  67. /package/front_end/panels/recorder/{recorderController.css → recorderPanel.css} +0 -0
@@ -48,9 +48,10 @@ import {CustomPreviewComponent} from './CustomPreviewComponent.js';
48
48
  import {JavaScriptREPL} from './JavaScriptREPL.js';
49
49
  import objectPropertiesSectionStyles from './objectPropertiesSection.css.js';
50
50
  import objectValueStyles from './objectValue.css.js';
51
- import {RemoteObjectPreviewFormatter, renderNodeTitle} from './RemoteObjectPreviewFormatter.js';
51
+ import {RemoteObjectPreviewFormatter, renderNodeTitle, renderTrustedType} from './RemoteObjectPreviewFormatter.js';
52
52
 
53
53
  export {objectPropertiesSectionStyles, objectValueStyles};
54
+
54
55
  const {widget} = UI.Widget;
55
56
  const {ref, repeat, ifDefined, classMap, until} = Directives;
56
57
  const UIStrings = {
@@ -259,8 +260,8 @@ export class ObjectTreeExpansionTracker {
259
260
  if (!(node instanceof ObjectTreeNode)) {
260
261
  return undefined;
261
262
  }
262
- return node.parent?.children?.internalProperties?.find(
263
- p => p.name === '[[Prototype]]' && p.children?.properties?.includes(node));
263
+ return node.parent?.children?.internalProperties?.find(p => p.name === '[[Prototype]]' &&
264
+ p.children?.properties?.includes(node));
264
265
  }
265
266
 
266
267
  static #keyType(node: ObjectTreeNodeBase): keyof NodeChildren|null {
@@ -572,8 +573,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
572
573
  }
573
574
 
574
575
  const {properties: objectProperties, internalProperties: objectInternalProperties} =
575
- await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(
576
- this.object, true /* generatePreview */, true /* nonIndexedPropertiesOnly */);
576
+ await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(this.object, true /* generatePreview */,
577
+ true /* nonIndexedPropertiesOnly */);
577
578
 
578
579
  const properties = objectProperties?.map(p => new ObjectTreeNode(p, effectiveParent, {
579
580
  readOnly: this.readOnly,
@@ -647,8 +648,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
647
648
  for (const property of properties) {
648
649
  if (property.property.isOwn) {
649
650
  if (property.property.getter) {
650
- const getterProperty = new SDK.RemoteObject.RemoteObjectProperty(
651
- 'get ' + property.property.name, property.property.getter, false);
651
+ const getterProperty = new SDK.RemoteObject.RemoteObjectProperty('get ' + property.property.name,
652
+ property.property.getter, false);
652
653
  gettersAndSetters.push(new ObjectTreeNode(getterProperty, property.parent, {
653
654
  propertiesMode: property.propertiesMode,
654
655
  readOnly: property.readOnly,
@@ -656,8 +657,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
656
657
  }));
657
658
  }
658
659
  if (property.property.setter) {
659
- const setterProperty = new SDK.RemoteObject.RemoteObjectProperty(
660
- 'set ' + property.property.name, property.property.setter, false);
660
+ const setterProperty = new SDK.RemoteObject.RemoteObjectProperty('set ' + property.property.name,
661
+ property.property.setter, false);
661
662
  gettersAndSetters.push(new ObjectTreeNode(setterProperty, property.parent, {
662
663
  propertiesMode: property.propertiesMode,
663
664
  readOnly: property.readOnly,
@@ -706,9 +707,8 @@ interface ArrayGroupRange {
706
707
  export class ArrayGroupTreeNode extends ObjectTreeNodeBase {
707
708
  readonly #object: SDK.RemoteObject.RemoteObject;
708
709
  readonly #range: ArrayGroupRange;
709
- constructor(
710
- object: SDK.RemoteObject.RemoteObject, range: ArrayGroupRange, parent: ObjectTreeNodeBase,
711
- options: ObjectTreeOptions) {
710
+ constructor(object: SDK.RemoteObject.RemoteObject, range: ArrayGroupRange, parent: ObjectTreeNodeBase,
711
+ options: ObjectTreeOptions) {
712
712
  super(parent, options);
713
713
  this.#object = object;
714
714
  this.#range = range;
@@ -879,9 +879,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
879
879
  titleElement: Element;
880
880
  skipProtoInternal?: boolean;
881
881
 
882
- constructor(
883
- object: SDK.RemoteObject.RemoteObject, title?: string|Element|null, linkifier?: Components.Linkifier.Linkifier,
884
- showOverflow?: boolean, editable = true) {
882
+ constructor(object: SDK.RemoteObject.RemoteObject, title?: string|Element|null,
883
+ linkifier?: Components.Linkifier.Linkifier, showOverflow?: boolean, editable = true) {
885
884
  super();
886
885
  this.root = new ObjectTree(object, {
887
886
  readOnly: !editable,
@@ -896,7 +895,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
896
895
  this.appendChild(this.#objectTreeElement);
897
896
  if (typeof title === 'string' || !title) {
898
897
  this.titleElement = this.element.createChild('span');
899
- this.titleElement.textContent = title || '';
898
+ this.titleElement.textContent = title ? Platform.StringUtilities.escapeUnicodeAsText(title) : '';
900
899
  } else {
901
900
  this.titleElement = title;
902
901
  this.element.appendChild(title);
@@ -910,9 +909,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
910
909
  this.rootElement().childrenListElement.classList.add('source-code', 'object-properties-section');
911
910
  }
912
911
 
913
- static defaultObjectPresentation(
914
- object: SDK.RemoteObject.RemoteObject, linkifier?: Components.Linkifier.Linkifier, skipProto?: boolean,
915
- readOnly?: boolean): Element {
912
+ static defaultObjectPresentation(object: SDK.RemoteObject.RemoteObject, linkifier?: Components.Linkifier.Linkifier,
913
+ skipProto?: boolean, readOnly?: boolean): Element {
916
914
  const objectPropertiesSection =
917
915
  ObjectPropertiesSection.defaultObjectPropertiesSection(object, linkifier, skipProto, readOnly);
918
916
  if (!object.hasChildren) {
@@ -921,9 +919,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
921
919
  return objectPropertiesSection.element;
922
920
  }
923
921
 
924
- static defaultObjectPropertiesSection(
925
- object: SDK.RemoteObject.RemoteObject, linkifier?: Components.Linkifier.Linkifier, skipProto?: boolean,
926
- readOnly?: boolean): ObjectPropertiesSection {
922
+ static defaultObjectPropertiesSection(object: SDK.RemoteObject.RemoteObject,
923
+ linkifier?: Components.Linkifier.Linkifier, skipProto?: boolean,
924
+ readOnly?: boolean): ObjectPropertiesSection {
927
925
  const titleElement = document.createElement('span');
928
926
  titleElement.classList.add('source-code');
929
927
  const shadowRoot = UI.UIUtils.createShadowRootWithCoreStyles(titleElement, {cssFile: objectValueStyles});
@@ -1001,24 +999,25 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1001
999
  if (name === null) {
1002
1000
  return element;
1003
1001
  }
1004
- if (/^\s|\s$|^$|\n/.test(name)) {
1005
- element.textContent = `"${name.replace(/\n/g, '\u21B5')}"`;
1002
+ const escapedName = Platform.StringUtilities.escapeUnicodeAsText(name);
1003
+ if (/^\s|\s$|^$|\n/.test(escapedName)) {
1004
+ element.textContent = `"${escapedName.replace(/\n/g, '\u21B5')}"`;
1006
1005
  return element;
1007
1006
  }
1008
1007
  if (isPrivate) {
1009
1008
  const privatePropertyHash = document.createElement('span');
1010
1009
  privatePropertyHash.classList.add('private-property-hash');
1011
- privatePropertyHash.textContent = name[0];
1010
+ privatePropertyHash.textContent = escapedName[0];
1012
1011
  element.appendChild(privatePropertyHash);
1013
- element.appendChild(document.createTextNode(name.substring(1)));
1012
+ element.appendChild(document.createTextNode(escapedName.substring(1)));
1014
1013
  return element;
1015
1014
  }
1016
- element.textContent = name;
1015
+ element.textContent = escapedName;
1017
1016
  return element;
1018
1017
  }
1019
1018
 
1020
- static valueElementForFunctionDescription(
1021
- description?: string, includePreview?: boolean, defaultName?: string, className?: string): LitTemplate {
1019
+ static valueElementForFunctionDescription(description?: string, includePreview?: boolean, defaultName?: string,
1020
+ className?: string): LitTemplate {
1022
1021
  const contents =
1023
1022
  (description: string, defaultName: string): {prefix: string, abbreviation: string, body: string} => {
1024
1023
  const text = description.replace(/^function [gs]et /, 'function ')
@@ -1095,17 +1094,17 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1095
1094
  }
1096
1095
  }
1097
1096
 
1098
- static createPropertyValueWithCustomSupport(
1099
- value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
1100
- linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty?: boolean, variableName?: string,
1101
- includeNullOrUndefined?: boolean): HTMLElement {
1097
+ static createPropertyValueWithCustomSupport(value: SDK.RemoteObject.RemoteObject, wasThrown: boolean,
1098
+ showPreview: boolean, linkifier?: Components.Linkifier.Linkifier,
1099
+ isSyntheticProperty?: boolean, variableName?: string,
1100
+ includeNullOrUndefined?: boolean): HTMLElement {
1102
1101
  if (value.customPreview()) {
1103
1102
  const result = (new CustomPreviewComponent(value)).element;
1104
1103
  result.classList.add('object-properties-section-custom-section');
1105
1104
  return result;
1106
1105
  }
1107
- return ObjectPropertiesSection.createPropertyValue(
1108
- value, wasThrown, showPreview, linkifier, isSyntheticProperty, variableName, includeNullOrUndefined);
1106
+ return ObjectPropertiesSection.createPropertyValue(value, wasThrown, showPreview, linkifier, isSyntheticProperty,
1107
+ variableName, includeNullOrUndefined);
1109
1108
  }
1110
1109
 
1111
1110
  static getMemoryIcon(object: SDK.RemoteObject.RemoteObject, expression?: string): LitTemplate {
@@ -1132,10 +1131,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1132
1131
  element.appendChild(fragment);
1133
1132
  }
1134
1133
 
1135
- static createPropertyValue(
1136
- value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
1137
- linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false, variableName?: string,
1138
- includeNullOrUndefined?: boolean): HTMLElement {
1134
+ static createPropertyValue(value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
1135
+ linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false,
1136
+ variableName?: string, includeNullOrUndefined?: boolean): HTMLElement {
1139
1137
  const propertyValue = document.createDocumentFragment();
1140
1138
  const type = value.type;
1141
1139
  const subtype = value.subtype;
@@ -1149,21 +1147,20 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1149
1147
  if (rawLocation && linkifier) {
1150
1148
  return html`${linkifier.linkifyRawLocation(rawLocation, Platform.DevToolsPath.EmptyUrlString, 'value')}`;
1151
1149
  }
1152
- return html`<span class=value title=${description}>${'<' + i18nString(UIStrings.unknown) + '>'}</span>`;
1150
+ const title = description || undefined;
1151
+ return html`<span class=value title=${ifDefined(title)}>${'<' + i18nString(UIStrings.unknown) + '>'}</span>`;
1153
1152
  }
1154
1153
  if (type === 'string' && typeof description === 'string') {
1155
- const text = Platform.StringUtilities.escapeUnicode(JSON.stringify(description));
1154
+ const text = Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(description));
1156
1155
  const tooLong = description.length > maxRenderableStringLength;
1157
1156
  return html`<span class="value object-value-string" title=${ifDefined(tooLong ? undefined : description)}>${
1158
1157
  tooLong ? widget(ExpandableTextPropertyValue, {text}) : text}</span>`;
1159
1158
  }
1160
1159
  if (type === 'object' && subtype === 'trustedtype') {
1161
- const text = `${className} '${description}'`;
1160
+ const text = `${className} "${description}"`;
1162
1161
  const tooLong = text.length > maxRenderableStringLength;
1163
1162
  return html`<span class="value object-value-trustedtype" title=${ifDefined(tooLong ? undefined : text)}>${
1164
- tooLong ? widget(ExpandableTextPropertyValue, {text}) :
1165
- html`${className} <span class=object-value-string title=${description}>${
1166
- Platform.StringUtilities.escapeUnicode(JSON.stringify(description))}</span>`}</span>`;
1163
+ tooLong ? widget(ExpandableTextPropertyValue, {text}) : renderTrustedType(description, className)}</span>`;
1167
1164
  }
1168
1165
  if (type === 'function') {
1169
1166
  return ObjectPropertiesSection.valueElementForFunctionDescription(description, undefined, undefined, 'value');
@@ -1194,10 +1191,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1194
1191
 
1195
1192
  if (wasThrown) {
1196
1193
  // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
1197
- render(
1198
- html`<span class="error value">${
1199
- uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.exceptionS, {PH1: contents()})}</span>`,
1200
- propertyValue);
1194
+ render(html`<span class="error value">${
1195
+ uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.exceptionS, {PH1: contents()})}</span>`,
1196
+ propertyValue);
1201
1197
  } else {
1202
1198
  // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
1203
1199
  render(contents(), propertyValue);
@@ -1209,9 +1205,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1209
1205
  return child;
1210
1206
  }
1211
1207
 
1212
- static formatObjectAsFunction(
1213
- func: SDK.RemoteObject.RemoteObject, element: Element, linkify: boolean,
1214
- includePreview?: boolean): Promise<void> {
1208
+ static formatObjectAsFunction(func: SDK.RemoteObject.RemoteObject, element: Element, linkify: boolean,
1209
+ includePreview?: boolean): Promise<void> {
1215
1210
  return func.debuggerModel().functionDetailsPromise(func).then(didGetDetails);
1216
1211
 
1217
1212
  function didGetDetails(response: SDK.DebuggerModel.FunctionDetails|null): void {
@@ -1230,16 +1225,14 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1230
1225
  }
1231
1226
  const valueElement = document.createDocumentFragment();
1232
1227
  // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
1233
- render(
1234
- ObjectPropertiesSection.valueElementForFunctionDescription(func.description, includePreview, defaultName),
1235
- valueElement);
1228
+ render(ObjectPropertiesSection.valueElementForFunctionDescription(func.description, includePreview, defaultName),
1229
+ valueElement);
1236
1230
  element.appendChild(valueElement);
1237
1231
  }
1238
1232
  }
1239
1233
 
1240
- static isDisplayableProperty(
1241
- property: SDK.RemoteObject.RemoteObjectProperty,
1242
- parentProperty?: SDK.RemoteObject.RemoteObjectProperty): boolean {
1234
+ static isDisplayableProperty(property: SDK.RemoteObject.RemoteObjectProperty,
1235
+ parentProperty?: SDK.RemoteObject.RemoteObjectProperty): boolean {
1243
1236
  if (!parentProperty?.synthetic) {
1244
1237
  return true;
1245
1238
  }
@@ -1272,9 +1265,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
1272
1265
  i18nString(UIStrings.expandRecursively),
1273
1266
  this.#objectTreeElement.expandRecursively.bind(this.#objectTreeElement, EXPANDABLE_MAX_DEPTH),
1274
1267
  {jslogContext: 'expand-recursively'});
1275
- contextMenu.viewSection().appendItem(
1276
- i18nString(UIStrings.collapseChildren),
1277
- this.#objectTreeElement.collapseChildren.bind(this.#objectTreeElement), {jslogContext: 'collapse-children'});
1268
+ contextMenu.viewSection().appendItem(i18nString(UIStrings.collapseChildren),
1269
+ this.#objectTreeElement.collapseChildren.bind(this.#objectTreeElement),
1270
+ {jslogContext: 'collapse-children'});
1278
1271
  }
1279
1272
  void contextMenu.show();
1280
1273
  }
@@ -1321,8 +1314,9 @@ export function populateObjectTreeContextMenu(
1321
1314
 
1322
1315
  if (object.object instanceof SDK.RemoteObject.LocalJSONObject) {
1323
1316
  const {value} = object.object;
1324
- const propertyValue =
1325
- typeof value === 'object' ? Platform.StringUtilities.escapeUnicode(JSON.stringify(value, null, 2)) : value;
1317
+ const propertyValue = typeof value === 'object' ?
1318
+ Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(value, null, 2)) :
1319
+ value;
1326
1320
  const copyValueHandler = (): void => {
1327
1321
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
1328
1322
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText((propertyValue as string | undefined));
@@ -1444,8 +1438,8 @@ class RootElement extends UI.TreeOutline.TreeElement {
1444
1438
  this.removeChildren();
1445
1439
  const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
1446
1440
  const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
1447
- return await ObjectPropertyTreeElement.populate(
1448
- this, this.object, skipProto, false, this.linkifier, this.emptyPlaceholder);
1441
+ return await ObjectPropertyTreeElement.populate(this, this.object, skipProto, false, this.linkifier,
1442
+ this.emptyPlaceholder);
1449
1443
  }
1450
1444
  }
1451
1445
 
@@ -2010,8 +2004,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
2010
2004
  contextMenu.appendApplicableItems(this.property.object);
2011
2005
  if (this.property.parent?.object instanceof SDK.RemoteObject.LocalJSONObject) {
2012
2006
  const {object: {value}} = this.property;
2013
- const propertyValue =
2014
- typeof value === 'object' ? Platform.StringUtilities.escapeUnicode(JSON.stringify(value, null, 2)) : value;
2007
+ const propertyValue = typeof value === 'object' ?
2008
+ Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(value, null, 2)) :
2009
+ value;
2015
2010
  const copyValueHandler = (): void => {
2016
2011
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
2017
2012
  Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText((propertyValue as string | undefined));
@@ -2381,7 +2376,7 @@ export const EXPANDABLE_TEXT_DEFAULT_VIEW: ExpandableTextView = (input, output,
2381
2376
  data-text=${i18nString(UIStrings.copy)}
2382
2377
  jslog=${VisualLogging.action('copy').track({click: true})}
2383
2378
  ></button>
2384
- </span>`,
2379
+ </span>`,
2385
2380
  // clang-format on
2386
2381
  target);
2387
2382
  };
@@ -313,7 +313,7 @@ export function renderNodeTitle(nodeTitle: string): LitTemplate|null {
313
313
  match[3] && html`<span class=webkit-html-attribute-name>${match[3]}</span>`}`;
314
314
  }
315
315
 
316
- export function renderTrustedType(description: string, className: string): LitTemplate {
316
+ export function renderTrustedType(description: string, className: string|null): LitTemplate {
317
317
  return html`${className} <span class=object-value-string title=${description}>"${
318
318
  description.replace(/\n/g, '\u21B5')}"</span>`;
319
319
  }
@@ -41,7 +41,7 @@
41
41
  .object-value-regexp,
42
42
  .object-value-symbol {
43
43
  white-space: pre;
44
- unicode-bidi: -webkit-isolate;
44
+ unicode-bidi: isolate;
45
45
  color: var(--sys-color-token-property-special);
46
46
  }
47
47
 
@@ -90,6 +90,7 @@
90
90
  .name {
91
91
  color: var(--sys-color-token-tag);
92
92
  flex-shrink: 0;
93
+ unicode-bidi: isolate;
93
94
  }
94
95
 
95
96
  .object-properties-preview .name {
@@ -1221,7 +1221,7 @@ devtools-toolbar {
1221
1221
 
1222
1222
  .webkit-html-text-node {
1223
1223
  color: var(--text-primary);
1224
- unicode-bidi: -webkit-isolate;
1224
+ unicode-bidi: isolate;
1225
1225
  }
1226
1226
 
1227
1227
  .webkit-html-entity-value {
@@ -1229,7 +1229,7 @@ devtools-toolbar {
1229
1229
  /* See: crbug.com/1152736 for color variable migration. */
1230
1230
  /* stylelint-disable-next-line plugin/use_theme_colors */
1231
1231
  background-color: rgb(0 0 0 / 15%);
1232
- unicode-bidi: -webkit-isolate;
1232
+ unicode-bidi: isolate;
1233
1233
  }
1234
1234
 
1235
1235
  .webkit-html-doctype {
@@ -1242,13 +1242,13 @@ devtools-toolbar {
1242
1242
  .webkit-html-attribute-name {
1243
1243
  /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
1244
1244
  color: var(--sys-color-token-attribute);
1245
- unicode-bidi: -webkit-isolate;
1245
+ unicode-bidi: isolate;
1246
1246
  }
1247
1247
 
1248
1248
  .webkit-html-attribute-value {
1249
1249
  /* Keep this in sync with view-source.css (.webkit-html-attribute-value) */
1250
1250
  color: var(--sys-color-token-attribute-value);
1251
- unicode-bidi: -webkit-isolate;
1251
+ unicode-bidi: isolate;
1252
1252
  word-break: break-all;
1253
1253
  }
1254
1254
 
@@ -27,6 +27,7 @@ export {
27
27
  } from './render.js';
28
28
  export {
29
29
  html,
30
+ isLitDirective,
30
31
  } from './strip-whitespace.js';
31
32
 
32
33
  export type LitTemplate = Lit.TemplateResult|typeof Lit.nothing;
@@ -15,6 +15,13 @@ export interface RenderOptions extends Lit.RenderOptions {
15
15
 
16
16
  const renderOptions = new WeakMap<HTMLElement|DocumentFragment, RenderOptions|undefined>();
17
17
 
18
+ interface ListenerEntry {
19
+ listener: EventListenerOrEventListenerObject;
20
+ wrapper: EventListener;
21
+ }
22
+
23
+ const containerListeners = new WeakMap<HTMLElement|DocumentFragment, Map<string, ListenerEntry>>();
24
+
18
25
  export function render(template: unknown, container: HTMLElement|DocumentFragment, options?: RenderOptions):
19
26
  ReturnType<typeof Lit.render> {
20
27
  const host = container instanceof ShadowRoot ? container.host : container;
@@ -62,22 +69,49 @@ export function render(template: unknown, container: HTMLElement|DocumentFragmen
62
69
  }
63
70
  }
64
71
 
65
- const oldListeners = renderOptions.get(container)?.container?.listeners;
66
- const newListeners = options?.container?.listeners;
67
- if (oldListeners) {
68
- for (const [name, listener] of Object.entries(oldListeners)) {
69
- if (newListeners?.[name] !== listener) {
70
- host.removeEventListener(name, listener);
71
- }
72
- }
72
+ let listenersMap = containerListeners.get(container);
73
+ if (!listenersMap) {
74
+ listenersMap = new Map();
75
+ containerListeners.set(container, listenersMap);
73
76
  }
77
+
78
+ const newListeners = options?.container?.listeners;
74
79
  if (newListeners) {
75
80
  for (const [name, listener] of Object.entries(newListeners)) {
76
- if (oldListeners?.[name] !== listener) {
77
- host.addEventListener(name, listener);
81
+ const entry = listenersMap.get(name);
82
+ if (entry) {
83
+ entry.listener = listener;
84
+ } else {
85
+ let currentListener = listener;
86
+ const newEntry: ListenerEntry = {
87
+ get listener() {
88
+ return currentListener;
89
+ },
90
+ set listener(val: EventListenerOrEventListenerObject) {
91
+ currentListener = val;
92
+ },
93
+ wrapper: (event: Event) => {
94
+ if (typeof currentListener === 'function') {
95
+ return currentListener.call(host, event);
96
+ }
97
+ if (currentListener && 'handleEvent' in currentListener) {
98
+ return currentListener.handleEvent(event);
99
+ }
100
+ }
101
+ };
102
+ listenersMap.set(name, newEntry);
103
+ host.addEventListener(name, newEntry.wrapper);
78
104
  }
79
105
  }
80
106
  }
107
+
108
+ // Remove old listeners that are no longer present
109
+ for (const [name, entry] of listenersMap.entries()) {
110
+ if (!newListeners || !(name in newListeners)) {
111
+ host.removeEventListener(name, entry.wrapper);
112
+ listenersMap.delete(name);
113
+ }
114
+ }
81
115
  renderOptions.set(container, options);
82
116
  return Lit.render(template, container, options);
83
117
  }
@@ -1,11 +1,16 @@
1
- // Copyright 2025 The Chromium Authors
1
+ // Copyright 2026 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
+ import * as Platform from '../../core/platform/platform.js';
5
6
  import * as Lit from '../../third_party/lit/lit.js';
6
7
 
7
8
  const templates = new WeakMap<TemplateStringsArray, TemplateStringsArray>();
8
9
 
10
+ export function isLitDirective(value: unknown): value is {values: unknown[]} {
11
+ return Boolean(typeof value === 'object' && value && '_$litDirective$' in value && 'values' in value);
12
+ }
13
+
9
14
  export function html(strings: TemplateStringsArray, ...values: unknown[]): Lit.TemplateResult {
10
15
  let stripped = templates.get(strings);
11
16
  if (!stripped) {
@@ -16,7 +21,23 @@ export function html(strings: TemplateStringsArray, ...values: unknown[]): Lit.T
16
21
  }
17
22
  }
18
23
  templates.set(strings, stripped);
19
- return Lit.html(stripped, ...values);
24
+
25
+ const escapeValue = (val: unknown): unknown => {
26
+ if (typeof val === 'string') {
27
+ return Platform.StringUtilities.safeEscapeUnicode(val);
28
+ }
29
+ if (Array.isArray(val)) {
30
+ return val.map(escapeValue);
31
+ }
32
+ if (isLitDirective(val)) {
33
+ val.values = val.values.map(escapeValue);
34
+ return val;
35
+ }
36
+ return val;
37
+ };
38
+ const escapedValues = values.map(escapeValue);
39
+
40
+ return Lit.html(stripped, ...escapedValues);
20
41
  }
21
42
 
22
43
  function strip(strings: TemplateStringsArray): TemplateStringsArray {
package/package.json CHANGED
@@ -92,5 +92,5 @@
92
92
  "webidl2": "24.5.0",
93
93
  "yargs": "17.7.2"
94
94
  },
95
- "version": "1.0.1662289"
95
+ "version": "1.0.1662965"
96
96
  }