Skip to content
Closed
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 @@ -189,6 +189,7 @@ rules in templates can be disabled with eslint directives with mustache or html
| Name | Description | 💼 | 🔧 | 💡 |
| :----------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- |
| [template-builtin-component-arguments](docs/rules/template-builtin-component-arguments.md) | disallow setting certain attributes on builtin components | | | |
| [template-no-args-paths](docs/rules/template-no-args-paths.md) | disallow @args in paths | | | |
| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | |
| [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | | | |

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

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

✅ The `extends: 'recommended'` property in a configuration file enables this rule.

Arguments that are passed to components are prefixed with the `@` symbol in Angle bracket syntax.
Ember Octane leverages this in the component's templates by allowing users to directly refer to an argument using the same prefix:

```hbs
<!-- todo-list.hbs -->
<ul>
{{#each @todos as |todo index|}}
<li>
{{yield (todo-item-component todo=todo) index}}
</li>
{{/each}}
</ul>
```

We can immediately tell now by looking at this template that `@todos` is an argument that was passed to the component externally. This is in fact _always true_ - there is no way to modify the value referenced by `@todos` from the component class, it is the original, unmodified value.

## Examples

This rule **forbids** the following:

```hbs
{{this.args.foo}}
{{args.foo}}
```

```hbs
{{my-helper this.args.foo}}
{{my-helper (hash value=this.args.foo)}}
```

```hbs
<MyComponent @value={{this.args.foo}} />
<div {{my-modifier this.args.foo}}></div>
```

This rule **allows** the following:

```hbs
{{my-helper this.args}}
{{my-helper (hash value=this.args)}}
```

```hbs
{{@foo}}
<MyComponent @value={{@foo}} />
<div {{my-modifier @foo}}></div>
```

## Migration

- find in templates `this.args.` replace to `@`

## Related Rules

- [no-curly-component-invocation](no-curly-component-invocation.md)

## References

- [RFC #276](https://github.com/emberjs/rfcs/blob/master/text/0276-named-args.md)
- [Coming Soon in Ember Octane - Part 2: Named Argument Syntax](https://www.pzuraq.com/blog/coming-soon-in-ember-octane-part-2-angle-brackets-and-named-arguments/#namedargumentsyntax)
- [Named arguments in Ember.js](https://www.balinterdi.com/blog/named-arguments-in-ember-js/)
- [ember-named-arguments-polyfill](https://github.com/rwjblue/ember-named-arguments-polyfill)
24 changes: 24 additions & 0 deletions lib/rules/template-no-args-paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow @args in paths',
category: 'Best Practices',
strictGjs: true,
strictGts: true,
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-args-paths.md',
},
schema: [],
messages: { argsPath: 'Do not use paths with @args, use @argName directly instead.' },
},
create(context) {
return {
GlimmerPathExpression(node) {
if (node.original?.startsWith('@args.')) {
context.report({ node, messageId: 'argsPath' });
}
},
};
},
};
17 changes: 17 additions & 0 deletions tests/lib/rules/template-no-args-paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const rule = require('../../../lib/rules/template-no-args-paths');
const RuleTester = require('eslint').RuleTester;

const ruleTester = new RuleTester({
parser: require.resolve('ember-eslint-parser'),
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
});
ruleTester.run('template-no-args-paths', rule, {
valid: ['<template>{{@foo}}</template>'],
invalid: [
{
code: '<template>{{@args.foo}}</template>',
output: null,
errors: [{ messageId: 'argsPath' }],
},
],
});
Loading