chrome-devtools-frontend 1.0.1021582 → 1.0.1022475

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 (49) hide show
  1. package/.eslintignore +14 -1
  2. package/extension-api/ExtensionAPI.d.ts +54 -4
  3. package/front_end/.eslintrc.js +3 -1
  4. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  5. package/front_end/core/host/UserMetrics.ts +18 -0
  6. package/front_end/core/i18n/locales/en-US.json +60 -0
  7. package/front_end/core/i18n/locales/en-XL.json +60 -0
  8. package/front_end/core/sdk/DebuggerModel.ts +10 -0
  9. package/front_end/devtools_compatibility.js +1 -0
  10. package/front_end/legacy_test_runner/sources_test_runner/DebuggerTestRunner.js +4 -3
  11. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +166 -117
  12. package/front_end/models/bindings/ResourceScriptMapping.ts +12 -1
  13. package/front_end/models/extensions/ExtensionAPI.ts +101 -13
  14. package/front_end/models/extensions/ExtensionServer.ts +63 -1
  15. package/front_end/models/extensions/LanguageExtensionEndpoint.ts +16 -3
  16. package/front_end/models/issues_manager/RelatedIssue.ts +1 -1
  17. package/front_end/models/issues_manager/descriptions/federatedAuthRequestErrorIdToken.md +1 -1
  18. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -1
  19. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -1
  20. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -1
  21. package/front_end/models/timeline_model/TimelineModel.ts +164 -7
  22. package/front_end/panels/application/AppManifestView.ts +13 -2
  23. package/front_end/panels/application/ApplicationPanelSidebar.ts +67 -5
  24. package/front_end/panels/elements/ElementsTreeOutline.ts +41 -7
  25. package/front_end/panels/elements/TopLayerContainer.ts +9 -1
  26. package/front_end/panels/elements/components/AdornerManager.ts +7 -0
  27. package/front_end/panels/elements/elementsTreeOutline.css +4 -0
  28. package/front_end/panels/network/components/RequestHeadersView.css +55 -0
  29. package/front_end/panels/network/components/RequestHeadersView.ts +278 -14
  30. package/front_end/panels/sources/AddSourceMapURLDialog.ts +17 -3
  31. package/front_end/panels/sources/CallStackSidebarPane.ts +7 -0
  32. package/front_end/panels/sources/DebuggerPlugin.ts +29 -3
  33. package/front_end/panels/sources/ScopeChainSidebarPane.ts +8 -0
  34. package/front_end/panels/sources/SourcesPanel.ts +14 -0
  35. package/front_end/third_party/acorn/acorn.ts +1 -1
  36. package/front_end/third_party/chromium/client-variations/client-variations.ts +1 -1
  37. package/front_end/third_party/diff/DiffWrapper.ts +2 -0
  38. package/front_end/third_party/i18n/i18n-impl.ts +5 -1
  39. package/front_end/third_party/i18n/i18n.ts +1 -1
  40. package/front_end/third_party/i18n/locales.ts +1 -1
  41. package/front_end/third_party/marked/marked.ts +1 -1
  42. package/front_end/third_party/puppeteer/puppeteer.ts +6 -6
  43. package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorController.ts +23 -1
  44. package/front_end/ui/legacy/ReportView.ts +8 -0
  45. package/package.json +1 -1
  46. package/scripts/eslint_rules/lib/custom_element_definitions_location.js +29 -14
  47. package/scripts/eslint_rules/lib/es_modules_import.js +5 -1
  48. package/scripts/eslint_rules/tests/custom_element_definitions_location_test.js +14 -2
  49. package/scripts/eslint_rules/tests/es_modules_import_test.js +5 -0
@@ -35,10 +35,12 @@
35
35
  import * as Common from '../../core/common/common.js';
36
36
  import * as i18n from '../../core/i18n/i18n.js';
37
37
  import * as SDK from '../../core/sdk/sdk.js';
38
+ import * as Adorners from '../../ui/components/adorners/adorners.js';
38
39
  import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
40
+ import * as IconButton from '../../ui/components/icon_button/icon_button.js';
39
41
  import * as UI from '../../ui/legacy/legacy.js';
40
42
 
41
- import {linkifyDeferredNodeReference} from './DOMLinkifier.js';
43
+ import * as ElementsComponents from './components/components.js';
42
44
  import {ElementsPanel} from './ElementsPanel.js';
43
45
  import {ElementsTreeElement, InitialChildrenLimit} from './ElementsTreeElement.js';
44
46
  import elementsTreeOutlineStyles from './elementsTreeOutline.css.js';
@@ -1629,13 +1631,45 @@ export class ShortcutTreeElement extends UI.TreeOutline.TreeElement {
1629
1631
  text = '<' + text + '>';
1630
1632
  }
1631
1633
  title.textContent = '\u21AA ' + text;
1632
-
1633
- const link = (linkifyDeferredNodeReference(nodeShortcut.deferredNode) as Element);
1634
- UI.UIUtils.createTextChild(this.listItemElement, ' ');
1635
- link.classList.add('elements-tree-shortcut-link');
1636
- link.textContent = i18nString(UIStrings.reveal);
1637
- this.listItemElement.appendChild(link);
1638
1634
  this.nodeShortcut = nodeShortcut;
1635
+ this.addRevealAdorner();
1636
+ }
1637
+
1638
+ addRevealAdorner(): void {
1639
+ const adorner = new Adorners.Adorner.Adorner();
1640
+ adorner.classList.add('adorner-reveal');
1641
+ const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
1642
+ ElementsComponents.AdornerManager.RegisteredAdorners.REVEAL);
1643
+ const name = config.name;
1644
+ const adornerContent = document.createElement('span');
1645
+ const linkIcon = new IconButton.Icon.Icon();
1646
+ linkIcon
1647
+ .data = {iconName: 'ic_show_node_16x16', color: 'var(--color-text-disabled)', width: '12px', height: '12px'};
1648
+ const slotText = document.createElement('span');
1649
+ slotText.textContent = name;
1650
+ adornerContent.append(linkIcon);
1651
+ adornerContent.append(slotText);
1652
+ adornerContent.classList.add('adorner-with-icon');
1653
+ adorner.data = {
1654
+ name,
1655
+ content: adornerContent,
1656
+ };
1657
+ this.listItemElement.appendChild(adorner);
1658
+ const onClick = (((): void => {
1659
+ this.nodeShortcut.deferredNode.resolve(
1660
+ node => {
1661
+ void Common.Revealer.reveal(node);
1662
+ },
1663
+ );
1664
+ }) as EventListener);
1665
+ adorner.addInteraction(onClick, {
1666
+ isToggle: false,
1667
+ shouldPropagateOnKeydown: false,
1668
+ ariaLabelDefault: i18nString(UIStrings.reveal),
1669
+ ariaLabelActive: i18nString(UIStrings.reveal),
1670
+ });
1671
+ adorner.addEventListener('mousedown', e => e.consume(), false);
1672
+ ElementsPanel.instance().registerAdorner(adorner);
1639
1673
  }
1640
1674
 
