Skip to content

Commit c9c9fcb

Browse files
committed
Sync with ember-template-lint
1 parent 8f5a5e7 commit c9c9fcb

4 files changed

Lines changed: 65 additions & 143 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ rules in templates can be disabled with eslint directives with mustache or html
257257
| [template-no-obsolete-elements](docs/rules/template-no-obsolete-elements.md) | disallow obsolete HTML elements | | | |
258258
| [template-no-outlet-outside-routes](docs/rules/template-no-outlet-outside-routes.md) | disallow {{outlet}} outside of route templates | | | |
259259
| [template-no-page-title-component](docs/rules/template-no-page-title-component.md) | disallow usage of ember-page-title component | | | |
260-
| [template-no-potential-path-strings](docs/rules/template-no-potential-path-strings.md) | disallow potential path strings in templates | | | |
260+
| [template-no-potential-path-strings](docs/rules/template-no-potential-path-strings.md) | disallow potential path strings in attribute values | | | |
261261
| [template-no-splattributes-with-class](docs/rules/template-no-splattributes-with-class.md) | disallow splattributes with class attribute | | | |
262262
| [template-no-trailing-spaces](docs/rules/template-no-trailing-spaces.md) | disallow trailing whitespace at the end of lines in templates | | 🔧 | |
263263
| [template-no-unavailable-this](docs/rules/template-no-unavailable-this.md) | disallow `this` in templates that are not inside a class or function | | | |

docs/rules/template-no-potential-path-strings.md

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,69 +2,30 @@
22

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

5-
Disallow potential path strings that should be dynamic values in templates.
6-
7-
## Rule Details
8-
95
It might happen sometimes that `{{` and `}}` are forgotten when invoking a component, and the string that is passed was actually supposed to be a property path or argument.
106

11-
This rule warns about attribute values and text content that look like they should be dynamic paths. Specifically, it catches:
12-
13-
- **Attribute values** that start with `this.` or `@` (e.g. `<img src="this.picture">` or `<img src="@img">`)
14-
- **Text content** that contains path-like strings (e.g. `<div>this.propertyName</div>` or `<div>foo.bar</div>`)
7+
This rule warns about all arguments and attributes that start with `this.` or `@`, but are missing the surrounding `{{` and `}}` characters.
158

169
## Examples
1710

18-
Examples of **incorrect** code for this rule:
11+
This rule **forbids** the following:
1912

20-
```gjs
21-
<template>
22-
<img src="this.picture">
23-
</template>
13+
```hbs
14+
<img src='this.picture' />
2415
```
2516

26-
```gjs
27-
<template>
28-
<img src="@img">
29-
</template>
17+
```hbs
18+
<img src='@img' />
3019
```
3120

32-
```gjs
33-
<template>
34-
<div>this.propertyName</div>
35-
</template>
36-
```
37-
38-
```gjs
39-
<template>
40-
<div>foo.bar</div>
41-
</template>
42-
```
43-
44-
Examples of **correct** code for this rule:
45-
46-
```gjs
47-
<template>
48-
<img src={{this.picture}}>
49-
</template>
50-
```
51-
52-
```gjs
53-
<template>
54-
<img src={{@img}}>
55-
</template>
56-
```
21+
This rule **allows** the following:
5722

58-
```gjs
59-
<template>
60-
<div>{{this.propertyName}}</div>
61-
</template>
23+
```hbs
24+
<img src={{this.picture}} />
6225
```
6326

64-
```gjs
65-
<template>
66-
<div>{{this.foo.bar}}</div>
67-
</template>
27+
```hbs
28+
<img src={{@img}} />
6829
```
6930

7031
## Migration

