Skip to content

Commit 3ba27aa

Browse files
committed
Extract rule: template-no-unbound
1 parent 707cf7b commit 3ba27aa

4 files changed

Lines changed: 111 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ rules in templates can be disabled with eslint directives with mustache or html
340340
| [template-no-attrs-in-components](docs/rules/template-no-attrs-in-components.md) | disallow attrs in component templates | | | |
341341
| [template-no-link-to-positional-params](docs/rules/template-no-link-to-positional-params.md) | disallow positional params in LinkTo component | | | |
342342
| [template-no-link-to-tagname](docs/rules/template-no-link-to-tagname.md) | disallow tagName attribute on LinkTo component | | | |
343+
| [template-no-unbound](docs/rules/template-no-unbound.md) | disallow {{unbound}} helper | | | |
343344
| [template-no-with](docs/rules/template-no-with.md) | disallow {{with}} helper | | | |
344345

345346
### Ember Data

docs/rules/template-no-unbound.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# ember/template-no-unbound
2+
3+
> **HBS Only**: This rule applies to classic `.hbs` template files only (loose mode). It is not relevant for `gjs`/`gts` files (strict mode), where these patterns cannot occur.
4+
5+
<!-- end auto-generated rule header -->
6+
7+
`{{unbound}}` is a legacy hold over from the days in which Ember's template engine was less performant. Its use today
8+
is vestigial, and it no longer offers performance benefits.
9+
10+
It is also a poor practice to use it for rendering only the initial value of a property that may later change.
11+
12+
## Examples
13+
14+
This rule **forbids** the following:
15+
16+
```hbs
17+
{{unbound aVar}}
18+
```
19+
20+
```hbs
21+
{{some-component foo=(unbound aVar)}}
22+
```
23+
24+
## References
25+
26+
- [deprecations/unbound block syntax](https://deprecations.emberjs.com/v1.x/#toc_block-and-multi-argument-unbound-helper)
27+
- [Ember api/unbound helper](https://api.emberjs.com/ember/release/classes/Ember.Templates.helpers/methods/each?anchor=unbound)

lib/rules/template-no-unbound.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'suggestion',
5+
docs: {
6+
description: 'disallow {{unbound}} helper',
7+
category: 'Deprecations',
8+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-unbound.md',
9+
templateMode: 'loose',
10+
},
11+
schema: [],
12+
messages: { unexpected: 'Unexpected unbound helper usage.' },
13+
originallyFrom: {
14+
name: 'ember-template-lint',
15+
rule: 'lib/rules/no-unbound.js',
16+
docs: 'docs/rule/no-unbound.md',
17+
tests: 'test/unit/rules/no-unbound-test.js',
18+
},
19+
},
20+
create(context) {
21+
function check(node) {
22+
if (node.path?.type === 'GlimmerPathExpression' && node.path.original === 'unbound') {
23+
context.report({ node, messageId: 'unexpected' });
24+
}
25+
}
26+
return {
27+
GlimmerMustacheStatement: check,
28+
GlimmerBlockStatement: check,
29+
GlimmerSubExpression: check,
30+
};
31+
},
32+
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const rule = require('../../../lib/rules/template-no-unbound');
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+
ruleTester.run('template-no-unbound', rule, {
9+
valid: [
10+
'<template>{{this.value}}</template>',
11+
'<template>{{foo}}</template>',
12+
'<template>{{button}}</template>',
13+
],
14+
invalid: [
15+
{
16+
code: '<template>{{unbound foo}}</template>',
17+
output: null,
18+
errors: [{ messageId: 'unexpected' }],
19+
},
20+
21+
{
22+
code: '<template>{{my-thing foo=(unbound foo)}}</template>',
23+
output: null,
24+
errors: [{ messageId: 'unexpected' }],
25+
},
26+
],
27+
});
28+
29+
const hbsRuleTester = new RuleTester({
30+
parser: require.resolve('ember-eslint-parser/hbs'),
31+
parserOptions: {
32+
ecmaVersion: 2022,
33+
sourceType: 'module',
34+
},
35+
});
36+
37+
hbsRuleTester.run('template-no-unbound', rule, {
38+
valid: ['{{foo}}', '{{button}}'],
39+
invalid: [
40+
{
41+
code: '{{unbound foo}}',
42+
output: null,
43+
errors: [{ message: 'Unexpected unbound helper usage.' }],
44+
},
45+
{
46+
code: '{{my-thing foo=(unbound foo)}}',
47+
output: null,
48+
errors: [{ message: 'Unexpected unbound helper usage.' }],
49+
},
50+
],
51+
});

0 commit comments

Comments
 (0)