Skip to content

Commit 4fc9ccc

Browse files
Merge pull request #2403 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-arguments-for-html-elements
Extract rule: template-no-arguments-for-html-elements
2 parents f0209b2 + 2710aab commit 4fc9ccc

6 files changed

Lines changed: 184 additions & 5 deletions

File tree

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,12 @@ rules in templates can be disabled with eslint directives with mustache or html
187187

188188
### Best Practices
189189

190-
| Name | Description | 💼 | 🔧 | 💡 |
191-
| :----------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- |
192-
| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
193-
| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | |
194-
| [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | | | |
190+
| Name | Description | 💼 | 🔧 | 💡 |
191+
| :----------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- |
192+
| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
193+
| [template-no-arguments-for-html-elements](docs/rules/template-no-arguments-for-html-elements.md) | disallow @arguments on HTML elements | | | |
194+
| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | |
195+
| [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | | | |
195196

196197
### Components
197198

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# ember/template-no-arguments-for-html-elements
2+
3+
<!-- end auto-generated rule header -->
4+
5+
💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`.
6+
7+
Disallow `@arguments` on HTML elements.
8+
9+
Arguments (using the `@` prefix) are a feature specific to Ember components. They should not be used on regular HTML elements, which only support standard HTML attributes.
10+
11+
## Rule Details
12+
13+
This rule disallows using `@arguments` on HTML elements. Use regular attributes instead.
14+
15+
## Examples
16+
17+
### Incorrect ❌
18+
19+
```gjs
20+
<template>
21+
<div @title="Hello">Content</div>
22+
</template>
23+
```
24+
25+
```gjs
26+
<template>
27+
<button @onClick={{this.handler}}>Click</button>
28+
</template>
29+
```
30+
31+
```gjs
32+
<template>
33+
<span @data={{this.info}}>Text</span>
34+
</template>
35+
```
36+
37+
### Correct ✅
38+
39+
```gjs
40+
<template>
41+
<div title="Hello">Content</div>
42+
</template>
43+
```
44+
45+
```gjs
46+
<template>
47+
<button {{on "click" this.handler}}>Click</button>
48+
</template>
49+
```
50+
51+
```gjs
52+
<template>
53+
<MyComponent @title="Hello" @onClick={{this.handler}} />
54+
</template>
55+
```
56+
57+
## Related Rules
58+
59+
- [template-no-block-params-for-html-elements](./template-no-block-params-for-html-elements.md)
60+
61+
## References
62+
63+
- [Ember Guides - Component Arguments](https://guides.emberjs.com/release/components/component-arguments-and-html-attributes/)
64+
- [eslint-plugin-ember template-no-args-paths](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-args-paths.md)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
const htmlTags = require('html-tags');
3+
4+
module.exports = {
5+
meta: {
6+
type: 'problem',
7+
docs: {
8+
description: 'disallow @arguments on HTML elements',
9+
category: 'Best Practices',
10+
strictGjs: true,
11+
strictGts: true,
12+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-arguments-for-html-elements.md',
13+
},
14+
fixable: null,
15+
schema: [],
16+
messages: {
17+
noArgumentsForHtmlElements:
18+
'@arguments can only be used on components, not HTML elements. Use regular attributes instead.',
19+
},
20+
},
21+
22+
create(context) {
23+
const sourceCode = context.sourceCode;
24+
const HTML_ELEMENTS = new Set(htmlTags);
25+
26+
return {
27+
GlimmerElementNode(node) {
28+
// Check if this is an HTML element (lowercase)
29+
if (!HTML_ELEMENTS.has(node.tag)) {
30+
return;
31+
}
32+
33+
// If the tag name is a variable in scope, it's being used as a component, not an HTML element
34+
const scope = sourceCode.getScope(node.parent);
35+
const isVariable = scope.references.some((ref) => ref.identifier === node.parts[0]);
36+
if (isVariable) {
37+
return;
38+
}
39+
40+
// Check for @arguments
41+
for (const attr of node.attributes) {
42+
if (attr.type === 'GlimmerAttrNode' && attr.name.startsWith('@')) {
43+
context.report({
44+
node: attr,
45+
messageId: 'noArgumentsForHtmlElements',
46+
});
47+
}
48+
}
49+
},
50+
};
51+
},
52+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"ember-rfc176-data": "^0.3.18",
6666
"eslint-utils": "^3.0.0",
6767
"estraverse": "^5.3.0",
68+
"html-tags": "^3.3.1",
6869
"lodash.camelcase": "^4.3.0",
6970
"lodash.kebabcase": "^4.1.1",
7071
"requireindex": "^1.2.0",

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.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const rule = require('../../../lib/rules/template-no-arguments-for-html-elements');
2+
const RuleTester = require('eslint').RuleTester;
3+
4+
const ruleTester = new RuleTester({
5+
parser: require.resolve('ember-eslint-parser'),
6+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
7+
});
8+
9+
ruleTester.run('template-no-arguments-for-html-elements', rule, {
10+
valid: [
11+
'<template><div class="container">Content</div></template>',
12+
'<template><button type="submit">Submit</button></template>',
13+
'<template><MyComponent @title="Hello" @onClick={{this.handler}} /></template>',
14+
'<template><CustomButton @disabled={{true}} /></template>',
15+
'<template><input value={{this.value}} /></template>',
16+
`let div = <template>{{@greeting}}</template>
17+
18+
<template>
19+
<div @greeting="hello" />
20+
</template>`,
21+
],
22+
23+
invalid: [
24+
{
25+
code: '<template><div @title="Hello">Content</div></template>',
26+
output: null,
27+
errors: [
28+
{
29+
message:
30+
'@arguments can only be used on components, not HTML elements. Use regular attributes instead.',
31+
type: 'GlimmerAttrNode',
32+
},
33+
],
34+
},
35+
{
36+
code: '<template><button @onClick={{this.handler}}>Click</button></template>',
37+
output: null,
38+
errors: [
39+
{
40+
message:
41+
'@arguments can only be used on components, not HTML elements. Use regular attributes instead.',
42+
type: 'GlimmerAttrNode',
43+
},
44+
],
45+
},
46+
{
47+
code: '<template><span @data={{this.info}}>Text</span></template>',
48+
output: null,
49+
errors: [
50+
{
51+
message:
52+
'@arguments can only be used on components, not HTML elements. Use regular attributes instead.',
53+
type: 'GlimmerAttrNode',
54+
},
55+
],
56+
},
57+
],
58+
});

0 commit comments

Comments
 (0)