Skip to content

Commit 1e20073

Browse files
Merge pull request #4 from ember-codemods/suchita/nonComputedDecorators
Handle correct transformation of `@tracked` property
2 parents 268f664 + 5771a91 commit 1e20073

File tree

5 files changed

+145
-40
lines changed

5 files changed

+145
-40
lines changed

transforms/tracked-properties/README.md

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ npx ember-tracked-properties-codemod path/of/files/ or/some**/*glob.js
99
## Input / Output
1010

1111
<!--FIXTURES_TOC_START-->
12-
* [basic-with-prefix-false](#basic-with-prefix-false)
13-
* [basic](#basic)
14-
* [chained-complex-computed](#chained-complex-computed)
15-
* [chained-computed](#chained-computed)
16-
* [complex](#complex)
17-
* [with-tracked](#with-tracked)
18-
<!--FIXTURES_TOC_END-->
12+
13+
- [basic-with-prefix-false](#basic-with-prefix-false)
14+
- [basic](#basic)
15+
- [chained-complex-computed](#chained-complex-computed)
16+
- [chained-computed](#chained-computed)
17+
- [complex](#complex)
18+
- [non-computed-decorators](#non-computed-decorators)
19+
- [with-tracked](#with-tracked)
20+
<!--FIXTURES_TOC_END-->
1921

2022
## <!--FIXTURES_CONTENT_START-->
2123

@@ -269,6 +271,65 @@ export default class AddTeamComponent extends Component {
269271

270272
---
271273

274+
<a id="non-computed-decorators">**non-computed-decorators**</a>
275+
276+
**Input** (<small>[non-computed-decorators.input.js](__testfixtures__/non-computed-decorators.input.js)</small>):
277+
278+
```js
279+
import Component from '@ember/component';
280+
import { computed, get } from '@ember/object';
281+
import { alias } from '@ember/object/computed';
282+
283+
export default class Foo extends Component {
284+
bar;
285+
// baz class property
286+
baz = 'barBaz';
287+
288+
@alias('model.isFoo')
289+
isFoo;
290+
291+
@computed('baz', 'isFoo')
292+
get bazInfo() {
293+
return get(this, 'isFoo') ? `Name: ${get(this, 'baz')}` : 'Baz';
294+
}
295+
296+
@computed('bar', 'isFoo').readOnly()
297+
get barInfo() {
298+
return get(this, 'isFoo') ? `Name: ${get(this, 'bab')}` : 'Bar';
299+
}
300+
}
301+
```
302+
303+
**Output** (<small>[non-computed-decorators.output.js](__testfixtures__/non-computed-decorators.output.js)</small>):
304+
305+
```js
306+
import { tracked } from '@glimmer/tracking';
307+
import Component from '@ember/component';
308+
import { computed, get } from '@ember/object';
309+
import { alias } from '@ember/object/computed';
310+
311+
export default class Foo extends Component {
312+
bar;
313+
// baz class property
314+
@tracked baz = 'barBaz';
315+
316+
@alias('model.isFoo')
317+
isFoo;
318+
319+
@computed('isFoo')
320+
get bazInfo() {
321+
return get(this, 'isFoo') ? `Name: ${get(this, 'baz')}` : 'Baz';
322+
}
323+
324+
@computed('bar', 'isFoo').readOnly()
325+
get barInfo() {
326+
return get(this, 'isFoo') ? `Name: ${get(this, 'bab')}` : 'Bar';
327+
}
328+
}
329+
```
330+
331+
---
332+
272333
<a id="with-tracked">**with-tracked**</a>
273334

274335
**Input** (<small>[with-tracked.input.js](__testfixtures__/with-tracked.input.js)</small>):
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Component from '@ember/component';
2+
import { computed, get } from '@ember/object';
3+
import { alias } from '@ember/object/computed';
4+
5+
export default class Foo extends Component {
6+
bar;
7+
// baz class property
8+
baz = 'barBaz';
9+
10+
@alias('model.isFoo')
11+
isFoo;
12+
13+
@computed('baz', 'isFoo')
14+
get bazInfo() {
15+
return get(this, 'isFoo') ? `Name: ${get(this, 'baz')}` : 'Baz';
16+
}
17+
18+
@computed('bar', 'isFoo').readOnly()
19+
get barInfo() {
20+
return get(this, 'isFoo') ? `Name: ${get(this, 'bab')}` : 'Bar';
21+
}
22+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { tracked } from '@glimmer/tracking';
2+
import Component from '@ember/component';
3+
import { computed, get } from '@ember/object';
4+
import { alias } from '@ember/object/computed';
5+
6+
export default class Foo extends Component {
7+
bar;
8+
// baz class property
9+
@tracked baz = 'barBaz';
10+
11+
@alias('model.isFoo')
12+
isFoo;
13+
14+
@computed('isFoo')
15+
get bazInfo() {
16+
return get(this, 'isFoo') ? `Name: ${get(this, 'baz')}` : 'Baz';
17+
}
18+
19+
@computed('bar', 'isFoo').readOnly()
20+
get barInfo() {
21+
return get(this, 'isFoo') ? `Name: ${get(this, 'bab')}` : 'Bar';
22+
}
23+
}

transforms/tracked-properties/index.js

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,28 @@ module.exports = function transformer(file, api) {
2525
path.node.body.forEach(classItem => {
2626
// Collect all the class properties in the file and add it to the
2727
// classProps array.
28-
if (classItem.type === 'ClassProperty') {
28+
if (classItem.type === 'ClassProperty' && !classItem.decorators) {
2929
classProps.push(classItem.key.name);
3030
}
3131
// Collect all the dependent keys of the computed properties present in the file
3232
// and add it to the computedProps array.
33-
if (classItem.type === 'ClassMethod') {
34-
if (classItem.kind === 'get') {
35-
classProps.push(classItem.key.name);
36-
}
37-
if (classItem.decorators) {
38-
classItem.decorators.forEach(decoratorItem => {
39-
if (
40-
decoratorItem.expression.callee &&
41-
decoratorItem.expression.callee.name === 'computed'
42-
) {
43-
const argValues = decoratorItem.expression.arguments.map(
44-
item => item.value
45-
);
46-
computedPropsMap[classItem.key.name] = argValues;
47-
computedProps = computedProps.concat(argValues);
48-
}
49-
});
50-
}
33+
if (
34+
classItem.type === 'ClassMethod' &&
35+
classItem.kind === 'get' &&
36+
classItem.decorators
37+
) {
38+
classItem.decorators.forEach(decoratorItem => {
39+
if (
40+
decoratorItem.expression.callee &&
41+
decoratorItem.expression.callee.name === 'computed'
42+
) {
43+
const argValues = decoratorItem.expression.arguments.map(
44+
item => item.value
45+
);
46+
computedPropsMap[classItem.key.name] = argValues;
47+
computedProps = computedProps.concat(argValues);
48+
}
49+
});
5150
}
5251
});
5352
});
@@ -61,14 +60,14 @@ module.exports = function transformer(file, api) {
6160
let trackedConvertedSource = j(file.source)
6261
.find(j.ClassProperty)
6362
.forEach(path => {
64-
if (computedProps.includes(path.node.key.name)) {
63+
if (!path.node.decorators && computedProps.includes(path.node.key.name)) {
6564
shouldImportBeAdded = true;
66-
var decorated = buildTrackedDecorator(
67-
path.node.key.name,
68-
path.node.value,
69-
j
70-
);
71-
path.replace(decorated);
65+
const trackedDecorator = buildTrackedDecorator(path.node.key.name, j);
66+
67+
// @TODO: Determine if @tracked can be prefixed alongside other decorators in a property,
68+
// if yes, then change this code to push the trackedDecorator along with the
69+
// others.
70+
path.node.decorators = trackedDecorator;
7271
}
7372
return path;
7473
})

transforms/tracked-properties/utils/helper.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ function _doesContainNonLocalArgs(argItem, computedMap, classProperties) {
5959

6060
while (stack.size() > 0) {
6161
currItem = stack.pop();
62-
// If currItem is not a class property, return true.
63-
if (!classProperties.includes(currItem)) {
62+
const dependentKeys = computedMap[currItem];
63+
64+
// If currItem is not a class property and
65+
// if it is not a computed property with dependent keys, return true.
66+
if (!classProperties.includes(currItem) && !dependentKeys) {
6467
return true;
6568
}
6669
// If currItem itself is a computed property, then it would have dependent keys.
6770
// Get the dependent keys and push them in the stack.
68-
const dependentKeys = computedMap[currItem];
6971
if (dependentKeys) {
7072
stack.push(...dependentKeys);
7173
}
@@ -78,15 +80,13 @@ function _doesContainNonLocalArgs(argItem, computedMap, classProperties) {
7880
* the key and values provided.
7981
* @param {*} macroName
8082
* @param {*} name
81-
* @param {*} value
8283
* @param {*} j
8384
*/
84-
function buildTrackedDecorator(name, value, j) {
85+
function buildTrackedDecorator(name, j) {
8586
var node = j('class Fake { @tracked' + ' ' + name + '; \n}')
8687
.find(j.ClassProperty)
8788
.get().node;
88-
node.value = value;
89-
return node;
89+
return node.decorators;
9090
}
9191

9292
/**

0 commit comments

Comments
 (0)