Skip to content

Commit a715623

Browse files
authored
Merge pull request #515 from lolmaus/opt-in-for-unambiguous-helpers
Move helper disambiguation to a flag that is off by default
2 parents 5b29cde + ab2a93c commit a715623

File tree

15 files changed

+137
-88
lines changed

15 files changed

+137
-88
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
root: true,
33
parserOptions: {
4-
ecmaVersion: 2017,
4+
ecmaVersion: 'latest',
55
},
66
env: {
77
node: true,

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,22 @@ If you would like to only convert certain component invocations to use the angle
191191
}
192192
```
193193

194+
### Making helper invocations unambiguous
195+
196+
You may want to convert invocations like `{{concat "foo" "bar"}}` into `{{(concat "foo" "bar")}}`, which may be useful as a temporary step when upgrading to strict-mode Embroider.
197+
198+
In your **config/anglebrackets-codemod-config.json**, add this:
199+
200+
```js
201+
{
202+
"unambiguousHelpers": true
203+
}
204+
```
205+
206+
Note that unambiguous helpers do not work in non-Embroider Ember, as of January 2024.
207+
208+
Note that ambiguous invocations that cannot be statically distinguished between a helper, a property and a component — will not be modified.
209+
194210
## Debugging Workflow
195211

196212
Oftentimes, you want to debug the codemod or the transform to identify issues with the code or to understand

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"yargs": "^17.7.2"
4343
},
4444
"devDependencies": {
45+
"compare-fixture": "^1.1.0",
4546
"coveralls": "^3.1.1",
4647
"eslint": "^8.22.0",
4748
"eslint-config-prettier": "^8.5.0",

pnpm-lock.yaml

Lines changed: 38 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/fixtures/with-telemetry/input/app/templates/application.hbs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,8 @@
1414
{{/bs-nav}}
1515
</div>
1616
<div class="col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3">
17-
{{utils/bee-bop}}
1817
{{-wat-wat}}
19-
{{utils/-wat-wat}}
20-
{{#if this.isDetailPage}}
21-
<h1>
22-
{{currentComponent.title}}
23-
</h1>
24-
<p class="lead">
25-
{{currentComponent.description}}
26-
</p>
27-
{{api-reference component=this.currentComponent}}
28-
{{/if}}
29-
{{outlet}}
30-
31-
{{#bs-button id="openModal" onClick=(action this.addModal)}}Open{{/bs-button}}
32-
33-
{{#if hasModal}}
34-
{{#bs-modal-simple open=modal onHidden=(action "removeModal") title="Dynamic Dialog"}}
35-
Hi there
36-
{{/bs-modal-simple}}
37-
{{/if}}
18+
{{outlet}}
3819
{{file-less foo=true}}
3920
</div>
4021
</div>
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
<div>this template has no js </div>
2-
{{#bs-button type="primary"}}Primary{{/bs-button}}

test/fixtures/with-telemetry/output/app/templates/application.hbs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,8 @@
1414
</BsNav>
1515
</div>
1616
<div class="col-sm-8 col-sm-pull-4 col-md-9 col-md-pull-3">
17-
{{(utils/bee-bop)}}
18-
{{(-wat-wat)}}
19-
{{(utils/-wat-wat)}}
20-
{{#if this.isDetailPage}}
21-
<h1>
22-
{{currentComponent.title}}
23-
</h1>
24-
<p class="lead">
25-
{{currentComponent.description}}
26-
</p>
27-
<ApiReference @component={{this.currentComponent}} />
28-
{{/if}}
29-
{{outlet}}
30-
31-
<BsButton @id="openModal" @onClick={{action this.addModal}}>Open</BsButton>
32-
33-
{{#if hasModal}}
34-
<BsModalSimple @open={{modal}} @onHidden={{action "removeModal"}} @title="Dynamic Dialog">
35-
Hi there
36-
</BsModalSimple>
37-
{{/if}}
17+
{{-wat-wat}}
18+
{{outlet}}
3819
<FileLess @foo={{true}} />
3920
</div>
4021
</div>
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
<div>this template has no js </div>
2-
<BsButton @type="primary">Primary</BsButton>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<button>
2-
{{(titleize "string helpers for ember")}}
2+
{{titleize "string helpers for ember"}}
33
</button>
4-
{{(biz-baz canConvert="no" why="helper" where="local")}}
4+
{{biz-baz canConvert="no" why="helper" where="local"}}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
{{site-header user=this.user class=(if this.user.isAdmin "admin")}}
1+
<SiteHeader @user={{this.user}} @class={{if this.user.isAdmin "admin"}} />
22

3-
{{#super-select selected=this.user.country as |s|}}
3+
<SuperSelect @selected={{this.user.country}} as |s|>
44
{{#each this.availableCountries as |country|}}
5-
{{#s.option value=country}}{{country.name}}{{/s.option}}
5+
<s.option @value={{country}}>{{country.name}}</s.option>
66
{{/each}}
7-
{{/super-select}}
7+
</SuperSelect>
88

9-
{{ui/button text="Click me"}}
9+
<Ui::Button @text="Click me" />

test/run-test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ const execOpts = { cwd: inputDir, stderr: 'inherit' };
4545
console.log('comparing results');
4646

4747
try {
48-
await execa('diff', ['-rq', './app', '../output/app'], execOpts);
48+
const compareFixture = await import('compare-fixture');
49+
compareFixture.default(path.join(inputDir, 'app'), path.join(inputDir, '../output/app'));
4950
} catch (e) {
5051
console.error('codemod did not run successfully');
5152
console.log(e);

transforms/angle-brackets/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function getOptions() {
3131

3232
options.includeValuelessDataTestAttributes = !!config.includeValuelessDataTestAttributes;
3333
options.skipBuiltInComponents = !!config.skipBuiltInComponents;
34+
options.unambiguousHelpers = !!config.unambiguousHelpers;
3435
}
3536

3637
if (cliOptions.telemetry) {

transforms/angle-brackets/telemetry/invokable.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,18 @@ const HELPER = 'Helper';
44
const COMPONENT = 'Component';
55

66
function invokableName(name, type) {
7-
let invokePath = type === HELPER ? '/helpers/' : '/components/';
7+
let invokePath;
8+
9+
if (name.startsWith('@ember/component/')) {
10+
invokePath = '@ember/component/';
11+
} else if (name.startsWith('@ember/routing/')) {
12+
invokePath = '@ember/routing/';
13+
} else if (type === HELPER) {
14+
invokePath = '/helpers/';
15+
} else {
16+
invokePath = '/components/';
17+
}
18+
819
return name.substring(name.lastIndexOf(invokePath) + invokePath.length, name.length);
920
}
1021

transforms/angle-brackets/transform.js

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -341,18 +341,26 @@ function isKnownHelper(fullName, config, invokableData) {
341341
}
342342

343343
if (isTelemetryData) {
344-
let isComponent =
345-
!config.helpers.includes(name) &&
346-
[...(components || []), ...BUILT_IN_COMPONENTS].includes(name);
344+
if (config.unambiguousHelpers) {
345+
let isComponent =
346+
!config.helpers.includes(name) &&
347+
[...(components || []), ...BUILT_IN_COMPONENTS].includes(name);
347348

348-
if (isComponent) {
349-
return false;
350-
}
349+
if (isComponent) {
350+
return false;
351+
}
351352

352-
let mergedHelpers = [...KNOWN_HELPERS, ...(helpers || [])];
353-
let isHelper = mergedHelpers.includes(name) || config.helpers.includes(name);
354-
let strName = `${name}`; // coerce boolean and number to string
355-
return isHelper && !strName.includes('.');
353+
let mergedHelpers = [...KNOWN_HELPERS, ...(helpers || [])];
354+
let isHelper = mergedHelpers.includes(name) || config.helpers.includes(name);
355+
let strName = `${name}`; // coerce boolean and number to string
356+
return isHelper && !strName.includes('.');
357+
} else {
358+
let mergedHelpers = [...KNOWN_HELPERS, ...(helpers || [])];
359+
let isHelper = mergedHelpers.includes(name) || config.helpers.includes(name);
360+
let isComponent = [...(components || []), ...BUILT_IN_COMPONENTS].includes(name);
361+
let strName = `${name}`; // coerce boolean and number to string
362+
return (isHelper || !isComponent) && !strName.includes('.');
363+
}
356364
} else {
357365
return KNOWN_HELPERS.includes(name) || config.helpers.includes(name);
358366
}
@@ -489,6 +497,7 @@ function transformToAngleBracket(fileInfo, config, invokableData) {
489497
) {
490498
return transformComponentNode(node, fileInfo, config);
491499
} else if (
500+
config.unambiguousHelpers &&
492501
isTagKnownHelper &&
493502
node.path.type !== 'SubExpression' &&
494503
walkerPath.parent.node.type !== 'AttrNode' &&

0 commit comments

Comments
 (0)