Skip to content

Commit 3adddfc

Browse files
Merge pull request #2530 from johanrd/autofix/no-action-modifiers
Restore autofix: `template-no-action-modifiers`
2 parents ec64db5 + 3af016f commit 3adddfc

4 files changed

Lines changed: 55 additions & 21 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ rules in templates can be disabled with eslint directives with mustache or html
202202
| Name                                          | Description | 💼 | 🔧 | 💡 |
203203
| :----------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :- | :- | :- |
204204
| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
205-
| [template-no-action-modifiers](docs/rules/template-no-action-modifiers.md) | disallow usage of {{action}} modifiers | | | |
205+
| [template-no-action-modifiers](docs/rules/template-no-action-modifiers.md) | disallow usage of {{action}} modifiers | | 🔧 | |
206206
| [template-no-action-on-submit-button](docs/rules/template-no-action-on-submit-button.md) | disallow action attribute on submit buttons | | | |
207207
| [template-no-args-paths](docs/rules/template-no-args-paths.md) | disallow args.foo paths in templates, use @foo instead | | 🔧 | |
208208
| [template-no-arguments-for-html-elements](docs/rules/template-no-arguments-for-html-elements.md) | disallow @arguments on HTML elements | | | |

docs/rules/template-no-action-modifiers.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# ember/template-no-action-modifiers
22

3+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
4+
35
<!-- end auto-generated rule header -->
46

57
💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`.

lib/rules/template-no-action-modifiers.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ module.exports = {
99
strictGts: true,
1010
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-action-modifiers.md',
1111
},
12-
fixable: null,
12+
fixable: 'code',
1313
schema: [
1414
{
1515
oneOf: [
@@ -40,6 +40,7 @@ module.exports = {
4040
create(context) {
4141
const firstOption = context.options[0];
4242
const allowlist = Array.isArray(firstOption) ? firstOption : firstOption?.allowlist || [];
43+
const sourceCode = context.sourceCode ?? context.getSourceCode();
4344

4445
function checkForActionModifier(node) {
4546
if (
@@ -49,9 +50,35 @@ module.exports = {
4950
node.path.head?.type !== 'AtHead' &&
5051
node.path.head?.type !== 'ThisHead'
5152
) {
53+
// Only offer autofix when the first param is a path expression
54+
const maybePath = node.params?.[0];
55+
const canFix = maybePath && maybePath.type === 'GlimmerPathExpression';
56+
5257
context.report({
5358
node,
5459
messageId: 'noActionModifier',
60+
fix: canFix
61+
? (fixer) => {
62+
const args = node.params.slice(1);
63+
const pathText = sourceCode.getText(maybePath);
64+
65+
let replacement;
66+
if (args.length === 0) {
67+
// {{action this.handleClick}} → {{on "click" this.handleClick}}
68+
replacement = `on "click" ${pathText}`;
69+
} else {
70+
// {{action this.handleClick "arg"}} → {{on "click" (fn this.handleClick "arg")}}
71+
const argsText = args.map((a) => sourceCode.getText(a)).join(' ');
72+
replacement = `on "click" (fn ${pathText} ${argsText})`;
73+
}
74+
75+
const lastParam = node.params.at(-1);
76+
return fixer.replaceTextRange(
77+
[node.path.range[0], lastParam.range[1]],
78+
replacement
79+
);
80+
}
81+
: null,
5582
});
5683
}
5784
}

tests/lib/rules/template-no-action-modifiers.js

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ ruleTester.run('template-no-action-modifiers', rule, {
1818
code: '<template><button {{action "save"}}>Save</button></template>',
1919
options: [{ allowlist: ['button'] }],
2020
},
21-
// Array shorthand config format (matching ember-template-lint)
2221
{
2322
code: '<template><button {{action "save"}}>Save</button></template>',
2423
options: [['button']],
@@ -27,34 +26,40 @@ ruleTester.run('template-no-action-modifiers', rule, {
2726

2827
invalid: [
2928
{
29+
// String literal first param — no autofix
3030
code: '<template><button {{action "save"}}>Save</button></template>',
3131
output: null,
32-
errors: [
33-
{
34-
message: 'Do not use action modifiers. Use on modifier with a function instead.',
35-
type: 'GlimmerElementModifierStatement',
36-
},
37-
],
32+
errors: [{ messageId: 'noActionModifier' }],
3833
},
3934
{
4035
code: '<template><div {{action "onClick"}}>Click me</div></template>',
4136
output: null,
42-
errors: [
43-
{
44-
message: 'Do not use action modifiers. Use on modifier with a function instead.',
45-
type: 'GlimmerElementModifierStatement',
46-
},
47-
],
37+
errors: [{ messageId: 'noActionModifier' }],
4838
},
4939
{
5040
code: '<template><form {{action "submit" on="submit"}}>Submit</form></template>',
5141
output: null,
52-
errors: [
53-
{
54-
message: 'Do not use action modifiers. Use on modifier with a function instead.',
55-
type: 'GlimmerElementModifierStatement',
56-
},
57-
],
42+
errors: [{ messageId: 'noActionModifier' }],
43+
},
44+
{
45+
// Path expression — autofix: {{action this.handleClick}} → {{on "click" this.handleClick}}
46+
code: '<template><button {{action this.handleClick}}>Save</button></template>',
47+
output: '<template><button {{on "click" this.handleClick}}>Save</button></template>',
48+
errors: [{ messageId: 'noActionModifier' }],
49+
},
50+
{
51+
// Path with args — autofix wraps in (fn ...)
52+
code: '<template><button {{action this.handleClick "arg1"}}>Save</button></template>',
53+
output:
54+
'<template><button {{on "click" (fn this.handleClick "arg1")}}>Save</button></template>',
55+
errors: [{ messageId: 'noActionModifier' }],
56+
},
57+
{
58+
// Path with multiple args
59+
code: '<template><button {{action this.handleClick "arg1" "arg2"}}>Save</button></template>',
60+
output:
61+
'<template><button {{on "click" (fn this.handleClick "arg1" "arg2")}}>Save</button></template>',
62+
errors: [{ messageId: 'noActionModifier' }],
5863
},
5964
],
6065
});

0 commit comments

Comments
 (0)