chrome-devtools-frontend 1.0.1643855 → 1.0.1646286

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 (95) hide show
  1. package/.agents/skills/devtools-source-maps/SKILL.md +124 -0
  2. package/docs/README.md +1 -0
  3. package/docs/using_source_maps.md +159 -0
  4. package/front_end/core/host/AidaClientTypes.ts +2 -0
  5. package/front_end/core/host/UserMetrics.ts +5 -3
  6. package/front_end/core/root/Runtime.ts +10 -0
  7. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
  8. package/front_end/core/sdk/DebuggerModel.ts +7 -9
  9. package/front_end/core/sdk/NetworkRequest.ts +0 -25
  10. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
  11. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  12. package/front_end/generated/SupportedCSSProperties.js +79 -2
  13. package/front_end/generated/protocol.ts +0 -5
  14. package/front_end/models/ai_assistance/AiAgent2.ts +52 -15
  15. package/front_end/models/ai_assistance/AiConversation.ts +4 -2
  16. package/front_end/models/ai_assistance/AiOrigins.ts +63 -2
  17. package/front_end/models/ai_assistance/README.md +20 -8
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  19. package/front_end/models/ai_assistance/agents/FileAgent.ts +9 -42
  20. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +2 -2
  21. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -133
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +25 -2
  23. package/front_end/models/ai_assistance/agents/README.md +64 -0
  24. package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
  25. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  26. package/front_end/models/ai_assistance/contexts/FileContext.ts +45 -0
  27. package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +48 -0
  28. package/front_end/models/ai_assistance/contexts/RequestContext.ts +116 -0
  29. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -1
  30. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +9 -12
  31. package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
  32. package/front_end/models/ai_assistance/tools/README.md +45 -0
  33. package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
  34. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
  35. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
  36. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
  37. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
  38. package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
  39. package/front_end/models/trace/Styles.ts +29 -7
  40. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
  41. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
  42. package/front_end/models/trace/helpers/Timing.ts +10 -0
  43. package/front_end/models/trace/types/TraceEvents.ts +22 -2
  44. package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
  45. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -15
  46. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  47. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
  48. package/front_end/panels/application/ApplicationPanelSidebar.ts +69 -0
  49. package/front_end/panels/application/ServiceWorkersView.ts +2 -2
  50. package/front_end/panels/application/WebMCPView.ts +40 -71
  51. package/front_end/panels/application/components/AdsView.ts +31 -28
  52. package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
  53. package/front_end/panels/application/components/adsView.css +6 -0
  54. package/front_end/panels/common/ExtensionServer.ts +5 -0
  55. package/front_end/panels/console/ConsoleView.ts +6 -1
  56. package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
  57. package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
  58. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
  59. package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
  60. package/front_end/panels/elements/PropertyRenderer.ts +0 -1
  61. package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
  62. package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
  63. package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
  64. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
  65. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
  66. package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
  67. package/front_end/panels/network/NetworkLogView.ts +34 -7
  68. package/front_end/panels/profiler/HeapProfileView.ts +0 -1
  69. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
  70. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  71. package/front_end/panels/profiler/IsolateSelector.ts +4 -2
  72. package/front_end/panels/profiler/ProfileLauncherView.ts +194 -126
  73. package/front_end/panels/profiler/ProfilesPanel.ts +1 -3
  74. package/front_end/panels/settings/components/SyncSection.ts +1 -1
  75. package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
  76. package/front_end/panels/timeline/TimelinePanel.ts +7 -0
  77. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
  78. package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
  79. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
  80. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
  81. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
  82. package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
  83. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
  84. package/front_end/third_party/chromium/README.chromium +1 -1
  85. package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
  86. package/front_end/ui/kit/link/Link.ts +16 -2
  87. package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
  88. package/front_end/ui/legacy/InspectorView.ts +4 -1
  89. package/front_end/ui/legacy/PlusButton.ts +6 -1
  90. package/front_end/ui/legacy/Widget.ts +19 -1
  91. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
  92. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
  93. package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
  94. package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
  95. package/package.json +1 -1
@@ -34,7 +34,6 @@
34
34
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
35
  */
36
36
 
37
- import type {Chrome} from '../../../extension-api/ExtensionAPI.js';
38
37
  import * as Common from '../../core/common/common.js';
39
38
  import * as Host from '../../core/host/host.js';
40
39
  import * as i18n from '../../core/i18n/i18n.js';
@@ -45,7 +44,6 @@ import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js'
45
44
  import * as Bindings from '../../models/bindings/bindings.js';
46
45
  import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
47
46
  import * as Logs from '../../models/logs/logs.js';
