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 } */
432module . 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' ,
0 commit comments