lib/rules/template-no-potential-path-strings.js

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1+
const FINE_SYMBOLS = ['|', '/', '\\'];
2+
13
/** @type {import('eslint').Rule.RuleModule} */
24
module.exports = {
35
meta: {
46
type: 'suggestion',
57
docs: {
6-
description: 'disallow potential path strings in templates',
8+
description: 'disallow potential path strings in attribute values',
79
category: 'Best Practices',
8-
recommended: false,
910
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-potential-path-strings.md',
1011
templateMode: 'both',
1112
},
1213
fixable: null,
1314
schema: [],
1415
messages: {
1516
noPotentialPathStrings:
16-
'Potential path string detected. Use dynamic values instead of path strings.',
17+
'Potential path in attribute string detected. Did you mean {{{{path}}}}?',
1718
},
1819
originallyFrom: {
1920
name: 'ember-template-lint',
@@ -24,36 +25,20 @@ module.exports = {
2425
},
2526

2627
create(context) {
27-
const attrTextNodes = new WeakSet();
28-
2928
return {
3029
GlimmerAttrNode(node) {
31-
if (node.value && node.value.type === 'GlimmerTextNode') {
32-
attrTextNodes.add(node.value);
33-
const text = node.value.chars;
34-
// Check for potential paths in attribute values:
35-
// - this.something (should be {{this.something}})
36-
// - @argName without / \ | (should be {{@argName}})
37-
if (/^this\.\w+/.test(text) || /^@[\w-]+$/.test(text)) {
38-
context.report({
39-
node: node.value,
40-
messageId: 'noPotentialPathStrings',
41-
});
42-
}
43-
}
44-
},
45-
46-
GlimmerTextNode(node) {
47-
if (!node.chars || attrTextNodes.has(node)) {
30+
if (!node.value || node.value.type !== 'GlimmerTextNode') {
4831
return;
4932
}
5033

51-
// Check if text content looks like it could be a path (e.g., "foo.bar" or "this.foo")
52-
const pathPattern = /\b(this\.\w+|\w+\.\w+)\b/;
53-
if (pathPattern.test(node.chars)) {
34+
const chars = node.value.chars;
35+
const hasSpecialPrefix = chars.startsWith('this.') || chars.startsWith('@');
36+
37+
if (hasSpecialPrefix && !FINE_SYMBOLS.some((symbol) => chars.includes(symbol))) {
5438
context.report({
55-
node,
39+
node: node.value,
5640
messageId: 'noPotentialPathStrings',
41+
data: { path: chars },
5742
});
5843
}
5944
},

tests/lib/rules/template-no-potential-path-strings.js

Lines changed: 42 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,6 @@ const ruleTester = new RuleTester({
88

99
ruleTester.run('template-no-potential-path-strings', rule, {
1010
valid: [
11-
{
12-
filename: 'my-component.gjs',
13-
code: `
14-
import Component from '@glimmer/component';
15-
export default class MyComponent extends Component {
16-
<template>
17-
<div>{{this.propertyName}}</div>
18-
</template>
19-
}
20-
`,
21-
output: null,
22-
},
23-
{
24-
filename: 'my-component.gjs',
25-
code: `
26-
import Component from '@glimmer/component';
27-
export default class MyComponent extends Component {
28-
<template>
29-
<div>Hello world</div>
30-
</template>
31-
}
32-
`,
33-
output: null,
34-
},
35-
3611
'<template><img src="foo.png"></template>',
3712
'<template><img src={{picture}}></template>',
3813
'<template><img src={{this.picture}}></template>',
@@ -45,69 +20,58 @@ ruleTester.run('template-no-potential-path-strings', rule, {
4520

4621
invalid: [
4722
{
48-
filename: 'my-component.gjs',
49-
code: `
50-
import Component from '@glimmer/component';
51-
export default class MyComponent extends Component {
52-
<template>
53-
<div>this.propertyName</div>
54-
</template>
55-
}
56-
`,
23+
code: '<template><img src="this.picture"></template>',
5724
output: null,
5825
errors: [
5926
{
60-
messageId: 'noPotentialPathStrings',
27+
message: 'Potential path in attribute string detected. Did you mean {{this.picture}}?',
6128
},
6229
],
6330
},
6431
{
65-
filename: 'my-component.gjs',
66-
code: `
67-
import Component from '@glimmer/component';
68-
export default class MyComponent extends Component {
69-
<template>
70-
<div>foo.bar</div>
71-
</template>
72-
}
73-
`,
32+
code: '<template><img src=this.picture></template>',
7433
output: null,
7534
errors: [
7635
{
77-
messageId: 'noPotentialPathStrings',
36+
message: 'Potential path in attribute string detected. Did you mean {{this.picture}}?',
7837
},
7938
],
8039
},
81-
82-
{
83-
code: '<template><img src="this.picture"></template>',
84-
output: null,
85-
errors: [{ messageId: 'noPotentialPathStrings' }],
86-
},
87-
{
88-
code: '<template><img src=this.picture></template>',
89-
output: null,
90-
errors: [{ messageId: 'noPotentialPathStrings' }],
91-
},
9240
{
9341
code: '<template><img src="@img"></template>',
9442
output: null,
95-
errors: [{ messageId: 'noPotentialPathStrings' }],
43+
errors: [
44+
{
45+
message: 'Potential path in attribute string detected. Did you mean {{@img}}?',
46+
},
47+
],
9648
},
9749
{
9850
code: '<template><img src=@img></template>',
9951
output: null,
100-
errors: [{ messageId: 'noPotentialPathStrings' }],
52+
errors: [
53+
{
54+
message: 'Potential path in attribute string detected. Did you mean {{@img}}?',
55+
},
56+
],
10157
},
10258
{
10359
code: '<template><SomeComponent @foo=@bar /></template>',
10460
output: null,
105-
errors: [{ messageId: 'noPotentialPathStrings' }],
61+
errors: [
62+
{
63+
message: 'Potential path in attribute string detected. Did you mean {{@bar}}?',
64+
},
65+
],
10666
},
10767
{
10868
code: '<template><SomeComponent @foo=this.bar /></template>',
10969
output: null,
110-
errors: [{ messageId: 'noPotentialPathStrings' }],
70+
errors: [
71+
{
72+
message: 'Potential path in attribute string detected. Did you mean {{this.bar}}?',
73+
},
74+
],
11175
},
11276
],
11377
});
@@ -136,42 +100,54 @@ hbsRuleTester.run('template-no-potential-path-strings', rule, {
136100
code: '<img src="this.picture">',
137101
output: null,
138102
errors: [
139-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
103+
{
104+
message: 'Potential path in attribute string detected. Did you mean {{this.picture}}?',
105+
},
140106
],
141107
},
142108
{
143109
code: '<img src=this.picture>',
144110
output: null,
145111
errors: [
146-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
112+
{
113+
message: 'Potential path in attribute string detected. Did you mean {{this.picture}}?',
114+
},
147115
],
148116
},
149117
{
150118
code: '<img src="@img">',
151119
output: null,
152120
errors: [
153-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
121+
{
122+
message: 'Potential path in attribute string detected. Did you mean {{@img}}?',
123+
},
154124
],
155125
},
156126
{
157127
code: '<img src=@img>',
158128
output: null,
159129
errors: [
160-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
130+
{
131+
message: 'Potential path in attribute string detected. Did you mean {{@img}}?',
132+
},
161133
],
162134
},
163135
{
164136
code: '<SomeComponent @foo=@bar />',
165137
output: null,
166138
errors: [
167-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
139+
{
140+
message: 'Potential path in attribute string detected. Did you mean {{@bar}}?',
141+
},
168142
],
169143
},
170144
{
171145
code: '<SomeComponent @foo=this.bar />',
172146
output: null,
173147
errors: [
174-
{ message: 'Potential path string detected. Use dynamic values instead of path strings.' },
148+
{
149+
message: 'Potential path in attribute string detected. Did you mean {{this.bar}}?',
150+
},
175151
],
176152
},
177153
],

0 commit comments

Comments
 (0)