Skip to content

Commit 144e3e4

Browse files
committed
Refactor to use ambiguity checks
1 parent 736961c commit 144e3e4

File tree

3 files changed

+58
-38
lines changed

3 files changed

+58
-38
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"prepublishOnly": "yarn build",
2424
"build": "tsc",
2525
"clean": "tsc --build --clean",
26+
"pretest": "yarn build",
2627
"test": "jest",
2728
"pretest:integration": "yarn build",
2829
"test:integration": "ts-node ./test/run-test.ts",

test/fixtures/3.28/input/app/components/gherkyn.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{{! template-lint-disable no-implicit-this }}
22
{{! template-lint-disable no-curly-component-invocation }}
3-
<h1>[{{property}}]</h1>
3+
<h1>[{{this.property}}]</h1>
44

55
<h1>[{{this.property}}]</h1>
66

transforms/no-implicit-this/helpers/plugin.ts

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,53 +28,64 @@ export default function transform(root: AST.Node, { customHelpers, resolver }: O
2828
},
2929
};
3030

31-
function handleParams(params: AST.Expression[]) {
32-
for (const param of params) {
33-
if (param.type !== 'PathExpression') continue;
34-
handlePathExpression(param);
35-
}
36-
}
37-
38-
function handleHash(hash: AST.Hash) {
39-
for (const pair of hash.pairs) {
40-
if (pair.value.type !== 'PathExpression') continue;
41-
handlePathExpression(pair.value);
42-
}
43-
}
31+
function isAmbiguous(
32+
node: AST.PathExpression
33+
): node is AST.PathExpression & { head: AST.VarHead } {
34+
const { head } = node;
4435

45-
function handlePathExpression(node: AST.PathExpression) {
4636
// skip this.foo
47-
if (node.this) {
37+
if (head.type === 'ThisHead') {
4838
debug(`Skipping \`%s\` because it is already prefixed with \`this.\``, node.original);
49-
return;
39+
return false;
5040
}
5141

5242
// skip @foo
53-
if (node.data) {
43+
if (head.type === 'AtHead') {
5444
debug(`Skipping \`%s\` because it is already prefixed with \`@\``, node.original);
55-
return;
45+
return false;
46+
}
47+
48+
// FIXME: Why special-case this rather than handle it in keywords.ts?
49+
// skip `hasBlock` keyword
50+
if (node.original === 'hasBlock') {
51+
debug(`Skipping \`%s\` because it is a keyword`, node.original);
52+
return false;
5653
}
5754

5855
// skip {#foo as |bar|}}{{bar}}{{/foo}}
5956
// skip <Foo as |bar|>{{bar}}</Foo>
60-
const firstPart = node.parts[0];
61-
if (firstPart && scopedParams.includes(firstPart)) {
57+
if (scopedParams.includes(head.name)) {
6258
debug(`Skipping \`%s\` because it is a scoped variable`, node.original);
63-
return;
59+
return false;
6460
}
6561

66-
// skip `hasBlock` keyword
67-
if (node.original === 'hasBlock') {
68-
debug(`Skipping \`%s\` because it is a keyword`, node.original);
69-
return;
62+
return true;
63+
}
64+
65+
function handleParams(params: AST.Expression[]) {
66+
for (const param of params) {
67+
if (param.type === 'PathExpression' && isAmbiguous(param)) {
68+
handleThisFallback(param);
69+
}
70+
}
71+
}
72+
73+
function handleHash(hash: AST.Hash) {
74+
for (const pair of hash.pairs) {
75+
if (pair.value.type === 'PathExpression' && isAmbiguous(pair.value)) {
76+
handleThisFallback(pair.value);
77+
}
7078
}
79+
}
7180

81+
function handleThisFallback(node: AST.PathExpression) {
7282
// add `this.` prefix
7383
debug(`Transforming \`%s\` to \`this.%s\``, node.original, node.original);
7484
Object.assign(node, b.path(`this.${node.original}`));
7585
}
7686

77-
function isHelper(name: string) {
87+
function hasHelper(name: string) {
88+
// FIXME: Move to resolver
7889
if (customHelpers.includes(name)) {
7990
debug(`Skipping \`%s\` because it is a custom configured helper`, name);
8091
return true;
@@ -89,9 +100,15 @@ export default function transform(root: AST.Node, { customHelpers, resolver }: O
89100
return false;
90101
}
91102

92-
function isComponent(name: string) {
93-
if (resolver.has('component', name)) {
94-
const message = `Skipping \`%s\` because it appears to be a component from the telemetry data: %s`;
103+
function hasAmbiguous(name: string) {
104+
// FIXME: Move to resolver
105+
if (customHelpers.includes(name)) {
106+
debug(`Skipping \`%s\` because it is a custom configured helper`, name);
107+
return true;
108+
}
109+
110+
if (resolver.has('ambiguous', name)) {
111+
const message = `Skipping \`%s\` because it appears to be a component or helper from the telemetry data: %s`;
95112
debug(message, name);
96113
return true;
97114
}
@@ -129,8 +146,8 @@ export default function transform(root: AST.Node, { customHelpers, resolver }: O
129146
// {{FOO}}
130147
if (path.type === 'PathExpression' && !hasParams && !hasHashPairs) {
131148
// {{FOO.bar}}
132-
if (path.parts.length > 1) {
133-
handlePathExpression(path);
149+
if (path.tail.length > 0 && isAmbiguous(path)) {
150+
handleThisFallback(path);
134151
return;
135152
}
136153

@@ -142,13 +159,15 @@ export default function transform(root: AST.Node, { customHelpers, resolver }: O
142159
return;
143160
}
144161

145-
// skip helpers
146-
if (isHelper(path.original)) return;
162+
if (isAmbiguous(path)) {
163+
if (inAttrNode && hasHelper(path.original)) {
164+
return;
165+
} else if (!inAttrNode && hasAmbiguous(path.original)) {
166+
return;
167+
}
147168

148-
// skip components
149-
if (!inAttrNode && isComponent(path.original)) return;
150-
151-
handlePathExpression(path);
169+
handleThisFallback(path);
170+
}
152171
}
153172
},
154173

0 commit comments

Comments
 (0)