Skip to content

Commit 5012674

Browse files
ssutarpzuraq
authored andcommitted
Handle decorator modifiers (#16)
This handles the computed modifiers mentioned in the #15
1 parent be7ae9f commit 5012674

12 files changed

Lines changed: 1196 additions & 790 deletions

package-lock.json

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

transforms/ember-object/__testfixtures__/decorators.input.js

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { alias, sum as add } from "@ember/object/computed";
1+
import {
2+
alias,
3+
readOnly,
4+
reads,
5+
oneWay as enoWay,
6+
sum as add
7+
} from "@ember/object/computed";
28
import { get, set, observer as watcher, computed } from "@ember/object";
39
import { inject as controller } from "@ember/controller";
410
import { inject as service } from "@ember/service";
@@ -59,22 +65,42 @@ const Foo = EmberObject.extend({
5965
this.set("lastName", lastName);
6066
return value;
6167
}
62-
}),
63-
68+
}).readOnly(),
6469
/**
6570
Computed description
6671
*/
6772
description: computed("fullName", "age", "country", function() {
6873
return `${this.get(
6974
"fullName"
7075
)}; Age: ${this.get("age")}; Country: ${this.get("country")}`;
71-
}),
76+
})
77+
.volatile()
78+
.readOnly(),
7279

7380
/**
7481
* Fname
7582
*/
7683
fName: alias("firstName"),
7784

85+
/**
86+
* Fname1
87+
*/
88+
fName1: alias("firstName"),
89+
90+
/**
91+
* Fname2
92+
*/
93+
fName2: computed("firstName", "lastName", function() {
94+
return true;
95+
}).readOnly(),
96+
97+
/**
98+
* Fname3
99+
*/
100+
fName3: computed("firstName", "lastName", function() {
101+
return true;
102+
}).volatile(),
103+
78104
/**
79105
* Lname
80106
*/
@@ -83,7 +109,27 @@ const Foo = EmberObject.extend({
83109
/**
84110
* Lname1
85111
*/
86-
lName1: add("description", "lastName").volatile()
112+
lName1: add("description", "lastName"),
113+
114+
/**
115+
* Lname2
116+
*/
117+
lName2: readOnly("description"),
118+
119+
/**
120+
* Lname3
121+
*/
122+
lName3: reads("description", "lastName"),
123+
124+
/**
125+
* Lname4
126+
*/
127+
lName4: enoWay("description", "lastName"),
128+
129+
/**
130+
* Lname5
131+
*/
132+
lName5: add("description", "lastName").readOnly()
87133
});
88134

