Skip to content

Commit 1a292b0

Browse files
committed
Handle @classname
1 parent 23aa921 commit 1a292b0

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

lib/__tests__/__snapshots__/transform.js.snap

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,39 @@ foo
330330
=========="
331331
`;
332332
333+
exports[`native components handles \`@className\` correctly 1`] = `
334+
"==========
335+
336+
import { className } from '@ember-decorators/component';
337+
338+
export default class FooComponent extends Component {
339+
@className('b') a;
340+
@className('y', 'z') x;
341+
@className(undefined, 'bar') foo;
342+
}
343+
344+
~~~~~~~~~~
345+
foo
346+
~~~~~~~~~~
347+
=> tagName: div
348+
~~~~~~~~~~
349+
350+
import { tagName } from '@ember-decorators/component';
351+
352+
@tagName(\\"\\")
353+
export default class FooComponent extends Component {
354+
a;
355+
x;
356+
foo;
357+
}
358+
359+
~~~~~~~~~~
360+
<div class=\\"{{if this.a \\"b\\"}} {{if this.x \\"y\\" \\"z\\"}} {{unless this.foo \\"bar\\"}}\\" ...attributes>
361+
foo
362+
</div>
363+
=========="
364+
`;
365+
333366
exports[`native components handles \`@classNameBindings\` correctly 1`] = `
334367
"==========
335368

lib/__tests__/transform.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,36 @@ describe('native components', function() {
301301
expect(generateSnapshot(source, template)).toMatchSnapshot();
302302
});
303303

304+
test('handles `@className` correctly', () => {
305+
let source = `
306+
import { className } from '@ember-decorators/component';
307+
308+
export default class FooComponent extends Component {
309+
@className('b') a;
310+
@className('y', 'z') x;
311+
@className(undefined, 'bar') foo;
312+
}
313+
`;
314+
315+
let template = `foo`;
316+
317+
expect(generateSnapshot(source, template)).toMatchSnapshot();
318+
});
319+
320+
test('throws for non-boolean @className', () => {
321+
let source = `
322+
import { className } from '@ember-decorators/component';
323+
324+
export default class FooComponent extends Component {
325+
@className activeClass = 'active';
326+
}
327+
`;
328+
329+
expect(() => transform(source, '')).toThrowErrorMatchingInlineSnapshot(
330+
`"Unsupported non-boolean \`@className\` for property: activeClass"`
331+
);
332+
});
333+
304334
test('handles `@classNames` correctly', () => {
305335
let source = `
306336
import { classNames } from '@ember-decorators/component';
@@ -343,6 +373,20 @@ describe('native components', function() {
343373
expect(generateSnapshot(source, template)).toMatchSnapshot();
344374
});
345375

376+
test('throws for non-boolean @classNameBindings', () => {
377+
let source = `
378+
import { classNameBindings } from '@ember-decorators/component';
379+
380+
@classNameBindings('a:b', 'foo')
381+
export default class FooComponent extends Component {
382+
}
383+
`;
384+
385+
expect(() => transform(source, '')).toThrowErrorMatchingInlineSnapshot(
386+
`"Unsupported non-boolean \`@classNameBindings\` value: foo"`
387+
);
388+
});
389+
346390
test('skips tagless components', () => {
347391
let source = `
348392
import { tagName } from '@ember-decorators/component';

lib/transform/native.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ module.exports = function transformNativeComponent(root, options) {
146146
j(classBody)
147147
.find(j.ClassProperty)
148148
.forEach(path => removeDecorator(root, path, 'attribute', '@ember-decorators/component'));
149+
j(classBody)
150+
.find(j.ClassProperty)
151+
.forEach(path => removeDecorator(root, path, 'className', '@ember-decorators/component'));
149152

150153
let newSource = root.toSource();
151154

lib/utils/native.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,34 @@ function findClassNameBindings(classDeclaration) {
139139
let parts = binding.split(':');
140140

141141
if (parts.length === 1) {
142-
throw new SilentError(`Unsupported non-boolean \`classNameBindings\` value: ${binding}`);
142+
throw new SilentError(`Unsupported non-boolean \`@classNameBindings\` value: ${binding}`);
143143
} else if (parts.length === 2) {
144144
classNameBindings.set(parts[0], [parts[1], null]);
145145
} else if (parts.length === 3) {
146146
classNameBindings.set(parts[0], [parts[1] || null, parts[2]]);
147147
} else {
148-
throw new SilentError(`Unexpected \`classNameBindings\` value: ${binding}`);
148+
throw new SilentError(`Unexpected \`@classNameBindings\` value: ${binding}`);
149149
}
150150
}
151151

152+
j(classDeclaration)
153+
.find(j.ClassProperty)
154+
.forEach(path => {
155+
let key = path.node.key.name;
156+
157+
if (findDecorator(path, 'className', false)) {
158+
throw new SilentError(`Unsupported non-boolean \`@className\` for property: ${key}`);
159+
}
160+
let decorator = findDecorator(path, 'className', true);
161+
if (!decorator) {
162+
return;
163+
}
164+
165+
let args = decorator.get('expression').value.arguments;
166+
let [truthy, falsy] = args.map(element => element.value);
167+
classNameBindings.set(key, [truthy || null, falsy || null]);
168+
});
169+
152170
return classNameBindings;
153171
}
154172

0 commit comments

Comments
 (0)