Skip to content

Commit df7e054

Browse files
Merge pull request #2456 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-at-ember-render-modifiers
Extract rule: template-no-at-ember-render-modifiers
2 parents aaf9e75 + 6357e5a commit df7e054

4 files changed

Lines changed: 243 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ rules in templates can be disabled with eslint directives with mustache or html
204204
| [template-no-action-on-submit-button](docs/rules/template-no-action-on-submit-button.md) | disallow action attribute on submit buttons | | | |
205205
| [template-no-arguments-for-html-elements](docs/rules/template-no-arguments-for-html-elements.md) | disallow @arguments on HTML elements | | | |
206206
| [template-no-array-prototype-extensions](docs/rules/template-no-array-prototype-extensions.md) | disallow usage of Ember Array prototype extensions | | | |
207+
| [template-no-at-ember-render-modifiers](docs/rules/template-no-at-ember-render-modifiers.md) | disallow usage of @ember/render-modifiers | | | |
207208
| [template-no-bare-yield](docs/rules/template-no-bare-yield.md) | disallow templates whose only meaningful content is a bare {{yield}} | | | |
208209
| [template-no-block-params-for-html-elements](docs/rules/template-no-block-params-for-html-elements.md) | disallow block params on HTML elements | | | |
209210
| [template-no-capital-arguments](docs/rules/template-no-capital-arguments.md) | disallow capital arguments (use lowercase @arg instead of @Arg) | | | |
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# ember/template-no-at-ember-render-modifiers
2+
3+
<!-- end auto-generated rule header -->
4+
5+
Disallows usage of modifiers from @ember/render-modifiers.
6+
7+
## Rule Details
8+
9+
The modifiers from `@ember/render-modifiers` (`{{did-insert}}`, `{{did-update}}`, `{{will-destroy}}`) should be replaced with alternatives from `ember-render-helpers` or other modern approaches.
10+
11+
## Examples
12+
13+
Examples of **incorrect** code for this rule:
14+
15+
```gjs
16+
<template>
17+
<div {{did-insert this.setup}}></div>
18+
</template>
19+
```
20+
21+
```gjs
22+
<template>
23+
<div {{did-update this.update}}></div>
24+
</template>
25+
```
26+
27+
```gjs
28+
<template>
29+
<div {{will-destroy this.cleanup}}></div>
30+
</template>
31+
```
32+
33+
Examples of **correct** code for this rule:
34+
35+
```gjs
36+
<template>
37+
<div {{on "click" this.handleClick}}></div>
38+
</template>
39+
```
40+
41+
## Migration
42+
43+
The migration path typically depends on what the render-modifier was used for, but if you need a custom modifier, the [`ember-modifier` README](https://github.com/ember-modifier/ember-modifier) covers everything you need to know for making custom modifiers.
44+
45+
For example, if render modifiers were used for setup/teardown, the migration to `ember-modifier` could be the following:
46+
47+
```js
48+
import Component from '@glimmer/component';
49+
import { modifier } from 'ember-modifier';
50+
51+
export default class MyComponent extends Component {
52+
myModifier = modifier((element) => {
53+
const handleEvent = () => {};
54+
55+
element.addEventListener('eventName', handleEvent);
56+
57+
return () => element.removeEventListener('eventName', handelEvent);
58+
});
59+
}
60+
```
61+
62+
```hbs
63+
<div {{this.myModifier}}>
64+
```
65+
66+
## References
67+
68+
- [eslint-plugin-ember template-no-at-ember-render-modifiers](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-at-ember-render-modifiers.md)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'suggestion',
5+
docs: {
6+
description: 'disallow usage of @ember/render-modifiers',
7+
category: 'Best Practices',
8+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-at-ember-render-modifiers.md',
9+
templateMode: 'both',
10+
},
11+
fixable: null,
12+
schema: [],
13+
messages: {
14+
noRenderModifier:
15+
'Do not use the `{{modifier}}` modifier. This modifier was intended to ease migration to Octane and not for long-term side-effects. Instead, either refactor to use data derivation patterns for a performance boost, or refactor to use a custom modifier. See https://github.com/ember-modifier/ember-modifier',
16+
},
17+
originallyFrom: {
18+
name: 'ember-template-lint',
19+
rule: 'lib/rules/no-at-ember-render-modifiers.js',
20+
docs: 'docs/rule/no-at-ember-render-modifiers.md',
21+
tests: 'test/unit/rules/no-at-ember-render-modifiers-test.js',
22+
},
23+
},
24+
25+
create(context) {
26+
return {
27+
GlimmerElementNode(node) {
28+
if (!node.modifiers) {
29+
return;
30+
}
31+
32+
for (const modifier of node.modifiers) {
33+
if (
34+
modifier.path &&
35+
modifier.path.type === 'GlimmerPathExpression' &&
36+
(modifier.path.original === 'did-insert' ||
37+
modifier.path.original === 'did-update' ||
38+
modifier.path.original === 'will-destroy')
39+
) {
40+
context.report({
41+
node: modifier,
42+
messageId: 'noRenderModifier',
43+
data: { modifier: modifier.path.original },
44+
});
45+
}
46+
}
47+
},
48+
};
49+
},
50+
};
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//------------------------------------------------------------------------------
2+
// Requirements
3+
//------------------------------------------------------------------------------
4+
5+
const rule = require('../../../lib/rules/template-no-at-ember-render-modifiers');
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-at-ember-render-modifiers', rule, {
18+
valid: [
19+
`<template>
20+
<div></div>
21+
</template>`,
22+
`<template>
23+
<div {{on "click" this.handleClick}}></div>
24+
</template>`,
25+
`<template>
26+
<MyComponent />
27+
</template>`,
28+
29+
'<template><div {{this.someModifier}}></div></template>',
30+
'<template><div {{someModifier}}></div></template>',
31+
'<template><div {{did-foo}}></div></template>',
32+
'<template>{{did-insert}}</template>',
33+
'<template>{{did-update}}</template>',
34+
'<template>{{will-destroy}}</template>',
35+
],
36+
37+
invalid: [
38+
{
39+
code: `<template>
40+
<div {{did-insert this.setup}}></div>
41+
</template>`,
42+
output: null,
43+
errors: [
44+
{
45+
messageId: 'noRenderModifier',
46+
type: 'GlimmerElementModifierStatement',
47+
},
48+
],
49+
},
50+
{
51+
code: `<template>
52+
<div {{did-update this.update}}></div>
53+
</template>`,
54+
output: null,
55+
errors: [
56+
{
57+
messageId: 'noRenderModifier',
58+
type: 'GlimmerElementModifierStatement',
59+
},
60+
],
61+
},
62+
{
63+
code: `<template>
64+
<div {{will-destroy this.cleanup}}></div>
65+
</template>`,
66+
output: null,
67+
errors: [
68+
{
69+
messageId: 'noRenderModifier',
70+
type: 'GlimmerElementModifierStatement',
71+
},
72+
],
73+
},
74+
75+
{
76+
code: '<template><div {{did-insert}}></div></template>',
77+
output: null,
78+
errors: [{ messageId: 'noRenderModifier' }],
79+
},
80+
{
81+
code: '<template><div {{did-update}}></div></template>',
82+
output: null,
83+
errors: [{ messageId: 'noRenderModifier' }],
84+
},
85+
{
86+
code: '<template><div {{will-destroy}}></div></template>',
87+
output: null,
88+
errors: [{ messageId: 'noRenderModifier' }],
89+
},
90+
],
91+
});
92+
93+
const hbsRuleTester = new RuleTester({
94+
parser: require.resolve('ember-eslint-parser/hbs'),
95+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
96+
});
97+
98+
hbsRuleTester.run('template-no-at-ember-render-modifiers (hbs)', rule, {
99+
valid: [
100+
'<div {{this.someModifier}}></div>',
101+
'<div {{someModifier}}></div>',
102+
'<div {{did-foo}}></div>',
103+
'{{did-insert}}',
104+
'{{did-update}}',
105+
'{{will-destroy}}',
106+
],
107+
invalid: [
108+
{
109+
code: '<div {{did-insert}}></div>',
110+
output: null,
111+
errors: [{ messageId: 'noRenderModifier' }],
112+
},
113+
{
114+
code: '<div {{did-update}}></div>',
115+
output: null,
116+
errors: [{ messageId: 'noRenderModifier' }],
117+
},
118+
{
119+
code: '<div {{will-destroy}}></div>',
120+
output: null,
121+
errors: [{ messageId: 'noRenderModifier' }],
122+
},
123+
],
124+
});

0 commit comments

Comments
 (0)