chrome-devtools-frontend 1.0.1013875 → 1.0.1015276

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 (104) hide show
  1. package/.eslintignore +1 -0
  2. package/config/gni/devtools_grd_files.gni +3 -2
  3. package/front_end/core/i18n/locales/af.json +195 -93
  4. package/front_end/core/i18n/locales/am.json +191 -89
  5. package/front_end/core/i18n/locales/ar.json +193 -91
  6. package/front_end/core/i18n/locales/as.json +192 -90
  7. package/front_end/core/i18n/locales/az.json +191 -89
  8. package/front_end/core/i18n/locales/be.json +191 -89
  9. package/front_end/core/i18n/locales/bg.json +190 -88
  10. package/front_end/core/i18n/locales/bn.json +191 -89
  11. package/front_end/core/i18n/locales/bs.json +193 -91
  12. package/front_end/core/i18n/locales/ca.json +189 -87
  13. package/front_end/core/i18n/locales/cs.json +191 -89
  14. package/front_end/core/i18n/locales/cy.json +191 -89
  15. package/front_end/core/i18n/locales/da.json +191 -89
  16. package/front_end/core/i18n/locales/de.json +193 -91
  17. package/front_end/core/i18n/locales/el.json +174 -72
  18. package/front_end/core/i18n/locales/en-GB.json +132 -30
  19. package/front_end/core/i18n/locales/en-US.json +3 -0
  20. package/front_end/core/i18n/locales/en-XL.json +3 -0
  21. package/front_end/core/i18n/locales/es-419.json +192 -90
  22. package/front_end/core/i18n/locales/es.json +200 -98
  23. package/front_end/core/i18n/locales/et.json +190 -88
  24. package/front_end/core/i18n/locales/eu.json +197 -95
  25. package/front_end/core/i18n/locales/fa.json +192 -90
  26. package/front_end/core/i18n/locales/fi.json +192 -90
  27. package/front_end/core/i18n/locales/fil.json +190 -88
  28. package/front_end/core/i18n/locales/fr-CA.json +191 -89
  29. package/front_end/core/i18n/locales/fr.json +192 -90
  30. package/front_end/core/i18n/locales/gl.json +173 -71
  31. package/front_end/core/i18n/locales/gu.json +192 -90
  32. package/front_end/core/i18n/locales/he.json +191 -89
  33. package/front_end/core/i18n/locales/hi.json +172 -70
  34. package/front_end/core/i18n/locales/hr.json +180 -78
  35. package/front_end/core/i18n/locales/hu.json +191 -89
  36. package/front_end/core/i18n/locales/hy.json +192 -90
  37. package/front_end/core/i18n/locales/id.json +192 -90
  38. package/front_end/core/i18n/locales/is.json +176 -74
  39. package/front_end/core/i18n/locales/it.json +192 -90
  40. package/front_end/core/i18n/locales/ja.json +190 -88
  41. package/front_end/core/i18n/locales/ka.json +190 -88
  42. package/front_end/core/i18n/locales/kk.json +198 -96
  43. package/front_end/core/i18n/locales/km.json +195 -93
  44. package/front_end/core/i18n/locales/kn.json +193 -91
  45. package/front_end/core/i18n/locales/ko.json +190 -88
  46. package/front_end/core/i18n/locales/ky.json +193 -91
  47. package/front_end/core/i18n/locales/lo.json +192 -90
  48. package/front_end/core/i18n/locales/lt.json +193 -91
  49. package/front_end/core/i18n/locales/lv.json +175 -73
  50. package/front_end/core/i18n/locales/mk.json +193 -91
  51. package/front_end/core/i18n/locales/ml.json +193 -91
  52. package/front_end/core/i18n/locales/mn.json +190 -88
  53. package/front_end/core/i18n/locales/mr.json +191 -89
  54. package/front_end/core/i18n/locales/ms.json +190 -88
  55. package/front_end/core/i18n/locales/my.json +191 -89
  56. package/front_end/core/i18n/locales/ne.json +172 -70
  57. package/front_end/core/i18n/locales/nl.json +191 -89
  58. package/front_end/core/i18n/locales/no.json +191 -89
  59. package/front_end/core/i18n/locales/or.json +196 -94
  60. package/front_end/core/i18n/locales/pa.json +191 -89
  61. package/front_end/core/i18n/locales/pl.json +191 -89
  62. package/front_end/core/i18n/locales/pt-PT.json +199 -97
  63. package/front_end/core/i18n/locales/pt.json +191 -89
  64. package/front_end/core/i18n/locales/ro.json +193 -91
  65. package/front_end/core/i18n/locales/ru.json +193 -91
  66. package/front_end/core/i18n/locales/si.json +191 -89
  67. package/front_end/core/i18n/locales/sk.json +192 -90
  68. package/front_end/core/i18n/locales/sl.json +191 -89
  69. package/front_end/core/i18n/locales/sq.json +193 -91
  70. package/front_end/core/i18n/locales/sr-Latn.json +190 -88
  71. package/front_end/core/i18n/locales/sr.json +190 -88
  72. package/front_end/core/i18n/locales/sv.json +191 -89
  73. package/front_end/core/i18n/locales/sw.json +192 -90
  74. package/front_end/core/i18n/locales/ta.json +193 -91
  75. package/front_end/core/i18n/locales/te.json +134 -32
  76. package/front_end/core/i18n/locales/th.json +190 -88
  77. package/front_end/core/i18n/locales/tr.json +193 -91
  78. package/front_end/core/i18n/locales/uk.json +193 -91
  79. package/front_end/core/i18n/locales/ur.json +191 -89
  80. package/front_end/core/i18n/locales/uz.json +190 -88
  81. package/front_end/core/i18n/locales/vi.json +190 -88
  82. package/front_end/core/i18n/locales/zh-HK.json +192 -90
  83. package/front_end/core/i18n/locales/zh-TW.json +195 -93
  84. package/front_end/core/i18n/locales/zh.json +191 -89
  85. package/front_end/core/i18n/locales/zu.json +192 -90
  86. package/front_end/core/sdk/SourceMap.ts +88 -27
  87. package/front_end/models/issues_manager/DeprecationIssue.ts +10 -0
  88. package/front_end/models/javascript_metadata/DOMPinnedProperties.ts +3322 -833
  89. package/front_end/models/source_map_scopes/NamesResolver.ts +88 -19
  90. package/front_end/panels/elements/components/ElementsBreadcrumbs.ts +3 -4
  91. package/front_end/panels/elements/components/LayoutPane.ts +3 -4
  92. package/front_end/panels/elements/components/QueryContainer.ts +3 -4
  93. package/front_end/panels/elements/components/components.ts +0 -2
  94. package/front_end/panels/lighthouse/LighthouseStartView.ts +1 -0
  95. package/front_end/{panels/elements/components → ui/components/node_text}/NodeText.ts +2 -1
  96. package/front_end/{panels/elements/components → ui/components/node_text}/nodeText.css +0 -0
  97. package/front_end/ui/components/node_text/node_text.ts +9 -0
  98. package/package.json +1 -1
  99. package/scripts/eslint_rules/lib/check_component_naming.js +14 -6
  100. package/scripts/eslint_rules/tests/check_component_naming_test.js +23 -0
  101. package/scripts/webidl-properties/config.js +305 -239
  102. package/scripts/webidl-properties/get-props.js +23 -12
  103. package/scripts/webidl-properties/index.js +14 -9
  104. package/scripts/webidl-properties/tests.js +58 -14
