Skip to content

Commit b4a9afd

Browse files
Merge pull request #2695 from johanrd/day_fix/template-no-shadowed-elements
Post-merge-review: Fix template-no-shadowed-elements: align HTML-element detection with upstream
2 parents 2a01def + 7eb499b commit b4a9afd

2 files changed

Lines changed: 58 additions & 16 deletions

File tree

lib/rules/template-no-shadowed-elements.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
1-
const htmlTags = require('html-tags');
1+
// Mirror upstream ember-template-lint's inverse-of-isAngleBracketComponent logic.
2+
// A tag is treated as an HTML element only when it:
3+
// - does NOT contain ':' (named blocks like <:slot>)
4+
// - does NOT contain '.' (path/namespaced invocations like <foo.bar>)
5+
// - does NOT start with '@' (argument invocations like <@foo>)
6+
// - has NO uppercase letters (component invocations like <MyThing>)
7+
// - does NOT contain '-' (HTML custom elements like <my-element>)
8+
// Everything else is a component / custom-element / slot — not a plain HTML element.
9+
function isHtmlElement(tagName) {
10+
if (!tagName) {
11+
return false;
12+
}
13+
if (tagName.startsWith('@')) {
14+
return false;
15+
}
16+
if (tagName.includes(':')) {
17+
return false;
18+
}
19+
if (tagName.includes('.')) {
20+
return false;
21+
}
22+
if (tagName.includes('-')) {
23+
return false;
24+
}
25+
if (tagName !== tagName.toLowerCase()) {
26+
return false;
27+
}
28+
return true;
29+
}
230

331
/** @type {import('eslint').Rule.RuleModule} */
432
module.exports = {
@@ -24,8 +52,6 @@ module.exports = {
2452
},
2553

2654
create(context) {
27-
const HTML_ELEMENTS = new Set(htmlTags);
28-
2955
const blockParamScope = [];
3056

3157
function pushScope(params) {
@@ -68,22 +94,17 @@ module.exports = {
6894
return;
6995
}
7096

71-
const containsDot = tag.includes('.');
72-
73-
if (containsDot) {
74-
// dot paths like bar.baz are not ambiguous
97+
// Mirror upstream: if the tag is an angle-bracket-component (i.e.
98+
// not a plain HTML element — contains '.', is PascalCase, has a
99+
// hyphen, etc.) it cannot be a shadow of a native HTML element.
100+
// Only a lowercase / simple tag that is a local block param is
101+
// considered shadowed. This also covers tags not in any static
102+
// html-tags list (upstream does not restrict to a known set).
103+
if (!isHtmlElement(tag)) {
75104
return;
76105
}
77106

78-
// Only check lowercase elements — a lowercase tag that is a local
79-
// block param and also a native HTML element name is shadowed.
80-
// PascalCase tags (e.g. <Input>, <Form>, <Select>) are Ember/Glimmer
81-
// component invocations and should not be flagged.
82-
const firstChar = tag.charAt(0);
83-
const isLowerCase =
84-
firstChar === firstChar.toLowerCase() && firstChar !== firstChar.toUpperCase();
85-
86-
if (isLowerCase && isLocal(tag) && HTML_ELEMENTS.has(tag)) {
107+
if (isLocal(tag)) {
87108
context.report({
88109
node,
89110
messageId: 'shadowed',

tests/lib/rules/template-no-shadowed-elements.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ ruleTester.run('template-no-shadowed-elements', rule, {
3535
},
3636
],
3737
},
38+
// Upstream flags any lowercase local block-param invocation, not just
39+
// names present in a static html-tags list.
40+
{
41+
code: '<template><FooBar as |foo|><foo></foo></FooBar></template>',
42+
output: null,
43+
errors: [
44+
{
45+
message: 'Component name "foo" shadows HTML element <foo>. Use a different name.',
46+
type: 'GlimmerElementNode',
47+
},
48+
],
49+
},
3850
],
3951
});
4052

@@ -63,5 +75,14 @@ hbsRuleTester.run('template-no-shadowed-elements', rule, {
6375
{ message: 'Component name "div" shadows HTML element <div>. Use a different name.' },
6476
],
6577
},
78+
// Upstream flags any lowercase local block-param invocation, not just
79+
// names present in a static html-tags list.
80+
{
81+
code: '<FooBar as |foo|><foo></foo></FooBar>',
82+
output: null,
83+
errors: [
84+
{ message: 'Component name "foo" shadows HTML element <foo>. Use a different name.' },
85+
],
86+
},
6687
],
6788
});

0 commit comments

Comments
 (0)