Skip to content

Commit ebe7c88

Browse files
author
Chris Garrett
authored
[FEAT] Removes @classname and @Attribute (#176)
Removes @classname and @Attribute decorators in favor of @classNameBindings and @attributeBindings class decorators
1 parent c1a0eff commit ebe7c88

File tree

5 files changed

+79
-133
lines changed

5 files changed

+79
-133
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import classic from 'ember-classic-decorator';
2-
import { attribute, className, classNames, tagName, layout as templateLayout } from '@ember-decorators/component';
2+
3+
import {
4+
classNames,
5+
attributeBindings,
6+
classNameBindings,
7+
tagName,
8+
layout as templateLayout,
9+
} from '@ember-decorators/component';
10+
311
import { observes as watcher, on } from '@ember-decorators/object';
412
import { inject as controller } from '@ember/controller';
513
import { inject as service } from '@ember/service';
@@ -80,20 +88,16 @@ class Foo extends EmberObject {
8088
}
8189

8290
@classic
91+
@classNameBindings('isEnabled:enabled:disabled', 'a:b:c', 'c:d')
92+
@attributeBindings('customHref:href')
8393
class Comp extends EmberObject {
8494
@computed('a', 'c')
85-
@className('enabled', 'disabled')
8695
get isEnabled() {
8796
return false;
8897
}
8998

90-
@className('b', 'c')
9199
a = true;
92-
93-
@className('d')
94100
c = '';
95-
96-
@attribute('href')
97101
customHref = 'http://emberjs.com';
98102
}
99103

transforms/helpers/EOProp.js

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,60 @@ const {
1414
* A wrapper object for ember object properties
1515
*/
1616
class EOProp {
17-
constructor(eoProp) {
17+
constructor(eoProp, runtimeData, importedDecoratedProps) {
1818
this._prop = eoProp;
1919
this.decorators = [];
2020
this.modifiers = [];
2121
this.decoratorArgs = {};
22+
23+
if (runtimeData.type) {
24+
const {
25+
type,
26+
computedProperties = [],
27+
offProperties = {},
28+
overriddenActions = [],
29+
overriddenProperties = [],
30+
unobservedProperties = {},
31+
} = runtimeData;
32+
33+
this.emberType = type;
34+
35+
const name = this.name;
36+
if (Object.keys(unobservedProperties).includes(name)) {
37+
this.decorators.push({ name: 'unobserves' });
38+
this.decoratorArgs['unobserves'] = unobservedProperties[name];
39+
}
40+
if (Object.keys(offProperties).includes(name)) {
41+
this.decorators.push({ name: 'off' });
42+
this.decoratorArgs['off'] = offProperties[name];
43+
}
44+
if (computedProperties.includes(name)) {
45+
this.isComputed = true;
46+
}
47+
if (this.isActions) {
48+
this.overriddenActions = overriddenActions;
49+
}
50+
this.isOverridden = overriddenProperties.includes(name);
51+
this.runtimeType = type;
52+
}
53+
54+
if (this.isCallExpression) {
55+
let calleeObject = get(this._prop, 'value');
56+
const modifiers = [getModifier(calleeObject)];
57+
while (get(calleeObject, 'callee.type') === 'MemberExpression') {
58+
calleeObject = get(calleeObject, 'callee.object');
59+
modifiers.push(getModifier(calleeObject));
60+
}
61+
this.calleeObject = calleeObject;
62+
this.modifiers = modifiers.reverse();
63+
this.modifiers.shift();
64+
65+
if (importedDecoratedProps[this.calleeName]) {
66+
this.decorators.push(importedDecoratedProps[this.calleeName]);
67+
} else if (this.isComputed) {
68+
this.decorators.push({ name: this.calleeName });
69+
}
70+
}
2271
}
2372

2473
get value() {
@@ -131,16 +180,16 @@ class EOProp {
131180
return this.name === 'classNames';
132181
}
133182

134-
get isAction() {
135-
return this.name === 'actions';
183+
get isClassNameBindings() {
184+
return this.name === 'classNameBindings';
136185
}
137186

138-
get hasClassNameDecorator() {
139-
return this.decoratorNames.includes('className');
187+
get isAttributeBindings() {
188+
return this.name === 'attributeBindings';
140189
}
141190

142-
get hasAttributeDecorator() {
143-
return this.decoratorNames.includes('attribute');
191+
get isActions() {
192+
return this.name === 'actions';
144193
}
145194

146195
get hasUnobservesDecorator() {
@@ -162,74 +211,6 @@ class EOProp {
162211
get hasMetaDecorator() {
163212
return this.decorators.find(d => d.isMetaDecorator);
164213
}
165-
166-
setCallExpressionProps() {
167-
let calleeObject = get(this._prop, 'value');
168-
const modifiers = [getModifier(calleeObject)];
169-
while (get(calleeObject, 'callee.type') === 'MemberExpression') {
170-
calleeObject = get(calleeObject, 'callee.object');
171-
modifiers.push(getModifier(calleeObject));
172-
}
173-
this.calleeObject = calleeObject;
174-
this.modifiers = modifiers.reverse();
175-
this.modifiers.shift();
176-
}
177-
178-
setDecorators(importedDecoratedProps) {
179-
if (this.isCallExpression) {
180-
this.setCallExpressionProps();
181-
182-
if (importedDecoratedProps[this.calleeName]) {
183-
this.decorators.push(importedDecoratedProps[this.calleeName]);
184-
} else if (this.isComputed) {
185-
this.decorators.push({ name: this.calleeName });
186-
}
187-
}
188-
}
189-
190-
addBindingProps(attributeBindingsProps, classNameBindingsProps) {
191-
if (attributeBindingsProps[this.name]) {
192-
this.decorators.push({ name: 'attribute' });
193-
this.propList = attributeBindingsProps[this.name];
194-
} else if (classNameBindingsProps[this.name]) {
195-
this.decorators.push({ name: 'className' });
196-
this.propList = classNameBindingsProps[this.name];
197-
}
198-
}
199-
200-
setRuntimeData({
201-
computedProperties = [],
202-
// observedProperties = [],
203-
// observerProperties = {},
204-
offProperties = {},
205-
overriddenActions = [],
206-
overriddenProperties = [],
207-
// ownProperties = [],
208-
type = '',
209-
unobservedProperties = {},
210-
}) {
211-
if (!type) {
212-
return;
213-
}
214-
215-
const name = this.name;
216-
if (Object.keys(unobservedProperties).includes(name)) {
217-
this.decorators.push({ name: 'unobserves' });
218-
this.decoratorArgs['unobserves'] = unobservedProperties[name];
219-
}
220-
if (Object.keys(offProperties).includes(name)) {
221-
this.decorators.push({ name: 'off' });
222-
this.decoratorArgs['off'] = offProperties[name];
223-
}
224-
if (computedProperties.includes(name)) {
225-
this.isComputed = true;
226-
}
227-
if (this.isAction) {
228-
this.overriddenActions = overriddenActions;
229-
}
230-
this.isOverridden = overriddenProperties.includes(name);
231-
this.runtimeType = type;
232-
}
233214
}
234215

235216
module.exports = EOProp;

transforms/helpers/parse-helper.js

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,13 @@ const logger = require('./log-helper');
2424
function getEmberObjectProps(j, eoExpression, importedDecoratedProps = {}, runtimeData = {}) {
2525
const objProps = get(eoExpression, 'properties') || [];
2626

27-
const instanceProps = [];
28-
const attributeBindingsProps = {};
29-
const classNameBindingsProps = {};
30-
31-
objProps.forEach(objProp => {
32-
const prop = new EOProp(objProp);
33-
if (prop.name === 'classNameBindings') {
34-
Object.assign(classNameBindingsProps, parseBindingProps(prop.value.elements));
35-
} else if (prop.name === 'attributeBindings') {
36-
Object.assign(attributeBindingsProps, parseBindingProps(prop.value.elements));
37-
} else {
38-
prop.setRuntimeData(runtimeData);
39-
prop.setDecorators(importedDecoratedProps);
40-
instanceProps.push(prop);
41-
}
42-
});
43-
44-
// Assign decorator names to the binding props if any
45-
instanceProps.forEach(instanceProp => {
46-
instanceProp.addBindingProps(attributeBindingsProps, classNameBindingsProps);
47-
});
48-
4927
return {
50-
instanceProps,
28+
instanceProps: objProps.map(
29+
objProp => new EOProp(objProp, runtimeData, importedDecoratedProps)
30+
),
5131
};
5232
}
5333

54-
/**
55-
* Split the binding property values using `:` as separator
56-
*
57-
* For example ["isEnabled:enabled:disabled", "a:b:c", "c:d"] will be parsed as
58-
* {
59-
* isEnabled:["enabled", "disabled"],
60-
* a: ["b", "c"],
61-
* c: ["d"]
62-
* }
63-
*
64-
* @param {Array} bindingPropElements
65-
* @returns {Object}
66-
*/
67-
function parseBindingProps(bindingPropElements = []) {
68-
return bindingPropElements.reduce((props, bindingElement) => {
69-
const [boundPropName, ...bindingElementList] = bindingElement.value.split(':');
70-
props[boundPropName.trim()] = bindingElementList;
71-
return props;
72-
}, {});
73-
}
74-
7534
/**
7635
* Get the map of decorators to import other than the computed props, services etc
7736
* which already have imports in the code
@@ -82,10 +41,10 @@ function parseBindingProps(bindingPropElements = []) {
8241
function getDecoratorsToImportMap(instanceProps, decoratorsMap = {}) {
8342
return instanceProps.reduce((specs, prop) => {
8443
return {
85-
action: specs.action || prop.isAction,
86-
attribute: specs.attribute || prop.hasAttributeDecorator,
87-
className: specs.className || prop.hasClassNameDecorator,
44+
action: specs.action || prop.isActions,
8845
classNames: specs.classNames || prop.isClassNames,
46+
classNameBindings: specs.classNameBindings || prop.isClassNameBindings,
47+
attributeBindings: specs.attributeBindings || prop.isAttributeBindings,
8948
layout: specs.layout || prop.isLayoutDecorator,
9049
templateLayout: specs.templateLayout || prop.isTemplateLayoutDecorator,
9150
off: specs.off || prop.hasOffDecorator,

transforms/helpers/util/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ const EMBER_DECORATOR_SPECIFIERS = {
4040
'@ember/object': ['action'],
4141
'@ember-decorators/object': ['off', 'on', 'unobserves'],
4242
'@ember-decorators/component': [
43-
'attribute',
44-
'className',
4543
'classNames',
44+
'attributeBindings',
45+
'classNameBindings',
4646
LAYOUT_DECORATOR_NAME,
4747
'tagName',
4848
LAYOUT_DECORATOR_LOCAL_NAME,
@@ -247,7 +247,9 @@ function startsWithUpperCaseLetter(word = '') {
247247
* @returns boolean
248248
*/
249249
function isClassDecoratorProp(propName) {
250-
return propName === 'tagName' || propName === 'classNames' || propName === 'layout';
250+
return ['layout', 'tagName', 'classNames', 'classNameBindings', 'attributeBindings'].includes(
251+
propName
252+
);
251253
}
252254

253255
/**

transforms/helpers/validation-helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function hasValidProps(
6969
);
7070
}
7171

72-
if (instanceProp.isAction) {
72+
if (instanceProp.isActions) {
7373
errors = errors.concat(getLifecycleHookErrors(instanceProp));
7474
errors = errors.concat(getInfiniteLoopErrors(j, instanceProp));
7575
}

0 commit comments

Comments
 (0)