Skip to content

Commit b23f8f7

Browse files
committed
Extract rule: template-no-unnecessary-concat
1 parent 3142567 commit b23f8f7

4 files changed

Lines changed: 157 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ rules in templates can be disabled with eslint directives with mustache or html
256256
| [template-no-obsolete-elements](docs/rules/template-no-obsolete-elements.md) | disallow obsolete HTML elements | | | |
257257
| [template-no-outlet-outside-routes](docs/rules/template-no-outlet-outside-routes.md) | disallow {{outlet}} outside of route templates | | | |
258258
| [template-no-page-title-component](docs/rules/template-no-page-title-component.md) | disallow usage of ember-page-title component | | | |
259+
| [template-no-unnecessary-concat](docs/rules/template-no-unnecessary-concat.md) | disallow unnecessary string concatenation | | 🔧 | |
259260
| [template-no-unnecessary-curly-parens](docs/rules/template-no-unnecessary-curly-parens.md) | disallow unnecessary parentheses enclosing statements in curlies | | 🔧 | |
260261
| [template-no-unused-block-params](docs/rules/template-no-unused-block-params.md) | disallow unused block parameters in templates | | | |
261262
| [template-no-valueless-arguments](docs/rules/template-no-valueless-arguments.md) | disallow valueless named arguments | | | |
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# ember/template-no-unnecessary-concat
2+
3+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
4+
5+
<!-- end auto-generated rule header -->
6+
7+
💅 The `extends: 'stylistic'` property in a configuration file enables this rule.
8+
9+
This rule forbids unnecessary use of quotes (`""`) around expressions like `{{myValue}}`.
10+
11+
## Examples
12+
13+
This rule **forbids** the following:
14+
15+
```gjs
16+
<template>
17+
<span class="{{if errors.length 'text-danger' 'text-grey'}}">
18+
19+
<img src="{{customSrc}}" alt="{{customAlt}}">
20+
21+
<label for="{{concat elementId "-date"}}">
22+
</template>
23+
```
24+
25+
This rule **allows** the following:
26+
27+
```gjs
28+
<template>
29+
<span class={{if errors.length 'text-danger' 'text-grey'}}>
30+
31+
<img src={{customSrc}} alt={{customAlt}}>
32+
33+
<label for={{concat elementId "-date"}}>
34+
</template>
35+
```
36+
37+
## Migration
38+
39+
Use regexp find-and-replace to fix existing violations of this rule:
40+
41+
| Before | After |
42+
| ---------------- | --------- |
43+
| `="{{([^}]+)}}"` | `={{$1}}` |
44+
45+
## References
46+
47+
- [Handlebars docs/expressions](https://handlebarsjs.com/guide/expressions.html)
48+
- [Ember api/concat helper](https://api.emberjs.com/ember/release/classes/Ember.Templates.helpers/methods/concat?anchor=concat)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'suggestion',
5+
docs: {
6+
description: 'disallow unnecessary string concatenation',
7+
category: 'Best Practices',
8+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-unnecessary-concat.md',
9+
templateMode: 'both',
10+
},
11+
fixable: 'code',
12+
schema: [],
13+
messages: {
14+
unnecessary: 'Unnecessary string concatenation. Use {{inner}} instead of {{outer}}.',
15+
},
16+
originallyFrom: {
17+
name: 'ember-template-lint',
18+
rule: 'lib/rules/no-unnecessary-concat.js',
19+
docs: 'docs/rule/no-unnecessary-concat.md',
20+
tests: 'test/unit/rules/no-unnecessary-concat-test.js',
21+
},
22+
},
23+
create(context) {
24+
return {
25+
GlimmerConcatStatement(node) {
26+
if (node.parts?.length === 1) {
27+
const sourceCode = context.sourceCode;
28+
context.report({
29+
node,
30+
messageId: 'unnecessary',
31+
data: {
32+
inner: sourceCode.getText(node.parts[0]),
33+
outer: sourceCode.getText(node),
34+
},
35+
fix(fixer) {
36+
return fixer.replaceText(node, sourceCode.getText(node.parts[0]));
37+
},
38+
});
39+
}
40+
},
41+
};
42+
},
43+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const rule = require('../../../lib/rules/template-no-unnecessary-concat');
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-unnecessary-concat', rule, {
9+
valid: [
10+
'<template><div class="foo {{bar}}"></div></template>',
11+
'<template><div class={{clazz}}></div></template>',
12+
'<template><div class="first {{second}}"></div></template>',
13+
'<template>"{{foo}}"</template>',
14+
],
15+
invalid: [
16+
{
17+
code: '<template><div class="{{foo}}"></div></template>',
18+
output: '<template><div class={{foo}}></div></template>',
19+
errors: [{ messageId: 'unnecessary' }],
20+
},
21+
22+
{
23+
code: '<template><div class="{{clazz}}"></div></template>',
24+
output: '<template><div class={{clazz}}></div></template>',
25+
errors: [{ messageId: 'unnecessary' }],
26+
},
27+
{
28+
code: '<template><img src="{{url}}" alt="{{t "alternate-text"}}"></template>',
29+
output: '<template><img src={{url}} alt={{t "alternate-text"}}></template>',
30+
errors: [{ messageId: 'unnecessary' }, { messageId: 'unnecessary' }],
31+
},
32+
],
33+
});
34+
35+
const hbsRuleTester = new RuleTester({
36+
parser: require.resolve('ember-eslint-parser/hbs'),
37+
parserOptions: {
38+
ecmaVersion: 2022,
39+
sourceType: 'module',
40+
},
41+
});
42+
43+
hbsRuleTester.run('template-no-unnecessary-concat', rule, {
44+
valid: ['<div class={{clazz}}></div>', '<div class="first {{second}}"></div>', '"{{foo}}"'],
45+
invalid: [
46+
{
47+
code: '<div class="{{clazz}}"></div>',
48+
output: '<div class={{clazz}}></div>',
49+
errors: [
50+
{ message: 'Unnecessary string concatenation. Use {{clazz}} instead of "{{clazz}}".' },
51+
],
52+
},
53+
{
54+
code: '<img src="{{url}}" alt="{{t "alternate-text"}}">',
55+
output: '<img src={{url}} alt={{t "alternate-text"}}>',
56+
errors: [
57+
{ message: 'Unnecessary string concatenation. Use {{url}} instead of "{{url}}".' },
58+
{
59+
message:
60+
'Unnecessary string concatenation. Use {{t "alternate-text"}} instead of "{{t "alternate-text"}}".',
61+
},
62+
],
63+
},
64+
],
65+
});

0 commit comments

Comments
 (0)