Skip to content

Commit 114c6ff

Browse files
committed
Sync with ember-template-lint
1 parent 5234d16 commit 114c6ff

2 files changed

Lines changed: 52 additions & 77 deletions

File tree

docs/rules/template-no-restricted-invocations.md

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,72 +6,44 @@ Disallow certain components, helpers or modifiers from being used.
66

77
Use cases include:
88

9-
- You bring in some addon with helpers or components, but your team deems one or many not suitable and wants to guard against their usage
9+
- You bring in some addon like ember-composable-helpers, but your team deems one or many of the helpers not suitable and wants to guard against their usage
1010
- You want to discourage use of a deprecated component
1111

1212
## Examples
1313

1414
Given a config of:
1515

1616
```json
17-
{ "template-no-restricted-invocations": ["foo-bar"] }
17+
["foo-bar"]
1818
```
1919

2020
This rule **forbids** the following:
2121

22-
```gjs
23-
<template>{{foo-bar}}</template>
22+
```hbs
23+
{{foo-bar}}
2424
```
2525

26-
```gjs
27-
<template>{{#foo-bar}}{{/foo-bar}}</template>
26+
```hbs
27+
{{#foo-bar}}{{/foo-bar}}
2828
```
2929

30-
```gjs
31-
<template><FooBar /></template>
32-
```
33-
34-
This rule **allows** the following:
35-
36-
```gjs
37-
<template>{{baz}}</template>
38-
```
39-
40-
```gjs
41-
<template><Baz /></template>
30+
```hbs
31+
<FooBar />
4232
```
4333

4434
## Configuration
4535

4636
One of these:
4737

48-
- `string[]` - helpers or components to disallow (using kebab-case names like `nested-scope/component-name`)
49-
- `object[]` - with the following keys:
50-
- `names` - `string[]` - helpers or components to disallow
51-
- `message` - `string` - custom error message to report for violations
52-
53-
```js
54-
// .eslintrc.js
55-
module.exports = {
56-
rules: {
57-
'ember/template-no-restricted-invocations': [
58-
'error',
59-
[
60-
'foo-bar',
61-
{
62-
names: ['deprecated-component'],
63-
message: 'Use new-component instead',
64-
},
65-
],
66-
],
67-
},
68-
};
69-
```
38+
- string[] - helpers or components to disallow (using kebab-case names like `nested-scope/component-name`)
39+
- object[] - with the following keys:
40+
- `names` - string[] - helpers or components to disallow (using kebab-case names like `nested-scope/component-name`)
41+
- `message` - string - custom error message to report for violations (typically a deprecation notice / explanation of why not to use it and a recommended replacement)
7042

7143
## Related Rules
7244

7345
- [ember/no-restricted-service-injections](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/no-restricted-service-injections.md)
7446

7547
## References
7648

77-
- [emberjs.com - Deprecations](https://guides.emberjs.com/release/deprecations/)
49+
- [ember-cli-deprecation-workflow](https://github.com/mixonic/ember-cli-deprecation-workflow)

lib/rules/template-no-restricted-invocations.js

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,18 @@ module.exports = {
129129
const scope = sourceCode.getScope(node.parent);
130130
const ref = scope.references.find((r) => r.identifier === node.parts[0]);
131131
// Only exempt if the reference actually resolves to a JS variable definition
132-
return ref != null && ref.resolved != null;
132+
return (
133+
ref !== null && ref !== undefined && ref.resolved !== null && ref.resolved !== undefined
134+
);
133135
}
134136

135137
// For mustache/block/sub/modifier statements, check the path's head
136138
if (node.path && node.path.head) {
137139
const scope = sourceCode.getScope(node);
138140
const ref = scope.references.find((r) => r.identifier === node.path.head);
139-
return ref != null && ref.resolved != null;
141+
return (
142+
ref !== null && ref !== undefined && ref.resolved !== null && ref.resolved !== undefined
143+
);
140144
}
141145
} catch {
142146
// sourceCode.getScope may not be available in .hbs-only mode; ignore.
@@ -231,22 +235,46 @@ module.exports = {
231235
return '';
232236
}
233237

238+
function checkElementModifiers(node) {
239+
if (!node.modifiers) {
240+
return;
241+
}
242+
for (const modifier of node.modifiers) {
243+
const modName =
244+
modifier.path && modifier.path.type === 'GlimmerPathExpression' && modifier.path.original;
245+
if (!modName) continue;
246+
if (isBlockParam(modName)) continue;
247+
if (isJsScopeVariable(modifier)) continue;
248+
249+
const modResult = isRestricted(modName);
250+
if (modResult.restricted) {
251+
context.report({
252+
node: modifier,
253+
message:
254+
modResult.message ||
255+
`Cannot use disallowed helper, component or modifier '{{${modName}}}'`,
256+
});
257+
}
258+
}
259+
}
260+
261+
function trackBlockParams(node) {
262+
if (node.blockParams && node.blockParams.length > 0) {
263+
pushBlockParams(node.blockParams);
264+
}
265+
}
266+
234267
return {
235268
GlimmerElementNode(node) {
236269
// For element nodes, check the raw tag against block params before dasherizing.
237270
if (node.tag && isBlockParam(node.tag)) {
238-
// Track block params from element nodes (e.g. <Foo as |bar|>).
239-
if (node.blockParams && node.blockParams.length > 0) {
240-
pushBlockParams(node.blockParams);
241-
}
271+
trackBlockParams(node);
242272
return;
243273
}
244274

245275
// In gjs/gts, skip if the tag resolves to a JS-scope variable (import, const, etc.)
246276
if (isJsScopeVariable(node)) {
247-
if (node.blockParams && node.blockParams.length > 0) {
248-
pushBlockParams(node.blockParams);
249-
}
277+
trackBlockParams(node);
250278
return;
251279
}
252280

@@ -263,33 +291,8 @@ module.exports = {
263291
}
264292
}
265293

266-
// Track block params from element nodes (e.g. <Foo as |bar|>).
267-
if (node.blockParams && node.blockParams.length > 0) {
268-
pushBlockParams(node.blockParams);
269-
}
270-
271-
// Check modifiers on the element
272-
if (node.modifiers) {
273-
for (const modifier of node.modifiers) {
274-
const modName =
275-
modifier.path &&
276-
modifier.path.type === 'GlimmerPathExpression' &&
277-
modifier.path.original;
278-
if (!modName) continue;
279-
if (isBlockParam(modName)) continue;
280-
if (isJsScopeVariable(modifier)) continue;
281-
282-
const modResult = isRestricted(modName);
283-
if (modResult.restricted) {
284-
context.report({
285-
node: modifier,
286-
message:
287-
modResult.message ||
288-
`Cannot use disallowed helper, component or modifier '{{${modName}}}'`,
289-
});
290-
}
291-
}
292-
}
294+
trackBlockParams(node);
295+
checkElementModifiers(node);
293296
},
294297

295298
'GlimmerElementNode:exit'(node) {

0 commit comments

Comments
 (0)