chrome-devtools-frontend 1.0.1650035 → 1.0.1650100

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.
@@ -11,7 +11,7 @@ import type * as Trace from '../../models/trace/trace.js';
11
11
  import * as Greendev from '../greendev/greendev.js';
12
12
  import type * as NetworkTimeCalculator from '../network_time_calculator/network_time_calculator.js';
13
13
 
14
- import {AccessibilityAgent, AccessibilityContext} from './agents/AccessibilityAgent.js';
14
+ import {AccessibilityAgent} from './agents/AccessibilityAgent.js';
15
15
  import {
16
16
  type AgentOptions,
17
17
  type AiAgent,
@@ -33,6 +33,7 @@ import {StylingAgent} from './agents/StylingAgent.js';
33
33
  import {AiAgent2} from './AiAgent2.js';
34
34
  import {AiHistoryStorage, ConversationType, type SerializedConversation} from './AiHistoryStorage.js';
35
35
  import type {ChangeManager} from './ChangeManager.js';
36
+ import {AccessibilityContext} from './contexts/AccessibilityContext.js';
36
37
  import {DOMNodeContext} from './contexts/DOMNodeContext.js';
37
38
  import {FileContext} from './contexts/FileContext.js';
38
39
  import {RequestContext} from './contexts/RequestContext.js';
@@ -19,9 +19,8 @@ import {ToolRegistry} from '../tools/ToolRegistry.js';
19
19
  import {
20
20
  AiAgent,
21
21
  type AiWidget,
22
- type ContextDetail,
23
22
  type ContextResponse,
24
- ConversationContext,
23
+ type ConversationContext,
25
24
  type RequestOptions,
26
25
  ResponseType,
27
26
  } from './AiAgent.js';
@@ -81,31 +80,6 @@ If the user asks a question that requires an investigation of a problem, use thi
81
80
  - [Suggestion 2]
82
81
  `;
83
82
 
84
- export class AccessibilityContext extends ConversationContext<LHModel.ReporterTypes.ReportJSON> {
85
- #lh: LHModel.ReporterTypes.ReportJSON;
86
-
87
- constructor(report: LHModel.ReporterTypes.ReportJSON) {
88
- super();
89
- this.#lh = report;
90
- }
91
-
92
- #url(): string {
93
- return this.#lh.finalUrl ?? this.#lh.finalDisplayedUrl;
94
- }
95
-
96
- override getURL(): string {
97
- return this.#url();
98
- }
99
-
100
- override getItem(): LHModel.ReporterTypes.ReportJSON {
101
- return this.#lh;
102
- }
103
-
104
- override getTitle(): string {
105
- return `Lighthouse report: ${this.#url()}`;
106
- }
107
- }
108
-
109
83
  /**
110
84
  * One agent instance handles one conversation. Create a new agent
111
85
  * instance for a new conversation.
@@ -184,10 +158,13 @@ export class AccessibilityAgent extends AiAgent<LHModel.ReporterTypes.ReportJSON
184
158
  return;
185
159
  }
186
160
 
187
- yield {
188
- type: ResponseType.CONTEXT,
189
- details: this.#createContextDetails(lhr),
190
- };
161
+ const details = await lhr.getUserFacingDetails();
162
+ if (details) {
163
+ yield {
164
+ type: ResponseType.CONTEXT,
165
+ details,
166
+ };
167
+ }
191
168
  }
192
169
 
193
170
  async #resolvePathToNode(path: string): Promise<SDK.DOMModel.DOMNode|null> {
@@ -517,38 +494,14 @@ export class AccessibilityAgent extends AiAgent<LHModel.ReporterTypes.ReportJSON
517
494
  });
518
495
  }
519
496
 
520
- /**
521
- * This is the initial payload we send at the start of a conversation.
522
- * Because the agent is focused on Accessibility, we include the
523
- * Accessibility Audits summary in the payload to avoid an extra round step of
524
- * the AI querying them.
525
- */
526
- #getInitialPayload(context: ConversationContext<LHModel.ReporterTypes.ReportJSON>): string {
527
- const report = context.getItem();
528
- const formatter = new LighthouseFormatter();
529
- const summary = formatter.summary(report);
530
- const audits = formatter.audits(report, 'accessibility');
531
- const allFailed = Object.values(report.categories).every(category => category.score === null);
532
- if (allFailed) {
533
- return '**CRITICAL**: The Lighthouse report failed to record or all category scores are error/unavailable (n/a). This indicates a failed run or missing data.';
534
- }
535
- return `# Lighthouse Report:\n${summary}\n${audits}`;
536
- }
537
-
538
497
  override async enhanceQuery(query: string, lhr: ConversationContext<LHModel.ReporterTypes.ReportJSON>|null):
