Skip to content

Commit 12c70f0

Browse files
authored
Merge pull request #10 from ssutar/multi_decorators
Support for multiple decorators
2 parents 88e0f1b + 3374ba9 commit 12c70f0

9 files changed

Lines changed: 470 additions & 307 deletions

File tree

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { alias, sum as add } from "@ember/object/computed";
2-
import { get, set, observer, computed } from "@ember/object";
2+
import { get, set, observer as watcher, computed } from "@ember/object";
33
import { inject as controller } from "@ember/controller";
44
import { inject as service } from "@ember/service";
55
import { on } from "@ember/object/evented";
@@ -11,8 +11,12 @@ const Foo = EmberObject.extend({
1111
a: "",
1212
b: service("store"),
1313
myController: controller("abc"),
14-
observedProp: observer("xyz"),
15-
event: on("click"),
14+
observedProp: watcher("xyz", function() {
15+
return "observed";
16+
}),
17+
event: on("click", function() {
18+
return "abc";
19+
}),
1620

1721
actions: {
1822
/**
@@ -28,7 +32,9 @@ const Foo = EmberObject.extend({
2832

2933
var comp = EmberObject.extend({
3034
classNameBindings: ["isEnabled:enabled:disabled", "a:b:c", "c:d"],
31-
isEnabled: false,
35+
isEnabled: computed("a", "c", function() {
36+
return false;
37+
}),
3238
a: true,
3339
c: "",
3440
attributeBindings: ["customHref:href"],

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { alias, sum as add } from "@ember/object/computed";
2-
import { get, set, observer, computed } from "@ember/object";
3-
import { inject as controller } from "@ember/controller";
4-
import { inject as service } from "@ember/service";
5-
import { on } from "@ember/object/evented";
1+
import { sum as add, alias } from "@ember-decorators/object/computed";
2+
import { get, set } from "@ember/object";
3+
import { computed, observes as watcher } from "@ember-decorators/object";
4+
import { controller as controller } from "@ember-decorators/controller";
5+
import { service as service } from "@ember-decorators/service";
6+
import { on } from "@ember-decorators/object/evented";
67
import layout from "components/templates/foo";
78

89
@tagName("div")
@@ -16,11 +17,15 @@ class Foo extends EmberObject {
1617
@controller("abc")
1718
myController;
1819

19-
@observes("xyz")
20-
observedProp;
20+
@watcher("xyz")
21+
observedProp() {
22+
return "observed";
23+
}
2124

2225
@on("click")
23-
event;
26+
event() {
27+
return "abc";
28+
}
2429

2530
/**
2631
Comments
@@ -38,8 +43,11 @@ class Foo extends EmberObject {
3843
}
3944

4045
class Comp extends EmberObject {
46+
@computed("a", "c")
4147
@className("enabled", "disabled")
42-
isEnabled = false;
48+
get isEnabled() {
49+
return false;
50+
}
4351

4452
@className("b", "c")
4553
a = true;
@@ -74,7 +82,7 @@ class Foo extends EmberObject {
7482
Computed description
7583
*/
7684
@computed("fullName", "age", "country")
77-
description() {
85+
get description() {
7886
return `${this.get(
7987
"fullName"
8088
)}; Age: ${this.get("age")}; Country: ${this.get("country")}`;

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { alias, sum as add } from "@ember/object/computed";
2-
import { get, set, observer, computed } from "@ember/object";
3-
import { inject as controller } from "@ember/controller";
4-
import { inject as service } from "@ember/service";
5-
import { on } from "@ember/object/evented";
1+
import { sum as add, alias } from "@ember-decorators/object/computed";
2+
import { get, set } from "@ember/object";
3+
import { computed, observes } from "@ember-decorators/object";
4+
import { controller as controller } from "@ember-decorators/controller";
5+
import { service as service } from "@ember-decorators/service";
6+
import { on } from "@ember-decorators/object/evented";
67
import layout from "components/templates/foo";
78
import MixinA from "mixins/A";
89
import MixinB from "mixins/B";
@@ -82,7 +83,7 @@ class Foo extends EmberObject.extend(MixinA, MixinB) {
8283
Computed description
8384
*/
8485
@computed("fullName", "age", "country")
85-
description() {
86+
get description() {
8687
return `${this.get(
8788
"fullName"
8889
)}; Age: ${this.get("age")}; Country: ${this.get("country")}`;

transforms/helpers/EOProp.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const {
2+
get,
3+
getPropName,
4+
getPropType,
5+
getPropCalleeName,
6+
isClassDecoratorProp,
7+
METHOD_DECORATORS
8+
} = require("./util");
9+
10+
/**
11+
* Ember Objet Property
12+
*
13+
* A wrapper object for ember object properties
14+
*/
15+
class EOProp {
16+
constructor(eoProp) {
17+
this._prop = eoProp;
18+
this.decoratorNames = [];
19+
}
20+
21+
get value() {
22+
return get(this._prop, "value");
23+
}
24+
25+
get kind() {
26+
let kind = get(this._prop, "kind");
27+
if (kind === "init" && this.hasDecorators && !this.hasMethodDecorator) {
28+
kind = "get";
29+
}
30+
return kind;
31+
}
32+
33+
get key() {
34+
return get(this._prop, "key");
35+
}
36+
37+
get name() {
38+
return getPropName(this._prop);
39+
}
40+
41+
get type() {
42+
return getPropType(this._prop);
43+
}
44+
45+
get calleeName() {
46+
return getPropCalleeName(this._prop);
47+
}
48+
49+
get comments() {
50+
return this._prop.comments;
51+
}
52+
53+
get computed() {
54+
return this._prop.computed;
55+
}
56+
57+
get isClassDecorator() {
58+
return isClassDecoratorProp(this.name);
59+
}
60+
61+
get isCallExpression() {
62+
return this.type === "CallExpression";
63+
}
64+
65+
get hasDecorators() {
66+
return this.decoratorNames.length;
67+
}
68+
69+
get callExprArgs() {
70+
return get(this._prop, "value.arguments") || [];
71+
}
72+
73+
get hasNonLiteralArg() {
74+
return this.callExprArgs.some(arg => arg.type !== "Literal");
75+
}
76+
77+
setDecorators(importedDecoratedProps) {
78+
if (this.isCallExpression) {
79+
const { decoratorName, importedName } =
80+
importedDecoratedProps[this.calleeName] || {};
81+
if (decoratorName) {
82+
this.hasMethodDecorator = METHOD_DECORATORS.includes(importedName);
83+
this.decoratorNames.push(decoratorName);
84+
}
85+
}
86+
}
87+
88+
addBindingProps(attributeBindingsProps, classNameBindingsProps) {
89+
if (attributeBindingsProps[this.name]) {
90+
this.decoratorNames.push("attribute");
91+
this.propList = attributeBindingsProps[this.name];
92+
} else if (classNameBindingsProps[this.name]) {
93+
this.decoratorNames.push("className");
94+
this.propList = classNameBindingsProps[this.name];
95+
}
96+
}
97+
}
98+
99+
module.exports = EOProp;

transforms/helpers/decorator-helper.js

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,15 @@ function withDecorators(to, decorators = []) {
1717
* Creates a list of class decorators `tagName` and `classNames`
1818
*
1919
* @param {Object} j - jscodeshift lib reference
20-
* @param {Property[]} classDecoratorProps
20+
* @param {Property} classDecoratorProp
2121
* @returns {Decorator[]}
2222
*/
23-
function createClassDecorators(j, classDecoratorProps = []) {
24-
return classDecoratorProps.map(classDecoratorProp => {
25-
return j.decorator(
26-
j.callExpression(j.identifier(classDecoratorProp.key.name), [
27-
classDecoratorProp.value
28-
])
29-
);
30-
});
23+
function createClassDecorator(j, classDecoratorProp) {
24+
return j.decorator(
25+
j.callExpression(j.identifier(classDecoratorProp.key.name), [
26+
classDecoratorProp.value
27+
])
28+
);
3129
}
3230

3331
/**
@@ -40,7 +38,7 @@ function createClassDecorators(j, classDecoratorProps = []) {
4038
* @returns {Decorator[]}
4139
*/
4240
function createCallExpressionDecorators(j, decoratorName, instanceProp) {
43-
if (decoratorName === "computed") {
41+
if (instanceProp.hasNonLiteralArg) {
4442
const decoratorArgs = get(instanceProp, "value.arguments").slice(0, -1);
4543
return [
4644
j.decorator(j.callExpression(j.identifier(decoratorName), decoratorArgs))
@@ -49,10 +47,7 @@ function createCallExpressionDecorators(j, decoratorName, instanceProp) {
4947
// clone the instance prop value
5048
const instancePropValue = JSON.parse(JSON.stringify(instanceProp.value));
5149
instancePropValue.callee.name = decoratorName;
52-
if (
53-
instanceProp.decoratorName &&
54-
get(instanceProp, "value.callee.object.callee.name")
55-
) {
50+
if (get(instanceProp, "value.callee.object.callee.name")) {
5651
const decoratorArgs = get(instancePropValue, "callee.object.arguments");
5752
instancePropValue.callee.object = get(
5853
instancePropValue,
@@ -101,19 +96,24 @@ function createBindingDecorators(j, decoratorName, instanceProp) {
10196
* @returns {Decorator[]}
10297
*/
10398
function createInstancePropDecorators(j, instanceProp) {
104-
const decoratorName = instanceProp.decoratorName;
105-
if (!decoratorName) {
106-
return [];
107-
}
108-
if (decoratorName === "className" || decoratorName === "attribute") {
109-
return createBindingDecorators(j, decoratorName, instanceProp);
110-
}
111-
return createCallExpressionDecorators(j, decoratorName, instanceProp);
99+
return instanceProp.decoratorNames.reduce((decorators, decoratorName) => {
100+
if (!decoratorName) {
101+
return decorators;
102+
}
103+
if (decoratorName === "className" || decoratorName === "attribute") {
104+
return decorators.concat(
105+
createBindingDecorators(j, decoratorName, instanceProp)
106+
);
107+
}
108+
return decorators.concat(
109+
createCallExpressionDecorators(j, decoratorName, instanceProp)
110+
);
111+
}, []);
112112
}
113113

114114
module.exports = {
115115
withDecorators,
116-
createClassDecorators,
116+
createClassDecorator,
117117
createActionDecorators,
118118
createCallExpressionDecorators,
119119
createInstancePropDecorators

0 commit comments

Comments
 (0)