css-to-react-native
Advanced tools
Comparing version 2.1.0 to 2.1.1
@@ -7,3 +7,2 @@ 'use strict'; | ||
var SYMBOL_BASE_MATCH = 'SYMBOL_BASE_MATCH'; | ||
var SYMBOL_MATCH = 'SYMBOL_MATCH'; | ||
@@ -15,6 +14,7 @@ | ||
this.index = 0; | ||
this.nodes = nodes; | ||
this.parent = parent; | ||
this.lastFunction = null; | ||
this.functionName = parent != null ? parent.value : null; | ||
this.lastValue = null; | ||
this.rewindIndex = -1; | ||
} | ||
@@ -25,15 +25,10 @@ | ||
value: function hasTokens() { | ||
return this.nodes.length > 0; | ||
return this.index <= this.nodes.length - 1; | ||
} | ||
}, { | ||
key: 'lookAhead', | ||
value: function lookAhead() { | ||
return new TokenStream(this.nodes.slice(1), this.parent); | ||
} | ||
}, { | ||
key: SYMBOL_BASE_MATCH, | ||
key: SYMBOL_MATCH, | ||
value: function value() { | ||
var node = this.node; | ||
if (!this.hasTokens()) return null; | ||
if (!node) return null; | ||
var node = this.nodes[this.index]; | ||
@@ -43,3 +38,7 @@ for (var i = 0; i < arguments.length; i += 1) { | ||
var value = tokenDescriptor(node); | ||
if (value !== null) return value; | ||
if (value !== null) { | ||
this.index += 1; | ||
this.lastValue = value; | ||
return value; | ||
} | ||
} | ||
@@ -50,17 +49,2 @@ | ||
}, { | ||
key: SYMBOL_MATCH, | ||
value: function value() { | ||
var value = this[SYMBOL_BASE_MATCH].apply(this, arguments); | ||
if (value === null) return null; | ||
this.nodes = this.nodes.slice(1); | ||
this.lastFunction = null; | ||
this.lastValue = value; | ||
return value; | ||
} | ||
}, { | ||
key: 'test', | ||
value: function test() { | ||
return this[SYMBOL_BASE_MATCH].apply(this, arguments) !== null; | ||
} | ||
}, { | ||
key: 'matches', | ||
@@ -74,4 +58,3 @@ value: function matches() { | ||
var value = this[SYMBOL_MATCH].apply(this, arguments); | ||
if (value !== null) return value; | ||
return this.throw(); | ||
return value !== null ? value : this.throw(); | ||
} | ||
@@ -81,7 +64,6 @@ }, { | ||
value: function matchesFunction() { | ||
var node = this.node; | ||
var node = this.nodes[this.index]; | ||
if (node.type !== 'function') return null; | ||
var value = new TokenStream(node.nodes, node); | ||
this.nodes = this.nodes.slice(1); | ||
this.lastFunction = value; | ||
this.index += 1; | ||
this.lastValue = null; | ||
@@ -94,4 +76,3 @@ return value; | ||
var value = this.matchesFunction(); | ||
if (value !== null) return value; | ||
return this.throw(); | ||
return value !== null ? value : this.throw(); | ||
} | ||
@@ -106,9 +87,16 @@ }, { | ||
value: function _throw() { | ||
throw new Error('Unexpected token type: ' + this.node.type); | ||
throw new Error('Unexpected token type: ' + this.nodes[this.index].type); | ||
} | ||
}, { | ||
key: 'node', | ||
get: function get() { | ||
return this.nodes[0]; | ||
key: 'saveRewindPoint', | ||
value: function saveRewindPoint() { | ||
this.rewindIndex = this.index; | ||
} | ||
}, { | ||
key: 'rewind', | ||
value: function rewind() { | ||
if (this.rewindIndex === -1) throw new Error('Internal error'); | ||
this.index = this.rewindIndex; | ||
this.lastValue = null; | ||
} | ||
}]); | ||
@@ -115,0 +103,0 @@ |
@@ -8,3 +8,3 @@ 'use strict'; | ||
SPACE = tokens.SPACE, | ||
WORD = tokens.WORD, | ||
COLOR = tokens.COLOR, | ||
LENGTH = tokens.LENGTH; | ||
@@ -22,3 +22,8 @@ | ||
return { | ||
$merge: { shadowOffset: { width: 0, height: 0 }, shadowRadius: 0, shadowColor: 'black' } | ||
$merge: { | ||
shadowOffset: { width: 0, height: 0 }, | ||
shadowRadius: 0, | ||
shadowColor: 'black', | ||
shadowOpacity: 1 | ||
} | ||
}; | ||
@@ -36,8 +41,10 @@ } | ||
if (tokenStream.lookAhead().matches(LENGTH)) { | ||
tokenStream.expect(SPACE); | ||
blurRadius = tokenStream.expect(LENGTH); | ||
tokenStream.saveRewindPoint(); | ||
if (tokenStream.matches(SPACE) && tokenStream.matches(LENGTH)) { | ||
blurRadius = tokenStream.lastValue; | ||
} else { | ||
tokenStream.rewind(); | ||
} | ||
} else if (color === undefined && (tokenStream.matchesFunction() || tokenStream.matches(WORD))) { | ||
color = String(tokenStream.lastValue); | ||
} else if (color === undefined && tokenStream.matches(COLOR)) { | ||
color = tokenStream.lastValue; | ||
} else { | ||
@@ -55,5 +62,6 @@ tokenStream.throw(); | ||
shadowRadius: blurRadius !== undefined ? blurRadius : 0, | ||
shadowColor: color !== undefined ? color : 'black' | ||
shadowColor: color !== undefined ? color : 'black', | ||
shadowOpacity: 1 | ||
}; | ||
return { $merge: $merge }; | ||
}; |
@@ -27,5 +27,9 @@ 'use strict'; | ||
return { $merge: { flexGrow: 0, flexShrink: 0 } }; | ||
} else if (tokenStream.test(AUTO) && !tokenStream.lookAhead().hasTokens()) { | ||
} | ||
tokenStream.saveRewindPoint(); | ||
if (tokenStream.matches(AUTO) && !tokenStream.hasTokens()) { | ||
return { $merge: { flexGrow: 1, flexShrink: 1 } }; | ||
} | ||
tokenStream.rewind(); | ||
@@ -39,5 +43,7 @@ var partsParsed = 0; | ||
if (tokenStream.lookAhead().matches(NUMBER)) { | ||
tokenStream.expect(SPACE); | ||
flexShrink = tokenStream.expect(NUMBER); | ||
tokenStream.saveRewindPoint(); | ||
if (tokenStream.matches(SPACE) && tokenStream.matches(NUMBER)) { | ||
flexShrink = tokenStream.lastValue; | ||
} else { | ||
tokenStream.rewind(); | ||
} | ||
@@ -44,0 +50,0 @@ } else if (flexBasis === undefined && tokenStream.matches(LENGTH)) { |
@@ -24,3 +24,5 @@ 'use strict'; | ||
var background = function background(tokenStream) { | ||
return { $merge: { backgroundColor: tokenStream.expect(COLOR) } }; | ||
return { | ||
$merge: { backgroundColor: tokenStream.expect(COLOR) } | ||
}; | ||
}; | ||
@@ -27,0 +29,0 @@ var border = anyOrderFactory({ |
@@ -78,6 +78,7 @@ 'use strict'; | ||
var functionStream = tokenStream.expectFunction(); | ||
var transformName = functionStream.parent.value; | ||
var transformedValues = partTransforms[transformName](functionStream); | ||
var functionName = functionStream.functionName; | ||
var transformedValues = partTransforms[functionName](functionStream); | ||
if (!Array.isArray(transformedValues)) { | ||
transformedValues = [_defineProperty({}, transformName, transformedValues)]; | ||
transformedValues = [_defineProperty({}, functionName, transformedValues)]; | ||
} | ||
@@ -84,0 +85,0 @@ transforms = transformedValues.concat(transforms); |
{ | ||
"name": "css-to-react-native", | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"description": "Convert CSS text to a React Native stylesheet object", | ||
@@ -10,3 +10,6 @@ "main": "dist/index.js", | ||
"test:watch": "jest --watch", | ||
"prepublish": "npm run build" | ||
"lint": "eslint src", | ||
"prepublish": "npm run build", | ||
"precommit": "lint-staged", | ||
"lint-staged": "lint-staged" | ||
}, | ||
@@ -39,4 +42,8 @@ "files": [ | ||
"eslint-config-airbnb-base": "^10.0.1", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-plugin-import": "^2.2.0", | ||
"jest": "^17.0.0" | ||
"eslint-plugin-prettier": "^2.6.0", | ||
"jest": "^17.0.0", | ||
"lint-staged": "^6.1.0", | ||
"prettier": "^1.10.2" | ||
}, | ||
@@ -47,3 +54,9 @@ "dependencies": { | ||
"postcss-value-parser": "^3.3.0" | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"eslint --fix", | ||
"git add" | ||
] | ||
} | ||
} |
/* eslint-disable no-param-reassign */ | ||
const parse = require('postcss-value-parser'); | ||
const camelizeStyleName = require('fbjs/lib/camelizeStyleName'); | ||
const transforms = require('./transforms'); | ||
const TokenStream = require('./TokenStream'); | ||
const parse = require('postcss-value-parser') | ||
const camelizeStyleName = require('fbjs/lib/camelizeStyleName') | ||
const transforms = require('./transforms') | ||
const TokenStream = require('./TokenStream') | ||
// Note if this is wrong, you'll need to change tokenTypes.js too | ||
const numberOrLengthRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)(?:px)?$/i; | ||
const boolRe = /^true|false$/i; | ||
const nullRe = /^null$/i; | ||
const undefinedRe = /^undefined$/i; | ||
const numberOrLengthRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)(?:px)?$/i | ||
const boolRe = /^true|false$/i | ||
const nullRe = /^null$/i | ||
const undefinedRe = /^undefined$/i | ||
// Undocumented export | ||
export const transformRawValue = (input) => { | ||
const value = input.trim(); | ||
export const transformRawValue = input => { | ||
const value = input.trim() | ||
const numberMatch = value.match(numberOrLengthRe); | ||
if (numberMatch !== null) return Number(numberMatch[1]); | ||
const numberMatch = value.match(numberOrLengthRe) | ||
if (numberMatch !== null) return Number(numberMatch[1]) | ||
const boolMatch = input.match(boolRe); | ||
if (boolMatch !== null) return boolMatch[0].toLowerCase() === 'true'; | ||
const boolMatch = input.match(boolRe) | ||
if (boolMatch !== null) return boolMatch[0].toLowerCase() === 'true' | ||
const nullMatch = input.match(nullRe); | ||
if (nullMatch !== null) return null; | ||
const nullMatch = input.match(nullRe) | ||
if (nullMatch !== null) return null | ||
const undefinedMatch = input.match(undefinedRe); | ||
if (undefinedMatch !== null) return undefined; | ||
const undefinedMatch = input.match(undefinedRe) | ||
if (undefinedMatch !== null) return undefined | ||
return value; | ||
}; | ||
return value | ||
} | ||
const baseTransformShorthandValue = (propName, inputValue) => { | ||
const ast = parse(inputValue.trim()); | ||
const tokenStream = new TokenStream(ast.nodes); | ||
return transforms[propName](tokenStream); | ||
}; | ||
const ast = parse(inputValue.trim()) | ||
const tokenStream = new TokenStream(ast.nodes) | ||
return transforms[propName](tokenStream) | ||
} | ||
const transformShorthandValue = (process.env.NODE_ENV === 'production') | ||
? baseTransformShorthandValue | ||
: (propName, inputValue) => { | ||
try { | ||
return baseTransformShorthandValue(propName, inputValue); | ||
} catch (e) { | ||
throw new Error(`Failed to parse declaration "${propName}: ${inputValue}"`); | ||
} | ||
}; | ||
const transformShorthandValue = | ||
process.env.NODE_ENV === 'production' | ||
? baseTransformShorthandValue | ||
: (propName, inputValue) => { | ||
try { | ||
return baseTransformShorthandValue(propName, inputValue) | ||
} catch (e) { | ||
throw new Error( | ||
`Failed to parse declaration "${propName}: ${inputValue}"` | ||
) | ||
} | ||
} | ||
export const getStylesForProperty = (propName, inputValue, allowShorthand) => { | ||
const isRawValue = (allowShorthand === false) || !(propName in transforms); | ||
const isRawValue = allowShorthand === false || !(propName in transforms) | ||
const propValue = isRawValue | ||
? transformRawValue(inputValue) | ||
: transformShorthandValue(propName, inputValue.trim()); | ||
: transformShorthandValue(propName, inputValue.trim()) | ||
return (propValue && propValue.$merge) | ||
return propValue && propValue.$merge | ||
? propValue.$merge | ||
: { [propName]: propValue }; | ||
}; | ||
: { [propName]: propValue } | ||
} | ||
export const getPropertyName = camelizeStyleName; | ||
export const getPropertyName = camelizeStyleName | ||
export default (rules, shorthandBlacklist = []) => rules.reduce((accum, rule) => { | ||
const propertyName = getPropertyName(rule[0]); | ||
const value = rule[1]; | ||
const allowShorthand = shorthandBlacklist.indexOf(propertyName) === -1; | ||
return Object.assign(accum, getStylesForProperty(propertyName, value, allowShorthand)); | ||
}, {}); | ||
export default (rules, shorthandBlacklist = []) => | ||
rules.reduce((accum, rule) => { | ||
const propertyName = getPropertyName(rule[0]) | ||
const value = rule[1] | ||
const allowShorthand = shorthandBlacklist.indexOf(propertyName) === -1 | ||
return Object.assign( | ||
accum, | ||
getStylesForProperty(propertyName, value, allowShorthand) | ||
) | ||
}, {}) |
/* global jest it, expect */ | ||
import transformCss, { getStylesForProperty } from '.'; | ||
import transformCss, { getStylesForProperty } from '.' | ||
const runTest = (inputCss, expectedStyles) => { | ||
const actualStyles = transformCss(inputCss); | ||
expect(actualStyles).toEqual(expectedStyles); | ||
}; | ||
const actualStyles = transformCss(inputCss) | ||
expect(actualStyles).toEqual(expectedStyles) | ||
} | ||
it('transforms numbers', () => runTest([ | ||
['top', '0'], | ||
['left', '0'], | ||
['right', '0'], | ||
['bottom', '0'], | ||
], { top: 0, left: 0, right: 0, bottom: 0 })); | ||
it('transforms numbers', () => | ||
runTest([['top', '0'], ['left', '0'], ['right', '0'], ['bottom', '0']], { | ||
top: 0, | ||
left: 0, | ||
right: 0, | ||
bottom: 0, | ||
})) | ||
it('allows pixels in unspecialized transform', () => runTest([ | ||
['top', '0px'], | ||
], { top: 0 })); | ||
it('allows pixels in unspecialized transform', () => | ||
runTest([['top', '0px']], { top: 0 })) | ||
it('allows boolean values', () => runTest([ | ||
['boolTrue1', 'true'], | ||
['boolTrue2', 'TRUE'], | ||
['boolFalse1', 'false'], | ||
['boolFalse2', 'FALSE'], | ||
], { | ||
boolTrue1: true, | ||
boolTrue2: true, | ||
boolFalse1: false, | ||
boolFalse2: false, | ||
})); | ||
it('allows boolean values', () => | ||
runTest( | ||
[ | ||
['boolTrue1', 'true'], | ||
['boolTrue2', 'TRUE'], | ||
['boolFalse1', 'false'], | ||
['boolFalse2', 'FALSE'], | ||
], | ||
{ | ||
boolTrue1: true, | ||
boolTrue2: true, | ||
boolFalse1: false, | ||
boolFalse2: false, | ||
} | ||
)) | ||
it('allows null values', () => runTest([ | ||
['null1', 'null'], | ||
['null2', 'NULL'], | ||
], { | ||
null1: null, | ||
null2: null, | ||
})); | ||
it('allows null values', () => | ||
runTest([['null1', 'null'], ['null2', 'NULL']], { | ||
null1: null, | ||
null2: null, | ||
})) | ||
it('allows undefined values', () => runTest([ | ||
['undefined1', 'undefined'], | ||
['undefined2', 'UNDEFINED'], | ||
], { | ||
undefined1: undefined, | ||
undefined2: undefined, | ||
})); | ||
it('allows undefined values', () => | ||
runTest([['undefined1', 'undefined'], ['undefined2', 'UNDEFINED']], { | ||
undefined1: undefined, | ||
undefined2: undefined, | ||
})) | ||
it('allows percent in unspecialized transform', () => runTest([ | ||
['top', '0%'], | ||
], { top: '0%' })); | ||
it('allows percent in unspecialized transform', () => | ||
runTest([['top', '0%']], { top: '0%' })) | ||
it('allows decimal values', () => { | ||
expect(getStylesForProperty('margin', '0.5px').marginTop).toBe(0.5); | ||
expect(getStylesForProperty('margin', '1.5px').marginTop).toBe(1.5); | ||
expect(getStylesForProperty('margin', '10.5px').marginTop).toBe(10.5); | ||
expect(getStylesForProperty('margin', '100.5px').marginTop).toBe(100.5); | ||
expect(getStylesForProperty('margin', '-0.5px').marginTop).toBe(-0.5); | ||
expect(getStylesForProperty('margin', '-1.5px').marginTop).toBe(-1.5); | ||
expect(getStylesForProperty('margin', '-10.5px').marginTop).toBe(-10.5); | ||
expect(getStylesForProperty('margin', '-100.5px').marginTop).toBe(-100.5); | ||
expect(getStylesForProperty('margin', '.5px').marginTop).toBe(0.5); | ||
expect(getStylesForProperty('margin', '-.5px').marginTop).toBe(-0.5); | ||
}); | ||
expect(getStylesForProperty('margin', '0.5px').marginTop).toBe(0.5) | ||
expect(getStylesForProperty('margin', '1.5px').marginTop).toBe(1.5) | ||
expect(getStylesForProperty('margin', '10.5px').marginTop).toBe(10.5) | ||
expect(getStylesForProperty('margin', '100.5px').marginTop).toBe(100.5) | ||
expect(getStylesForProperty('margin', '-0.5px').marginTop).toBe(-0.5) | ||
expect(getStylesForProperty('margin', '-1.5px').marginTop).toBe(-1.5) | ||
expect(getStylesForProperty('margin', '-10.5px').marginTop).toBe(-10.5) | ||
expect(getStylesForProperty('margin', '-100.5px').marginTop).toBe(-100.5) | ||
expect(getStylesForProperty('margin', '.5px').marginTop).toBe(0.5) | ||
expect(getStylesForProperty('margin', '-.5px').marginTop).toBe(-0.5) | ||
}) | ||
it('allows decimal values in transformed values', () => runTest([ | ||
['border-radius', '1.5px'], | ||
], { | ||
borderTopLeftRadius: 1.5, | ||
borderTopRightRadius: 1.5, | ||
borderBottomRightRadius: 1.5, | ||
borderBottomLeftRadius: 1.5, | ||
})); | ||
it('allows decimal values in transformed values', () => | ||
runTest([['border-radius', '1.5px']], { | ||
borderTopLeftRadius: 1.5, | ||
borderTopRightRadius: 1.5, | ||
borderBottomRightRadius: 1.5, | ||
borderBottomLeftRadius: 1.5, | ||
})) | ||
it('allows negative values in transformed values', () => runTest([ | ||
['border-radius', '-1.5px'], | ||
], { | ||
borderTopLeftRadius: -1.5, | ||
borderTopRightRadius: -1.5, | ||
borderBottomRightRadius: -1.5, | ||
borderBottomLeftRadius: -1.5, | ||
})); | ||
it('allows negative values in transformed values', () => | ||
runTest([['border-radius', '-1.5px']], { | ||
borderTopLeftRadius: -1.5, | ||
borderTopRightRadius: -1.5, | ||
borderBottomRightRadius: -1.5, | ||
borderBottomLeftRadius: -1.5, | ||
})) | ||
it('allows percent values in transformed values', () => runTest([ | ||
['margin', '10%'], | ||
], { | ||
marginTop: '10%', | ||
marginRight: '10%', | ||
marginBottom: '10%', | ||
marginLeft: '10%', | ||
})); | ||
it('allows percent values in transformed values', () => | ||
runTest([['margin', '10%']], { | ||
marginTop: '10%', | ||
marginRight: '10%', | ||
marginBottom: '10%', | ||
marginLeft: '10%', | ||
})) | ||
it('allows color values in transformed border-color values', () => runTest([ | ||
['border-color', 'red'], | ||
], { | ||
borderTopColor: 'red', | ||
borderRightColor: 'red', | ||
borderBottomColor: 'red', | ||
borderLeftColor: 'red', | ||
})); | ||
it('allows color values in transformed border-color values', () => | ||
runTest([['border-color', 'red']], { | ||
borderTopColor: 'red', | ||
borderRightColor: 'red', | ||
borderBottomColor: 'red', | ||
borderLeftColor: 'red', | ||
})) | ||
it('allows omitting units for 0', () => runTest([ | ||
['margin', '10px 0'], | ||
], { | ||
marginTop: 10, | ||
marginRight: 0, | ||
marginBottom: 10, | ||
marginLeft: 0, | ||
})); | ||
it('allows omitting units for 0', () => | ||
runTest([['margin', '10px 0']], { | ||
marginTop: 10, | ||
marginRight: 0, | ||
marginBottom: 10, | ||
marginLeft: 0, | ||
})) | ||
it('transforms strings', () => runTest([ | ||
['color', 'red'], | ||
], { color: 'red' })); | ||
it('transforms strings', () => runTest([['color', 'red']], { color: 'red' })) | ||
it('transforms hex colors', () => runTest([ | ||
['color', '#f00'], | ||
], { color: '#f00' })); | ||
it('transforms hex colors', () => | ||
runTest([['color', '#f00']], { color: '#f00' })) | ||
it('transforms rgb colors', () => runTest([ | ||
['color', 'rgb(255, 0, 0)'], | ||
], { color: 'rgb(255, 0, 0)' })); | ||
it('transforms rgb colors', () => | ||
runTest([['color', 'rgb(255, 0, 0)']], { color: 'rgb(255, 0, 0)' })) | ||
it('converts to camel-case', () => runTest([ | ||
['background-color', 'red'], | ||
], { backgroundColor: 'red' })); | ||
it('converts to camel-case', () => | ||
runTest([['background-color', 'red']], { backgroundColor: 'red' })) | ||
it('transforms background to backgroundColor', () => runTest([ | ||
['background', '#f00'], | ||
], { backgroundColor: '#f00' })); | ||
it('transforms background to backgroundColor', () => | ||
runTest([['background', '#f00']], { backgroundColor: '#f00' })) | ||
it('transforms background to backgroundColor with rgb', () => runTest([ | ||
['background', 'rgb(255, 0, 0)'], | ||
], { backgroundColor: 'rgb(255, 0, 0)' })); | ||
it('transforms background to backgroundColor with rgb', () => | ||
runTest([['background', 'rgb(255, 0, 0)']], { | ||
backgroundColor: 'rgb(255, 0, 0)', | ||
})) | ||
it('transforms background to backgroundColor with named colour', () => runTest([ | ||
['background', 'red'], | ||
], { backgroundColor: 'red' })); | ||
it('transforms background to backgroundColor with named colour', () => | ||
runTest([['background', 'red']], { backgroundColor: 'red' })) | ||
it('transforms font weights as strings', () => runTest([ | ||
['font-weight', ' 400'], | ||
], { fontWeight: '400' })); | ||
it('transforms font weights as strings', () => | ||
runTest([['font-weight', ' 400']], { fontWeight: '400' })) | ||
it('transforms font variant as an array', () => runTest([ | ||
['font-variant', 'tabular-nums'], | ||
], { fontVariant: ['tabular-nums'] })); | ||
it('transforms font variant as an array', () => | ||
runTest([['font-variant', 'tabular-nums']], { | ||
fontVariant: ['tabular-nums'], | ||
})) | ||
it('transforms shadow offsets', () => runTest([ | ||
['shadow-offset', '10px 5px'], | ||
], { shadowOffset: { width: 10, height: 5 } })); | ||
it('transforms shadow offsets', () => | ||
runTest([['shadow-offset', '10px 5px']], { | ||
shadowOffset: { width: 10, height: 5 }, | ||
})) | ||
it('transforms text shadow offsets', () => runTest([ | ||
['text-shadow-offset', '10px 5px'], | ||
], { textShadowOffset: { width: 10, height: 5 } })); | ||
it('transforms text shadow offsets', () => | ||
runTest([['text-shadow-offset', '10px 5px']], { | ||
textShadowOffset: { width: 10, height: 5 }, | ||
})) | ||
it('transforms a single transform value with number', () => runTest([ | ||
['transform', 'scaleX(5)'], | ||
], { transform: [{ scaleX: 5 }] })); | ||
it('transforms a single transform value with number', () => | ||
runTest([['transform', 'scaleX(5)']], { transform: [{ scaleX: 5 }] })) | ||
it('transforms a single transform value with string', () => runTest([ | ||
['transform', 'rotate(5deg)'], | ||
], { transform: [{ rotate: '5deg' }] })); | ||
it('transforms a single transform value with string', () => | ||
runTest([['transform', 'rotate(5deg)']], { | ||
transform: [{ rotate: '5deg' }], | ||
})) | ||
it('transforms multiple transform values', () => runTest([ | ||
['transform', 'scaleX(5) skewX(1deg)'], | ||
], { transform: [{ skewX: '1deg' }, { scaleX: 5 }] })); | ||
it('transforms multiple transform values', () => | ||
runTest([['transform', 'scaleX(5) skewX(1deg)']], { | ||
transform: [{ skewX: '1deg' }, { scaleX: 5 }], | ||
})) | ||
it('transforms scale(number, number) to scaleX and scaleY', () => runTest([ | ||
['transform', 'scale(2, 3)'], | ||
], { transform: [{ scaleY: 3 }, { scaleX: 2 }] })); | ||
it('transforms scale(number, number) to scaleX and scaleY', () => | ||
runTest([['transform', 'scale(2, 3)']], { | ||
transform: [{ scaleY: 3 }, { scaleX: 2 }], | ||
})) | ||
it('transforms scale(number) to scale', () => runTest([ | ||
['transform', 'scale(5)'], | ||
], { transform: [{ scale: 5 }] })); | ||
it('transforms scale(number) to scale', () => | ||
runTest([['transform', 'scale(5)']], { transform: [{ scale: 5 }] })) | ||
it('transforms translate(length, length) to translateX and translateY', () => runTest([ | ||
['transform', 'translate(2px, 3px)'], | ||
], { transform: [{ translateY: 3 }, { translateX: 2 }] })); | ||
it('transforms translate(length, length) to translateX and translateY', () => | ||
runTest([['transform', 'translate(2px, 3px)']], { | ||
transform: [{ translateY: 3 }, { translateX: 2 }], | ||
})) | ||
it('transforms translate(length) to translateX and translateY', () => runTest([ | ||
['transform', 'translate(5px)'], | ||
], { transform: [{ translateY: 0 }, { translateX: 5 }] })); | ||
it('transforms translate(length) to translateX and translateY', () => | ||
runTest([['transform', 'translate(5px)']], { | ||
transform: [{ translateY: 0 }, { translateX: 5 }], | ||
})) | ||
it('transforms skew(angle, angle) to skewX and skewY', () => runTest([ | ||
['transform', 'skew(2deg, 3deg)'], | ||
], { transform: [{ skewY: '3deg' }, { skewX: '2deg' }] })); | ||
it('transforms skew(angle, angle) to skewX and skewY', () => | ||
runTest([['transform', 'skew(2deg, 3deg)']], { | ||
transform: [{ skewY: '3deg' }, { skewX: '2deg' }], | ||
})) | ||
it('transforms skew(angle) to skewX and skewY', () => runTest([ | ||
['transform', 'skew(5deg)'], | ||
], { transform: [{ skewY: '0deg' }, { skewX: '5deg' }] })); | ||
it('transforms skew(angle) to skewX and skewY', () => | ||
runTest([['transform', 'skew(5deg)']], { | ||
transform: [{ skewY: '0deg' }, { skewX: '5deg' }], | ||
})) | ||
it('transforms border shorthand', () => runTest([ | ||
['border', '2px dashed #f00'], | ||
], { borderWidth: 2, borderColor: '#f00', borderStyle: 'dashed' })); | ||
it('transforms border shorthand', () => | ||
runTest([['border', '2px dashed #f00']], { | ||
borderWidth: 2, | ||
borderColor: '#f00', | ||
borderStyle: 'dashed', | ||
})) | ||
it('transforms border shorthand in other order', () => runTest([ | ||
['border', '#f00 2px dashed'], | ||
], { borderWidth: 2, borderColor: '#f00', borderStyle: 'dashed' })); | ||
it('transforms border shorthand in other order', () => | ||
runTest([['border', '#f00 2px dashed']], { | ||
borderWidth: 2, | ||
borderColor: '#f00', | ||
borderStyle: 'dashed', | ||
})) | ||
it('transforms border shorthand missing color', () => runTest([ | ||
['border', '2px dashed'], | ||
], { borderWidth: 2, borderColor: 'black', borderStyle: 'dashed' })); | ||
it('transforms border shorthand missing color', () => | ||
runTest([['border', '2px dashed']], { | ||
borderWidth: 2, | ||
borderColor: 'black', | ||
borderStyle: 'dashed', | ||
})) | ||
it('transforms border shorthand missing style', () => runTest([ | ||
['border', '2px #f00'], | ||
], { borderWidth: 2, borderColor: '#f00', borderStyle: 'solid' })); | ||
it('transforms border shorthand missing style', () => | ||
runTest([['border', '2px #f00']], { | ||
borderWidth: 2, | ||
borderColor: '#f00', | ||
borderStyle: 'solid', | ||
})) | ||
it('transforms border shorthand missing width', () => runTest([ | ||
['border', '#f00 dashed'], | ||
], { borderWidth: 1, borderColor: '#f00', borderStyle: 'dashed' })); | ||
it('transforms border shorthand missing width', () => | ||
runTest([['border', '#f00 dashed']], { | ||
borderWidth: 1, | ||
borderColor: '#f00', | ||
borderStyle: 'dashed', | ||
})) | ||
it('transforms border shorthand missing color & width', () => runTest([ | ||
['border', 'dashed'], | ||
], { borderWidth: 1, borderColor: 'black', borderStyle: 'dashed' })); | ||
it('transforms border shorthand missing color & width', () => | ||
runTest([['border', 'dashed']], { | ||
borderWidth: 1, | ||
borderColor: 'black', | ||
borderStyle: 'dashed', | ||
})) | ||
it('transforms border shorthand missing style & width', () => runTest([ | ||
['border', '#f00'], | ||
], { borderWidth: 1, borderColor: '#f00', borderStyle: 'solid' })); | ||
it('transforms border shorthand missing style & width', () => | ||
runTest([['border', '#f00']], { | ||
borderWidth: 1, | ||
borderColor: '#f00', | ||
borderStyle: 'solid', | ||
})) | ||
it('transforms border shorthand missing color & style', () => runTest([ | ||
['border', '2px'], | ||
], { borderWidth: 2, borderColor: 'black', borderStyle: 'solid' })); | ||
it('transforms border shorthand missing color & style', () => | ||
runTest([['border', '2px']], { | ||
borderWidth: 2, | ||
borderColor: 'black', | ||
borderStyle: 'solid', | ||
})) | ||
it('transforms margin shorthands using 4 values', () => runTest([ | ||
['margin', '10px 20px 30px 40px'], | ||
], { marginTop: 10, marginRight: 20, marginBottom: 30, marginLeft: 40 })); | ||
it('transforms margin shorthands using 4 values', () => | ||
runTest([['margin', '10px 20px 30px 40px']], { | ||
marginTop: 10, | ||
marginRight: 20, | ||
marginBottom: 30, | ||
marginLeft: 40, | ||
})) | ||
it('transforms margin shorthands using 3 values', () => runTest([ | ||
['margin', '10px 20px 30px'], | ||
], { marginTop: 10, marginRight: 20, marginBottom: 30, marginLeft: 20 })); | ||
it('transforms margin shorthands using 3 values', () => | ||
runTest([['margin', '10px 20px 30px']], { | ||
marginTop: 10, | ||
marginRight: 20, | ||
marginBottom: 30, | ||
marginLeft: 20, | ||
})) | ||
it('transforms margin shorthands using 2 values', () => runTest([ | ||
['margin', '10px 20px'], | ||
], { marginTop: 10, marginRight: 20, marginBottom: 10, marginLeft: 20 })); | ||
it('transforms margin shorthands using 2 values', () => | ||
runTest([['margin', '10px 20px']], { | ||
marginTop: 10, | ||
marginRight: 20, | ||
marginBottom: 10, | ||
marginLeft: 20, | ||
})) | ||
it('transforms margin shorthands using 1 value', () => runTest([ | ||
['margin', '10px'], | ||
], { marginTop: 10, marginRight: 10, marginBottom: 10, marginLeft: 10 })); | ||
it('transforms margin shorthands using 1 value', () => | ||
runTest([['margin', '10px']], { | ||
marginTop: 10, | ||
marginRight: 10, | ||
marginBottom: 10, | ||
marginLeft: 10, | ||
})) | ||
it('shorthand with 1 value should override previous values', () => runTest([ | ||
['margin-top', '2px'], | ||
['margin', '1px'], | ||
], { marginTop: 1, marginRight: 1, marginBottom: 1, marginLeft: 1 })); | ||
it('shorthand with 1 value should override previous values', () => | ||
runTest([['margin-top', '2px'], ['margin', '1px']], { | ||
marginTop: 1, | ||
marginRight: 1, | ||
marginBottom: 1, | ||
marginLeft: 1, | ||
})) | ||
it('transforms flex shorthand with 3 values', () => runTest([ | ||
['flex', '1 2 3px'], | ||
], { flexGrow: 1, flexShrink: 2, flexBasis: 3 })); | ||
it('transforms flex shorthand with 3 values', () => | ||
runTest([['flex', '1 2 3px']], { flexGrow: 1, flexShrink: 2, flexBasis: 3 })) | ||
it('transforms flex shorthand with 3 values in reverse order', () => runTest([ | ||
['flex', '3px 1 2'], | ||
], { flexGrow: 1, flexShrink: 2, flexBasis: 3 })); | ||
it('transforms flex shorthand with 3 values in reverse order', () => | ||
runTest([['flex', '3px 1 2']], { flexGrow: 1, flexShrink: 2, flexBasis: 3 })) | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-shrink', () => runTest([ | ||
['flex', '1 2'], | ||
], { flexGrow: 1, flexShrink: 2, flexBasis: 0 })); | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-shrink', () => | ||
runTest([['flex', '1 2']], { flexGrow: 1, flexShrink: 2, flexBasis: 0 })) | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-basis', () => runTest([ | ||
['flex', '2 2px'], | ||
], { flexGrow: 2, flexShrink: 1, flexBasis: 2 })); | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-basis', () => | ||
runTest([['flex', '2 2px']], { flexGrow: 2, flexShrink: 1, flexBasis: 2 })) | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-basis (reversed)', () => runTest([ | ||
['flex', '2px 2'], | ||
], { flexGrow: 2, flexShrink: 1, flexBasis: 2 })); | ||
it('transforms flex shorthand with 2 values of flex-grow and flex-basis (reversed)', () => | ||
runTest([['flex', '2px 2']], { flexGrow: 2, flexShrink: 1, flexBasis: 2 })) | ||
it('transforms flex shorthand with 1 value of flex-grow', () => runTest([ | ||
['flex', '2'], | ||
], { flexGrow: 2, flexShrink: 1, flexBasis: 0 })); | ||
it('transforms flex shorthand with 1 value of flex-grow', () => | ||
runTest([['flex', '2']], { flexGrow: 2, flexShrink: 1, flexBasis: 0 })) | ||
it('transforms flex shorthand with 1 value of flex-basis', () => runTest([ | ||
['flex', '10px'], | ||
], { flexGrow: 1, flexShrink: 1, flexBasis: 10 })); | ||
it('transforms flex shorthand with 1 value of flex-basis', () => | ||
runTest([['flex', '10px']], { flexGrow: 1, flexShrink: 1, flexBasis: 10 })) | ||
@@ -276,237 +307,264 @@ /* | ||
*/ | ||
it('transforms flex shorthand with flex-grow/shrink taking priority over basis', () => runTest([ | ||
['flex', '0 1 0'], | ||
], { flexGrow: 0, flexShrink: 1, flexBasis: 0 })); | ||
it('transforms flex shorthand with flex-grow/shrink taking priority over basis', () => | ||
runTest([['flex', '0 1 0']], { flexGrow: 0, flexShrink: 1, flexBasis: 0 })) | ||
it('transforms flex shorthand with flex-basis set to auto', () => runTest([ | ||
['flex', '0 1 auto'], | ||
], { flexGrow: 0, flexShrink: 1 })); | ||
it('transforms flex shorthand with flex-basis set to auto', () => | ||
runTest([['flex', '0 1 auto']], { flexGrow: 0, flexShrink: 1 })) | ||
it('transforms flex shorthand with flex-basis set to auto appearing first', () => runTest([ | ||
['flex', 'auto 0 1'], | ||
], { flexGrow: 0, flexShrink: 1 })); | ||
it('transforms flex shorthand with flex-basis set to auto appearing first', () => | ||
runTest([['flex', 'auto 0 1']], { flexGrow: 0, flexShrink: 1 })) | ||
it('transforms flex auto keyword', () => runTest([ | ||
['flex', 'auto'], | ||
], { flexGrow: 1, flexShrink: 1 })); | ||
it('transforms flex auto keyword', () => | ||
runTest([['flex', 'auto']], { flexGrow: 1, flexShrink: 1 })) | ||
it('transforms flex none keyword', () => runTest([ | ||
['flex', 'none'], | ||
], { flexGrow: 0, flexShrink: 0 })); | ||
it('transforms flex none keyword', () => | ||
runTest([['flex', 'none']], { flexGrow: 0, flexShrink: 0 })) | ||
it('transforms flexFlow shorthand with two values', () => runTest([ | ||
['flex-flow', 'column wrap'], | ||
], { flexDirection: 'column', flexWrap: 'wrap' })); | ||
it('transforms flexFlow shorthand with two values', () => | ||
runTest([['flex-flow', 'column wrap']], { | ||
flexDirection: 'column', | ||
flexWrap: 'wrap', | ||
})) | ||
it('transforms flexFlow shorthand missing flexDirection', () => runTest([ | ||
['flex-flow', 'wrap'], | ||
], { flexDirection: 'row', flexWrap: 'wrap' })); | ||
it('transforms flexFlow shorthand missing flexDirection', () => | ||
runTest([['flex-flow', 'wrap']], { flexDirection: 'row', flexWrap: 'wrap' })) | ||
it('transforms flexFlow shorthand missing flexWrap', () => runTest([ | ||
['flex-flow', 'column'], | ||
], { flexDirection: 'column', flexWrap: 'nowrap' })); | ||
it('transforms flexFlow shorthand missing flexWrap', () => | ||
runTest([['flex-flow', 'column']], { | ||
flexDirection: 'column', | ||
flexWrap: 'nowrap', | ||
})) | ||
it('transforms font', () => runTest([ | ||
['font', 'bold italic small-caps 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font', () => | ||
runTest([['font', 'bold italic small-caps 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font missing font-variant', () => runTest([ | ||
['font', 'bold italic 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font missing font-variant', () => | ||
runTest([['font', 'bold italic 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font missing font-style', () => runTest([ | ||
['font', 'bold small-caps 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'normal', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font missing font-style', () => | ||
runTest([['font', 'bold small-caps 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'normal', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font missing font-weight', () => runTest([ | ||
['font', 'italic small-caps 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font missing font-weight', () => | ||
runTest([['font', 'italic small-caps 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font with font-weight normal', () => runTest([ | ||
['font', 'normal 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font with font-weight normal', () => | ||
runTest([['font', 'normal 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font with font-weight and font-style normal', () => runTest([ | ||
['font', 'normal normal 16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font with font-weight and font-style normal', () => | ||
runTest([['font', 'normal normal 16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font with no font-weight, font-style, and font-variant', () => runTest([ | ||
['font', '16px/18px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font with no font-weight, font-style, and font-variant', () => | ||
runTest([['font', '16px/18px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 18, | ||
})) | ||
it('omits line height if not specified', () => runTest([ | ||
['font', '16px "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
})); | ||
it('omits line height if not specified', () => | ||
runTest([['font', '16px "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
})) | ||
it('allows line height as multiple', () => runTest([ | ||
['font', '16px/1.5 "Helvetica"'], | ||
], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 24, | ||
})); | ||
it('allows line height as multiple', () => | ||
runTest([['font', '16px/1.5 "Helvetica"']], { | ||
fontFamily: 'Helvetica', | ||
fontSize: 16, | ||
fontWeight: 'normal', | ||
fontStyle: 'normal', | ||
fontVariant: [], | ||
lineHeight: 24, | ||
})) | ||
it('transforms font without quotes', () => runTest([ | ||
['font', 'bold italic small-caps 16px/18px Helvetica Neue'], | ||
], { | ||
fontFamily: 'Helvetica Neue', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})); | ||
it('transforms font without quotes', () => | ||
runTest([['font', 'bold italic small-caps 16px/18px Helvetica Neue']], { | ||
fontFamily: 'Helvetica Neue', | ||
fontSize: 16, | ||
fontWeight: 'bold', | ||
fontStyle: 'italic', | ||
fontVariant: ['small-caps'], | ||
lineHeight: 18, | ||
})) | ||
it('transforms font-family with double quotes', () => runTest([ | ||
['font-family', '"Helvetica Neue"'], | ||
], { | ||
fontFamily: 'Helvetica Neue', | ||
})); | ||
it('transforms font-family with double quotes', () => | ||
runTest([['font-family', '"Helvetica Neue"']], { | ||
fontFamily: 'Helvetica Neue', | ||
})) | ||
it('transforms font-family with single quotes', () => runTest([ | ||
['font-family', '\'Helvetica Neue\''], | ||
], { | ||
fontFamily: 'Helvetica Neue', | ||
})); | ||
it('transforms font-family with single quotes', () => | ||
runTest([['font-family', "'Helvetica Neue'"]], { | ||
fontFamily: 'Helvetica Neue', | ||
})) | ||
it('transforms font-family without quotes', () => runTest([ | ||
['font-family', 'Helvetica Neue'], | ||
], { | ||
fontFamily: 'Helvetica Neue', | ||
})); | ||
it('transforms font-family without quotes', () => | ||
runTest([['font-family', 'Helvetica Neue']], { | ||
fontFamily: 'Helvetica Neue', | ||
})) | ||
it('transforms font-family with quotes with otherwise invalid values', () => runTest([ | ||
['font-family', '"Goudy Bookletter 1911"'], | ||
], { | ||
fontFamily: 'Goudy Bookletter 1911', | ||
})); | ||
it('transforms font-family with quotes with otherwise invalid values', () => | ||
runTest([['font-family', '"Goudy Bookletter 1911"']], { | ||
fontFamily: 'Goudy Bookletter 1911', | ||
})) | ||
it('transforms font-family with quotes with escaped values', () => runTest([ | ||
['font-family', '"test\\A test"'], | ||
], { | ||
fontFamily: 'test\ntest', | ||
})); | ||
it('transforms font-family with quotes with escaped values', () => | ||
runTest([['font-family', '"test\\A test"']], { | ||
fontFamily: 'test\ntest', | ||
})) | ||
it('transforms font-family with quotes with escaped quote', () => runTest([ | ||
['font-family', '"test\\"test"'], | ||
], { | ||
fontFamily: 'test"test', | ||
})); | ||
it('transforms font-family with quotes with escaped quote', () => | ||
runTest([['font-family', '"test\\"test"']], { | ||
fontFamily: 'test"test', | ||
})) | ||
it('does not transform invalid unquoted font-family', () => { | ||
expect(() => transformCss([['font-family', 'Goudy Bookletter 1911']])).toThrow(); | ||
}); | ||
expect(() => | ||
transformCss([['font-family', 'Goudy Bookletter 1911']]) | ||
).toThrow() | ||
}) | ||
it('does not transform invalid flex', () => { | ||
expect(() => transformCss([['flex', '1 2px 3']])).toThrow(); | ||
}); | ||
expect(() => transformCss([['flex', '1 2px 3']])).toThrow() | ||
}) | ||
it('transforms box-shadow into shadow- properties', () => runTest([ | ||
['box-shadow', '10px 20px 30px red'], | ||
], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 30, | ||
shadowColor: 'red', | ||
})); | ||
it('transforms box-shadow into shadow- properties', () => | ||
runTest([['box-shadow', '10px 20px 30px red']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 30, | ||
shadowColor: 'red', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow without blur-radius', () => runTest([ | ||
['box-shadow', '10px 20px red'], | ||
], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'red', | ||
})); | ||
it('transforms box-shadow without blur-radius', () => | ||
runTest([['box-shadow', '10px 20px red']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'red', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow without color', () => runTest([ | ||
['box-shadow', '10px 20px red'], | ||
], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'red', | ||
})); | ||
it('transforms box-shadow without color', () => | ||
runTest([['box-shadow', '10px 20px 30px']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 30, | ||
shadowColor: 'black', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow without blur-radius, color', () => runTest([ | ||
['box-shadow', '10px 20px'], | ||
], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'black', | ||
})); | ||
it('transforms box-shadow without blur-radius, color', () => | ||
runTest([['box-shadow', '10px 20px']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'black', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow with rgb color', () => | ||
runTest([['box-shadow', '10px 20px rgb(100, 100, 100)']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'rgb(100, 100, 100)', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow with rgba color', () => | ||
runTest([['box-shadow', '10px 20px rgba(100, 100, 100, 0.5)']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'rgba(100, 100, 100, 0.5)', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow with hsl color', () => | ||
runTest([['box-shadow', '10px 20px hsl(120, 100%, 50%)']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'hsl(120, 100%, 50%)', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow with hsla color', () => | ||
runTest([['box-shadow', '10px 20px hsla(120, 100%, 50%, 0.7)']], { | ||
shadowOffset: { width: 10, height: 20 }, | ||
shadowRadius: 0, | ||
shadowColor: 'hsla(120, 100%, 50%, 0.7)', | ||
shadowOpacity: 1, | ||
})) | ||
it('transforms box-shadow and throws if multiple colors are used', () => { | ||
expect(() => | ||
transformCss([['box-shadow', '0 0 0 red yellow green blue']]) | ||
).toThrow( | ||
'Failed to parse declaration "boxShadow: 0 0 0 red yellow green blue"' | ||
) | ||
}) | ||
it('transforms box-shadow enforces offset to be present', () => { | ||
expect(() => transformCss([['box-shadow', 'red']])) | ||
.toThrow('Failed to parse declaration "boxShadow: red"'); | ||
}); | ||
expect(() => transformCss([['box-shadow', 'red']])).toThrow( | ||
'Failed to parse declaration "boxShadow: red"' | ||
) | ||
}) | ||
it('transforms box-shadow and enforces offset-y if offset-x present', () => { | ||
expect(() => transformCss([['box-shadow', '10px']])) | ||
.toThrow('Failed to parse declaration "boxShadow: 10px"'); | ||
}); | ||
expect(() => transformCss([['box-shadow', '10px']])).toThrow( | ||
'Failed to parse declaration "boxShadow: 10px"' | ||
) | ||
}) | ||
it('allows blacklisting shorthands', () => { | ||
const actualStyles = transformCss([['border-radius', '50']], ['borderRadius']); | ||
expect(actualStyles).toEqual({ borderRadius: 50 }); | ||
}); | ||
const actualStyles = transformCss([['border-radius', '50']], ['borderRadius']) | ||
expect(actualStyles).toEqual({ borderRadius: 50 }) | ||
}) | ||
it('throws useful errors', () => { | ||
expect(() => transformCss([['margin', '10']])) | ||
.toThrow('Failed to parse declaration "margin: 10"'); | ||
}); | ||
expect(() => transformCss([['margin', '10']])).toThrow( | ||
'Failed to parse declaration "margin: 10"' | ||
) | ||
}) |
@@ -1,84 +0,74 @@ | ||
const SYMBOL_BASE_MATCH = 'SYMBOL_BASE_MATCH'; | ||
const SYMBOL_MATCH = 'SYMBOL_MATCH'; | ||
const SYMBOL_MATCH = 'SYMBOL_MATCH' | ||
module.exports = class TokenStream { | ||
constructor(nodes, parent) { | ||
this.nodes = nodes; | ||
this.parent = parent; | ||
this.lastFunction = null; | ||
this.lastValue = null; | ||
this.index = 0 | ||
this.nodes = nodes | ||
this.functionName = parent != null ? parent.value : null | ||
this.lastValue = null | ||
this.rewindIndex = -1 | ||
} | ||
get node() { | ||
return this.nodes[0]; | ||
} | ||
hasTokens() { | ||
return this.nodes.length > 0; | ||
return this.index <= this.nodes.length - 1 | ||
} | ||
lookAhead() { | ||
return new TokenStream(this.nodes.slice(1), this.parent); | ||
} | ||
[SYMBOL_MATCH](...tokenDescriptors) { | ||
if (!this.hasTokens()) return null | ||
[SYMBOL_BASE_MATCH](...tokenDescriptors) { | ||
const node = this.node; | ||
const node = this.nodes[this.index] | ||
if (!node) return null; | ||
for (let i = 0; i < tokenDescriptors.length; i += 1) { | ||
const tokenDescriptor = tokenDescriptors[i]; | ||
const value = tokenDescriptor(node); | ||
if (value !== null) return value; | ||
const tokenDescriptor = tokenDescriptors[i] | ||
const value = tokenDescriptor(node) | ||
if (value !== null) { | ||
this.index += 1 | ||
this.lastValue = value | ||
return value | ||
} | ||
} | ||
return null; | ||
return null | ||
} | ||
[SYMBOL_MATCH](...tokenDescriptors) { | ||
const value = this[SYMBOL_BASE_MATCH](...tokenDescriptors); | ||
if (value === null) return null; | ||
this.nodes = this.nodes.slice(1); | ||
this.lastFunction = null; | ||
this.lastValue = value; | ||
return value; | ||
} | ||
test(...tokenDescriptors) { | ||
return this[SYMBOL_BASE_MATCH](...tokenDescriptors) !== null; | ||
} | ||
matches(...tokenDescriptors) { | ||
return this[SYMBOL_MATCH](...tokenDescriptors) !== null; | ||
return this[SYMBOL_MATCH](...tokenDescriptors) !== null | ||
} | ||
expect(...tokenDescriptors) { | ||
const value = this[SYMBOL_MATCH](...tokenDescriptors); | ||
if (value !== null) return value; | ||
return this.throw(); | ||
const value = this[SYMBOL_MATCH](...tokenDescriptors) | ||
return value !== null ? value : this.throw() | ||
} | ||
matchesFunction() { | ||
const node = this.node; | ||
if (node.type !== 'function') return null; | ||
const value = new TokenStream(node.nodes, node); | ||
this.nodes = this.nodes.slice(1); | ||
this.lastFunction = value; | ||
this.lastValue = null; | ||
return value; | ||
const node = this.nodes[this.index] | ||
if (node.type !== 'function') return null | ||
const value = new TokenStream(node.nodes, node) | ||
this.index += 1 | ||
this.lastValue = null | ||
return value | ||
} | ||
expectFunction() { | ||
const value = this.matchesFunction(); | ||
if (value !== null) return value; | ||
return this.throw(); | ||
const value = this.matchesFunction() | ||
return value !== null ? value : this.throw() | ||
} | ||
expectEmpty() { | ||
if (this.hasTokens()) this.throw(); | ||
if (this.hasTokens()) this.throw() | ||
} | ||
throw() { | ||
throw new Error(`Unexpected token type: ${this.node.type}`); | ||
throw new Error(`Unexpected token type: ${this.nodes[this.index].type}`) | ||
} | ||
}; | ||
saveRewindPoint() { | ||
this.rewindIndex = this.index | ||
} | ||
rewind() { | ||
if (this.rewindIndex === -1) throw new Error('Internal error') | ||
this.index = this.rewindIndex | ||
this.lastValue = null | ||
} | ||
} |
@@ -1,51 +0,55 @@ | ||
const { stringify } = require('postcss-value-parser'); | ||
const cssColorKeywords = require('css-color-keywords'); | ||
const { stringify } = require('postcss-value-parser') | ||
const cssColorKeywords = require('css-color-keywords') | ||
const matchString = (node) => { | ||
if (node.type !== 'string') return null; | ||
const matchString = node => { | ||
if (node.type !== 'string') return null | ||
return node.value | ||
.replace(/\\([0-9a-f]{1,6})(?:\s|$)/gi, (match, charCode) => ( | ||
.replace(/\\([0-9a-f]{1,6})(?:\s|$)/gi, (match, charCode) => | ||
String.fromCharCode(parseInt(charCode, 16)) | ||
)) | ||
.replace(/\\/g, ''); | ||
}; | ||
) | ||
.replace(/\\/g, '') | ||
} | ||
const hexColorRe = /^(#(?:[0-9a-f]{3,4}){1,2})$/i; | ||
const cssFunctionNameRe = /^(rgba?|hsla?|hwb|lab|lch|gray|color)$/; | ||
const hexColorRe = /^(#(?:[0-9a-f]{3,4}){1,2})$/i | ||
const cssFunctionNameRe = /^(rgba?|hsla?|hwb|lab|lch|gray|color)$/ | ||
const matchColor = (node) => { | ||
if (node.type === 'word' && (hexColorRe.test(node.value) || node.value in cssColorKeywords)) { | ||
return node.value; | ||
const matchColor = node => { | ||
if ( | ||
node.type === 'word' && | ||
(hexColorRe.test(node.value) || node.value in cssColorKeywords) | ||
) { | ||
return node.value | ||
} else if (node.type === 'function' && cssFunctionNameRe.test(node.value)) { | ||
return stringify(node); | ||
return stringify(node) | ||
} | ||
return null; | ||
}; | ||
return null | ||
} | ||
const noneRe = /^(none)$/i; | ||
const autoRe = /^(auto)$/i; | ||
const identRe = /(^-?[_a-z][_a-z0-9-]*$)/i; | ||
const noneRe = /^(none)$/i | ||
const autoRe = /^(auto)$/i | ||
const identRe = /(^-?[_a-z][_a-z0-9-]*$)/i | ||
// Note if these are wrong, you'll need to change index.js too | ||
const numberRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)$/; | ||
const numberRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)$/ | ||
// Note lengthRe is sneaky: you can omit units for 0 | ||
const lengthRe = /^(0$|(?:[+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)(?=px$))/; | ||
const angleRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?(?:deg|rad))$/; | ||
const percentRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?%)$/; | ||
const lengthRe = /^(0$|(?:[+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?)(?=px$))/ | ||
const angleRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?(?:deg|rad))$/ | ||
const percentRe = /^([+-]?(?:\d*\.)?\d+(?:[Ee][+-]?\d+)?%)$/ | ||
const noopToken = predicate => node => (predicate(node) ? '<token>' : null); | ||
const noopToken = predicate => node => (predicate(node) ? '<token>' : null) | ||
const valueForTypeToken = type => node => (node.type === type ? node.value : null); | ||
const valueForTypeToken = type => node => | ||
node.type === type ? node.value : null | ||
const regExpToken = (regExp, transform = String) => (node) => { | ||
if (node.type !== 'word') return null; | ||
const regExpToken = (regExp, transform = String) => node => { | ||
if (node.type !== 'word') return null | ||
const match = node.value.match(regExp); | ||
if (match === null) return null; | ||
const match = node.value.match(regExp) | ||
if (match === null) return null | ||
const value = transform(match[1]); | ||
const value = transform(match[1]) | ||
return value; | ||
}; | ||
return value | ||
} | ||
module.exports.regExpToken = regExpToken; | ||
module.exports.regExpToken = regExpToken | ||
@@ -66,2 +70,2 @@ module.exports.tokens = { | ||
COLOR: matchColor, | ||
}; | ||
} |
@@ -1,43 +0,48 @@ | ||
const { tokens } = require('../tokenTypes'); | ||
const { tokens } = require('../tokenTypes') | ||
const { NONE, SPACE, WORD, LENGTH } = tokens; | ||
const { NONE, SPACE, COLOR, LENGTH } = tokens | ||
module.exports = (tokenStream) => { | ||
let offsetX; | ||
let offsetY; | ||
let blurRadius; | ||
let color; | ||
module.exports = tokenStream => { | ||
let offsetX | ||
let offsetY | ||
let blurRadius | ||
let color | ||
if (tokenStream.matches(NONE)) { | ||
tokenStream.expectEmpty(); | ||
tokenStream.expectEmpty() | ||
return { | ||
$merge: { shadowOffset: { width: 0, height: 0 }, shadowRadius: 0, shadowColor: 'black' }, | ||
}; | ||
$merge: { | ||
shadowOffset: { width: 0, height: 0 }, | ||
shadowRadius: 0, | ||
shadowColor: 'black', | ||
shadowOpacity: 1, | ||
}, | ||
} | ||
} | ||
let didParseFirst = false; | ||
let didParseFirst = false | ||
while (tokenStream.hasTokens()) { | ||
if (didParseFirst) tokenStream.expect(SPACE); | ||
if (didParseFirst) tokenStream.expect(SPACE) | ||
if (offsetX === undefined && tokenStream.matches(LENGTH)) { | ||
offsetX = tokenStream.lastValue; | ||
tokenStream.expect(SPACE); | ||
offsetY = tokenStream.expect(LENGTH); | ||
offsetX = tokenStream.lastValue | ||
tokenStream.expect(SPACE) | ||
offsetY = tokenStream.expect(LENGTH) | ||
if (tokenStream.lookAhead().matches(LENGTH)) { | ||
tokenStream.expect(SPACE); | ||
blurRadius = tokenStream.expect(LENGTH); | ||
tokenStream.saveRewindPoint() | ||
if (tokenStream.matches(SPACE) && tokenStream.matches(LENGTH)) { | ||
blurRadius = tokenStream.lastValue | ||
} else { | ||
tokenStream.rewind() | ||
} | ||
} else if (color === undefined && ( | ||
tokenStream.matchesFunction() || tokenStream.matches(WORD) | ||
)) { | ||
color = String(tokenStream.lastValue); | ||
} else if (color === undefined && tokenStream.matches(COLOR)) { | ||
color = tokenStream.lastValue | ||
} else { | ||
tokenStream.throw(); | ||
tokenStream.throw() | ||
} | ||
didParseFirst = true; | ||
didParseFirst = true | ||
} | ||
if (offsetX === undefined) tokenStream.throw(); | ||
if (offsetX === undefined) tokenStream.throw() | ||
@@ -48,4 +53,5 @@ const $merge = { | ||
shadowColor: color !== undefined ? color : 'black', | ||
}; | ||
return { $merge }; | ||
}; | ||
shadowOpacity: 1, | ||
} | ||
return { $merge } | ||
} |
@@ -1,54 +0,60 @@ | ||
const { tokens } = require('../tokenTypes'); | ||
const { tokens } = require('../tokenTypes') | ||
const { NONE, AUTO, NUMBER, LENGTH, SPACE } = tokens; | ||
const { NONE, AUTO, NUMBER, LENGTH, SPACE } = tokens | ||
const defaultFlexGrow = 1; | ||
const defaultFlexShrink = 1; | ||
const defaultFlexBasis = 0; | ||
const defaultFlexGrow = 1 | ||
const defaultFlexShrink = 1 | ||
const defaultFlexBasis = 0 | ||
const FLEX_BASIS_AUTO = {}; // Used for reference equality | ||
const FLEX_BASIS_AUTO = {} // Used for reference equality | ||
module.exports = (tokenStream) => { | ||
let flexGrow; | ||
let flexShrink; | ||
let flexBasis; | ||
module.exports = tokenStream => { | ||
let flexGrow | ||
let flexShrink | ||
let flexBasis | ||
if (tokenStream.matches(NONE)) { | ||
tokenStream.expectEmpty(); | ||
return { $merge: { flexGrow: 0, flexShrink: 0 } }; | ||
} else if (tokenStream.test(AUTO) && !tokenStream.lookAhead().hasTokens()) { | ||
return { $merge: { flexGrow: 1, flexShrink: 1 } }; | ||
tokenStream.expectEmpty() | ||
return { $merge: { flexGrow: 0, flexShrink: 0 } } | ||
} | ||
let partsParsed = 0; | ||
tokenStream.saveRewindPoint() | ||
if (tokenStream.matches(AUTO) && !tokenStream.hasTokens()) { | ||
return { $merge: { flexGrow: 1, flexShrink: 1 } } | ||
} | ||
tokenStream.rewind() | ||
let partsParsed = 0 | ||
while (partsParsed < 2 && tokenStream.hasTokens()) { | ||
if (partsParsed !== 0) tokenStream.expect(SPACE); | ||
if (partsParsed !== 0) tokenStream.expect(SPACE) | ||
if (flexGrow === undefined && tokenStream.matches(NUMBER)) { | ||
flexGrow = tokenStream.lastValue; | ||
flexGrow = tokenStream.lastValue | ||
if (tokenStream.lookAhead().matches(NUMBER)) { | ||
tokenStream.expect(SPACE); | ||
flexShrink = tokenStream.expect(NUMBER); | ||
tokenStream.saveRewindPoint() | ||
if (tokenStream.matches(SPACE) && tokenStream.matches(NUMBER)) { | ||
flexShrink = tokenStream.lastValue | ||
} else { | ||
tokenStream.rewind() | ||
} | ||
} else if (flexBasis === undefined && tokenStream.matches(LENGTH)) { | ||
flexBasis = tokenStream.lastValue; | ||
flexBasis = tokenStream.lastValue | ||
} else if (flexBasis === undefined && tokenStream.matches(AUTO)) { | ||
flexBasis = FLEX_BASIS_AUTO; | ||
flexBasis = FLEX_BASIS_AUTO | ||
} else { | ||
tokenStream.throw(); | ||
tokenStream.throw() | ||
} | ||
partsParsed += 1; | ||
partsParsed += 1 | ||
} | ||
tokenStream.expectEmpty(); | ||
tokenStream.expectEmpty() | ||
if (flexGrow === undefined) flexGrow = defaultFlexGrow; | ||
if (flexShrink === undefined) flexShrink = defaultFlexShrink; | ||
if (flexBasis === undefined) flexBasis = defaultFlexBasis; | ||
if (flexGrow === undefined) flexGrow = defaultFlexGrow | ||
if (flexShrink === undefined) flexShrink = defaultFlexShrink | ||
if (flexBasis === undefined) flexBasis = defaultFlexBasis | ||
return flexBasis !== FLEX_BASIS_AUTO | ||
? { $merge: { flexGrow, flexShrink, flexBasis } } | ||
: { $merge: { flexGrow, flexShrink } }; | ||
}; | ||
: { $merge: { flexGrow, flexShrink } } | ||
} |
@@ -1,23 +0,23 @@ | ||
const parseFontFamily = require('./fontFamily'); | ||
const { regExpToken, tokens } = require('../tokenTypes'); | ||
const parseFontFamily = require('./fontFamily') | ||
const { regExpToken, tokens } = require('../tokenTypes') | ||
const { SPACE, LENGTH, NUMBER, SLASH } = tokens; | ||
const NORMAL = regExpToken(/^(normal)$/); | ||
const STYLE = regExpToken(/^(italic)$/); | ||
const WEIGHT = regExpToken(/^([1-9]00|bold)$/); | ||
const VARIANT = regExpToken(/^(small-caps)$/); | ||
const { SPACE, LENGTH, NUMBER, SLASH } = tokens | ||
const NORMAL = regExpToken(/^(normal)$/) | ||
const STYLE = regExpToken(/^(italic)$/) | ||
const WEIGHT = regExpToken(/^([1-9]00|bold)$/) | ||
const VARIANT = regExpToken(/^(small-caps)$/) | ||
const defaultFontStyle = 'normal'; | ||
const defaultFontWeight = 'normal'; | ||
const defaultFontVariant = []; | ||
const defaultFontStyle = 'normal' | ||
const defaultFontWeight = 'normal' | ||
const defaultFontVariant = [] | ||
module.exports = (tokenStream) => { | ||
let fontStyle; | ||
let fontWeight; | ||
let fontVariant; | ||
module.exports = tokenStream => { | ||
let fontStyle | ||
let fontWeight | ||
let fontVariant | ||
// let fontSize; | ||
let lineHeight; | ||
let lineHeight | ||
// let fontFamily; | ||
let numStyleWeightVariantMatched = 0; | ||
let numStyleWeightVariantMatched = 0 | ||
while (numStyleWeightVariantMatched < 3 && tokenStream.hasTokens()) { | ||
@@ -27,37 +27,37 @@ if (tokenStream.matches(NORMAL)) { | ||
} else if (fontStyle === undefined && tokenStream.matches(STYLE)) { | ||
fontStyle = tokenStream.lastValue; | ||
fontStyle = tokenStream.lastValue | ||
} else if (fontWeight === undefined && tokenStream.matches(WEIGHT)) { | ||
fontWeight = tokenStream.lastValue; | ||
fontWeight = tokenStream.lastValue | ||
} else if (fontVariant === undefined && tokenStream.matches(VARIANT)) { | ||
fontVariant = [tokenStream.lastValue]; | ||
fontVariant = [tokenStream.lastValue] | ||
} else { | ||
break; | ||
break | ||
} | ||
tokenStream.expect(SPACE); | ||
numStyleWeightVariantMatched += 1; | ||
tokenStream.expect(SPACE) | ||
numStyleWeightVariantMatched += 1 | ||
} | ||
const fontSize = tokenStream.expect(LENGTH); | ||
const fontSize = tokenStream.expect(LENGTH) | ||
if (tokenStream.matches(SLASH)) { | ||
if (tokenStream.matches(NUMBER)) { | ||
lineHeight = fontSize * tokenStream.lastValue; | ||
lineHeight = fontSize * tokenStream.lastValue | ||
} else { | ||
lineHeight = tokenStream.expect(LENGTH); | ||
lineHeight = tokenStream.expect(LENGTH) | ||
} | ||
} | ||
tokenStream.expect(SPACE); | ||
tokenStream.expect(SPACE) | ||
const fontFamily = parseFontFamily(tokenStream); | ||
const fontFamily = parseFontFamily(tokenStream) | ||
if (fontStyle === undefined) fontStyle = defaultFontStyle; | ||
if (fontWeight === undefined) fontWeight = defaultFontWeight; | ||
if (fontVariant === undefined) fontVariant = defaultFontVariant; | ||
if (fontStyle === undefined) fontStyle = defaultFontStyle | ||
if (fontWeight === undefined) fontWeight = defaultFontWeight | ||
if (fontVariant === undefined) fontVariant = defaultFontVariant | ||
const out = { fontStyle, fontWeight, fontVariant, fontSize, fontFamily }; | ||
if (lineHeight !== undefined) out.lineHeight = lineHeight; | ||
const out = { fontStyle, fontWeight, fontVariant, fontSize, fontFamily } | ||
if (lineHeight !== undefined) out.lineHeight = lineHeight | ||
return { $merge: out }; | ||
}; | ||
return { $merge: out } | ||
} |
@@ -1,22 +0,22 @@ | ||
const { tokens } = require('../tokenTypes'); | ||
const { tokens } = require('../tokenTypes') | ||
const { SPACE, IDENT, STRING } = tokens; | ||
const { SPACE, IDENT, STRING } = tokens | ||
module.exports = (tokenStream) => { | ||
let fontFamily; | ||
module.exports = tokenStream => { | ||
let fontFamily | ||
if (tokenStream.matches(STRING)) { | ||
fontFamily = tokenStream.lastValue; | ||
fontFamily = tokenStream.lastValue | ||
} else { | ||
fontFamily = tokenStream.expect(IDENT); | ||
fontFamily = tokenStream.expect(IDENT) | ||
while (tokenStream.hasTokens()) { | ||
tokenStream.expect(SPACE); | ||
const nextIdent = tokenStream.expect(IDENT); | ||
fontFamily += ` ${nextIdent}`; | ||
tokenStream.expect(SPACE) | ||
const nextIdent = tokenStream.expect(IDENT) | ||
fontFamily += ` ${nextIdent}` | ||
} | ||
} | ||
tokenStream.expectEmpty(); | ||
tokenStream.expectEmpty() | ||
return fontFamily; | ||
}; | ||
return fontFamily | ||
} |
@@ -1,12 +0,18 @@ | ||
const { regExpToken, tokens } = require('../tokenTypes'); | ||
const boxShadow = require('./boxShadow'); | ||
const flex = require('./flex'); | ||
const font = require('./font'); | ||
const fontFamily = require('./fontFamily'); | ||
const transform = require('./transform'); | ||
const { directionFactory, anyOrderFactory, shadowOffsetFactory } = require('./util'); | ||
const { regExpToken, tokens } = require('../tokenTypes') | ||
const boxShadow = require('./boxShadow') | ||
const flex = require('./flex') | ||
const font = require('./font') | ||
const fontFamily = require('./fontFamily') | ||
const transform = require('./transform') | ||
const { | ||
directionFactory, | ||
anyOrderFactory, | ||
shadowOffsetFactory, | ||
} = require('./util') | ||
const { IDENT, WORD, COLOR } = tokens; | ||
const { IDENT, WORD, COLOR } = tokens | ||
const background = tokenStream => ({ $merge: { backgroundColor: tokenStream.expect(COLOR) } }); | ||
const background = tokenStream => ({ | ||
$merge: { backgroundColor: tokenStream.expect(COLOR) }, | ||
}) | ||
const border = anyOrderFactory({ | ||
@@ -25,3 +31,3 @@ borderWidth: { | ||
}, | ||
}); | ||
}) | ||
const borderColor = directionFactory({ | ||
@@ -31,3 +37,3 @@ types: [WORD], | ||
suffix: 'Color', | ||
}); | ||
}) | ||
const borderRadius = directionFactory({ | ||
@@ -37,6 +43,6 @@ directions: ['TopRight', 'BottomRight', 'BottomLeft', 'TopLeft'], | ||
suffix: 'Radius', | ||
}); | ||
const borderWidth = directionFactory({ prefix: 'border', suffix: 'Width' }); | ||
const margin = directionFactory({ prefix: 'margin' }); | ||
const padding = directionFactory({ prefix: 'padding' }); | ||
}) | ||
const borderWidth = directionFactory({ prefix: 'border', suffix: 'Width' }) | ||
const margin = directionFactory({ prefix: 'margin' }) | ||
const padding = directionFactory({ prefix: 'padding' }) | ||
const flexFlow = anyOrderFactory({ | ||
@@ -51,7 +57,7 @@ flexWrap: { | ||
}, | ||
}); | ||
const fontVariant = tokenStream => [tokenStream.expect(IDENT)]; | ||
const fontWeight = tokenStream => tokenStream.expect(WORD); // Also match numbers as strings | ||
const shadowOffset = shadowOffsetFactory(); | ||
const textShadowOffset = shadowOffsetFactory(); | ||
}) | ||
const fontVariant = tokenStream => [tokenStream.expect(IDENT)] | ||
const fontWeight = tokenStream => tokenStream.expect(WORD) // Also match numbers as strings | ||
const shadowOffset = shadowOffsetFactory() | ||
const textShadowOffset = shadowOffsetFactory() | ||
@@ -76,2 +82,2 @@ module.exports = { | ||
transform, | ||
}; | ||
} |
@@ -1,36 +0,39 @@ | ||
const { tokens } = require('../tokenTypes'); | ||
const { tokens } = require('../tokenTypes') | ||
const { SPACE, COMMA, LENGTH, NUMBER, ANGLE } = tokens; | ||
const { SPACE, COMMA, LENGTH, NUMBER, ANGLE } = tokens | ||
const oneOfType = tokenType => (functionStream) => { | ||
const value = functionStream.expect(tokenType); | ||
functionStream.expectEmpty(); | ||
return value; | ||
}; | ||
const oneOfType = tokenType => functionStream => { | ||
const value = functionStream.expect(tokenType) | ||
functionStream.expectEmpty() | ||
return value | ||
} | ||
const singleNumber = oneOfType(NUMBER); | ||
const singleLength = oneOfType(LENGTH); | ||
const singleAngle = oneOfType(ANGLE); | ||
const xyTransformFactory = tokenType => (key, valueIfOmitted) => (functionStream) => { | ||
const x = functionStream.expect(tokenType); | ||
const singleNumber = oneOfType(NUMBER) | ||
const singleLength = oneOfType(LENGTH) | ||
const singleAngle = oneOfType(ANGLE) | ||
const xyTransformFactory = tokenType => ( | ||
key, | ||
valueIfOmitted | ||
) => functionStream => { | ||
const x = functionStream.expect(tokenType) | ||
let y; | ||
let y | ||
if (functionStream.hasTokens()) { | ||
functionStream.expect(COMMA); | ||
y = functionStream.expect(tokenType); | ||
functionStream.expect(COMMA) | ||
y = functionStream.expect(tokenType) | ||
} else if (valueIfOmitted !== undefined) { | ||
y = valueIfOmitted; | ||
y = valueIfOmitted | ||
} else { | ||
// Assumption, if x === y, then we can omit XY | ||
// I.e. scale(5) => [{ scale: 5 }] rather than [{ scaleX: 5 }, { scaleY: 5 }] | ||
return x; | ||
return x | ||
} | ||
functionStream.expectEmpty(); | ||
functionStream.expectEmpty() | ||
return [{ [`${key}Y`]: y }, { [`${key}X`]: x }]; | ||
}; | ||
const xyNumber = xyTransformFactory(NUMBER); | ||
const xyLength = xyTransformFactory(LENGTH); | ||
const xyAngle = xyTransformFactory(ANGLE); | ||
return [{ [`${key}Y`]: y }, { [`${key}X`]: x }] | ||
} | ||
const xyNumber = xyTransformFactory(NUMBER) | ||
const xyLength = xyTransformFactory(LENGTH) | ||
const xyAngle = xyTransformFactory(ANGLE) | ||
@@ -52,23 +55,23 @@ const partTransforms = { | ||
skew: xyAngle('skew', '0deg'), | ||
}; | ||
} | ||
module.exports = (tokenStream) => { | ||
let transforms = []; | ||
module.exports = tokenStream => { | ||
let transforms = [] | ||
let didParseFirst = false; | ||
let didParseFirst = false | ||
while (tokenStream.hasTokens()) { | ||
if (didParseFirst) tokenStream.expect(SPACE); | ||
if (didParseFirst) tokenStream.expect(SPACE) | ||
const functionStream = tokenStream.expectFunction(); | ||
const transformName = functionStream.parent.value; | ||
let transformedValues = partTransforms[transformName](functionStream); | ||
const functionStream = tokenStream.expectFunction() | ||
const { functionName } = functionStream | ||
let transformedValues = partTransforms[functionName](functionStream) | ||
if (!Array.isArray(transformedValues)) { | ||
transformedValues = [{ [transformName]: transformedValues }]; | ||
transformedValues = [{ [functionName]: transformedValues }] | ||
} | ||
transforms = transformedValues.concat(transforms); | ||
transforms = transformedValues.concat(transforms) | ||
didParseFirst = true; | ||
didParseFirst = true | ||
} | ||
return transforms; | ||
}; | ||
return transforms | ||
} |
@@ -1,4 +0,4 @@ | ||
const { tokens } = require('../tokenTypes'); | ||
const { tokens } = require('../tokenTypes') | ||
const { LENGTH, PERCENT, SPACE } = tokens; | ||
const { LENGTH, PERCENT, SPACE } = tokens | ||
@@ -10,18 +10,18 @@ module.exports.directionFactory = ({ | ||
suffix = '', | ||
}) => (tokenStream) => { | ||
const values = []; | ||
}) => tokenStream => { | ||
const values = [] | ||
// borderWidth doesn't currently allow a percent value, but may do in the future | ||
values.push(tokenStream.expect(...types)); | ||
values.push(tokenStream.expect(...types)) | ||
while (values.length < 4 && tokenStream.hasTokens()) { | ||
tokenStream.expect(SPACE); | ||
values.push(tokenStream.expect(...types)); | ||
tokenStream.expect(SPACE) | ||
values.push(tokenStream.expect(...types)) | ||
} | ||
tokenStream.expectEmpty(); | ||
tokenStream.expectEmpty() | ||
const [top, right = top, bottom = top, left = right] = values; | ||
const [top, right = top, bottom = top, left = right] = values | ||
const keyFor = n => `${prefix}${directions[n]}${suffix}`; | ||
const keyFor = n => `${prefix}${directions[n]}${suffix}` | ||
@@ -33,47 +33,48 @@ const output = { | ||
[keyFor(3)]: left, | ||
}; | ||
} | ||
return { $merge: output }; | ||
}; | ||
return { $merge: output } | ||
} | ||
module.exports.anyOrderFactory = (properties, delim = SPACE) => (tokenStream) => { | ||
const propertyNames = Object.keys(properties); | ||
module.exports.anyOrderFactory = (properties, delim = SPACE) => tokenStream => { | ||
const propertyNames = Object.keys(properties) | ||
const values = propertyNames.reduce((accum, propertyName) => { | ||
accum[propertyName] === undefined; // eslint-disable-line | ||
return accum; | ||
}, {}); | ||
accum[propertyName] === undefined // eslint-disable-line | ||
return accum | ||
}, {}) | ||
let numParsed = 0; | ||
let numParsed = 0 | ||
while (numParsed < propertyNames.length && tokenStream.hasTokens()) { | ||
if (numParsed) tokenStream.expect(delim); | ||
if (numParsed) tokenStream.expect(delim) | ||
const matchedPropertyName = propertyNames.find(propertyName => ( | ||
values[propertyName] === undefined && tokenStream.matches(properties[propertyName].token) | ||
)); | ||
const matchedPropertyName = propertyNames.find( | ||
propertyName => | ||
values[propertyName] === undefined && | ||
tokenStream.matches(properties[propertyName].token) | ||
) | ||
if (!matchedPropertyName) { | ||
tokenStream.throw(); | ||
tokenStream.throw() | ||
} else { | ||
values[matchedPropertyName] = tokenStream.lastValue; | ||
values[matchedPropertyName] = tokenStream.lastValue | ||
} | ||
numParsed += 1; | ||
numParsed += 1 | ||
} | ||
tokenStream.expectEmpty(); | ||
tokenStream.expectEmpty() | ||
propertyNames.forEach((propertyName) => { | ||
if (values[propertyName] === undefined) values[propertyName] = properties[propertyName].default; | ||
}); | ||
propertyNames.forEach(propertyName => { | ||
if (values[propertyName] === undefined) | ||
values[propertyName] = properties[propertyName].default | ||
}) | ||
return { $merge: values }; | ||
}; | ||
return { $merge: values } | ||
} | ||
module.exports.shadowOffsetFactory = () => (tokenStream) => { | ||
const width = tokenStream.expect(LENGTH); | ||
const height = tokenStream.matches(SPACE) | ||
? tokenStream.expect(LENGTH) | ||
: width; | ||
tokenStream.expectEmpty(); | ||
return { width, height }; | ||
}; | ||
module.exports.shadowOffsetFactory = () => tokenStream => { | ||
const width = tokenStream.expect(LENGTH) | ||
const height = tokenStream.matches(SPACE) ? tokenStream.expect(LENGTH) : width | ||
tokenStream.expectEmpty() | ||
return { width, height } | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
63213
1634
10