@@ -174,6 +174,15 @@ export const scopeIdentifiers = async function(
174
174
  }
175
175
  };
176
176
 
177
+ const identifierAndPunctuationRegExp = /^\s*([A-Za-z_$][A-Za-z_$0-9]*)\s*([.;,]?)\s*$/;
178
+
179
+ const enum Punctuation {
180
+ None = 0,
181
+ Comma = 1,
182
+ Dot = 2,
183
+ Semicolon = 3,
184
+ }
185
+
177
186
  const resolveScope =
178
187
  async(scope: SDK.DebuggerModel
179
188
  .ScopeChainEntry): Promise<{variableMapping: Map<string, string>, thisMapping: string | null}> => {
@@ -182,8 +191,6 @@ const resolveScope =
182
191
  const sourceMap = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().sourceMapForScript(script);
183
192
 
184
193
  if (!cachedScopeMap || cachedScopeMap.sourceMap !== sourceMap) {
185
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
186
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
194
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
188
195
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
189
196
  const identifiersPromise =
@@ -260,33 +267,95 @@ const resolveScope =
260
267
  script: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap, name: string,
261
268
  position: {lineNumber: number, columnNumber: number},
262
269
  textCache: Map<string, TextUtils.Text.Text>): Promise<string|null> {
263
- const startEntry = sourceMap.findEntry(position.lineNumber, position.columnNumber);
264
- const endEntry = sourceMap.findEntry(position.lineNumber, position.columnNumber + name.length);
265
- if (!startEntry || !endEntry || !startEntry.sourceURL || startEntry.sourceURL !== endEntry.sourceURL ||
266
- !startEntry.sourceLineNumber || !startEntry.sourceColumnNumber || !endEntry.sourceLineNumber ||
267
- !endEntry.sourceColumnNumber) {
270
+ const ranges = sourceMap.findEntryRanges(position.lineNumber, position.columnNumber);
271
+ if (!ranges) {
268
272
  return null;
269
273
  }
270
- const sourceTextRange = new TextUtils.TextRange.TextRange(
271
- startEntry.sourceLineNumber, startEntry.sourceColumnNumber, endEntry.sourceLineNumber,
272
- endEntry.sourceColumnNumber);
274
+ // Extract the underlying text from the compiled code's range and make sure that
275
+ // it starts with the identifier |name|.
273
276
  const uiSourceCode =
274
277
  Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().uiSourceCodeForSourceMapSourceURL(
275
- script.debuggerModel, startEntry.sourceURL, script.isContentScript());
278
+ script.debuggerModel, ranges.sourceURL, script.isContentScript());
276
279
  if (!uiSourceCode) {
277
280
  return null;
278
281
  }
279
- const {content} = await uiSourceCode.requestContent();
280
- if (!content) {
282
+ const compiledText = getTextFor((await script.requestContent()).content);
283
+ if (!compiledText) {
284
+ return null;
285
+ }
286
+ const compiledToken = compiledText.extract(ranges.range);
287
+ const parsedCompiledToken = extractIdentifier(compiledToken);
288
+ if (!parsedCompiledToken) {
281
289
  return null;
282
290
  }
283
- let text = textCache.get(content);
284
- if (!text) {
285
- text = new TextUtils.Text.Text(content);
286
- textCache.set(content, text);
291
+ const {name: compiledName, punctuation: compiledPunctuation} = parsedCompiledToken;
292
+ if (compiledName !== name) {
293
+ return null;
294
+ }
295
+
296
+ // Extract the mapped name from the source code range and ensure that the punctuation
297
+ // matches the one from the compiled code.
298
+ const sourceText = getTextFor((await uiSourceCode.requestContent()).content);
299
+ if (!sourceText) {
300
+ return null;
301
+ }
302
+ const sourceToken = sourceText.extract(ranges.sourceRange);
303
+ const parsedSourceToken = extractIdentifier(sourceToken);
304
+ if (!parsedSourceToken) {
305
+ return null;
306
+ }
307
+ const {name: sourceName, punctuation: sourcePunctuation} = parsedSourceToken;
308
+ // Accept the source name if it is followed by the same punctuation.
309
+ if (compiledPunctuation === sourcePunctuation) {
310
+ return sourceName;
311
+ }
312
+ // Let us also allow semicolons into commas since that it is a common transformation.
313
+ if (compiledPunctuation === Punctuation.Comma && sourcePunctuation === Punctuation.Semicolon) {
314
+ return sourceName;
315
+ }
316
+
317
+ return null;
318
+
319
+ function extractIdentifier(token: string): {name: string, punctuation: Punctuation}|null {
320
+ const match = token.match(identifierAndPunctuationRegExp);
321
+ if (!match) {
322
+ return null;
323
+ }
324
+
325
+ const name = match[1];
326
+ let punctuation: Punctuation|null = null;
327
+ switch (match[2]) {
328
+ case '.':
329
+ punctuation = Punctuation.Dot;
330
+ break;
331
+ case ',':
332
+ punctuation = Punctuation.Comma;
333
+ break;
334
+ case ';':
335
+ punctuation = Punctuation.Semicolon;
336
+ break;
337
+ case '':
338
+ punctuation = Punctuation.None;
339
+ break;
340
+ default:
341
+ console.error(`Name token parsing error: unexpected token "${match[2]}"`);
342
+ return null;
343
+ }
344
+
345
+ return {name, punctuation};
346
+ }
347
+
348
+ function getTextFor(content: string|null): TextUtils.Text.Text|null {
349
+ if (!content) {
350
+ return null;
351
+ }
352
+ let text = textCache.get(content);
353
+ if (!text) {
354
+ text = new TextUtils.Text.Text(content);
355
+ textCache.set(content, text);
356
+ }
357
+ return text;
287
358
  }
288
- const originalIdentifier = text.extract(sourceTextRange).trim();
289
- return /[a-zA-Z0-9_$]+/.test(originalIdentifier) ? originalIdentifier : null;
290
359
  }
291
360
 
292
361
  function findFunctionScope(): SDK.DebuggerModel.ScopeChainEntry|null {
@@ -14,8 +14,7 @@ import {crumbsToRender} from './ElementsBreadcrumbsUtils.js';
14
14
  import type * as SDK from '../../../core/sdk/sdk.js';
15
15
  import type {DOMNode} from './Helper.js';
16
16
 
17
- import {NodeText} from './NodeText.js';
18
- import type {NodeTextData} from './NodeText.js';
17
+ import * as NodeText from '../../../ui/components/node_text/node_text.js';
19
18
 
20
19
  const UIStrings = {
21
20
  /**
@@ -300,11 +299,11 @@ export class ElementsBreadcrumbs extends HTMLElement {
300
299
  @mouseleave=${this.#onCrumbMouseLeave(crumb.node)}
301
300
  @focus=${this.#onCrumbFocus(crumb.node)}
302
301
  @blur=${this.#onCrumbBlur(crumb.node)}
303
- ><${NodeText.litTagName} data-node-title=${crumb.title.main} .data=${{
302
+ ><${NodeText.NodeText.NodeText.litTagName} data-node-title=${crumb.title.main} .data=${{
304
303
  nodeTitle: crumb.title.main,
305
304
  nodeId: crumb.title.extras.id,
306
305
  nodeClasses: crumb.title.extras.classes,
307
- } as NodeTextData}></${NodeText.litTagName}></a>
306
+ } as NodeText.NodeText.NodeTextData}></${NodeText.NodeText.NodeText.litTagName}></a>
308
307
  </li>`;
309
308
  })}
310
309
  </ul>
@@ -10,10 +10,9 @@ import * as LitHtml from '../../../ui/lit-html/lit-html.js';
10
10
  import type {BooleanSetting, EnumSetting, Setting} from './LayoutPaneUtils.js';
11
11
  import type {LayoutElement} from './LayoutPaneUtils.js';
12
12
 
13
- import type {NodeTextData} from './NodeText.js';
14
- import {NodeText} from './NodeText.js';
15
13
  import layoutPaneStyles from '../layoutPane.css.js';
16
14
  import * as Input from '../../../ui/components/input/input.js';
15
+ import * as NodeText from '../../../ui/components/node_text/node_text.js';
17
16
  // eslint-disable-next-line rulesdir/es_modules_import
18
17
  import inspectorCommonStyles from '../../../ui/legacy/inspectorCommon.css.js';
19
18
 
@@ -262,11 +261,11 @@ export class LayoutPane extends HTMLElement {
262
261
  <label data-element="true" class="checkbox-label">
263
262
  <input data-input="true" type="checkbox" .checked=${element.enabled} @change=${onElementToggle} />
264
263
  <span class="node-text-container" data-label="true" @mouseenter=${onMouseEnter} @mouseleave=${onMouseLeave}>
265
- <${NodeText.litTagName} .data=${{
264
+ <${NodeText.NodeText.NodeText.litTagName} .data=${{
266
265
  nodeId: element.domId,
267
266
  nodeTitle: element.name,
268
267
  nodeClasses: element.domClasses,
269
- } as NodeTextData}></${NodeText.litTagName}>
268
+ } as NodeText.NodeText.NodeTextData}></${NodeText.NodeText.NodeText.litTagName}>
270
269
  </span>
271
270
  </label>
272
271
  <label @keyup=${onColorLabelKeyUp} @keydown=${onColorLabelKeyDown} tabindex="0" title=${i18nString(UIStrings.chooseElementOverlayColor)} class="color-picker-label" style="background: ${element.color};">
@@ -5,11 +5,10 @@
5
5
  import * as SDK from '../../../core/sdk/sdk.js';
6
6
  import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
7
7
  import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
8
+ import * as NodeText from '../../../ui/components/node_text/node_text.js';
8
9
  import * as LitHtml from '../../../ui/lit-html/lit-html.js';
9
10
 
10
11
  import type {DOMNode} from './Helper.js';
11
- import {NodeText} from './NodeText.js';
12
- import type {NodeTextData} from './NodeText.js';
13
12
  import queryContainerStyles from './queryContainer.css.js';
14
13
 
15
14
  const {render, html} = LitHtml;
@@ -90,13 +89,13 @@ export class QueryContainer extends HTMLElement {
90
89
  @click=${this.#onContainerLinkClick}
91
90
  @mouseenter=${this.#onContainerLinkMouseEnter}
92
91
  @mouseleave=${this.#onContainerLinkMouseLeave}
93
- ><${NodeText.litTagName}
92
+ ><${NodeText.NodeText.NodeText.litTagName}
94
93
  data-node-title=${nodeTitle}
95
94
  .data=${{
96
95
  nodeTitle,
97
96
  nodeId: idToDisplay,
98
97
  nodeClasses: classesToDisplay,
99
- } as NodeTextData}></${NodeText.litTagName}></a>
98
+ } as NodeText.NodeText.NodeTextData}></${NodeText.NodeText.NodeText.litTagName}></a>
100
99
  ${this.#isContainerLinkHovered ? this.#renderQueriedSizeDetails() : LitHtml.nothing}
101
100
  `, this.#shadow, {
102
101
  host: this,
@@ -15,7 +15,6 @@ import * as ElementsPanelLink from './ElementsPanelLink.js';
15
15
  import * as Helper from './Helper.js';
16
16
  import * as LayoutPane from './LayoutPane.js';
17
17
  import * as LayoutPaneUtils from './LayoutPaneUtils.js';
18
- import * as NodeText from './NodeText.js';
19
18
  import * as QueryContainer from './QueryContainer.js';
20
19
  import * as StylePropertyEditor from './StylePropertyEditor.js';
21
20
 
@@ -33,7 +32,6 @@ export {
33
32
  Helper,
34
33
  LayoutPane,
35
34
  LayoutPaneUtils,
36
- NodeText,
37
35
  QueryContainer,
38
36
  StylePropertyEditor,
39
37
  };
@@ -256,6 +256,7 @@ export class StartView extends UI.Widget.Widget {
256
256
  }
257
257
  wasShown(): void {
258
258
  super.wasShown();
259
+ this.controller.recomputePageAuditability();
259
260
  this.registerCSSFiles([lighthouseStartViewStyles]);
260
261
  }
261
262
  }
@@ -2,8 +2,9 @@
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 ComponentHelpers from '../../../ui/components/helpers/helpers.js';
6
5
  import * as LitHtml from '../../../ui/lit-html/lit-html.js';
6
+ import * as ComponentHelpers from '../helpers/helpers.js';
7
+
7
8
  import nodeTextStyles from './nodeText.css.js';
8
9
 
9
10
  const {render, html} = LitHtml;
@@ -0,0 +1,9 @@
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
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 NodeText from './NodeText.js';
6
+
7
+ export {
8
+ NodeText,
9
+ };
package/package.json CHANGED
@@ -55,5 +55,5 @@
55
55
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
56
56
  "watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
57
57
  },
58
- "version": "1.0.1013875"
58
+ "version": "1.0.1015276"
59
59
  }
@@ -19,6 +19,7 @@ module.exports = {
19
19
  noDefineCall: 'Could not find a defineComponent() call for the component {{ tagName }}.',
20
20
  defineCallNonLiteral: 'defineComponent() first argument must be a string literal.',
21
21
  staticLiteralInvalid: 'static readonly litTagName must use a literal string, with no interpolation.',
22
+ duplicateStaticLitTagName: 'found a duplicated litTagName: {{ tagName }}',
22
23
  litTagNameNotLiteral:
23
24
  'litTagName must be defined as a string passed in as LitHtml.literal`component-name`, but no tagged template was found.',
24
25
  staticLiteralNotReadonly: 'static litTagName must be readonly.'
@@ -90,8 +91,9 @@ module.exports = {
90
91
  });
91
92
  }
92
93
 
93
- /** @type {Set<{classNode: any, tagName: string}>} */
94
- const componentClassDefinitionLitTagNamesFound = new Set();
94
+ // Map of litTagName to the class node.
95
+ /** @type {Map<string, any}>} */
96
+ const componentClassDefinitionLitTagNameNodes = new Map();
95
97
 
96
98
  /** @type {Set<string>} */
97
99
  const defineComponentCallsFound = new Set();
@@ -147,8 +149,15 @@ module.exports = {
147
149
  // Grab the name of the component, e.g:
148
150
  // LitHtml.literal`devtools-foo` will pull "devtools-foo" out.
149
151
  const componentTagName = componentTagNameNode.value.quasi.quasis[0].value.cooked;
150
- componentClassDefinitionLitTagNamesFound.add(
151
- {tagName: componentTagName, classNode: componentClassDefinition});
152
+
153
+ // Now we ensure that we haven't found this tag name before. If we
154
+ // have, we have two components with the same litTagName property,
155
+ // which is an error.
156
+ if (componentClassDefinitionLitTagNameNodes.has(componentTagName)) {
157
+ context.report({node: componentClassDefinition, messageId: 'duplicateStaticLitTagName', data: {tagName: componentTagName}});
158
+ }
159
+
160
+ componentClassDefinitionLitTagNameNodes.set(componentTagName, componentClassDefinition);
152
161
  }
153
162
 
154
163
  // Find all defineComponent() calls and store the arguments to them.
@@ -177,8 +186,7 @@ module.exports = {
177
186
  }
178
187
  }
179
188
 
180
- for (const foundComponentClass of componentClassDefinitionLitTagNamesFound) {
181
- const {tagName, classNode} = foundComponentClass;
189
+ for (const [tagName, classNode] of componentClassDefinitionLitTagNameNodes) {
182
190
  // Check that each tagName has a matching entry in both other places we expect it.
183
191
  if (!defineComponentCallsFound.has(tagName)) {
184
192
  context.report({node: classNode, messageId: 'noDefineCall', data: {tagName}});
@@ -233,5 +233,28 @@ ruleTester.run('check_component_naming', rule, {
233
233
  filename: 'front_end/ui/components/Foo.ts',
234
234
  errors: [{messageId: 'noDefineCall', data: {tagName: 'devtools-bar'}}]
235
235
  },
236
+ {
237
+ // Multiple components in one file is valid.
238
+ // But here devtools-foo is fine, but devtools-bar has the wrong static tag name
239
+ code: `export class Foo extends HTMLElement {
240
+ static readonly litTagName = LitHtml.literal\`devtools-foo\`
241
+ }
242
+
243
+ export class Bar extends HTMLElement {
244
+ static readonly litTagName = LitHtml.literal\`devtools-foo\`
245
+ }
246
+
247
+ ComponentHelpers.CustomElements.defineComponent('devtools-foo', Foo);
248
+ ComponentHelpers.CustomElements.defineComponent('devtools-bar', Foo);
249
+
250
+ declare global {
251
+ interface HTMLElementTagNameMap {
252
+ 'devtools-foo': Foo
253
+ 'devtools-bar': Bar
254
+ }
255
+ }`,
256
+ filename: 'front_end/ui/components/Foo.ts',
257
+ errors: [{messageId: 'duplicateStaticLitTagName', data: {tagName: 'devtools-foo'}}]
258
+ },
236
259
  ]
237
260
  });