89135
const Foo = EmberObject.extend({

transforms/ember-object/__testfixtures__/decorators.invalid.input.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,36 @@ const Foo = EmberObject.extend({
88
const Foo = EmberObject.extend({
99
macroValue: macro()
1010
});
11+
12+
// Do not transform as a computed property has readOnly and volatile with meta
13+
const Foo = EmberObject.extend({
14+
firstName: "",
15+
lastName: "",
16+
17+
fName2: computed("firstName", "lastName", function() {
18+
return true;
19+
})
20+
.property("baz")
21+
.readOnly()
22+
.volatile()
23+
.meta({ type: "Property" })
24+
});
25+
26+
// Do not transform as a computed meta has volatile
27+
const Foo = EmberObject.extend({
28+
lName1: add("description", "lastName").volatile()
29+
});
30+
31+
// Do not transform as computed prop has `property`
32+
const Foo = EmberObject.extend({
33+
fName2: computed("firstName", "lastName", function() {
34+
return true;
35+
}).property("baz")
36+
});
37+
38+
// Do not transform as computed prop has `meta`
39+
const Foo = EmberObject.extend({
40+
fName2: computed("firstName", "lastName", function() {
41+
return true;
42+
}).meta({ type: "Property" })
43+
});

transforms/ember-object/__testfixtures__/decorators.invalid.output.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,36 @@ const Foo = EmberObject.extend({
88
const Foo = EmberObject.extend({
99
macroValue: macro()
1010
});
11+
12+
// Do not transform as a computed property has readOnly and volatile with meta
13+
const Foo = EmberObject.extend({
14+
firstName: "",
15+
lastName: "",
16+
17+
fName2: computed("firstName", "lastName", function() {
18+
return true;
19+
})
20+
.property("baz")
21+
.readOnly()
22+
.volatile()
23+
.meta({ type: "Property" })
24+
});
25+
26+
// Do not transform as a computed meta has volatile
27+
const Foo = EmberObject.extend({
28+
lName1: add("description", "lastName").volatile()
29+
});
30+
31+
// Do not transform as computed prop has `property`
32+
const Foo = EmberObject.extend({
33+
fName2: computed("firstName", "lastName", function() {
34+
return true;
35+
}).property("baz")
36+
});
37+
38+
// Do not transform as computed prop has `meta`
39+
const Foo = EmberObject.extend({
40+
fName2: computed("firstName", "lastName", function() {
41+
return true;
42+
}).meta({ type: "Property" })
43+
});

transforms/ember-object/__testfixtures__/decorators.output.js

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { sum as add, alias } from "@ember-decorators/object/computed";
1+
import { sum as add, overridableReads as enoWay, overridableReads, reads, alias } from "@ember-decorators/object/computed";
22
import { get, set } from "@ember/object";
33
import { computed, observes as watcher } from "@ember-decorators/object";
44
import { controller } from "@ember-decorators/controller";
55
import { service } from "@ember-decorators/service";
66
import { on } from "@ember-decorators/object/evented";
77
import layout from "components/templates/foo";
88

9+
import { volatile, readOnly } from "@ember-decorators/object";
10+
911
@tagName("div")
1012
@classNames(["test-class", "custom-class"])
1113
class Foo extends EmberObject {
@@ -67,11 +69,12 @@ class Foo extends EmberObject {
6769
Computed fullname
6870
*/
6971
@computed("firstName", "lastName")
70-
get fullName(key) {
72+
@readOnly
73+
get fullName() {
7174
return `${this.get("firstName")} ${this.get("lastName")}`;
7275
}
7376

74-
set fullName(key, value) {
77+
set fullName(value) {
7578
let [firstName, lastName] = value.split(/\s+/);
7679
this.set("firstName", firstName);
7780
this.set("lastName", lastName);
@@ -81,7 +84,6 @@ class Foo extends EmberObject {
8184
/**
8285
Computed description
8386
*/
84-
@computed("fullName", "age", "country")
8587
get description() {
8688
return `${this.get(
8789
"fullName"
@@ -94,18 +96,68 @@ class Foo extends EmberObject {
9496
@alias("firstName")
9597
fName;
9698

99+
/**
100+
* Fname1
101+
*/
102+
@alias("firstName")
103+
fName1;
104+
105+
/**
106+
* Fname2
107+
*/
108+
@computed("firstName", "lastName")
109+
@readOnly
110+
get fName2() {
111+
return true;
112+
}
113+
114+
/**
115+
* Fname3
116+
*/
117+
@computed("firstName", "lastName")
118+
@volatile
119+
get fName3() {
120+
return true;
121+
}
122+
97123
/**
98124
* Lname
99125
*/
100-
@alias.readOnly("firstName", "lastName")
126+
@alias("firstName", "lastName")
127+
@readOnly
101128
lName;
102129

103130
/**
104131
* Lname1
105132
*/
106-
@add.volatile("description", "lastName")
133+
@add("description", "lastName")
107134
lName1;
135+
136+
/**
137+
* Lname2
138+
*/
139+
@reads("description")
140+
lName2;
141+
142+
/**
143+
* Lname3
144+
*/
145+
@overridableReads("description", "lastName")
146+
lName3;
147+
148+
/**
149+
* Lname4
150+
*/
151+
@enoWay("description", "lastName")
152+
lName4;
153+
154+
/**
155+
* Lname5
156+
*/
157+
@add("description", "lastName")
158+
@readOnly
159+
lName5;
108160
}
109161

110162
@layout(layout)
111-
class Foo extends EmberObject {}
163+
class Foo extends EmberObject {}

transforms/ember-object/index.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
const { getOptions } = require("codemod-cli");
22
const { replaceEmberObjectExpressions } = require("../helpers/parse-helper");
33

4-
module.exports = function transformer(file, api, options) {
4+
module.exports = function transformer(file, api) {
55
const j = api.jscodeshift;
66
const root = j(file.source);
77

8-
replaceEmberObjectExpressions(
9-
j,
10-
root,
11-
file.path,
12-
Object.assign({}, options, getOptions())
13-
);
8+
replaceEmberObjectExpressions(j, root, file.path, getOptions());
149

1510
return root.toSource();
1611
};

transforms/helpers/EOProp.js

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ const {
22
get,
33
getPropName,
44
getPropType,
5-
getPropCalleeName,
6-
isClassDecoratorProp,
7-
METHOD_DECORATORS
5+
getModifier,
6+
isClassDecoratorProp
87
} = require("./util");
98

109
/**
@@ -16,6 +15,7 @@ class EOProp {
1615
constructor(eoProp) {
1716
this._prop = eoProp;
1817
this.decoratorNames = [];
18+
this.modifiers = [];
1919
}
2020

2121
get value() {
@@ -43,7 +43,7 @@ class EOProp {
4343
}
4444

4545
get calleeName() {
46-
return getPropCalleeName(this._prop);
46+
return get(this.calleeObject, "callee.name");
4747
}
4848

4949
get comments() {
@@ -67,19 +67,53 @@ class EOProp {
6767
}
6868

6969
get callExprArgs() {
70-
return get(this._prop, "value.arguments") || [];
70+
return get(this.calleeObject, "arguments") || [];
7171
}
7272

7373
get hasNonLiteralArg() {
7474
return this.callExprArgs.some(arg => arg.type !== "Literal");
7575
}
7676

77+
get hasModifierWithArgs() {
78+
return this.modifiers.some(modifier => modifier.args.length);
79+
}
80+
81+
get hasVolatile() {
82+
return this.modifiers.some(
83+
modifier => get(modifier, "prop.name") === "volatile"
84+
);
85+
}
86+
87+
get hasReadOnly() {
88+
return this.modifiers.some(
89+
modifier => get(modifier, "prop.name") === "readOnly"
90+
);
91+
}
92+
93+
get isVolatileReadOnly() {
94+
return this.modifiers.length === 2 && this.hasVolatile && this.hasReadOnly;
95+
}
96+
97+
setCallExpressionProps() {
98+
let calleeObject = get(this._prop, "value");
99+
const modifiers = [getModifier(calleeObject)];
100+
while (get(calleeObject, "callee.type") === "MemberExpression") {
101+
calleeObject = get(calleeObject, "callee.object");
102+
modifiers.push(getModifier(calleeObject));
103+
}
104+
this.calleeObject = calleeObject;
105+
this.modifiers = modifiers.reverse();
106+
this.modifiers.shift();
107+
}
108+
77109
setDecorators(importedDecoratedProps) {
78110
if (this.isCallExpression) {
79-
const { decoratorName, importedName } =
111+
this.setCallExpressionProps();
112+
const { decoratorName, isMethodDecorator, isMetaDecorator } =
80113
importedDecoratedProps[this.calleeName] || {};
81114
if (decoratorName) {
82-
this.hasMethodDecorator = METHOD_DECORATORS.includes(importedName);
115+
this.hasMethodDecorator = isMethodDecorator;
116+
this.hasMetaDecorator = isMetaDecorator;
83117
this.decoratorNames.push(decoratorName);
84118
}
85119
}

0 commit comments

Comments
 (0)