Skip to content

Commit 8c3a3d6

Browse files
authored
Improve className attribute, to be more obvious (#71)
Closes #69 So it basically make work with className attribute more obvious. If you pass array — you expect array, variable — variable.
1 parent 2eccbc1 commit 8c3a3d6

8 files changed

+301
-42
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`JavaScript output: transformed source code 1`] = `
4+
"const object = {
5+
first: 'one-in-object',
6+
second: 'two-in-object'
7+
};
8+
9+
const array = ['arr-one', 'arr-two'];
10+
11+
module.exports = <div><div className=\\"one two\\" /><div className=\\"one two\\" /><div className={100} /><div className={array} /><div className={object} /><div className={['one', 'two']} /><div className={['one', 'two'].join(' ')} /><div className={{ first: true }} /><div className=\\"mix one two\\" /><div className={'mix ' + 100} /><div className={'mix ' + array} /><div className={'mix ' + object} /><div className={['mix', 'one', 'two']} /><div className={'mix ' + ['one', 'two'].join(' ')} /><div className={'mix ' + { first: true }} /></div>;"
12+
`;
13+
14+
exports[`html output: generated html 1`] = `
15+
<div>
16+
<div
17+
className="one two"
18+
/>
19+
<div
20+
className="one two"
21+
/>
22+
<div
23+
className={100}
24+
/>
25+
<div
26+
className={
27+
Array [
28+
"arr-one",
29+
"arr-two",
30+
]
31+
}
32+
/>
33+
<div
34+
className={
35+
Object {
36+
"first": "one-in-object",
37+
"second": "two-in-object",
38+
}
39+
}
40+
/>
41+
<div
42+
className={
43+
Array [
44+
"one",
45+
"two",
46+
]
47+
}
48+
/>
49+
<div
50+
className="one two"
51+
/>
52+
<div
53+
className={
54+
Object {
55+
"first": true,
56+
}
57+
}
58+
/>
59+
<div
60+
className="mix one two"
61+
/>
62+
<div
63+
className="mix 100"
64+
/>
65+
<div
66+
className="mix arr-one,arr-two"
67+
/>
68+
<div
69+
className="mix [object Object]"
70+
/>
71+
<div
72+
className={
73+
Array [
74+
"mix",
75+
"one",
76+
"two",
77+
]
78+
}
79+
/>
80+
<div
81+
className="mix one two"
82+
/>
83+
<div
84+
className="mix [object Object]"
85+
/>
86+
</div>
87+
`;
88+
89+
exports[`static html output: static html 1`] = `"<div><div class=\\"one two\\"></div><div class=\\"one two\\"></div><div class=\\"100\\"></div><div class=\\"arr-one,arr-two\\"></div><div class=\\"[object Object]\\"></div><div class=\\"one,two\\"></div><div class=\\"one two\\"></div><div class=\\"[object Object]\\"></div><div class=\\"mix one two\\"></div><div class=\\"mix 100\\"></div><div class=\\"mix arr-one,arr-two\\"></div><div class=\\"mix [object Object]\\"></div><div class=\\"mix,one,two\\"></div><div class=\\"mix one two\\"></div><div class=\\"mix [object Object]\\"></div></div>"`;

