Skip to content

Commit 6b27474

Browse files
Merge pull request #2423 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-action
Extract rule: template-no-action
2 parents a86e4b3 + 5d346a2 commit 6b27474

File tree

4 files changed

+186
-0
lines changed

4 files changed

+186
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ rules in templates can be disabled with eslint directives with mustache or html
247247
| [no-observers](docs/rules/no-observers.md) | disallow usage of observers || | |
248248
| [no-old-shims](docs/rules/no-old-shims.md) | disallow usage of old shims for modules || 🔧 | |
249249
| [no-string-prototype-extensions](docs/rules/no-string-prototype-extensions.md) | disallow usage of `String` prototype extensions || | |
250+
| [template-no-action](docs/rules/template-no-action.md) | disallow {{action}} helper | | | |
250251

251252
### Ember Data
252253

docs/rules/template-no-action.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# ember/template-no-action
2+
3+
<!-- end auto-generated rule header -->
4+
5+
Disallows the use of `{{action}}` helper.
6+
7+
The `{{action}}` helper is deprecated in favor of the `{{on}}` modifier and `{{fn}}` helper, which provide better performance and clearer intent.
8+
9+
## Examples
10+
11+
Examples of **incorrect** code for this rule:
12+
13+
```gjs
14+
<template>
15+
<button {{on "click" (action "save")}}>Save</button>
16+
</template>
17+
```
18+
19+
```gjs
20+
<template>
21+
{{action "doSomething"}}
22+
</template>
23+
```
24+
25+
Examples of **correct** code for this rule:
26+
27+
```gjs
28+
<template>
29+
<button {{on "click" this.save}}>Save</button>
30+
</template>
31+
```
32+
33+
```gjs
34+
<template>
35+
<button {{on "click" (fn this.save "arg")}}>Save with arg</button>
36+
</template>
37+
```
38+
39+
```gjs
40+
<template>
41+
{{this.action}}
42+
</template>
43+
```
44+
45+
## Migration
46+
47+
- Replace `(action "methodName")` with method references or `(fn this.methodName)`
48+
- Replace `<button onclick={{action ...}}>` with `<button {{on "click" ...}}>`
49+
50+
## References
51+
52+
- [eslint-plugin-ember template-no-action](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-action.md)
53+
- [Ember.js Deprecations - action helper](https://deprecations.emberjs.com/v3.x/#toc_action-helper)
54+
- [Ember Modifier Documentation](https://guides.emberjs.com/release/components/template-lifecycle-dom-and-modifiers/)

lib/rules/template-no-action.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
function isActionHelper(node) {
2+
if (!node.path || node.path.type !== 'GlimmerPathExpression') {
3+
return false;
4+
}
5+
6+
// Check if it's the action helper (not this.action or @action)
7+
const path = node.path;
8+
if (path.original === 'action') {
9+
// Check head.type to avoid deprecated data/this properties
10+
const head = path.head;
11+
if (head && (head.type === 'AtHead' || head.type === 'ThisHead')) {
12+
return false;
13+
}
14+
return true;
15+
}
16+
17+
return false;
18+
}
19+
20+
/** @type {import('eslint').Rule.RuleModule} */
21+
module.exports = {
22+
meta: {
23+
type: 'suggestion',
24+
docs: {
25+
description: 'disallow {{action}} helper',
26+
category: 'Deprecations',
27+
strictGjs: true,
28+
strictGts: true,
29+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-action.md',
30+
},
31+
fixable: null,
32+
schema: [],
33+
messages: {
34+
subExpression:
35+
'Do not use `action` as (action ...). Instead, use the `on` modifier and `fn` helper.',
36+
mustache: 'Do not use `action` in templates. Instead, use the `on` modifier and `fn` helper.',
37+
},
38+
},
39+
40+
create(context) {
41+
return {
42+
GlimmerSubExpression(node) {
43+
if (isActionHelper(node)) {
44+
context.report({
45+
node,
46+
messageId: 'subExpression',
47+
});
48+
}
49+
},
50+
51+
GlimmerMustacheStatement(node) {
52+
// Skip if inside an attribute
53+
let parent = node.parent;
54+
while (parent) {
55+
if (parent.type === 'GlimmerAttrNode') {
56+
return;
57+
}
58+
parent = parent.parent;
59+
}
60+
61+
if (isActionHelper(node)) {
62+
context.report({
63+
node,
64+
messageId: 'mustache',
65+
});
66+
}
67+
},
68+
};
69+
},
70+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//------------------------------------------------------------------------------
2+
// Requirements
3+
//------------------------------------------------------------------------------
4+
5+
const rule = require('../../../lib/rules/template-no-action');
6+
const RuleTester = require('eslint').RuleTester;
7+
8+
//------------------------------------------------------------------------------
9+
// Tests
10+
//------------------------------------------------------------------------------
11+
12+
const ruleTester = new RuleTester({
13+
parser: require.resolve('ember-eslint-parser'),
14+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
15+
});
16+
17+
ruleTester.run('template-no-action', rule, {
18+
valid: [
19+
`<template>
20+
<button {{on "click" this.handleClick}}>Click</button>
21+
</template>`,
22+
`<template>
23+
<button {{on "click" (fn this.save "arg")}}>Save</button>
24+
</template>`,
25+
`<template>
26+
{{this.action}}
27+
</template>`,
28+
`<template>
29+
{{@action}}
30+
</template>`,
31+
],
32+
33+
invalid: [
34+
{
35+
code: `<template>
36+
<button {{on "click" (action "save")}}>Save</button>
37+
</template>`,
38+
output: null,
39+
errors: [
40+
{
41+
message:
42+
'Do not use `action` as (action ...). Instead, use the `on` modifier and `fn` helper.',
43+
type: 'GlimmerSubExpression',
44+
},
45+
],
46+
},
47+
{
48+
code: `<template>
49+
{{action "doSomething"}}
50+
</template>`,
51+
output: null,
52+
errors: [
53+
{
54+
message:
55+
'Do not use `action` in templates. Instead, use the `on` modifier and `fn` helper.',
56+
type: 'GlimmerMustacheStatement',
57+
},
58+
],
59+
},
60+
],
61+
});

0 commit comments

Comments
 (0)