539
498
  Promise<string> {
540
499
  this.clearDeclaredFunctions();
541
500
  if (lhr) {
542
501
  this.#declareFunctions();
543
502
  }
544
- const enhancedQuery = lhr ? `${this.#getInitialPayload(lhr)}\n# User request:\n\n` : '';
503
+ const promptDetails = lhr ? await lhr.getPromptDetails() : null;
504
+ const enhancedQuery = promptDetails ? `${promptDetails}\n# User request:\n\n` : '';
545
505
  return `${enhancedQuery}${query}`;
546
506
  }
547
-
548
- #createContextDetails(lhr: ConversationContext<LHModel.ReporterTypes.ReportJSON>):
549
- [ContextDetail, ...ContextDetail[]] {
550
- return [
551
- {title: 'Lighthouse report', text: this.#getInitialPayload(lhr)},
552
- ];
553
- }
554
507
  }
@@ -14,13 +14,13 @@ import * as NetworkTimeCalculator from '../../network_time_calculator/network_ti
14
14
  import type * as Trace from '../../trace/trace.js';
15
15
  import * as Workspace from '../../workspace/workspace.js';
16
16
  import {isOpaqueOrigin} from '../AiOrigins.js';
17
+ import {AccessibilityContext} from '../contexts/AccessibilityContext.js';
17
18
  import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
18
19
  import {FileContext} from '../contexts/FileContext.js';
19
20
  import {getRequestContextOrigin, RequestContext} from '../contexts/RequestContext.js';
20
21
  import {debugLog} from '../debug.js';
21
22
  import {StorageItem} from '../StorageItem.js';
22
23
 