src/__tests__/__snapshots__/option-class-attribute.test.js.snap

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
exports[`JavaScript output: transformed source code 1`] = `
44
"const name = 'jack';
55
6-
module.exports = <div className=\\"first-a first-b\\"><p className=\\"second-a second-b second-c second-d\\" /><p styleName=\\"third-e third-f\\" className=\\"third-a third-b third-c third-d third-g third-h\\" /><p styleName=\\"fourth-a fourth-b\\" /><p className=\\"fivth-a fivth-b\\" /><p styleName=\\"two\\" className={[[\\"one\\", name].join(' ')].join(' ')} />{((_pug_nodes, _pug_arr) => {
6+
module.exports = <div className=\\"first-a first-b\\"><p className=\\"second-a second-b second-c second-d\\" /><p styleName=\\"third-c third-d\\" className=\\"third-a third-b third-e third-f\\" /><p styleName=\\"fourth-a fourth-b\\" /><p className=\\"fivth-a fivth-b\\" /><p styleName=\\"two\\" className=\\"one\\" />{((_pug_nodes, _pug_arr) => {
77
if (!(_pug_arr == null || Array.isArray(_pug_arr))) throw new Error('Expected \\"[1, 2, 3]\\" to be an array because it is passed to each.');
88
if (_pug_arr == null || _pug_arr.length === 0) return undefined;
99
1010
for (let _pug_index = 0; _pug_index < _pug_arr.length; _pug_index++) {
1111
const item = _pug_arr[_pug_index];
12-
_pug_nodes[_pug_nodes.length] = <p className={['seventh-a', 'seventh-b', \\"seventh-i-\\" + item, \\"seventh-g-\\" + item].join(' ')} key={'pug' + item + ':0'} />;
12+
_pug_nodes[_pug_nodes.length] = <p className={'seventh-a seventh-b ' + (\\"seventh-i-\\" + item)} key={'pug' + item + ':0'} />;
1313
}
1414
1515
return _pug_nodes;
@@ -19,13 +19,13 @@ module.exports = <div className=\\"first-a first-b\\"><p className=\\"second-a s
1919
exports[`JavaScript output: transformed source code 2`] = `
2020
"const name = 'jack';
2121
22-
module.exports = <div styleName=\\"first-a first-b\\"><p styleName=\\"second-a second-b second-c second-d\\" /><p className=\\"third-g third-h\\" styleName=\\"third-a third-b third-c third-d third-e third-f\\" /><p styleName=\\"fourth-a fourth-b\\" /><p className=\\"fivth-a fivth-b\\" /><p styleName={[[\\"one\\", name].join(' '), \\"two\\"].join(' ')} />{((_pug_nodes, _pug_arr) => {
22+
module.exports = <div styleName=\\"first-a first-b\\"><p styleName=\\"second-a second-b second-c second-d\\" /><p className=\\"third-e third-f\\" styleName=\\"third-a third-b third-c third-d\\" /><p styleName=\\"fourth-a fourth-b\\" /><p className=\\"fivth-a fivth-b\\" /><p styleName=\\"one two\\" />{((_pug_nodes, _pug_arr) => {
2323
if (!(_pug_arr == null || Array.isArray(_pug_arr))) throw new Error('Expected \\"[1, 2, 3]\\" to be an array because it is passed to each.');
2424
if (_pug_arr == null || _pug_arr.length === 0) return undefined;
2525
2626
for (let _pug_index = 0; _pug_index < _pug_arr.length; _pug_index++) {
2727
const item = _pug_arr[_pug_index];
28-
_pug_nodes[_pug_nodes.length] = <p className={\\"seventh-g-\\" + item} styleName={['seventh-a', 'seventh-b', \\"seventh-i-\\" + item].join(' ')} key={'pug' + item + ':0'} />;
28+
_pug_nodes[_pug_nodes.length] = <p className={\\"seventh-i-\\" + item} styleName=\\"seventh-a seventh-b\\" key={'pug' + item + ':0'} />;
2929
}
3030
3131
return _pug_nodes;
@@ -40,8 +40,8 @@ exports[`html output: generated html 1`] = `
4040
className="second-a second-b second-c second-d"
4141
/>
4242
<p
43-
className="third-a third-b third-c third-d third-g third-h"
44-
styleName="third-e third-f"
43+
className="third-a third-b third-e third-f"
44+
styleName="third-c third-d"
4545
/>
4646
<p
4747
styleName="fourth-a fourth-b"
@@ -50,17 +50,17 @@ exports[`html output: generated html 1`] = `
5050
className="fivth-a fivth-b"
5151
/>
5252
<p
53-
className="one jack"
53+
className="one"
5454
styleName="two"
5555
/>
5656
<p
57-
className="seventh-a seventh-b seventh-i-1 seventh-g-1"
57+
className="seventh-a seventh-b seventh-i-1"
5858
/>
5959
<p
60-
className="seventh-a seventh-b seventh-i-2 seventh-g-2"
60+
className="seventh-a seventh-b seventh-i-2"
6161
/>
6262
<p
63-
className="seventh-a seventh-b seventh-i-3 seventh-g-3"
63+
className="seventh-a seventh-b seventh-i-3"
6464
/>
6565
</div>
6666
`;
@@ -73,8 +73,8 @@ exports[`html output: generated html 2`] = `
7373
styleName="second-a second-b second-c second-d"
7474
/>
7575
<p
76-
className="third-g third-h"
77-
styleName="third-a third-b third-c third-d third-e third-f"
76+
className="third-e third-f"
77+
styleName="third-a third-b third-c third-d"
7878
/>
7979
<p
8080
styleName="fourth-a fourth-b"
@@ -83,23 +83,23 @@ exports[`html output: generated html 2`] = `
8383
className="fivth-a fivth-b"
8484
/>
8585
<p
86-
styleName="one jack two"
86+
styleName="one two"
8787
/>
8888
<p
89-
className="seventh-g-1"
90-
styleName="seventh-a seventh-b seventh-i-1"
89+
className="seventh-i-1"
90+
styleName="seventh-a seventh-b"
9191
/>
9292
<p
93-
className="seventh-g-2"
94-
styleName="seventh-a seventh-b seventh-i-2"
93+
className="seventh-i-2"
94+
styleName="seventh-a seventh-b"
9595
/>
9696
<p
97-
className="seventh-g-3"
98-
styleName="seventh-a seventh-b seventh-i-3"
97+
className="seventh-i-3"
98+
styleName="seventh-a seventh-b"
9999
/>
100100
</div>
101101
`;
102102

103-
exports[`static html output: static html 1`] = `"<div class=\\"first-a first-b\\"><p class=\\"second-a second-b second-c second-d\\"></p><p styleName=\\"third-e third-f\\" class=\\"third-a third-b third-c third-d third-g third-h\\"></p><p styleName=\\"fourth-a fourth-b\\"></p><p class=\\"fivth-a fivth-b\\"></p><p styleName=\\"two\\" class=\\"one jack\\"></p><p class=\\"seventh-a seventh-b seventh-i-1 seventh-g-1\\"></p><p class=\\"seventh-a seventh-b seventh-i-2 seventh-g-2\\"></p><p class=\\"seventh-a seventh-b seventh-i-3 seventh-g-3\\"></p></div>"`;
103+
exports[`static html output: static html 1`] = `"<div class=\\"first-a first-b\\"><p class=\\"second-a second-b second-c second-d\\"></p><p styleName=\\"third-c third-d\\" class=\\"third-a third-b third-e third-f\\"></p><p styleName=\\"fourth-a fourth-b\\"></p><p class=\\"fivth-a fivth-b\\"></p><p styleName=\\"two\\" class=\\"one\\"></p><p class=\\"seventh-a seventh-b seventh-i-1\\"></p><p class=\\"seventh-a seventh-b seventh-i-2\\"></p><p class=\\"seventh-a seventh-b seventh-i-3\\"></p></div>"`;
104104
105-
exports[`static html output: static html 2`] = `"<div styleName=\\"first-a first-b\\"><p styleName=\\"second-a second-b second-c second-d\\"></p><p class=\\"third-g third-h\\" styleName=\\"third-a third-b third-c third-d third-e third-f\\"></p><p styleName=\\"fourth-a fourth-b\\"></p><p class=\\"fivth-a fivth-b\\"></p><p styleName=\\"one jack two\\"></p><p class=\\"seventh-g-1\\" styleName=\\"seventh-a seventh-b seventh-i-1\\"></p><p class=\\"seventh-g-2\\" styleName=\\"seventh-a seventh-b seventh-i-2\\"></p><p class=\\"seventh-g-3\\" styleName=\\"seventh-a seventh-b seventh-i-3\\"></p></div>"`;
105+
exports[`static html output: static html 2`] = `"<div styleName=\\"first-a first-b\\"><p styleName=\\"second-a second-b second-c second-d\\"></p><p class=\\"third-e third-f\\" styleName=\\"third-a third-b third-c third-d\\"></p><p styleName=\\"fourth-a fourth-b\\"></p><p class=\\"fivth-a fivth-b\\"></p><p styleName=\\"one two\\"></p><p class=\\"seventh-i-1\\" styleName=\\"seventh-a seventh-b\\"></p><p class=\\"seventh-i-2\\" styleName=\\"seventh-a seventh-b\\"></p><p class=\\"seventh-i-3\\" styleName=\\"seventh-a seventh-b\\"></p></div>"`;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const object = {
2+
first: 'one-in-object',
3+
second: 'two-in-object',
4+
};
5+
6+
const array = ['arr-one', 'arr-two'];
7+
8+
module.exports = pug`
9+
div
10+
.one.two
11+
div(className="one two")
12+
div(className=100)
13+
div(className=array)
14+
div(className=object)
15+
div(className=['one', 'two'])
16+
div(className=['one', 'two'].join(' '))
17+
div(className={first: true})
18+
19+
.mix(className="one two")
20+
.mix(className=100)
21+
.mix(className=array)
22+
.mix(className=object)
23+
.mix(className=['one', 'two'])
24+
.mix(className=['one', 'two'].join(' '))
25+
.mix(className={first: true})
26+
`;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import testHelper from './test-helper';
2+
3+
testHelper(__dirname + '/attributes-transformation.input.js');
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import {transform} from 'babel-core';
3+
import renderer from 'react-test-renderer';
4+
import transformReactPug from '../';
5+
6+
const transformationOptions = {
7+
babelrc: false,
8+
plugins: [transformReactPug],
9+
};
10+
11+
const transformer = code => {
12+
return transform(`pug\`${code}\``, transformationOptions).code;
13+
};
14+
15+
const ExpectedError = /We can't use expressions in shorthands, use "className" instead of "class"/;
16+
17+
describe('throws error when', () => {
18+
it('is number', () => {
19+
const result = () => transformer(`div(class=42)`);
20+
21+
expect(result).toThrowError(ExpectedError);
22+
});
23+
24+
it('is array', () => {
25+
const result = () => transformer(`div(class=[1, 2])`);
26+
27+
expect(result).toThrowError(ExpectedError);
28+
});
29+
30+
it('is variable', () => {
31+
const result = () => transformer(`div(class=test)`);
32+
33+
expect(result).toThrowError(ExpectedError);
34+
});
35+
});
36+
37+
describe('does not throw error when', () => {
38+
it('is string', () => {
39+
const result = () => transformer(`div(class="text")`);
40+
41+
expect(result).not.toThrowError();
42+
});
43+
});

src/__tests__/option-class-attribute.input.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ module.exports = pug`
44
div.first-a.first-b
55
p.second-a.second-b(class="second-c second-d")
66
p.third-a.third-b(
7-
class="third-c third-d"
8-
styleName="third-e third-f"
9-
className="third-g third-h"
7+
styleName="third-c third-d"
8+
className="third-e third-f"
109
)
1110
p(styleName="fourth-a fourth-b")
1211
p(className="fivth-a fivth-b")
13-
p(class=["one", name].join(' ') styleName="two")
12+
p.one(styleName="two")
1413
1514
each item in [1, 2, 3]
1615
p.seventh-a.seventh-b(
1716
key=item
18-
class="seventh-i-" + item
19-
className="seventh-g-" + item
17+
className="seventh-i-" + item
2018
)
2119
`;

src/utils/get-class-name-value.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// @flow
2+
3+
import t from '../lib/babel-types';
4+
5+
function getPlainShorthandValue(classes: Array<StringLiteral>): string | null {
6+
if (classes.length) {
7+
return classes
8+
.map(item => item.value)
9+
.filter(Boolean)
10+
.join(' ');
11+
}
12+
13+
return null;
14+
}
15+
16+
function getPlainClassNameValue(
17+
classes: Array<ArrayExpression & CallExpression & StringLiteral>,
18+
): string | ArrayExpression | CallExpression | null | Array<any> {
19+
if (classes.every(item => t.isStringLiteral(item))) {
20+
return classes
21+
.map(item => item.value)
22+
.filter(Boolean)
23+
.join(' ');
24+
}
25+
26+
if (classes.every(item => t.isArrayExpression(item))) {
27+
return classes.reduce((all, item) => all.concat(item.elements), []);
28+
}
29+
30+
if (Array.isArray(classes)) {
31+
return classes[0];
32+
}
33+
34+
return null;
35+
}
36+
37+
function mergeStringWithClassName(
38+
shorthand: string | null,
39+
attribute: string | ArrayExpression | CallExpression | null | Array<any>,
40+
) {
41+
// There are several branches:
42+
// - when attribute exists
43+
// - when shorthand only exists
44+
// - otherwise
45+
46+
if (attribute) {
47+
if (typeof attribute === 'string') {
48+
if (shorthand) {
49+
return t.stringLiteral(shorthand + ' ' + attribute);
50+
}
51+
return t.stringLiteral(attribute);
52+
}
53+
54+
if (Array.isArray(attribute)) {
55+
if (shorthand) {
56+
return t.jSXExpressionContainer(
57+
t.arrayExpression([t.stringLiteral(shorthand)].concat(attribute)),
58+
);
59+
}
60+
return t.jSXExpressionContainer(t.arrayExpression(attribute));
61+
}
62+
63+
if (shorthand) {
64+
return t.jSXExpressionContainer(
65+
t.binaryExpression('+', t.stringLiteral(shorthand + ' '), attribute),
66+
);
67+
}
68+
69+
return t.jSXExpressionContainer(attribute);
70+
}
71+
72+
if (shorthand) {
73+
if (typeof shorthand === 'string') {
74+
return t.stringLiteral(shorthand);
75+
}
76+
77+
return t.jSXExpressionContainer(shorthand);
78+
}
79+
80+
return null;
81+
}
82+
83+
function getClassNameValue(
84+
classesViaShorthand: Array<StringLiteral>,
85+
classesViaAttribute: Array<ArrayExpression & CallExpression & StringLiteral>,
86+
): any {
87+
const shorthandValue = getPlainShorthandValue(classesViaShorthand);
88+
const attributeValue = getPlainClassNameValue(classesViaAttribute);
89+
90+
return mergeStringWithClassName(shorthandValue, attributeValue);
91+
}
92+
93+
export default getClassNameValue;

0 commit comments

Comments
 (0)