Skip to content

Commit 6026249

Browse files
committed
Handle @classname
1 parent a8a6b4a commit 6026249

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
@@ -354,6 +354,39 @@ foo
354354
=========="
355355
`;
356356
357+
exports[`native components handles \`@className\` correctly 1`] = `
358+
"==========
359+
360+
import { className } from '@ember-decorators/component';
361+
362+
export default class FooComponent extends Component {
363+
@className('b') a;
364+
@className('y', 'z') x;
365+
@className(undefined, 'bar') foo;
366+
}
367+
368+
~~~~~~~~~~
369+
foo
370+
~~~~~~~~~~
371+
=> tagName: div
372+
~~~~~~~~~~
373+
374+
import { tagName } from '@ember-decorators/component';
375+
376+
@tagName(\\"\\")
377+
export default class FooComponent extends Component {
378+
a;
379+
x;
380+
foo;
381+
}
382+
383+
~~~~~~~~~~
384+
<div class=\\"{{if this.a \\"b\\"}} {{if this.x \\"y\\" \\"z\\"}} {{unless this.foo \\"bar\\"}}\\" ...attributes>
385+
foo
386+
</div>
387+
=========="
388+
`;
389+
357390
exports[`native components handles \`@classNameBindings\` correctly 1`] = `
358391
"==========
359392

lib/__tests__/transform.js

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

341+
test('handles `@className` correctly', () => {
342+
let source = `
343+
import { className } from '@ember-decorators/component';
344+
345+
export default class FooComponent extends Component {
346+
@className('b') a;
347+
@className('y', 'z') x;
348+
@className(undefined, 'bar') foo;
349+
}
350+
`;
351+
352+
let template = `foo`;
353+
354+
expect(generateSnapshot(source, template)).toMatchSnapshot();
355+
});
356+
357+
test('throws for non-boolean @className', () => {
358+
let source = `
359+
import { className } from '@ember-decorators/component';
360+
361+
export default class FooComponent extends Component {
362+
@className activeClass = 'active';
363+
}
364+
`;
365+
366+
expect(() => transform(source, '')).toThrowErrorMatchingInlineSnapshot(
367+
`"Unsupported non-boolean \`@className\` for property: activeClass"`
368+
);
369+
});
370+
341371
test('handles `@classNames` correctly', () => {
342372
let source = `
343373
import { classNames } from '@ember-decorators/component';
@@ -380,6 +410,20 @@ describe('native components', function() {
380410
expect(generateSnapshot(source, template)).toMatchSnapshot();
381411
});
382412

413+
test('throws for non-boolean @classNameBindings', () => {
414+
let source = `
415+
import { classNameBindings } from '@ember-decorators/component';
416+
417+
@classNameBindings('a:b', 'foo')
418+
export default class FooComponent extends Component {
419+
}
420+
`;
421+
422+
expect(() => transform(source, '')).toThrowErrorMatchingInlineSnapshot(
423+
`"Unsupported non-boolean \`@classNameBindings\` value: foo"`
424+
);
425+
});
426+
383427
test('skips tagless components', () => {
384428
let source = `
385429
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)