Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ rules in templates can be disabled with eslint directives with mustache or html
| [template-no-attrs-in-components](docs/rules/template-no-attrs-in-components.md) | disallow attrs in component templates | | | |
| [template-no-link-to-positional-params](docs/rules/template-no-link-to-positional-params.md) | disallow positional params in LinkTo component | | | |
| [template-no-link-to-tagname](docs/rules/template-no-link-to-tagname.md) | disallow tagName attribute on LinkTo component | | | |
| [template-no-with](docs/rules/template-no-with.md) | disallow {{with}} helper | | | |

### Ember Data

Expand Down
74 changes: 74 additions & 0 deletions docs/rules/template-no-with.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# ember/template-no-with

> **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.

<!-- end auto-generated rule header -->

The use of `{{with}}` has been deprecated, you should replace it with either `{{let}}` or a combination of `{{let}}`, `{{if}}` and `{{else}}`.

## Examples

This rule **forbids** the following:

```gjs
<template>
{{#with (hash name="Ben" age=4) as |person|}}
Hi {{person.name}}, you are {{person.age}} years old.
{{/with}}
</template>
```

```gjs
<template>
{{#with user.posts as |blogPosts|}}
There are {{blogPosts.length}} blog posts.
{{/with}}
</template>
```

```gjs
<template>
{{#with user.posts as |blogPosts|}}
There are {{blogPosts.length}} blog posts.
{{else}}
There are no blog posts.
{{/with}}
</template>
```

This rule **allows** the following:

```gjs
<template>
{{#let (hash name="Ben" age=4) as |person|}}
Hi {{person.name}}, you are {{person.age}} years old.
{{/let}}
</template>
```

```gjs
<template>
{{#let user.posts as |blogPosts|}}
{{#if blogPosts.length}}
There are {{blogPosts.length}} blog posts.
{{/if}}
{{/let}}
</template>
```

```gjs
<template>
{{#let user.posts as |blogPosts|}}
{{#if blogPosts.length}}
There are {{blogPosts.length}} blog posts.
{{else}}
There are no blog posts.
{{/if}}
{{/let}}
</template>
```

## References

- [Deprecate {{with}} RFC](https://github.com/emberjs/rfcs/blob/master/text/0445-deprecate-with.md)
- More information is available at the [Deprecation Guide](https://deprecations.emberjs.com/v3.x/#toc_ember-glimmer-with-syntax)
33 changes: 33 additions & 0 deletions lib/rules/template-no-with.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/** @type {import('eslint').Rule.RuleModule} */
const DEPRECATION_URL = 'https://deprecations.emberjs.com/v3.x/#toc_ember-glimmer-with-syntax';

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow {{with}} helper',
category: 'Deprecations',
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-with.md',
templateMode: 'loose',
},
schema: [],
messages: {
deprecated: `The use of \`{{withHelper}}\` has been deprecated. Please see the deprecation guide at ${DEPRECATION_URL}.`,
},
originallyFrom: {
name: 'ember-template-lint',
rule: 'lib/rules/no-with.js',
docs: 'docs/rule/no-with.md',
tests: 'test/unit/rules/no-with-test.js',
},
},
create(context) {
return {
GlimmerBlockStatement(node) {
if (node.path?.type === 'GlimmerPathExpression' && node.path.original === 'with') {
context.report({ node, messageId: 'deprecated', data: { withHelper: '{{with}}' } });
}
},
};
},
};
58 changes: 58 additions & 0 deletions tests/lib/rules/template-no-with.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const rule = require('../../../lib/rules/template-no-with');
const RuleTester = require('eslint').RuleTester;

const validHbs = [
'{{@with}}',
'{{this.with}}',
'{{with "foo" bar="baz"}}',
'{{#if @model.posts}}{{@model.posts}}{{/if}}',
'{{#let @model.posts as |blogPosts|}}{{blogPosts}}{{/let}}',
];

const invalidHbs = [
{
code: '{{#with this.foo as |bar|}}{{bar}}{{/with}}',
output: null,
errors: [{ messageId: 'deprecated' }],
},
{
code: '{{#with (hash firstName="John" lastName="Doe") as |user|}}{{user.firstName}} {{user.lastName}}{{/with}}',
output: null,
errors: [{ messageId: 'deprecated' }],
},
];

function wrapTemplate(entry) {
if (typeof entry === 'string') {
return `<template>${entry}</template>`;
}

return {
...entry,
code: `<template>${entry.code}</template>`,
output: entry.output ? `<template>${entry.output}</template>` : entry.output,
};
}

const gjsRuleTester = new RuleTester({
parser: require.resolve('ember-eslint-parser'),
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
});

gjsRuleTester.run('template-no-with', rule, {
valid: validHbs.map(wrapTemplate),
invalid: invalidHbs.map(wrapTemplate),
});

const hbsRuleTester = new RuleTester({
parser: require.resolve('ember-eslint-parser/hbs'),
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
});

hbsRuleTester.run('template-no-with', rule, {
valid: validHbs,
invalid: invalidHbs,
});
Loading