1641
1675
  get hovered(): boolean {
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
  import * as i18n from '../../core/i18n/i18n.js';
5
5
  import * as SDK from '../../core/sdk/sdk.js';
6
+ import * as IconButton from '../../ui/components/icon_button/icon_button.js';
6
7
  import * as UI from '../../ui/legacy/legacy.js';
7
8
 
8
9
  import * as ElementsComponents from './components/components.js';
@@ -79,7 +80,14 @@ export class TopLayerContainer extends UI.TreeOutline.TreeElement {
79
80
  const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
80
81
  ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER);
81
82
  const adornerContent = document.createElement('span');
82
- adornerContent.textContent = ` top-layer (${topLayerElementIndex}) `;
83
+ adornerContent.classList.add('adorner-with-icon');
84
+ const linkIcon = new IconButton.Icon.Icon();
85
+ linkIcon
86
+ .data = {iconName: 'ic_show_node_16x16', color: 'var(--color-text-disabled)', width: '12px', height: '12px'};
87
+ const adornerText = document.createElement('span');
88
+ adornerText.textContent = ` top-layer (${topLayerElementIndex}) `;
89
+ adornerContent.append(linkIcon);
90
+ adornerContent.append(adornerText);
83
91
  const adorner = element?.adorn(config, adornerContent);
84
92
  if (adorner) {
85
93
  const onClick = (((): void => {
@@ -31,6 +31,7 @@ export enum RegisteredAdorners {
31
31
  CONTAINER = 'container',
32
32
  SLOT = 'slot',
33
33
  TOP_LAYER = 'top-layer',
34
+ REVEAL = 'reveal',
34
35
  }
35
36
 
36
37
  // This enum-like const object serves as the authoritative registry for all the
@@ -79,6 +80,12 @@ export function getRegisteredAdorner(which: RegisteredAdorners): RegisteredAdorn
79
80
  category: AdornerCategories.LAYOUT,
80
81
  enabledByDefault: true,
81
82
  };
83
+ case RegisteredAdorners.REVEAL:
84
+ return {
85
+ name: 'reveal',
86
+ category: AdornerCategories.DEFAULT,
87
+ enabledByDefault: true,
88
+ };
82
89
  }
83
90
  }
84
91
 
@@ -27,6 +27,10 @@
27
27
  display: none;
28
28
  }
29
29
 
30
+ .adorner-reveal {
31
+ margin: 3px;
32
+ }
33
+
30
34
  .adorner-with-icon {
31
35
  display: flex;
32
36
  justify-content: center;
@@ -109,3 +109,58 @@ div.raw-headers-row {
109
109
  white-space: pre-wrap;
110
110
  word-break: break-all;
111
111
  }
112
+
113
+ .header-badge-text {
114
+ font-variant: small-caps;
115
+ font-weight: 500;
116
+ white-space: pre-wrap;
117
+ word-break: break-all;
118
+ }
119
+
120
+ .header-badge {
121
+ display: inline;
122
+ margin-right: 0.75em;
123
+ background-color: var(--color-accent-red);
124
+ color: var(--color-background);
125
+ border-radius: 100vh;
126
+ padding-left: 6px;
127
+ padding-right: 6px;
128
+ }
129
+
130
+ .call-to-action {
131
+ background-color: var(--color-background-elevation-1);
132
+ padding: 8px;
133
+ border-radius: 2px;
134
+ }
135
+
136
+ .call-to-action-body {
137
+ padding: 6px 0;
138
+ margin-left: 9.5px;
139
+ border-left: 2px solid var(--issue-color-yellow);
140
+ padding-left: 18px;
141
+ line-height: 20px;
142
+ }
143
+
144
+ .call-to-action .explanation {
145
+ font-weight: bold;
146
+ }
147
+
148
+ .call-to-action code {
149
+ font-size: 90%;
150
+ }
151
+
152
+ .call-to-action .example .comment::before {
153
+ content: " — ";
154
+ }
155
+
156
+ .link,
157
+ .devtools-link {
158
+ color: var(--color-link);
159
+ text-decoration: underline;
160
+ cursor: pointer;
161
+ padding: 2px 0; /* adjust focus ring size */
162
+ }
163
+
164
+ .inline-icon {
165
+ vertical-align: middle;
166
+ }
@@ -3,11 +3,16 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  import * as Common from '../../../core/common/common.js';
6
+ import * as Host from '../../../core/host/host.js';
6
7
  import * as i18n from '../../../core/i18n/i18n.js';
8
+ import * as Platform from '../../../core/platform/platform.js';
7
9
  import {assertNotNullOrUndefined} from '../../../core/platform/platform.js';
8
10
  import * as SDK from '../../../core/sdk/sdk.js';
11
+ import * as Protocol from '../../../generated/protocol.js';
12
+ import * as IssuesManager from '../../../models/issues_manager/issues_manager.js';
9
13
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
10
14
  import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
15
+ import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
11
16
  import * as Input from '../../../ui/components/input/input.js';
12
17
  import * as UI from '../../../ui/legacy/legacy.js';
13
18
  import * as LitHtml from '../../../ui/lit-html/lit-html.js';
@@ -19,6 +24,11 @@ const {render, html} = LitHtml;
19
24
 
20
25
  const UIStrings = {
21
26
  /**
27
+ *@description Text in Headers View of the Network panel
28
+ */
29
+ chooseThisOptionIfTheResourceAnd:
30
+ 'Choose this option if the resource and the document are served from the same site.',
31
+ /**
22
32
  *@description Text in Request Headers View of the Network panel
23
33
  */
24
34
  fromDiskCache: '(from disk cache)',
@@ -47,10 +57,23 @@ const UIStrings = {
47
57
  */
48
58
  general: 'General',
49
59
  /**
60
+ *@description Text that is usually a hyperlink to more documentation
61
+ */
62
+ learnMore: 'Learn more',
63
+ /**
64
+ *@description Text for a link to the issues panel
65
+ */
66
+ learnMoreInTheIssuesTab: 'Learn more in the issues tab',
67
+ /**
50
68
  *@description Label for a checkbox to switch between raw and parsed headers
51
69
  */
52
70
  raw: 'Raw',
53
71
  /**
72
+ *@description Text in Headers View of the Network panel
73
+ */
74
+ onlyChooseThisOptionIfAn:
75
+ 'Only choose this option if an arbitrary website including this resource does not impose a security risk.',
76
+ /**
54
77
  *@description Text in Request Headers View of the Network panel
55
78
  */
56
79
  referrerPolicy: 'Referrer Policy',
@@ -82,9 +105,35 @@ const UIStrings = {
82
105
  *@description HTTP response code
83
106
  */
84
107
  statusCode: 'Status Code',
108
+ /**
109
+ *@description Text in Headers View of the Network panel
110
+ */
111
+ thisDocumentWasBlockedFrom:
112
+ 'This document was blocked from loading in an `iframe` with a `sandbox` attribute because this document specified a cross-origin opener policy.',
113
+ /**
114
+ *@description Text in Headers View of the Network panel
115
+ */
116
+ toEmbedThisFrameInYourDocument:
117
+ 'To embed this frame in your document, the response needs to enable the cross-origin embedder policy by specifying the following response header:',
118
+ /**
119
+ *@description Text in Headers View of the Network panel
120
+ */
121
+ toUseThisResourceFromADifferent:
122
+ 'To use this resource from a different origin, the server needs to specify a cross-origin resource policy in the response headers:',
123
+ /**
124
+ *@description Text in Headers View of the Network panel
125
+ */
126
+ toUseThisResourceFromADifferentOrigin:
127
+ 'To use this resource from a different origin, the server may relax the cross-origin resource policy response header:',
128
+ /**
129
+ *@description Text in Headers View of the Network panel
130
+ */
131
+ toUseThisResourceFromADifferentSite:
132
+ 'To use this resource from a different site, the server may relax the cross-origin resource policy response header:',
85
133
  };
86
134
  const str_ = i18n.i18n.registerUIStrings('panels/network/components/RequestHeadersView.ts', UIStrings);
87
135
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
136
+ const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
88
137
 
89
138
  export class RequestHeadersView extends UI.Widget.VBox {
90
139
  readonly #headersView = new RequestHeadersComponent();
@@ -152,6 +201,39 @@ export class RequestHeadersComponent extends HTMLElement {
152
201
  #renderResponseHeaders(): LitHtml.TemplateResult {
153
202
  assertNotNullOrUndefined(this.#request);
154
203
 
204
+ const headersWithIssues = [];
205
+ if (this.#request.wasBlocked()) {
206
+ const headerWithIssues =
207
+ BlockedReasonDetails.get((this.#request.blockedReason() as Protocol.Network.BlockedReason));
208
+ if (headerWithIssues) {
209
+ headersWithIssues.push(headerWithIssues);
210
+ }
211
+ }
212
+
213
+ function mergeHeadersWithIssues(
214
+ headers: SDK.NetworkRequest.NameValue[], headersWithIssues: HeaderDescriptor[]): HeaderDescriptor[] {
215
+ let i = 0, j = 0;
216
+ const result: HeaderDescriptor[] = [];
217
+ while (i < headers.length && j < headersWithIssues.length) {
218
+ if (headers[i].name < headersWithIssues[j].name) {
219
+ result.push({...headers[i++], headerNotSet: false});
220
+ } else if (headers[i].name > headersWithIssues[j].name) {
221
+ result.push({...headersWithIssues[j++], headerNotSet: true});
222
+ } else {
223
+ result.push({...headersWithIssues[j++], ...headers[i++], headerNotSet: false});
224
+ }
225
+ }
226
+ while (i < headers.length) {
227
+ result.push({...headers[i++], headerNotSet: false});
228
+ }
229
+ while (j < headersWithIssues.length) {
230
+ result.push({...headersWithIssues[j++], headerNotSet: true});
231
+ }
232
+ return result;
233
+ }
234
+
235
+ const mergedHeaders = mergeHeadersWithIssues(this.#request.sortedResponseHeaders.slice(), headersWithIssues);
236
+
155
237
  const toggleShowRaw = (): void => {
156
238
  this.#showResponseHeadersText = !this.#showResponseHeadersText;
157
239
  this.#render();
@@ -172,12 +254,7 @@ export class RequestHeadersComponent extends HTMLElement {
172
254
  >
173
255
  ${this.#showResponseHeadersText ?
174
256
  this.#renderRawHeaders(this.#request.responseHeadersText, true) : html`
175
- ${this.#request.sortedResponseHeaders.map(header => html`
176
- <div class="row">
177
- <div class="header-name">${header.name}:</div>
178
- <div class="header-value">${header.value}</div>
179
- </div>
180
- `)}
257
+ ${mergedHeaders.map(header => this.#renderHeader(header))}
181
258
  `}
182
259
  </${Category.litTagName}>
183
260
  `;
@@ -186,13 +263,17 @@ export class RequestHeadersComponent extends HTMLElement {
186
263
  #renderRequestHeaders(): LitHtml.TemplateResult {
187
264
  assertNotNullOrUndefined(this.#request);
188
265
 
266
+ const headers = this.#request.requestHeaders().slice();
267
+ headers.sort(function(a, b) {
268
+ return Platform.StringUtilities.compare(a.name.toLowerCase(), b.name.toLowerCase());
269
+ });
270
+ const requestHeadersText = this.#request.requestHeadersText();
271
+
189
272
  const toggleShowRaw = (): void => {
190
273
  this.#showRequestHeadersText = !this.#showRequestHeadersText;
191
274
  this.#render();
192
275
  };
193
276
 
194
- const requestHeadersText = this.#request.requestHeadersText();
195
-
196
277
  // Disabled until https://crbug.com/1079231 is fixed.
197
278
  // clang-format off
198
279
  return html`
@@ -208,17 +289,85 @@ export class RequestHeadersComponent extends HTMLElement {
208
289
  >
209
290
  ${(this.#showRequestHeadersText && requestHeadersText) ?
210
291
  this.#renderRawHeaders(requestHeadersText, false) : html`
211
- ${this.#request.requestHeaders().map(header => html`
212
- <div class="row">
213
- <div class="header-name">${header.name}:</div>
214
- <div class="header-value">${header.value}</div>
215
- </div>
216
- `)}
292
+ ${headers.map(header => this.#renderHeader({...header, headerNotSet: false}))}
217
293
  `}
218
294
  </${Category.litTagName}>
219
295
  `;
220
296
  }
221
297
 
298
+ #renderHeader(header: HeaderDescriptor): LitHtml.TemplateResult {
299
+ return html`
300
+ <div class="row">
301
+ <div class="header-name">${header.headerNotSet ? html`<div class="header-badge header-badge-text">not-set</div>` : ''}${header.name}:</div>
302
+ <div class="header-value ${header.headerValueIncorrect ? 'header-warning' : ''}">${header.value?.toString()||''}</div>
303
+ </div>
304
+ ${this.#maybeRenderHeaderDetails(header.details)}
305
+ `;
306
+ }
307
+
308
+ #maybeRenderHeaderDetails(headerDetails?: HeaderDetailsDescriptor): LitHtml.LitTemplate {
309
+ if (!headerDetails) {
310
+ return LitHtml.nothing;
311
+ }
312
+ return html`
313
+ <div class="header-details">
314
+ <div class="call-to-action">
315
+ <div class="call-to-action-body">
316
+ <div class="explanation">${headerDetails.explanation()}</div>
317
+ ${headerDetails.examples.map(example => html`
318
+ <div class="example">
319
+ <code>${example.codeSnippet}</code>
320
+ ${example.comment ? html`
321
+ <span class="comment">${example.comment()}</span>
322
+ ` : ''}
323
+ </div>
324
+ `)}
325
+ ${this.#maybeRenderHeaderDetailsLink(headerDetails)}
326
+ </div>
327
+ </div>
328
+ </div>
329
+ `;
330
+ }
331
+
332
+ #maybeRenderHeaderDetailsLink(headerDetails?: HeaderDetailsDescriptor): LitHtml.LitTemplate {
333
+ if (this.#request && IssuesManager.RelatedIssue.hasIssueOfCategory(this.#request, IssuesManager.Issue.IssueCategory.CrossOriginEmbedderPolicy)) {
334
+ const followLink = (): void => {
335
+ Host.userMetrics.issuesPanelOpenedFrom(Host.UserMetrics.IssueOpener.LearnMoreLinkCOEP);
336
+ if (this.#request) {
337
+ void IssuesManager.RelatedIssue.reveal(
338
+ this.#request, IssuesManager.Issue.IssueCategory.CrossOriginEmbedderPolicy);
339
+ }
340
+ };
341
+ return html`
342
+ <div class="devtools-link" @click=${followLink}>
343
+ <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
344
+ iconName: 'issue-exclamation-icon',
345
+ color: 'var(--issue-color-yellow)',
346
+ width: '16px',
347
+ height: '16px',
348
+ } as IconButton.Icon.IconData}>
349
+ </${IconButton.Icon.Icon.litTagName}>
350
+ ${i18nString(UIStrings.learnMoreInTheIssuesTab)}
351
+ </div>
352
+ `;
353
+ }
354
+ if (headerDetails?.link) {
355
+ return html`
356
+ <x-link href=${headerDetails.link.url} class="link">
357
+ <${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
358
+ iconName: 'link_icon',
359
+ color: 'var(--color-link)',
360
+ width: '16px',
361
+ height: '16px',
362
+ } as IconButton.Icon.IconData}>
363
+ </${IconButton.Icon.Icon.litTagName}
364
+ >${i18nString(UIStrings.learnMore)}
365
+ </x-link>
366
+ `;
367
+ }
368
+ return LitHtml.nothing;
369
+ }
370
+
222
371
  #renderRawHeaders(rawHeadersText: string, forResponseHeaders: boolean): LitHtml.TemplateResult {
223
372
  const trimmed = rawHeadersText.trim();
224
373
  const showFull = forResponseHeaders ? this.#showResponseHeadersTextFull : this.#showRequestHeadersTextFull;
@@ -434,3 +583,118 @@ declare global {
434
583
  'devtools-request-headers-category': Category;
435
584
  }
436
585
  }
586
+
587
+ interface HeaderDetailsDescriptor {
588
+ explanation: () => string;
589
+ examples: Array<{
590
+ codeSnippet: string,
591
+ comment?: (() => string),
592
+ }>;
593
+ link: {
594
+ url: string,
595
+ }|null;
596
+ }
597
+
598
+ interface HeaderDescriptor {
599
+ name: string;
600
+ value: Object|null;
601
+ headerValueIncorrect?: boolean|null;
602
+ details?: HeaderDetailsDescriptor;
603
+ headerNotSet: boolean|null;
604
+ }
605
+
606
+ const BlockedReasonDetails = new Map<Protocol.Network.BlockedReason, HeaderDescriptor>([
607
+ [
608
+ Protocol.Network.BlockedReason.CoepFrameResourceNeedsCoepHeader,
609
+ {
610
+ name: 'cross-origin-embedder-policy',
611
+ value: null,
612
+ headerValueIncorrect: null,
613
+ details: {
614
+ explanation: i18nLazyString(UIStrings.toEmbedThisFrameInYourDocument),
615
+ examples: [{codeSnippet: 'Cross-Origin-Embedder-Policy: require-corp', comment: undefined}],
616
+ link: {url: 'https://web.dev/coop-coep/'},
617
+ },
618
+ headerNotSet: null,
619
+ },
620
+ ],
621
+ [
622
+ Protocol.Network.BlockedReason.CorpNotSameOriginAfterDefaultedToSameOriginByCoep,
623
+ {
624
+ name: 'cross-origin-resource-policy',
625
+ value: null,
626
+ headerValueIncorrect: null,
627
+ details: {
628
+ explanation: i18nLazyString(UIStrings.toUseThisResourceFromADifferent),
629
+ examples: [
630
+ {
631
+ codeSnippet: 'Cross-Origin-Resource-Policy: same-site',
632
+ comment: i18nLazyString(UIStrings.chooseThisOptionIfTheResourceAnd),
633
+ },
634
+ {
635
+ codeSnippet: 'Cross-Origin-Resource-Policy: cross-origin',
636
+ comment: i18nLazyString(UIStrings.onlyChooseThisOptionIfAn),
637
+ },
638
+ ],
639
+ link: {url: 'https://web.dev/coop-coep/'},
640
+ },
641
+ headerNotSet: null,
642
+ },
643
+ ],
644
+ [
645
+ Protocol.Network.BlockedReason.CoopSandboxedIframeCannotNavigateToCoopPage,
646
+ {
647
+ name: 'cross-origin-opener-policy',
648
+ value: null,
649
+ headerValueIncorrect: false,
650
+ details: {
651
+ explanation: i18nLazyString(UIStrings.thisDocumentWasBlockedFrom),
652
+ examples: [],
653
+ link: {url: 'https://web.dev/coop-coep/'},
654
+ },
655
+ headerNotSet: null,
656
+ },
657
+ ],
658
+ [
659
+ Protocol.Network.BlockedReason.CorpNotSameSite,
660
+ {
661
+ name: 'cross-origin-resource-policy',
662
+ value: null,
663
+ headerValueIncorrect: true,
664
+ details: {
665
+ explanation: i18nLazyString(UIStrings.toUseThisResourceFromADifferentSite),
666
+ examples: [
667
+ {
668
+ codeSnippet: 'Cross-Origin-Resource-Policy: cross-origin',
669
+ comment: i18nLazyString(UIStrings.onlyChooseThisOptionIfAn),
670
+ },
671
+ ],
672
+ link: null,
673
+ },
674
+ headerNotSet: null,
675
+ },
676
+ ],
677
+ [
678
+ Protocol.Network.BlockedReason.CorpNotSameOrigin,
679
+ {
680
+ name: 'cross-origin-resource-policy',
681
+ value: null,
682
+ headerValueIncorrect: true,
683
+ details: {
684
+ explanation: i18nLazyString(UIStrings.toUseThisResourceFromADifferentOrigin),
685
+ examples: [
686
+ {
687
+ codeSnippet: 'Cross-Origin-Resource-Policy: same-site',
688
+ comment: i18nLazyString(UIStrings.chooseThisOptionIfTheResourceAnd),
689
+ },
690
+ {
691
+ codeSnippet: 'Cross-Origin-Resource-Policy: cross-origin',
692
+ comment: i18nLazyString(UIStrings.onlyChooseThisOptionIfAn),
693
+ },
694
+ ],
695
+ link: null,
696
+ },
697
+ headerNotSet: null,
698
+ },
699
+ ],
700
+ ]);
@@ -14,20 +14,25 @@ const UIStrings = {
14
14
  */
15
15
  sourceMapUrl: 'Source map URL: ',
16
16
  /**
17
+ *@description Text in Add Debug Info URL Dialog of the Sources panel
18
+ */
19
+ debugInfoUrl: 'DWARF symbols URL: ',
20
+ /**
17
21
  *@description Text to add something
18
22
  */
19
23
  add: 'Add',
20
24
  };
21
25
  const str_ = i18n.i18n.registerUIStrings('panels/sources/AddSourceMapURLDialog.ts', UIStrings);
22
26
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
23
- export class AddSourceMapURLDialog extends UI.Widget.HBox {
27
+ export class AddDebugInfoURLDialog extends UI.Widget.HBox {
24
28
  private readonly input: HTMLInputElement;
25
29
  private readonly dialog: UI.Dialog.Dialog;
26
30
  private readonly callback: (arg0: Platform.DevToolsPath.UrlString) => void;
27
- constructor(callback: (arg0: Platform.DevToolsPath.UrlString) => void) {
31
+ private constructor(
32
+ label: Platform.UIString.LocalizedString, callback: (arg0: Platform.DevToolsPath.UrlString) => void) {
28
33
  super(/* isWebComponent */ true);
29
34
 
30
- this.contentElement.createChild('label').textContent = i18nString(UIStrings.sourceMapUrl);
35
+ this.contentElement.createChild('label').textContent = label;
31
36
 
32
37
  this.input = UI.UIUtils.createInput('add-source-map', 'text');
33
38
  this.input.addEventListener('keydown', this.onKeyDown.bind(this), false);
@@ -43,6 +48,15 @@ export class AddSourceMapURLDialog extends UI.Widget.HBox {
43
48
  this.callback = callback;
44
49
  }
45
50
 
51
+ static createAddSourceMapURLDialog(callback: (arg0: Platform.DevToolsPath.UrlString) => void): AddDebugInfoURLDialog {
52
+ return new AddDebugInfoURLDialog(i18nString(UIStrings.sourceMapUrl), callback);
53
+ }
54
+
55
+ static createAddDWARFSymbolsURLDialog(callback: (arg0: Platform.DevToolsPath.UrlString) => void):
56
+ AddDebugInfoURLDialog {
57
+ return new AddDebugInfoURLDialog(i18nString(UIStrings.debugInfoUrl), callback);
58
+ }
59
+
46
60
  show(): void {
47
61
  super.show(this.dialog.contentElement);
48
62
  // UI.Dialog extends GlassPane and overrides the `show` method with a wider
@@ -160,6 +160,9 @@ export class CallStackSidebarPane extends UI.View.SimpleView implements UI.Conte
160
160
 
161
161
  this.updateItemThrottler = new Common.Throttler.Throttler(100);
162
162
  this.scheduledForUpdateItems = new Set();
163
+
164
+ SDK.TargetManager.TargetManager.instance().addModelListener(
165
+ SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebugInfoAttached, this.debugInfoAttached, this);
163
166
  }
164
167
 
165
168
  static instance(opts: {
@@ -179,6 +182,10 @@ export class CallStackSidebarPane extends UI.View.SimpleView implements UI.Conte
179
182
  this.update();
180
183
  }
181
184
 
185
+ private debugInfoAttached(): void {
186
+ this.update();
187
+ }
188
+
182
189
  private update(): void {
183
190
  void this.updateThrottler.schedule(() => this.doUpdate());
184
191
  }
@@ -45,7 +45,7 @@ import * as SourceFrame from '../../ui/legacy/components/source_frame/source_fra
45
45
  import * as UI from '../../ui/legacy/legacy.js';
46
46
  import type * as TextEditor from '../../ui/components/text_editor/text_editor.js';
47
47
 
48
- import {AddSourceMapURLDialog} from './AddSourceMapURLDialog.js';
48
+ import {AddDebugInfoURLDialog} from './AddSourceMapURLDialog.js';
49
49
  import {BreakpointEditDialog, LogpointPrefix} from './BreakpointEditDialog.js';
50
50
  import {Plugin} from './Plugin.js';
51
51
  import {ScriptFormatterEditorAction} from './ScriptFormatterEditorAction.js';
@@ -112,6 +112,10 @@ const UIStrings = {
112
112
  /**
113
113
  *@description Text in Debugger Plugin of the Sources panel
114
114
  */
115
+ addWasmDebugInfo: 'Add DWARF debug info…',
116
+ /**
117
+ *@description Text in Debugger Plugin of the Sources panel
118
+ */
115
119
  sourceMapDetected: 'Source map detected.',
116
120
  /**
117
121
  *@description Text in Debugger Plugin of the Sources panel
@@ -480,7 +484,8 @@ export class DebuggerPlugin extends Plugin {
480
484
 
481
485
  populateTextAreaContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
482
486
  function addSourceMapURL(scriptFile: Bindings.ResourceScriptMapping.ResourceScriptFile): void {
483
- const dialog = new AddSourceMapURLDialog(addSourceMapURLDialogCallback.bind(null, scriptFile));
487
+ const dialog =
488
+ AddDebugInfoURLDialog.createAddSourceMapURLDialog(addSourceMapURLDialogCallback.bind(null, scriptFile));
484
489
  dialog.show();
485
490
  }
486
491
 
@@ -492,13 +497,34 @@ export class DebuggerPlugin extends Plugin {
492
497
  scriptFile.addSourceMapURL(url);
493
498
  }
494
499
 
500
+ function addDebugInfoURL(scriptFile: Bindings.ResourceScriptMapping.ResourceScriptFile): void {
501
+ const dialog =
502
+ AddDebugInfoURLDialog.createAddDWARFSymbolsURLDialog(addDebugInfoURLDialogCallback.bind(null, scriptFile));
503
+ dialog.show();
504
+ }
505
+
506
+ function addDebugInfoURLDialogCallback(
507
+ scriptFile: Bindings.ResourceScriptMapping.ResourceScriptFile, url: Platform.DevToolsPath.UrlString): void {
508
+ if (!url) {
509
+ return;
510
+ }
511
+ scriptFile.addDebugInfoURL(url);
512
+ }
513
+
495
514
  if (this.uiSourceCode.project().type() === Workspace.Workspace.projectTypes.Network &&
496
515
  Common.Settings.Settings.instance().moduleSetting('jsSourceMapsEnabled').get() &&
497
516
  !Bindings.IgnoreListManager.IgnoreListManager.instance().isIgnoreListedUISourceCode(this.uiSourceCode)) {
498
517
  if (this.scriptFileForDebuggerModel.size) {
499
- const scriptFile = this.scriptFileForDebuggerModel.values().next().value;
518
+ const scriptFile: Bindings.ResourceScriptMapping.ResourceScriptFile =
519
+ this.scriptFileForDebuggerModel.values().next().value;
500
520
  const addSourceMapURLLabel = i18nString(UIStrings.addSourceMap);
501
521
  contextMenu.debugSection().appendItem(addSourceMapURLLabel, addSourceMapURL.bind(null, scriptFile));
522
+ if (scriptFile.script?.isWasm() &&
523
+ !Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().pluginManager?.hasPluginForScript(
524
+ scriptFile.script)) {
525
+ contextMenu.debugSection().appendItem(
526
+ i18nString(UIStrings.addWasmDebugInfo), addDebugInfoURL.bind(null, scriptFile));
527
+ }
502
528
  }
503
529
  }
504
530
  }