23
- import {AccessibilityContext} from './AccessibilityAgent.js';
24
24
  import {
25
25
  type AgentOptions,
26
26
  AiAgent,
@@ -22,6 +22,7 @@ import * as AiOrigins from './AiOrigins.js';
22
22
  import * as AiUtils from './AiUtils.js';
23
23
  import * as BuiltInAi from './BuiltInAi.js';
24
24
  import * as ChangeManager from './ChangeManager.js';
25
+ import * as AccessibilityContext from './contexts/AccessibilityContext.js';
25
26
  import * as DOMNodeContext from './contexts/DOMNodeContext.js';
26
27
  import * as FileContext from './contexts/FileContext.js';
27
28
  import * as RequestContext from './contexts/RequestContext.js';
@@ -50,6 +51,7 @@ import * as ToolRegistry from './tools/ToolRegistry.js';
50
51
 
51
52
  export {
52
53
  AccessibilityAgent,
54
+ AccessibilityContext,
53
55
  AgentProject,
54
56
  AiAgent,
55
57
  AiAgent2,
@@ -0,0 +1,26 @@
1
+ Title: AccessibilityContext should return prompt details correctly
2
+ Content:
3
+ # Lighthouse Report:
4
+ # Lighthouse Report Summary
5
+ URL: https://example.com
6
+ Fetch Time: 2026-03-12
7
+ Lighthouse Version: 1.0.0
8
+
9
+ ## Category Scores
10
+ - Accessibility: 50
11
+ # Audits for Accessibility
12
+
13
+ The following audits in this category have a score below 90 and may need attention:
14
+ - **Accessibility Audit**: 50 (Fail)
15
+ * Description of accessibility audit
16
+ === end content
17
+
18
+ Title: AccessibilityContext should return user facing details correctly
19
+ Content:
20
+ [
21
+ {
22
+ "title": "Lighthouse report",
23
+ "text": "# Lighthouse Report:\n# Lighthouse Report Summary\nURL: https://example.com\nFetch Time: 2026-03-12\nLighthouse Version: 1.0.0\n\n## Category Scores\n- Accessibility: 50\n# Audits for Accessibility\n\nThe following audits in this category have a score below 90 and may need attention:\n- **Accessibility Audit**: 50 (Fail)\n * Description of accessibility audit"
24
+ }
25
+ ]
26
+ === end content
@@ -0,0 +1,63 @@
1
+ // Copyright 2026 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 LHModel from '../../lighthouse/lighthouse.js';
6
+ import {type ContextDetail, ConversationContext} from '../agents/AiAgent.js';
7
+ import {LighthouseFormatter} from '../data_formatters/LighthouseFormatter.js';
8
+
9
+ export class AccessibilityContext extends ConversationContext<LHModel.ReporterTypes.ReportJSON> {
10
+ readonly #lh: LHModel.ReporterTypes.ReportJSON;
11
+ #cachedPayload: string|null = null;
12
+
13
+ constructor(report: LHModel.ReporterTypes.ReportJSON) {
14
+ super();
15
+ this.#lh = report;
16
+ }
17
+
18
+ #url(): string {
19
+ return this.#lh.finalUrl ?? this.#lh.finalDisplayedUrl;
20
+ }
21
+
22
+ override getURL(): string {
23
+ return this.#url();
24
+ }
25
+
26
+ override getItem(): LHModel.ReporterTypes.ReportJSON {
27
+ return this.#lh;
28
+ }
29
+
30
+ override getTitle(): string {
31
+ return `Lighthouse report: ${this.#url()}`;
32
+ }
33
+
34
+ #getInitialPayload(): string {
35
+ if (this.#cachedPayload !== null) {
36
+ return this.#cachedPayload;
37
+ }
38
+ const formatter = new LighthouseFormatter();
39
+ const summary = formatter.summary(this.#lh);
40
+ const audits = formatter.audits(this.#lh, 'accessibility');
41
+ const allFailed = Object.values(this.#lh.categories).every(category => category.score === null);
42
+ if (allFailed) {
43
+ this.#cachedPayload =
44
+ '**CRITICAL**: The Lighthouse report failed to record or all category scores are error/unavailable (n/a). This indicates a failed run or missing data.';
45
+ } else {
46
+ this.#cachedPayload = `# Lighthouse Report:\n${summary}\n${audits}`;
47
+ }
48
+ return this.#cachedPayload;
49
+ }
50
+
51
+ override async getPromptDetails(): Promise<string|null> {
52
+ return this.#getInitialPayload();
53
+ }
54
+
55
+ override async getUserFacingDetails(): Promise<[ContextDetail, ...ContextDetail[]]|null> {
56
+ return [
57
+ {
58
+ title: 'Lighthouse report',
59
+ text: this.#getInitialPayload(),
60
+ },
61
+ ];
62
+ }
63
+ }
@@ -7,7 +7,7 @@ import * as Platform from '../../core/platform/platform.js';
7
7
  import * as Root from '../../core/root/root.js';
8
8
  import * as SDK from '../../core/sdk/sdk.js';
9
9
  import * as Protocol from '../../generated/protocol.js';
10
- import * as StackTrace from '../stack_trace/stack_trace.js';
10
+ import type * as StackTrace from '../stack_trace/stack_trace.js';
11
11
  // eslint-disable-next-line @devtools/es-modules-import
12
12
  import * as StackTraceImpl from '../stack_trace/stack_trace_impl.js';
13
13
  import type * as TextUtils from '../text_utils/text_utils.js';
@@ -254,7 +254,8 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
254
254
 
255
255
  const issueSummary = fetchedExceptionDetails?.exceptionMetaData?.issueSummary;
256
256
  if (typeof issueSummary === 'string') {
257
- errorStack = StackTrace.ErrorStackParser.concatErrorDescriptionAndIssueSummary(errorStack, issueSummary);
257
+ errorStack =
258
+ StackTraceImpl.DetailedErrorStackParser.concatErrorDescriptionAndIssueSummary(errorStack, issueSummary);
258
259
  }
259
260
 
260
261
  if (!stackTrace) {
@@ -212,3 +212,21 @@ export function augmentRawFramesWithScriptIds(
212
212
  augmentFrame(rawFrame);
213
213
  }
214
214
  }
215
+
216
+ /**
217
+ * Combines the error description (essentially the `Error#stack` property value)
218
+ * with the `issueSummary`.
219
+ *
220
+ * @param description the `description` property of the `Error` remote object.
221
+ * @param issueSummary the optional `issueSummary` of the `exceptionMetaData`.
222
+ * @returns the enriched description.
223
+ * @see https://goo.gle/devtools-reduce-network-noise-design
224
+ */
225
+ export function concatErrorDescriptionAndIssueSummary(description: string, issueSummary: string): string {
226
+ // Insert the issue summary right after the error message.
227
+ const pos = description.indexOf('\n');
228
+ const prefix = pos === -1 ? description : description.substring(0, pos);
229
+ const suffix = pos === -1 ? '' : description.substring(pos);
230
+ description = `${prefix}. ${issueSummary}${suffix}`;
231
+ return description;
232
+ }
@@ -2,12 +2,8 @@
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 ErrorStackParser from './ErrorStackParser.js';
6
5
  import * as StackTrace from './StackTrace.js';
7
6
 
8
7
  export {
9
- // TODO(crbug.com/485142682): Move to stack_trace_impl.js once all usage
10
- // goes through createStackTraceFromErrorObject.
11
- ErrorStackParser,
12
8
  StackTrace,
13
9
  };
@@ -79,6 +79,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
79
79
  <devtools-prompt
80
80
  completions=completions
81
81
  class="monospace"
82
+ value=${attribute.value}
82
83
  @mousedown=${onStartEditing.bind(null, attribute)}
83
84
  .completionTimeout=${0}
84
85
  ?editing=${input.attributeBeingEdited === attribute}
@@ -623,12 +623,12 @@ function createFileContext(file: Workspace.UISourceCode.UISourceCode|null): AiAs
623
623
  return new AiAssistanceModel.FileContext.FileContext(file);
624
624
  }
625
625
 
626
- function createAccessibilityContext(report: LighthousePanel.LighthousePanel.ActiveLighthouseReport|null):
627
- AiAssistanceModel.AccessibilityAgent.AccessibilityContext|null {
626
+ function createAccessibilityContext(report: LighthousePanel.LighthousePanel.ActiveLighthouseReport|
627
+ null): AiAssistanceModel.AccessibilityContext.AccessibilityContext|null {
628
628
  if (!report) {
629
629
  return null;
630
630
  }
631
- return new AiAssistanceModel.AccessibilityAgent.AccessibilityContext(report.report);
631
+ return new AiAssistanceModel.AccessibilityContext.AccessibilityContext(report.report);
632
632
  }
633
633
 
634
634
  function createRequestContext(request: SDK.NetworkRequest.NetworkRequest|
@@ -710,7 +710,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
710
710
  #selectedPerformanceTrace: AiAssistanceModel.PerformanceAgent.PerformanceTraceContext|null = null;
711
711
  #selectedRequest: AiAssistanceModel.RequestContext.RequestContext|null = null;
712
712
 
713
- #selectedAccessibility: AiAssistanceModel.AccessibilityAgent.AccessibilityContext|null = null;
713
+ #selectedAccessibility: AiAssistanceModel.AccessibilityContext.AccessibilityContext|null = null;
714
714
  #selectedStorage: AiAssistanceModel.StorageAgent.StorageContext|null = null;
715
715
 
716
716
  // Messages displayed in the `ChatView` component.
@@ -1781,7 +1781,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1781
1781
  } else if (data instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext) {
1782
1782
  this.#selectedPerformanceTrace = data;
1783
1783
 
1784
- } else if (data instanceof AiAssistanceModel.AccessibilityAgent.AccessibilityContext) {
1784
+ } else if (data instanceof AiAssistanceModel.AccessibilityContext.AccessibilityContext) {
1785
1785
  this.#selectedAccessibility = data;
1786
1786
  } else if (data instanceof AiAssistanceModel.StorageAgent.StorageContext) {
1787
1787
  this.#selectedStorage = data;
@@ -355,7 +355,7 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
355
355
  PanelUtils.PanelUtils.getIconForNetworkRequest(input.context.getItem()) :
356
356
  input.context instanceof AiAssistanceModel.FileContext.FileContext ?
357
357
  PanelUtils.PanelUtils.getIconForSourceFile(input.context.getItem()) :
358
- input.context instanceof AiAssistanceModel.AccessibilityAgent.AccessibilityContext ?
358
+ input.context instanceof AiAssistanceModel.AccessibilityContext.AccessibilityContext ?
359
359
  html`<devtools-icon class="icon" name="performance" title="Lighthouse"></devtools-icon>` :
360
360
  input.context instanceof AiAssistanceModel.PerformanceAgent.PerformanceTraceContext ?
361
361
  html`<devtools-icon class="icon" name="performance" title="Performance"></devtools-icon>` :
@@ -1060,15 +1060,21 @@ export class LinkHandlerSettingUI {
1060
1060
 
1061
1061
  update(): void {
1062
1062
  this.element.removeChildren();
1063
- const names = [...linkHandlers.keys()];
1064
- names.unshift(i18nString(UIStrings.auto));
1065
- for (const name of names) {
1063
+ // Populate the dropdown with extension origins. The first option is the
1064
+ // special "Auto" value which is not a real origin.
1065
+ const origins = [...linkHandlers.keys()];
1066
+ origins.unshift(i18nString(UIStrings.auto));
1067
+ for (const origin of origins) {
1066
1068
  const option = document.createElement('option');
1067
- option.textContent = name;
1068
- option.selected = name === Linkifier.linkHandlerSetting().get();
1069
+ const registration = linkHandlers.get(origin);
1070
+ // If the origin has a registered handler, display its user-friendly title.
1071
+ // Otherwise, fallback to the origin string itself (e.g. for the "Auto" option).
1072
+ option.textContent = registration === undefined ? origin : registration.title;
1073
+ option.value = origin;
1074
+ option.selected = origin === Linkifier.linkHandlerSetting().get();
1069
1075
  this.element.appendChild(option);
1070
1076
  }
1071
- this.element.disabled = names.length <= 1;
1077
+ this.element.disabled = origins.length <= 1;
1072
1078
  }
1073
1079
 
1074
1080
  private onChange(event: Event): void {
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.1650035"
95
+ "version": "1.0.1650100"
96
96
  }
@@ -1,174 +0,0 @@
1
- // Copyright 2022 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 * as Common from '../../core/common/common.js';
6
- import type * as Platform from '../../core/platform/platform.js';
7
- import type * as SDK from '../../core/sdk/sdk.js';
8
- import type * as Protocol from '../../generated/protocol.js';
9
-
10
- export interface ParsedErrorFrame {
11
- line: string;
12
- isCallFrame?: boolean;
13
- link?: {
14
- url: Platform.DevToolsPath.UrlString,
15
- prefix: string,
16
- suffix: string,
17
- enclosedInBraces: boolean,
18
- lineNumber?: number,
19
- columnNumber?: number,
20
- scriptId?: Protocol.Runtime.ScriptId,
21
- };
22
- }
23
-
24
- /**
25
- * Combines the error description (essentially the `Error#stack` property value)
26
- * with the `issueSummary`.
27
- *
28
- * @param description the `description` property of the `Error` remote object.
29
- * @param issueSummary the optional `issueSummary` of the `exceptionMetaData`.
30
- * @returns the enriched description.
31
- * @see https://goo.gle/devtools-reduce-network-noise-design
32
- */
33
- export function concatErrorDescriptionAndIssueSummary(description: string, issueSummary: string): string {
34
- // Insert the issue summary right after the error message.
35
- const pos = description.indexOf('\n');
36
- const prefix = pos === -1 ? description : description.substring(0, pos);
37
- const suffix = pos === -1 ? '' : description.substring(pos);
38
- description = `${prefix}. ${issueSummary}${suffix}`;
39
- return description;
40
- }
41
-
42
- /**
43
- * Takes a V8 Error#stack string and extracts source position information.
44
- *
45
- * The result includes the url, line and column number, as well as where
46
- * the url is found in the raw line.
47
- *
48
- * @returns Null if the provided string has an unexpected format. A
49
- * populated `ParsedErrorFrame[]` otherwise.
50
- */
51
- export function parseSourcePositionsFromErrorStack(
52
- runtimeModel: SDK.RuntimeModel.RuntimeModel, stack: string): ParsedErrorFrame[]|null {
53
- if (!(/\n\s*at\s/.test(stack) || stack.startsWith('SyntaxError:'))) {
54
- return null;
55
- }
56
- const debuggerModel = runtimeModel.debuggerModel();
57
- const baseURL = runtimeModel.target().inspectedURL();
58
-
59
- const lines = stack.split('\n');
60
- const linkInfos = [];
61
- for (const line of lines) {
62
- const match = /^\s*at\s(async\s)?/.exec(line);
63
- if (!match) {
64
- if (linkInfos.length && linkInfos[linkInfos.length - 1].isCallFrame) {
65
- return null;
66
- }
67
- linkInfos.push({line});
68
- continue;
69
- }
70
-
71
- const isCallFrame = true;
72
- let left = match[0].length;
73
- let right = line.length;
74
- let enclosedInBraces = false;
75
- if (line[right - 1] === ')') {
76
- right--;
77
- enclosedInBraces = true;
78
- left = line.lastIndexOf(' (', right);
79
- if (left < 0) {
80
- return null;
81
- }
82
- left += 2;
83
- // Relevant in the `eval at ...` case.
84
- const newRight = line.indexOf('), ', left);
85
- if (newRight > left) {
86
- right = newRight;
87
- }
88
- }
89
-
90
- const linkCandidate = line.substring(left, right);
91
- const splitResult = Common.ParsedURL.ParsedURL.splitLineAndColumn(linkCandidate);
92
- if (splitResult.url === '<anonymous>') {
93
- if (linkInfos.length && linkInfos[linkInfos.length - 1].isCallFrame && !linkInfos[linkInfos.length - 1].link) {
94
- // Combine builtin frames.
95
- linkInfos[linkInfos.length - 1].line += `\n${line}`;
96
- } else {
97
- linkInfos.push({line, isCallFrame});
98
- }
99
- continue;
100
- }
101
- let url = parseOrScriptMatch(debuggerModel, splitResult.url);
102
- if (!url && Common.ParsedURL.ParsedURL.isRelativeURL(splitResult.url)) {
103
- url = parseOrScriptMatch(debuggerModel, Common.ParsedURL.ParsedURL.completeURL(baseURL, splitResult.url));
104
- }
105
- if (!url) {
106
- return null;
107
- }
108
-
109
- linkInfos.push({
110
- line,
111
- isCallFrame,
112
- link: {
113
- url,
114
- prefix: line.substring(0, left),
115
- suffix: line.substring(right),
116
- enclosedInBraces,
117
- lineNumber: splitResult.lineNumber,
118
- columnNumber: splitResult.columnNumber,
119
- },
120
- });
121
- }
122
- return linkInfos;
123
- }
124
-
125
- function parseOrScriptMatch(debuggerModel: SDK.DebuggerModel.DebuggerModel, url: Platform.DevToolsPath.UrlString|null):
126
- Platform.DevToolsPath.UrlString|null {
127
- if (!url) {
128
- return null;
129
- }
130
- if (Common.ParsedURL.ParsedURL.isValidUrlString(url)) {
131
- return url;
132
- }
133
- if (debuggerModel.scriptsForSourceURL(url).length) {
134
- return url;
135
- }
136
- // nodejs stack traces contain (absolute) file paths, but v8 reports them as file: urls.
137
- const fileUrl = new URL(url, 'file://');
138
- if (debuggerModel.scriptsForSourceURL(fileUrl.href).length) {
139
- return fileUrl.href as Platform.DevToolsPath.UrlString;
140
- }
141
- return null;
142
- }
143
-
144
- /**
145
- * Error#stack output only contains script URLs. In some cases we are able to
146
- * retrieve additional exception details from V8 that we can use to augment
147
- * the parsed Error#stack with script IDs.
148
- * This function sets the `scriptId` field in `ParsedErrorFrame` when it finds
149
- * the corresponding info in `Protocol.Runtime.StackTrace`.
150
- */
151
- export function augmentErrorStackWithScriptIds(
152
- parsedFrames: ParsedErrorFrame[], protocolStackTrace: Protocol.Runtime.StackTrace): void {
153
- // Note that the number of frames between the two stack traces can differ. The
154
- // parsed Error#stack can contain Builtin frames which are not present in the protocol
155
- // stack. This means its easier to always search the whole protocol stack for a matching
156
- // frame rather then trying to detect the Builtin frames and skipping them.
157
- for (const parsedFrame of parsedFrames) {
158
- const protocolFrame = protocolStackTrace.callFrames.find(frame => framesMatch(parsedFrame, frame));
159
- if (protocolFrame && parsedFrame.link) {
160
- parsedFrame.link.scriptId = protocolFrame.scriptId;
161
- }
162
- }
163
- }
164
-
165
- /** Returns true iff both stack frames have the same url and line/column numbers. The function name is ignored */
166
- function framesMatch(parsedFrame: ParsedErrorFrame, protocolFrame: Protocol.Runtime.CallFrame): boolean {
167
- if (!parsedFrame.link) {
168
- return false;
169
- }
170
-
171
- const {url, lineNumber, columnNumber} = parsedFrame.link;
172
- return url === protocolFrame.url && lineNumber === protocolFrame.lineNumber &&
173
- columnNumber === protocolFrame.columnNumber;
174
- }