Skip to content

Commit fbc68ce

Browse files
committed
fix(template-no-arguments-for-html-elements): extend allowlist with svg-tags
Adds svg-tags to the html-tags allowlist so `<circle @r="x">` etc. are flagged alongside HTML elements. Documents accepted false negatives (custom elements, namespaced components, named blocks) via new test cases. Also adds a test for the scope-check path (`div` rebound in GJS is treated as a component, not flagged).
1 parent 56f913d commit fbc68ce

4 files changed

Lines changed: 25 additions & 7 deletions

File tree

lib/rules/template-no-arguments-for-html-elements.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
/** @type {import('eslint').Rule.RuleModule} */
21
const htmlTags = require('html-tags');
2+
const svgTags = require('svg-tags');
3+
4+
const ELEMENT_TAGS = new Set([...htmlTags, ...svgTags]);
35

6+
/** @type {import('eslint').Rule.RuleModule} */
47
module.exports = {
58
meta: {
69
type: 'problem',
@@ -16,27 +19,31 @@ module.exports = {
1619
noArgumentsForHtmlElements:
1720
'@arguments can only be used on components, not HTML elements. Use regular attributes instead.',
1821
},
22+
originallyFrom: {
23+
name: 'ember-template-lint',
24+
rule: 'lib/rules/no-arguments-for-html-elements.js',
25+
docs: 'docs/rule/no-arguments-for-html-elements.md',
26+
tests: 'test/unit/rules/no-arguments-for-html-elements-test.js',
27+
},
1928
},
2029

2130
create(context) {
2231
const sourceCode = context.sourceCode;
23-
const HTML_ELEMENTS = new Set(htmlTags);
2432

2533
return {
2634
GlimmerElementNode(node) {
27-
// Check if this is an HTML element (lowercase)
28-
if (!HTML_ELEMENTS.has(node.tag)) {
35+
if (!ELEMENT_TAGS.has(node.tag)) {
2936
return;
3037
}
3138

32-
// If the tag name is a variable in scope, it's being used as a component, not an HTML element
39+
// A known HTML/SVG tag can still be a component if it's bound in scope
40+
// (block param, import, local).
3341
const scope = sourceCode.getScope(node.parent);
3442
const isVariable = scope.references.some((ref) => ref.identifier === node.parts[0]);
3543
if (isVariable) {
3644
return;
3745
}
3846

39-
// Check for @arguments
4047
for (const attr of node.attributes) {
4148
if (attr.type === 'GlimmerAttrNode' && attr.name.startsWith('@')) {
4249
context.report({

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-arguments-for-html-elements.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ ruleTester.run('template-no-arguments-for-html-elements', rule, {
1313
'<template><MyComponent @title="Hello" @onClick={{this.handler}} /></template>',
1414
'<template><CustomButton @disabled={{true}} /></template>',
1515
'<template><input value={{this.value}} /></template>',
16+
// Custom elements aren't in the html-tags/svg-tags allowlists, so they're
17+
// not flagged. Accepted false negative — web component namespace is open.
18+
'<template><my-element @foo="x" /></template>',
19+
// Namespaced/path component invocations aren't in the allowlists either.
20+
'<template><NS.Foo @bar="baz" /></template>',
21+
// Named blocks (colon-prefixed) aren't in the allowlists either.
22+
'<template><Thing><:slot @item="x">content</:slot></Thing></template>',
1623
`let div = <template>{{@greeting}}</template>
1724
1825
<template>

0 commit comments

Comments
 (0)