Skip to content

Commit 4faabdc

Browse files
committed
fix(template-no-block-params-for-html-elements): switch to html-tags/svg-tags + scope
Replaces the inverse component-detection heuristic with a whitelist of HTML and SVG tag names plus a scope check. With ember-tooling/ember-eslint-parser#189 populating block-param scope in HBS, lists + scope now works in both modes. Custom elements and unknown lowercase tags remain accepted false negatives.
1 parent da0ad2b commit 4faabdc

File tree

4 files changed

+15
-37
lines changed

4 files changed

+15
-37
lines changed

lib/rules/template-no-block-params-for-html-elements.js

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,9 @@
1-
/** @type {import('eslint').Rule.RuleModule} */
1+
const htmlTags = require('html-tags');
2+
const svgTags = require('svg-tags');
23

3-
// A tag is treated as an HTML element only when it:
4-
// - does NOT contain ':' (named blocks like <:slot>)
5-
// - does NOT contain '.' (path/namespaced invocations like <foo.bar>)
6-
// - does NOT start with '@' (argument invocations like <@foo>)
7-
// - has NO uppercase letters (component invocations like <MyThing>)
8-
// - does NOT contain '-' (HTML custom elements like <my-element>)
9-
// Everything else is a component / custom-element / slot — not a plain HTML element.
10-
function isHtmlElement(tagName) {
11-
if (!tagName) {
12-
return false;
13-
}
14-
if (tagName.startsWith('@')) {
15-
return false;
16-
}
17-
if (tagName.includes(':')) {
18-
return false;
19-
}
20-
if (tagName.includes('.')) {
21-
return false;
22-
}
23-
if (tagName.includes('-')) {
24-
return false;
25-
}
26-
if (tagName !== tagName.toLowerCase()) {
27-
return false;
28-
}
29-
return true;
30-
}
4+
const ELEMENT_TAGS = new Set([...htmlTags, ...svgTags]);
315

6+
/** @type {import('eslint').Rule.RuleModule} */
327
module.exports = {
338
meta: {
349
type: 'problem',
@@ -51,19 +26,18 @@ module.exports = {
5126

5227
return {
5328
GlimmerElementNode(node) {
54-
// Check if this is an HTML element (not a component / custom element / slot)
55-
if (!isHtmlElement(node.tag)) {
29+
if (!ELEMENT_TAGS.has(node.tag)) {
5630
return;
5731
}
5832

59-
// If the tag name is a variable in scope, it's being used as a component, not an HTML element
33+
// A known HTML/SVG tag can still be a component if it's bound in scope
34+
// (block param, import, local).
6035
const scope = sourceCode.getScope(node.parent);
6136
const isVariable = scope.references.some((ref) => ref.identifier === node.parts[0]);
6237
if (isVariable) {
6338
return;
6439
}
6540

66-
// Check for block params
6741
if (node.blockParams && node.blockParams.length > 0) {
6842
context.report({
6943
node,

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@
7474
"lodash.camelcase": "^4.3.0",
7575
"lodash.kebabcase": "^4.1.1",
7676
"requireindex": "^1.2.0",
77-
"snake-case": "^3.0.3"
77+
"snake-case": "^3.0.3",
78+
"svg-tags": "^1.0.0"
7879
},
7980
"devDependencies": {
8081
"@babel/core": "^7.25.9",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/lib/rules/template-no-block-params-for-html-elements.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ ruleTester.run('template-no-block-params-for-html-elements', rule, {
1717
'<template><MyComponent as |item|>{{item.name}}</MyComponent></template>',
1818
'<template>{{#each this.items as |item|}}<li>{{item}}</li>{{/each}}</template>',
1919
'<template><button>Click</button></template>',
20-
// Custom elements (with a dash) are not HTML elements per upstream's
21-
// isAngleBracketComponent inverse; they should not be flagged.
20+
// Custom elements aren't in the html-tags/svg-tags allowlists, so they're
21+
// not flagged. Accepted false negative — web component namespace is open.
2222
'<template><my-element as |x|>{{x}}</my-element></template>',
23-
// Namespaced/path component invocations should not be treated as HTML elements.
23+
// Namespaced/path component invocations aren't in the allowlists either.
2424
'<template><NS.Foo as |x|>{{x}}</NS.Foo></template>',
2525
],
2626

0 commit comments

Comments
 (0)