Skip to content

Commit 17adff0

Browse files
authored
Merge pull request #39 from styled-components/fix-zero-literal-matches
Fix parsing various shorthands when a value is zero (fixes #38)
2 parents 6e925c6 + ba3f1e5 commit 17adff0

File tree

10 files changed

+66
-30
lines changed

10 files changed

+66
-30
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "css-to-react-native",
3-
"version": "2.0.3",
3+
"version": "2.0.4",
44
"description": "Convert CSS text to a React Native stylesheet object",
55
"main": "dist/index.js",
66
"scripts": {

src/TokenStream.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const SYMBOL_MATCH = 'SYMBOL_MATCH';
2+
13
module.exports = class TokenStream {
24
constructor(nodes, parent) {
35
this.nodes = nodes;
@@ -18,7 +20,7 @@ module.exports = class TokenStream {
1820
return new TokenStream(this.nodes.slice(1), this.parent);
1921
}
2022

21-
match(...tokenDescriptors) {
23+
[SYMBOL_MATCH](...tokenDescriptors) {
2224
const node = this.node;
2325

2426
if (!node) return null;
@@ -38,8 +40,12 @@ module.exports = class TokenStream {
3840
return null;
3941
}
4042

43+
matches(...tokenDescriptors) {
44+
return this[SYMBOL_MATCH](...tokenDescriptors) !== null;
45+
}
46+
4147
expect(...tokenDescriptors) {
42-
const value = this.match(...tokenDescriptors);
48+
const value = this[SYMBOL_MATCH](...tokenDescriptors);
4349
if (value !== null) return value;
4450
return this.throw();
4551
}

src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ export const transformRawValue = (input) => {
1313
const value = input.trim();
1414

1515
const numberMatch = value.match(numberOrLengthRe);
16-
if (numberMatch) return Number(numberMatch[1]);
16+
if (numberMatch !== null) return Number(numberMatch[1]);
1717

1818
const boolMatch = input.match(boolRe);
19-
if (boolMatch) return boolMatch[0].toLowerCase() === 'true';
19+
if (boolMatch !== null) return boolMatch[0].toLowerCase() === 'true';
2020

2121
return value;
2222
};

src/index.test.js

+29-4
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,34 @@ it('transforms flex shorthand with 3 values in reverse order', () => runTest([
232232
['flex', '3px 1 2'],
233233
], { flexGrow: 1, flexShrink: 2, flexBasis: 3 }));
234234

235-
it('transforms flex shorthand with 2 values', () => runTest([
235+
it('transforms flex shorthand with 2 values of flex-grow and flex-shrink', () => runTest([
236236
['flex', '1 2'],
237237
], { flexGrow: 1, flexShrink: 2, flexBasis: 0 }));
238238

239-
it('transforms flex shorthand with 1 values', () => runTest([
240-
['flex', '1'],
241-
], { flexGrow: 1, flexShrink: 1, flexBasis: 0 }));
239+
it('transforms flex shorthand with 2 values of flex-grow and flex-basis', () => runTest([
240+
['flex', '2 2px'],
241+
], { flexGrow: 2, flexShrink: 1, flexBasis: 2 }));
242+
243+
it('transforms flex shorthand with 2 values of flex-grow and flex-basis (reversed)', () => runTest([
244+
['flex', '2px 2'],
245+
], { flexGrow: 2, flexShrink: 1, flexBasis: 2 }));
246+
247+
it('transforms flex shorthand with 1 value of flex-grow', () => runTest([
248+
['flex', '2'],
249+
], { flexGrow: 2, flexShrink: 1, flexBasis: 0 }));
250+
251+
it('transforms flex shorthand with 1 value of flex-basis', () => runTest([
252+
['flex', '10px'],
253+
], { flexGrow: 1, flexShrink: 1, flexBasis: 10 }));
254+
255+
/*
256+
A unitless zero that is not already preceded by two flex factors must be interpreted as a flex
257+
factor. To avoid misinterpretation or invalid declarations, authors must specify a zero
258+
<‘flex-basis’> component with a unit or precede it by two flex factors.
259+
*/
260+
it('transforms flex shorthand with flex-grow/shrink taking priority over basis', () => runTest([
261+
['flex', '0 1 0'],
262+
], { flexGrow: 0, flexShrink: 1, flexBasis: 0 }));
242263

243264
it('transforms flexFlow shorthand with two values', () => runTest([
244265
['flex-flow', 'column wrap'],
@@ -401,6 +422,10 @@ it('does not transform invalid unquoted font-family', () => {
401422
expect(() => transformCss([['font-family', 'Goudy Bookletter 1911']])).toThrow();
402423
});
403424

425+
it('does not transform invalid flex', () => {
426+
expect(() => transformCss([['flex', '1 2px 3']])).toThrow();
427+
});
428+
404429
it('allows blacklisting shorthands', () => {
405430
const actualStyles = transformCss([['border-radius', '50']], ['borderRadius']);
406431
expect(actualStyles).toEqual({ borderRadius: 50 });

src/tokenTypes.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ const matchColor = (node) => {
2222
return null;
2323
};
2424

25-
const noneRe = /^(none)$/;
25+
const noneRe = /^(none)$/i;
26+
const autoRe = /^(auto)$/i;
2627
const identRe = /(^-?[_a-z][_a-z0-9-]*$)/i;
2728
// Note if these are wrong, you'll need to change index.js too
2829
const numberRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)$/;
@@ -39,7 +40,7 @@ const regExpToken = (regExp, transform = String) => (node) => {
3940
if (node.type !== 'word') return null;
4041

4142
const match = node.value.match(regExp);
42-
if (!match) return null;
43+
if (match === null) return null;
4344

4445
const value = transform(match[1]);
4546

@@ -54,6 +55,7 @@ module.exports.tokens = {
5455
COMMA: noopToken(node => node.type === 'div' && node.value === ','),
5556
WORD: valueForTypeToken('word'),
5657
NONE: regExpToken(noneRe),
58+
AUTO: regExpToken(autoRe),
5759
NUMBER: regExpToken(numberRe, Number),
5860
LENGTH: regExpToken(lengthRe, Number),
5961
ANGLE: regExpToken(angleRe),

src/transforms/flex.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { tokens } = require('../tokenTypes');
22

3-
const { NONE, NUMBER, LENGTH, SPACE } = tokens;
3+
const { NONE, AUTO, NUMBER, LENGTH, SPACE } = tokens;
44

55
const defaultFlexGrow = 1;
66
const defaultFlexShrink = 1;
@@ -11,23 +11,26 @@ module.exports = (tokenStream) => {
1111
let flexShrink;
1212
let flexBasis;
1313

14-
if (tokenStream.match(NONE)) {
14+
if (tokenStream.matches(NONE)) {
1515
tokenStream.expectEmpty();
1616
return { $merge: { flexGrow: 0, flexShrink: 0 } };
17+
} else if (tokenStream.matches(AUTO)) {
18+
tokenStream.expectEmpty();
19+
return { $merge: { flexGrow: 1, flexShrink: 1 } };
1720
}
1821

1922
let partsParsed = 0;
2023
while (partsParsed < 2 && tokenStream.hasTokens()) {
21-
if (partsParsed) tokenStream.expect(SPACE);
24+
if (partsParsed !== 0) tokenStream.expect(SPACE);
2225

23-
if (flexGrow === undefined && tokenStream.match(NUMBER)) {
26+
if (flexGrow === undefined && tokenStream.matches(NUMBER)) {
2427
flexGrow = tokenStream.lastValue;
2528

26-
if (tokenStream.lookahead().match(NUMBER)) {
29+
if (tokenStream.lookahead().matches(NUMBER)) {
2730
tokenStream.expect(SPACE);
28-
flexShrink = tokenStream.match(NUMBER);
31+
flexShrink = tokenStream.expect(NUMBER);
2932
}
30-
} else if (flexBasis === undefined && tokenStream.match(LENGTH)) {
33+
} else if (flexBasis === undefined && tokenStream.matches(LENGTH)) {
3134
flexBasis = tokenStream.lastValue;
3235
} else {
3336
tokenStream.throw();

src/transforms/font.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ module.exports = (tokenStream) => {
2121

2222
let numStyleWeightVariantMatched = 0;
2323
while (numStyleWeightVariantMatched < 3 && tokenStream.hasTokens()) {
24-
if (tokenStream.match(NORMAL)) {
24+
if (tokenStream.matches(NORMAL)) {
2525
/* pass */
26-
} else if (fontStyle === undefined && tokenStream.match(STYLE)) {
26+
} else if (fontStyle === undefined && tokenStream.matches(STYLE)) {
2727
fontStyle = tokenStream.lastValue;
28-
} else if (fontWeight === undefined && tokenStream.match(WEIGHT)) {
28+
} else if (fontWeight === undefined && tokenStream.matches(WEIGHT)) {
2929
fontWeight = tokenStream.lastValue;
30-
} else if (fontVariant === undefined && tokenStream.match(VARIANT)) {
30+
} else if (fontVariant === undefined && tokenStream.matches(VARIANT)) {
3131
fontVariant = [tokenStream.lastValue];
3232
} else {
3333
break;
@@ -39,8 +39,8 @@ module.exports = (tokenStream) => {
3939

4040
const fontSize = tokenStream.expect(LENGTH);
4141

42-
if (tokenStream.match(SLASH)) {
43-
if (tokenStream.match(NUMBER)) {
42+
if (tokenStream.matches(SLASH)) {
43+
if (tokenStream.matches(NUMBER)) {
4444
lineHeight = fontSize * tokenStream.lastValue;
4545
} else {
4646
lineHeight = tokenStream.expect(LENGTH);

src/transforms/fontFamily.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { SPACE, IDENT, STRING } = tokens;
55
module.exports = (tokenStream) => {
66
let fontFamily;
77

8-
if (tokenStream.match(STRING)) {
8+
if (tokenStream.matches(STRING)) {
99
fontFamily = tokenStream.lastValue;
1010
} else {
1111
fontFamily = tokenStream.expect(IDENT);

src/transforms/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const { directionFactory, anyOrderFactory, shadowOffsetFactory } = require('./ut
77

88
const { IDENT, WORD, COLOR } = tokens;
99

10-
const background = tokenStream => ({ $merge: { backgroundColor: tokenStream.match(COLOR) } });
10+
const background = tokenStream => ({ $merge: { backgroundColor: tokenStream.expect(COLOR) } });
1111
const border = anyOrderFactory({
1212
borderWidth: {
1313
token: tokens.LENGTH,
@@ -45,8 +45,8 @@ const flexFlow = anyOrderFactory({
4545
default: 'row',
4646
},
4747
});
48-
const fontVariant = tokenStream => [tokenStream.match(IDENT)];
49-
const fontWeight = tokenStream => tokenStream.match(WORD); // Also match numbers as strings
48+
const fontVariant = tokenStream => [tokenStream.expect(IDENT)];
49+
const fontWeight = tokenStream => tokenStream.expect(WORD); // Also match numbers as strings
5050
const shadowOffset = shadowOffsetFactory();
5151
const textShadowOffset = shadowOffsetFactory();
5252

src/transforms/util.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports.anyOrderFactory = (properties, delim = SPACE) => (tokenStream) =>
4646
if (numParsed) tokenStream.expect(delim);
4747

4848
const matchedPropertyName = propertyNames.find(propertyName => (
49-
values[propertyName] === undefined && tokenStream.match(properties[propertyName].token)
49+
values[propertyName] === undefined && tokenStream.matches(properties[propertyName].token)
5050
));
5151

5252
if (!matchedPropertyName) {
@@ -69,7 +69,7 @@ module.exports.anyOrderFactory = (properties, delim = SPACE) => (tokenStream) =>
6969

7070
module.exports.shadowOffsetFactory = () => (tokenStream) => {
7171
const width = tokenStream.expect(LENGTH);
72-
const height = tokenStream.match(SPACE)
72+
const height = tokenStream.matches(SPACE)
7373
? tokenStream.expect(LENGTH)
7474
: width;
7575
tokenStream.expectEmpty();

0 commit comments

Comments
 (0)