48
- import * as StackTrace from '../../models/stack_trace/stack_trace.js';
49
47
  import * as TextUtils from '../../models/text_utils/text_utils.js';
50
48
  import * as Workspace from '../../models/workspace/workspace.js';
51
49
  import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
@@ -66,6 +64,7 @@ import {format, updateStyle} from './ConsoleFormat.js';
66
64
  import {ConsoleInsightTeaser} from './ConsoleInsightTeaser.js';
67
65
  import consoleViewStyles from './consoleView.css.js';
68
66
  import type {ConsoleViewportElement} from './ConsoleViewport.js';
67
+ import {SymbolizedErrorWidget} from './SymbolizedErrorWidget.js';
69
68
 
70
69
  const UIStrings = {
71
70
  /**
@@ -449,7 +448,14 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
449
448
  if (this.message.parameters?.length === 1) {
450
449
  const parameter = this.message.parameters[0];
451
450
  if (typeof parameter !== 'string' && parameter.type === 'string') {
452
- messageElement = this.tryFormatAsError((parameter.value as string));
451
+ const value = parameter.value as string;
452
+ const runtimeModel = this.message.runtimeModel();
453
+ if (runtimeModel && Bindings.SymbolizedError.isErrorLike(value)) {
454
+ const remoteObj = parameter instanceof SDK.RemoteObject.RemoteObject ?
455
+ parameter :
456
+ runtimeModel.createRemoteObject(parameter);
457
+ messageElement = this.renderSymbolizedError(remoteObj);
458
+ }
453
459
  }
454
460
  }
455
461
  const args = this.message.parameters || [messageText];
@@ -570,23 +576,21 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
570
576
  const userMetric = this.#getLinkifierMetric();
571
577
  if (stackFrameWithBreakpoint) {
572
578
  return this.linkifier.maybeLinkifyConsoleCallFrame(runtimeModel.target(), stackFrameWithBreakpoint, {
573
- inlineFrameIndex: 0,
574
579
  revealBreakpoint: true,
575
580
  userMetric,
576
581
  });
577
582
  }
578
583
  if (scriptId) {
579
- return this.linkifier.linkifyScriptLocation(
580
- runtimeModel.target(), scriptId, url || Platform.DevToolsPath.EmptyUrlString, line,
581
- {columnNumber: column, inlineFrameIndex: 0, userMetric});
584
+ return this.linkifier.linkifyScriptLocation(runtimeModel.target(), scriptId,
585
+ url || Platform.DevToolsPath.EmptyUrlString, line,
586
+ {columnNumber: column, userMetric});
582
587
  }
583
588
  if (stackTrace?.callFrames.length) {
584
589
  return this.linkifier.linkifyStackTraceTopFrame(runtimeModel.target(), stackTrace);
585
590
  }
586
591
  if (url && url !== 'undefined') {
587
- return this.linkifier.linkifyScriptLocation(
588
- runtimeModel.target(), /* scriptId */ null, url, line,
589
- {columnNumber: column, inlineFrameIndex: 0, userMetric});
592
+ return this.linkifier.linkifyScriptLocation(runtimeModel.target(), /* scriptId */ null, url, line,
593
+ {columnNumber: column, userMetric});
590
594
  }
591
595
  return null;
592
596
  };
@@ -695,17 +699,19 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
695
699
  stackTracePreview.options = {widthConstrained: true};
696
700
  if (stackTraceTarget && stackTrace) {
697
701
  const selectableChildIndex = this.selectableChildren.length;
698
- void Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
699
- .createStackTraceFromProtocolRuntime(stackTrace, stackTraceTarget)
700
- .then(stackTrace => {
701
- stackTracePreview.stackTrace = stackTrace;
702
- return stackTracePreview.updateComplete;
703
- })
704
- .then(() => {
705
- const selectableLinks =
706
- stackTracePreview.linkElements.map(element => ({element, forceSelect: () => element.focus()}));
707
- this.selectableChildren.splice(selectableChildIndex, 0, ...selectableLinks);
708
- });
702
+ const stackTracePromise = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
703
+ .createStackTraceFromProtocolRuntime(stackTrace, stackTraceTarget)
704
+ .then(stackTrace => {
705
+ stackTracePreview.stackTrace = stackTrace;
706
+ return stackTracePreview.updateComplete;
707
+ })
708
+ .then(() => {
709
+ const selectableLinks = stackTracePreview.linkElements.map(
710
+ (element: HTMLElement) => ({element, forceSelect: () => element.focus()}));
711
+ this.selectableChildren.splice(selectableChildIndex, 0, ...selectableLinks);
712
+ });
713
+ this.#formatErrorStackPromiseForTest =
714
+ Promise.all([this.#formatErrorStackPromiseForTest, stackTracePromise]).then(() => {});
709
715
  }
710
716
  stackTracePreview.markAsRoot();
711
717
  stackTracePreview.show(stackTraceElement);
@@ -771,7 +777,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
771
777
  let element;
772
778
  switch (outputType) {
773
779
  case 'error':
774
- element = this.formatParameterAsError(output);
780
+ element = this.renderSymbolizedError(output);
775
781
  break;
776
782
  case 'function':
777
783
  element = this.formatParameterAsFunction(output, includePreview);
@@ -980,42 +986,28 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
980
986
  return result;
981
987
  }
982
988
 
983
- private formatParameterAsError(output: SDK.RemoteObject.RemoteObject): HTMLElement {
984
- const result = document.createElement('span');
985
-
986
- // Combine the ExceptionDetails for this error object with the parsed Error#stack.
987
- // The Exceptiondetails include script IDs for stack frames, which allows more accurate
988
- // linking.
989
- const formatErrorStack =
990
- async(errorObj: SDK.RemoteObject.RemoteObject, includeCausedByPrefix: boolean): Promise<void> => {
991
- const error = SDK.RemoteObject.RemoteError.objectAsError(errorObj);
992
- const [details, cause] = await Promise.all([error.exceptionDetails(), error.cause()]);
993
- let errorElement = this.tryFormatAsError(error.errorStack, details);
994
- if (!errorElement) {
995
- errorElement = document.createElement('span');
996
- appendOrShow(errorElement, this.linkifyStringAsFragment(error.errorStack));
997
- }
998
-
999
- if (includeCausedByPrefix) {
1000
- const causeElement = document.createElement('div');
1001
- causeElement.append('Caused by: ', errorElement);
1002
- result.appendChild(causeElement);
1003
- } else {
1004
- result.appendChild(errorElement);
1005
- }
989
+ private renderSymbolizedError(errorRemoteObject: SDK.RemoteObject.RemoteObject): HTMLElement {
990
+ const container = document.createElement('span');
991
+ const widget = new SymbolizedErrorWidget();
992
+ widget.ignoreListManager = Workspace.IgnoreListManager.IgnoreListManager.instance();
993
+ const selectableChildIndex = this.selectableChildren.length;
1006
994
 
1007
- if (cause?.subtype === 'error') {
1008
- await formatErrorStack(cause, /* includeCausedByPrefix */ true);
1009
- } else if (cause?.type === 'string') {
1010
- const stringCauseElement = document.createElement('div');
1011
- stringCauseElement.append(`Caused by: ${cause.value}`);
1012
- result.append(stringCauseElement);
995
+ const format = async(): Promise<void> => {
996
+ const error = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createSymbolizedError(
997
+ errorRemoteObject, this.message.exceptionDetails);
998
+ if (error) {
999
+ widget.error = error;
1013
1000
  }
1001
+ await widget.updateComplete;
1002
+ const selectableLinks =
1003
+ widget.linkElements.map((element: HTMLElement) => ({element, forceSelect: () => element.focus()}));
1004
+ this.selectableChildren.splice(selectableChildIndex, 0, ...selectableLinks);
1014
1005
  };
1015
1006
 
1016
- this.#formatErrorStackPromiseForTest = formatErrorStack(output, /* includeCausedByPrefix */ false);
1017
-
1018
- return result;
1007
+ this.#formatErrorStackPromiseForTest = Promise.all([this.#formatErrorStackPromiseForTest, format()]).then(() => {});
1008
+ widget.markAsRoot();
1009
+ widget.show(container);
1010
+ return container;
1019
1011
  }
1020
1012
 
1021
1013
  private formatAsArrayEntry(output: SDK.RemoteObject.RemoteObject): DocumentFragment {
@@ -1781,165 +1773,6 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1781
1773
  return this.searchHighlightNodes[index];
1782
1774
  }
1783
1775
 
1784
- private async getInlineFrames(
1785
- debuggerModel: SDK.DebuggerModel.DebuggerModel, url: Platform.DevToolsPath.UrlString,
1786
- lineNumber: number|undefined, columnNumber: number|undefined): Promise<{frames: Chrome.DevTools.FunctionInfo[]}> {
1787
- const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
1788
- const projects = Workspace.Workspace.WorkspaceImpl.instance().projects();
1789
- const uiSourceCodes = projects.map(project => project.uiSourceCodeForURL(url)).flat().filter(f => !!f);
1790
- const scripts =
1791
- uiSourceCodes.map(uiSourceCode => debuggerWorkspaceBinding.scriptsForUISourceCode(uiSourceCode)).flat();
1792
- if (scripts.length) {
1793
- const location =
1794
- new SDK.DebuggerModel.Location(debuggerModel, scripts[0].scriptId, lineNumber || 0, columnNumber);
1795
- const functionInfo = await debuggerWorkspaceBinding.pluginManager.getFunctionInfo(scripts[0], location);
1796
- return functionInfo && 'frames' in functionInfo ? functionInfo : {frames: []};
1797
- }
1798
-
1799
- return {frames: []};
1800
- }
1801
-
1802
- // Expand inline stack frames in the formatted error in the stackTrace element, inserting new elements before the
1803
- // insertBefore anchor.
1804
- private async expandInlineStackFrames(
1805
- debuggerModel: SDK.DebuggerModel.DebuggerModel, prefix: string, suffix: string,
1806
- url: Platform.DevToolsPath.UrlString, lineNumber: number|undefined, columnNumber: number|undefined,
1807
- stackTrace: HTMLElement, insertBefore: HTMLElement): Promise<boolean> {
1808
- const {frames} = await this.getInlineFrames(debuggerModel, url, lineNumber, columnNumber);
1809
- if (!frames.length) {
1810
- return false;
1811
- }
1812
-
1813
- for (let f = 0; f < frames.length; ++f) {
1814
- const {name} = frames[f];
1815
- const formattedLine = document.createElement('span');
1816
- appendOrShow(formattedLine, this.linkifyStringAsFragment(`${prefix} ${name} (`));
1817
- const scriptLocationLink = this.linkifier.linkifyScriptLocation(
1818
- debuggerModel.target(), null, url, lineNumber, {columnNumber, inlineFrameIndex: f});
1819
- scriptLocationLink.tabIndex = -1;
1820
- this.selectableChildren.push({element: scriptLocationLink, forceSelect: () => scriptLocationLink.focus()});
1821
- formattedLine.appendChild(scriptLocationLink);
1822
- appendOrShow(formattedLine, this.linkifyStringAsFragment(suffix));
1823
- formattedLine.classList.add('formatted-stack-frame');
1824
- stackTrace.insertBefore(formattedLine, insertBefore);
1825
- }
1826
- return true;
1827
- }
1828
-
1829
- private createScriptLocationLinkForSyntaxError(
1830
- debuggerModel: SDK.DebuggerModel.DebuggerModel, exceptionDetails: Protocol.Runtime.ExceptionDetails): HTMLElement
1831
- |undefined {
1832
- const {scriptId, lineNumber, columnNumber} = exceptionDetails;
1833
- if (!scriptId) {
1834
- return;
1835
- }
1836
-
1837
- // SyntaxErrors might not populate the URL field. Try to resolve it via scriptId.
1838
- const url =
1839
- exceptionDetails.url as Platform.DevToolsPath.UrlString || debuggerModel.scriptForId(scriptId)?.sourceURL;
1840
- if (!url) {
1841
- return;
1842
- }
1843
-
1844
- const scriptLocationLink = this.linkifier.linkifyScriptLocation(
1845
- debuggerModel.target(), exceptionDetails.scriptId || null, url, lineNumber, {
1846
- columnNumber,
1847
- inlineFrameIndex: 0,
1848
- showColumnNumber: true,
1849
- });
1850
- scriptLocationLink.tabIndex = -1;
1851
- return scriptLocationLink;
1852
- }
1853
-
1854
- private tryFormatAsError(string: string, exceptionDetails?: Protocol.Runtime.ExceptionDetails): HTMLElement|null {
1855
- const runtimeModel = this.message.runtimeModel();
1856
- if (!runtimeModel) {
1857
- return null;
1858
- }
1859
-
1860
- const issueSummary = exceptionDetails?.exceptionMetaData?.issueSummary;
1861
- if (typeof issueSummary === 'string') {
1862
- string = StackTrace.ErrorStackParser.concatErrorDescriptionAndIssueSummary(string, issueSummary);
1863
- }
1864
-
1865
- const linkInfos = StackTrace.ErrorStackParser.parseSourcePositionsFromErrorStack(runtimeModel, string);
1866
- if (!linkInfos?.length) {
1867
- return null;
1868
- }
1869
- if (exceptionDetails?.stackTrace) {
1870
- StackTrace.ErrorStackParser.augmentErrorStackWithScriptIds(linkInfos, exceptionDetails.stackTrace);
1871
- }
1872
-
1873
- const debuggerModel = runtimeModel.debuggerModel();
1874
- const formattedResult = document.createElement('span');
1875
-
1876
- for (let i = 0; i < linkInfos.length; ++i) {
1877
- const newline = i < linkInfos.length - 1 ? '\n' : '';
1878
- const {line, link, isCallFrame} = linkInfos[i];
1879
- // Syntax errors don't have a stack frame that points to the source position
1880
- // where the error occurred. We use the source location from the
1881
- // exceptionDetails and append it to the end of the message instead.
1882
- if (!link && exceptionDetails && line.startsWith('SyntaxError')) {
1883
- appendOrShow(formattedResult, this.linkifyStringAsFragment(line));
1884
- const maybeScriptLocation = this.createScriptLocationLinkForSyntaxError(debuggerModel, exceptionDetails);
1885
- if (maybeScriptLocation) {
1886
- formattedResult.append(' (at ');
1887
- formattedResult.appendChild(maybeScriptLocation);
1888
- formattedResult.append(')');
1889
- }
1890
- formattedResult.append(newline);
1891
- continue;
1892
- }
1893
- if (!isCallFrame) {
1894
- appendOrShow(formattedResult, this.linkifyStringAsFragment(`${line}${newline}`));
1895
- continue;
1896
- }
1897
- const formattedLine = document.createElement('span');
1898
- if (!link) {
1899
- appendOrShow(formattedLine, this.linkifyStringAsFragment(`${line}${newline}`));
1900
- formattedLine.classList.add('formatted-builtin-stack-frame');
1901
- formattedResult.appendChild(formattedLine);
1902
- continue;
1903
- }
1904
- const suffix = `${link.suffix}${newline}`;
1905
- appendOrShow(formattedLine, this.linkifyStringAsFragment(link.prefix));
1906
- const scriptLocationLink = this.linkifier.linkifyScriptLocation(
1907
- debuggerModel.target(), link.scriptId || null, link.url, link.lineNumber, {
1908
- columnNumber: link.columnNumber,
1909
- inlineFrameIndex: 0,
1910
- showColumnNumber: true,
1911
- });
1912
- scriptLocationLink.tabIndex = -1;
1913
- this.selectableChildren.push({element: scriptLocationLink, forceSelect: () => scriptLocationLink.focus()});
1914
- formattedLine.appendChild(scriptLocationLink);
1915
- appendOrShow(formattedLine, this.linkifyStringAsFragment(suffix));
1916
- formattedLine.classList.add('formatted-stack-frame');
1917
- formattedResult.appendChild(formattedLine);
1918
-
1919
- if (!link.enclosedInBraces) {
1920
- continue;
1921
- }
1922
-
1923
- const prefixWithoutFunction = link.prefix.substring(0, link.prefix.lastIndexOf(' ', link.prefix.length - 3));
1924
-
1925
- // If we were able to parse the function name from the stack trace line, try to replace it with an expansion of
1926
- // any inline frames.
1927
- const selectableChildIndex = this.selectableChildren.length - 1;
1928
- void this
1929
- .expandInlineStackFrames(
1930
- debuggerModel, prefixWithoutFunction, suffix, link.url, link.lineNumber, link.columnNumber,
1931
- formattedResult, formattedLine)
1932
- .then(modified => {
1933
- if (modified) {
1934
- formattedResult.removeChild(formattedLine);
1935
- this.selectableChildren.splice(selectableChildIndex, 1);
1936
- }
1937
- });
1938
- }
1939
-
1940
- return formattedResult;
1941
- }
1942
-
1943
1776
  static linkifyWithCustomLinkifier(
1944
1777
  string: string,
1945
1778
  linkifier: (arg0: string, arg1: Platform.DevToolsPath.UrlString, arg2?: number, arg3?: number) => Node):
@@ -122,7 +122,6 @@ const DEFAULT_VIEW = (input: ViewInput, _output: object, target: HTMLElement): v
122
122
 
123
123
  const linkOptions: Components.Linkifier.LinkifyOptions = {
124
124
  showColumnNumber: true,
125
- inlineFrameIndex: 0,
126
125
  maxLength: UI.UIUtils.MaxLengthForDisplayedURLsInConsole,
127
126
  ignoreListManager: input.ignoreListManager,
128
127
  };
@@ -171,6 +170,10 @@ export class SymbolizedErrorWidget extends UI.Widget.Widget {
171
170
  this.#view = view;
172
171
  }
173
172
 
173
+ get linkElements(): readonly HTMLElement[] {
174
+ return [...this.contentElement.querySelectorAll<HTMLElement>('.devtools-link')];
175
+ }
176
+
174
177
  set ignoreListManager(ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager) {
175
178
  this.#ignoreListManager = ignoreListManager;
176
179
  this.requestUpdate();
@@ -58,7 +58,6 @@ export class AdoptedStyleSheetTreeElement extends UI.TreeOutline.TreeElement {
58
58
  text: linkText,
59
59
  preventClick: true,
60
60
  showColumnNumber: false,
61
- inlineFrameIndex: 0,
62
61
  }));
63
62
  UI.UIUtils.createTextChild(documentElement, ')');
64
63
  }
@@ -644,7 +644,6 @@ function renderTitle(
644
644
  text,
645
645
  preventClick: true,
646
646
  showColumnNumber: false,
647
- inlineFrameIndex: 0,
648
647
  })}</span>)</span>`;
649
648
  }
650
649
 
@@ -733,7 +732,6 @@ function renderLinkifiedValue(value: string, node: SDK.DOMModel.DOMNode): Lit.Te
733
732
  text: value,
734
733
  preventClick: true,
735
734
  showColumnNumber: false,
736
- inlineFrameIndex: 0,
737
735
  onRef: link => {
738
736
  ImagePreviewPopover.setImageUrl(link, rewrittenHref);
739
737
  }
@@ -556,7 +556,6 @@ export class URLRenderer extends rendererBase(SDK.CSSPropertyParserMatchers.URLM
556
556
  // at the same time, which complicates both StylesSidebarPane and StylePropertyTreeElement.
557
557
  bypassURLTrimming: true,
558
558
  showColumnNumber: false,
559
- inlineFrameIndex: 0,
560
559
  }),
561
560
  hrefUrl || url);
562
561
  container.appendChild(link);
@@ -235,6 +235,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
235
235
  #shouldRenderLazily = false;
236
236
  #lazyRenderObserver?: IntersectionObserver;
237
237
  #lazyRenderCallbacks = new WeakMap<Element, () => void>();
238
+ #updateId = 0;
238
239
 
239
240
  constructor(computedStyleModel: ComputedStyle.ComputedStyleModel.ComputedStyleModel) {
240
241
  super(computedStyleModel, {delegatesFocus: true, useShadowDom: true, classes: ['flex-none']});
@@ -616,9 +617,15 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
616
617
  this.dispatchEventToListeners(Events.INITIAL_UPDATE_COMPLETED);
617
618
  }
618
619
 
619
- this.nodeStylesUpdatedForTest((this.node() as SDK.DOMModel.DOMNode), true);
620
+ this.#updateId += 1;
621
+ const currentUpdateId = this.#updateId;
620
622
 
621
- this.dispatchEventToListeners(Events.STYLES_UPDATE_COMPLETED, {hasMatchedStyles: this.hasMatchedStyles});
623
+ void UI.Widget.Widget.allUpdatesComplete.then(() => {
624
+ if (this.#updateId === currentUpdateId) {
625
+ this.nodeStylesUpdatedForTest((this.node() as SDK.DOMModel.DOMNode), true);
626
+ this.dispatchEventToListeners(Events.STYLES_UPDATE_COMPLETED, {hasMatchedStyles: this.hasMatchedStyles});
627
+ }
628
+ });
622
629
  }
623
630
 
624
631
  #getRegisteredPropertyDetails(matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles, variableName: string):
@@ -252,7 +252,7 @@ export abstract class AffectedResourcesView extends UI.TreeOutline.TreeElement {
252
252
  const linkifier = new Components.Linkifier.Linkifier(UI.UIUtils.MaxLengthForDisplayedURLsInConsole);
253
253
  const sourceAnchor = linkifier.linkifyScriptLocation(
254
254
  target || null, sourceLocation.scriptId || null, sourceLocation.url as Platform.DevToolsPath.UrlString,
255
- sourceLocation.lineNumber, {columnNumber: sourceLocation.columnNumber, inlineFrameIndex: 0});
255
+ sourceLocation.lineNumber, {columnNumber: sourceLocation.columnNumber});
256
256
  sourceAnchor.setAttribute('jslog', `${VisualLogging.link('source-location').track({click: true})}`);
257
257
  sourceCodeLocation.appendChild(sourceAnchor);
258
258
  }
@@ -39,7 +39,7 @@ export class AffectedSourcesView extends AffectedResourcesView {
39
39
  const cellElement = document.createElement('td');
40
40
  // TODO(chromium:1072331): Check feasibility of plumping through scriptId for `linkifyScriptLocation`
41
41
  // to support source maps and formatted scripts.
42
- const linkifierURLOptions = {columnNumber, lineNumber, tabStop: true, showColumnNumber: false, inlineFrameIndex: 0};
42
+ const linkifierURLOptions = {columnNumber, lineNumber, tabStop: true, showColumnNumber: false};
43
43
  // An element created with linkifyURL can subscribe to the events
44
44
  // 'click' neither 'keydown' if that key is the 'Enter' key.
45
45
  // Also, this element has a context menu, so we should be able to
@@ -198,7 +198,6 @@ export class LighthouseReportRenderer {
198
198
  lineNumber: line,
199
199
  columnNumber: column,
200
200
  showColumnNumber: false,
201
- inlineFrameIndex: 0,
202
201
  maxLength: MaxLengthForLinks,
203
202
  });
204
203
  UI.Tooltip.Tooltip.install(origHTMLElement, '');
@@ -180,10 +180,20 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
180
180
  /**
181
181
  * This promise resolves after the first compute pressure record is observed.
182
182
  * The object it returns is always up-to-date with the most recent record observed.
183
+ *
184
+ * Note: The returned value measures the host machine's compute pressure. When
185
+ * debugging a remote device, this may trigger irrelevant high-pressure warnings.
183
186
  */
184
187
  function createComputePressurePromise(): Promise<{state: string}> {
185
188
  const result = {state: ''};
186
189
 
190
+ // @ts-expect-error typescript/lib version needs to be updated.
191
+ if (typeof PressureObserver === 'undefined') {
192
+ // The Compute Pressure API is used only for showing warnings to the user.
193
+ // If it's unavailable, resolve immediately to proceed without warnings.
194
+ return Promise.resolve(result);
195
+ }
196
+
187
197
  return new Promise(resolve => {
188
198
  // @ts-expect-error typescript/lib version needs to be updated.
189
199
  const observer = new PressureObserver(records => {
@@ -1515,8 +1515,7 @@ export class NetworkRequestNode extends NetworkNode {
1515
1515
  this.linkifiedInitiatorAnchor = linkifier.linkifyStackTraceTopFrame(target, initiator.stack);
1516
1516
  } else {
1517
1517
  this.linkifiedInitiatorAnchor = linkifier.linkifyScriptLocation(
1518
- target, initiator.scriptId, initiator.url, initiator.lineNumber,
1519
- {columnNumber: initiator.columnNumber, inlineFrameIndex: 0});
1518
+ target, initiator.scriptId, initiator.url, initiator.lineNumber, {columnNumber: initiator.columnNumber});
1520
1519
  }
1521
1520
  UI.Tooltip.Tooltip.install((this.linkifiedInitiatorAnchor), '');
1522
1521
  cell.appendChild(this.linkifiedInitiatorAnchor);
@@ -505,6 +505,11 @@ const UIStrings = {
505
505
  * @description Context menu item in Network panel to assess security headers of a request via AI.
506
506
  */
507
507
  assessSecurityHeaders: 'Assess security headers',
508
+ /**
509
+ * @description A comment in a generated command indicating that the URL scheme is unsupported. The placeholder is the comment prefix (e.g. '//' or '#').
510
+ * @example {//} PH1
511
+ */
512
+ unsupportedUrlScheme: '{PH1} Unsupported URL scheme',
508
513
  } as const;
509
514
  const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkLogView.ts', UIStrings);
510
515
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -557,6 +562,8 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
557
562
  private readonly textFilterSetting: Common.Settings.Setting<string>;
558
563
  private networkRequestToNode: WeakMap<SDK.NetworkRequest.NetworkRequest, NetworkRequestNode>;
559
564
 
565
+ static #allowedSchemes = new Set(['http:', 'https:', 'ws:', 'wss:', 'data:']);
566
+
560
567
  constructor(
561
568
  filterBar: UI.FilterBar.FilterBar, progressBarContainer: Element,
562
569
  networkLogLargeRowsSetting: Common.Settings.Setting<boolean>) {
@@ -2319,6 +2326,18 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
2319
2326
  return requests.filter(request => !request.isBlobRequest());
2320
2327
  }
2321
2328
 
2329
+ static #getValidClipboardUrl(url: string): Platform.DevToolsPath.UrlString|null {
2330
+ try {
2331
+ const parsedUrl = new URL(url);
2332
+ if (!NetworkLogView.#allowedSchemes.has(parsedUrl.protocol)) {
2333
+ return null;
2334
+ }
2335
+ return url as Platform.DevToolsPath.UrlString;
2336
+ } catch {
2337
+ return null;
2338
+ }
2339
+ }
2340
+
2322
2341
  private async generateFetchCall(request: SDK.NetworkRequest.NetworkRequest, style: FetchStyle): Promise<string> {
2323
2342
  const ignoredHeaders = new Set<string>([
2324
2343
  // Internal headers
@@ -2355,7 +2374,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
2355
2374
 
2356
2375
  const credentialHeaders = new Set<string>(['cookie', 'authorization']);
2357
2376
 
2358
- const url = JSON.stringify(request.url());
2377
+ const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
2378
+ if (!validUrl) {
2379
+ return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '//'});
2380
+ }
2381
+ const url = JSON.stringify(validUrl);
2359
2382
 
2360
2383
  const requestHeaders = request.requestHeaders();
2361
2384
  const headerData: Headers = requestHeaders.reduce((result, header) => {
@@ -2507,11 +2530,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
2507
2530
  // (it may be different from the inspected page platform).
2508
2531
  const escapeString = platform === 'win' ? escapeStringWin : escapeStringPosix;
2509
2532
 
2510
- // The shell escaping above protects the *shell* parser, but not curl's own
2511
- // argv parser: if the (HAR-imported) URL begins with '-', curl will parse
2512
- // it as an option (e.g. "-K//host/share/file" -> --config UNC path).
2513
- // Passing the URL via --url forces curl to treat it as a URL operand.
2514
- command.push('--url ' + escapeString(request.url()).replace(/[[{}\]]/g, '\\$&'));
2533
+ const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
2534
+ if (!validUrl) {
2535
+ return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '#'});
2536
+ }
2537
+ command.push('--url ' + escapeString(validUrl).replace(/[[{}\]]/g, '\\$&'));
2515
2538
 
2516
2539
  let inferredMethod = 'GET';
2517
2540
  const data = [];
@@ -2617,7 +2640,11 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
2617
2640
  return null;
2618
2641
  }
2619
2642
 
2620
- command.push('-Uri ' + escapeString(request.url()));
2643
+ const validUrl = NetworkLogView.#getValidClipboardUrl(request.url());
2644
+ if (!validUrl) {
2645
+ return i18nString(UIStrings.unsupportedUrlScheme, {PH1: '#'});
2646
+ }
2647
+ command.push('-Uri ' + escapeString(validUrl));
2621
2648
 
2622
2649
  if (request.requestMethod !== 'GET') {
2623
2650
  command.push('-Method ' + escapeString(request.requestMethod));
@@ -628,7 +628,6 @@ export class NodeFormatter implements Formatter {
628
628
  const target = heapProfilerModel ? heapProfilerModel.target() : null;
629
629
  const options = {
630
630
  className: 'profile-node-file',
631
- inlineFrameIndex: 0,
632
631
  };
633
632
  return this.profileView.linkifier().maybeLinkifyConsoleCallFrame(target, node.profileNode.callFrame, options);
634
633
  }
@@ -1467,7 +1467,6 @@ export class AllocationGridNode extends HeapSnapshotGridNode {
1467
1467
  String(allocationNode.scriptId) as Protocol.Runtime.ScriptId,
1468
1468
  allocationNode.scriptName as Platform.DevToolsPath.UrlString, allocationNode.line - 1, {
1469
1469
  columnNumber: allocationNode.column - 1,
1470
- inlineFrameIndex: 0,
1471
1470
  className: 'profile-node-file',
1472
1471
  });
1473
1472
  urlElement.style.maxWidth = '75%';
@@ -1949,7 +1949,7 @@ export class HeapAllocationStackView extends UI.Widget.Widget {
1949
1949
  continue;
1950
1950
  }
1951
1951
  const target = this.heapProfilerModel ? this.heapProfilerModel.target() : null;
1952
- const options = {columnNumber: frame.column - 1, inlineFrameIndex: 0};
1952
+ const options = {columnNumber: frame.column - 1};
1953
1953
  const urlElement = this.linkifier.linkifyScriptLocation(
1954
1954
  target, String(frame.scriptId) as Protocol.Runtime.ScriptId,
1955
1955
  frame.scriptName as Platform.DevToolsPath.UrlString, frame.line - 1, options);
@@ -66,8 +66,10 @@ export class IsolateSelector extends UI.Widget.VBox implements UI.ListControl.Li
66
66
  totalValueDiv: HTMLElement;
67
67
  readonly totalTrendDiv: HTMLElement;
68
68
 
69
- constructor() {
70
- super();
69
+ // `devtools-widget` passes its host element into widget constructors.
70
+ // Accept and forward it so this widget attaches to that host element.
71
+ constructor(element?: HTMLElement) {
72
+ super(element);
71
73
 
72
74
  this.items = new UI.ListModel.ListModel();
73
75
  this.list = new UI.ListControl.ListControl(this.items, this, UI.ListControl.ListMode.NonViewport);