Skip to content

Commit 339f907

Browse files
NullVoxPopuliclaude
andcommitted
Fix false positives: remove PascalCase component shadowing detection
The original ember-template-lint no-shadowed-elements rule only checks lowercase HTML elements shadowed by local block params. PascalCase tags like <Input>, <Form>, <Select>, <Textarea> are legitimate Ember/Glimmer component invocations and should not be flagged. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent a7b61b0 commit 339f907

2 files changed

Lines changed: 26 additions & 64 deletions

File tree

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

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -177,40 +177,27 @@ module.exports = {
177177
return;
178178
}
179179

180-
const firstChar = tag.charAt(0);
181-
const startsWithUpperCase =
182-
firstChar === firstChar.toUpperCase() && firstChar !== firstChar.toLowerCase();
183180
const containsDot = tag.includes('.');
184181

185182
if (containsDot) {
186183
// dot paths like bar.baz are not ambiguous
187184
return;
188185
}
189186

190-
if (startsWithUpperCase) {
191-
// PascalCase element
192-
if (isLocal(tag)) {
193-
// Local block param starting with uppercase → unambiguous → don't flag
194-
return;
195-
}
196-
// Not a local: check if it shadows HTML element
197-
const lowerTag = tag.toLowerCase();
198-
if (HTML_ELEMENTS.has(lowerTag)) {
199-
context.report({
200-
node,
201-
messageId: 'shadowed',
202-
data: { name: lowerTag },
203-
});
204-
}
205-
} else {
206-
// Lowercase element - check if it's a local that shadows HTML element
207-
if (isLocal(tag) && HTML_ELEMENTS.has(tag)) {
208-
context.report({
209-
node,
210-
messageId: 'shadowed',
211-
data: { name: tag },
212-
});
213-
}
187+
// Only check lowercase elements — a lowercase tag that is a local
188+
// block param and also a native HTML element name is shadowed.
189+
// PascalCase tags (e.g. <Input>, <Form>, <Select>) are Ember/Glimmer
190+
// component invocations and should not be flagged.
191+
const firstChar = tag.charAt(0);
192+
const isLowerCase =
193+
firstChar === firstChar.toLowerCase() && firstChar !== firstChar.toUpperCase();
194+
195+
if (isLowerCase && isLocal(tag) && HTML_ELEMENTS.has(tag)) {
196+
context.report({
197+
node,
198+
messageId: 'shadowed',
199+
data: { name: tag },
200+
});
214201
}
215202
},
216203

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

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ ruleTester.run('template-no-shadowed-elements', rule, {
2525
`<template>
2626
<CustomForm />
2727
</template>`,
28+
`<template>
29+
<Form>Content</Form>
30+
</template>`,
31+
`<template>
32+
<Input @type="text" />
33+
</template>`,
34+
`<template>
35+
<Select @options={{this.options}} />
36+
</template>`,
37+
`<template>
38+
<Textarea @value={{this.text}} />
39+
</template>`,
2840
`<template>
2941
<div>Content</div>
3042
</template>`,
@@ -36,43 +48,6 @@ ruleTester.run('template-no-shadowed-elements', rule, {
3648
],
3749

3850
invalid: [
39-
{
40-
code: `<template>
41-
<Form>Content</Form>
42-
</template>`,
43-
output: null,
44-
errors: [
45-
{
46-
message: 'Component name "form" shadows HTML element <form>. Use a different name.',
47-
type: 'GlimmerElementNode',
48-
},
49-
],
50-
},
51-
{
52-
code: `<template>
53-
<Input @type="text" />
54-
</template>`,
55-
output: null,
56-
errors: [
57-
{
58-
message: 'Component name "input" shadows HTML element <input>. Use a different name.',
59-
type: 'GlimmerElementNode',
60-
},
61-
],
62-
},
63-
{
64-
code: `<template>
65-
<Select @options={{this.options}} />
66-
</template>`,
67-
output: null,
68-
errors: [
69-
{
70-
message: 'Component name "select" shadows HTML element <select>. Use a different name.',
71-
type: 'GlimmerElementNode',
72-
},
73-
],
74-
},
75-
7651
{
7752
code: '<template><FooBar as |div|><div></div></FooBar></template>',
7853
output: null,

0 commit comments

Comments
 (0)