Skip to content

Commit 58a690f

Browse files
Merge pull request #2588 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-unnecessary-curly-strings
Extract rule: template-no-unnecessary-curly-strings
2 parents a0c4d1a + 2f1370f commit 58a690f

4 files changed

Lines changed: 164 additions & 0 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,12 @@ rules in templates can be disabled with eslint directives with mustache or html
431431
| [no-unnecessary-service-injection-argument](docs/rules/no-unnecessary-service-injection-argument.md) | disallow unnecessary argument when injecting services | | 🔧 | |
432432
| [no-unused-services](docs/rules/no-unused-services.md) | disallow unused service injections (see rule doc for limitations) | | | 💡 |
433433

434+
### Style
435+
436+
| Name | Description | 💼 | 🔧 | 💡 |
437+
| :------------------------------------------------------------------------------------------- | :--------------------------------------------------------- | :- | :- | :- |
438+
| [template-no-unnecessary-curly-strings](docs/rules/template-no-unnecessary-curly-strings.md) | disallow unnecessary curly braces in string interpolations | | 🔧 | |
439+
434440
### Stylistic Issues
435441

436442
| Name                           | Description | 💼 | 🔧 | 💡 |
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# ember/template-no-unnecessary-curly-strings
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+
Strings need not be wrapped in curly braces (mustache expressions).
8+
9+
## Examples
10+
11+
This rule **forbids** the following:
12+
13+
```gjs
14+
<template><FooBar class={{"btn"}} /></template>
15+
```
16+
17+
```gjs
18+
<template><FooBar class="btn">{{"Hello"}}</FooBar></template>
19+
```
20+
21+
This rule **allows** the following:
22+
23+
```gjs
24+
<template><FooBar class="btn" /></template>
25+
```
26+
27+
```gjs
28+
<template><FooBar class="btn">Hello</FooBar></template>
29+
```
30+
31+
## References
32+
33+
- [Handlebars expressions](https://handlebarsjs.com/guide/expressions.html)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'suggestion',
5+
docs: {
6+
description: 'disallow unnecessary curly braces in string interpolations',
7+
category: 'Style',
8+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-unnecessary-curly-strings.md',
9+
templateMode: 'both',
10+
},
11+
fixable: 'code',
12+
schema: [],
13+
messages: { unnecessary: 'Unnecessary curly braces around string' },
14+
originallyFrom: {
15+
name: 'ember-template-lint',
16+
rule: 'lib/rules/no-unnecessary-curly-strings.js',
17+
docs: 'docs/rule/no-unnecessary-curly-strings.md',
18+
tests: 'test/unit/rules/no-unnecessary-curly-strings-test.js',
19+
},
20+
},
21+
create(context) {
22+
const sourceCode = context.sourceCode || context.getSourceCode();
23+
24+
return {
25+
GlimmerAttrNode(node) {
26+
if (
27+
node.value?.type === 'GlimmerMustacheStatement' &&
28+
node.value.path?.type === 'GlimmerStringLiteral'
29+
) {
30+
const strNode = node.value.path;
31+
const strValue = strNode.value || strNode.original;
32+
context.report({
33+
node: node.value,
34+
messageId: 'unnecessary',
35+
fix(fixer) {
36+
const strSource = sourceCode.getText(strNode);
37+
const quoteChar = strSource[0] === "'" ? "'" : '"';
38+
return fixer.replaceText(node.value, `${quoteChar}${strValue}${quoteChar}`);
39+
},
40+
});
41+
}
42+
},
43+
GlimmerMustacheStatement(node) {
44+
if (node.path?.type === 'GlimmerStringLiteral' && node.parent?.type !== 'GlimmerAttrNode') {
45+
const strValue = node.path.value || node.path.original;
46+
context.report({
47+
node,
48+
messageId: 'unnecessary',
49+
fix(fixer) {
50+
return fixer.replaceText(node, strValue);
51+
},
52+
});
53+
}
54+
},
55+
};
56+
},
57+
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const rule = require('../../../lib/rules/template-no-unnecessary-curly-strings');
2+
const RuleTester = require('eslint').RuleTester;
3+
4+
const validHbs = [
5+
'<FooBar class="btn" />',
6+
'{{foo}}',
7+
'{{(foo)}}',
8+
'{{this.calculate 1 2 op="add"}}',
9+
'{{get address part}}',
10+
'foo',
11+
'"foo"',
12+
'<FooBar value=12345 />',
13+
'<FooBar value=null />',
14+
'<FooBar value=true />',
15+
'<FooBar value=undefined />',
16+
'<FooBar value={{12345}} />',
17+
'<FooBar value={{null}} />',
18+
'<FooBar value={{true}} />',
19+
'<FooBar value={{undefined}} />',
20+
];
21+
22+
const invalidHbs = [
23+
{
24+
code: '<FooBar class={{"btn"}} @fooArg={{\'barbaz\'}} />',
25+
output: '<FooBar class="btn" @fooArg=\'barbaz\' />',
26+
errors: [{ messageId: 'unnecessary' }, { messageId: 'unnecessary' }],
27+
},
28+
{
29+
code: '<FooBar class="btn">{{"Foo"}}</FooBar>',
30+
output: '<FooBar class="btn">Foo</FooBar>',
31+
errors: [{ messageId: 'unnecessary' }],
32+
},
33+
];
34+
35+
function wrapTemplate(entry) {
36+
if (typeof entry === 'string') {
37+
return `<template>${entry}</template>`;
38+
}
39+
40+
return {
41+
...entry,
42+
code: `<template>${entry.code}</template>`,
43+
output: entry.output ? `<template>${entry.output}</template>` : entry.output,
44+
};
45+
}
46+
47+
const gjsRuleTester = new RuleTester({
48+
parser: require.resolve('ember-eslint-parser'),
49+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
50+
});
51+
52+
gjsRuleTester.run('template-no-unnecessary-curly-strings', rule, {
53+
valid: validHbs.map(wrapTemplate),
54+
invalid: invalidHbs.map(wrapTemplate),
55+
});
56+
57+
const hbsRuleTester = new RuleTester({
58+
parser: require.resolve('ember-eslint-parser/hbs'),
59+
parserOptions: {
60+
ecmaVersion: 2022,
61+
sourceType: 'module',
62+
},
63+
});
64+
65+
hbsRuleTester.run('template-no-unnecessary-curly-strings', rule, {
66+
valid: validHbs,
67+
invalid: invalidHbs,
68+
});

0 commit comments

Comments
 (0)