Socket
Socket
Sign inDemoInstall

css-to-react-native

Package Overview
Dependencies
Maintainers
2
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-to-react-native - npm Package Compare versions

Comparing version 2.1.0 to 2.1.1

66

dist/TokenStream.js

@@ -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 }
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc