Skip to content

Commit eac1278

Browse files
committed
Fix parser functions
* TYPES values ​​have been changed to allow bitwise operations. * Fixed valueType() function. * Other parser functions have been modified to match the changes to the valueType() function.
1 parent 11fa40f commit eac1278

10 files changed

+470
-175
lines changed

lib/parsers.js

+134-112
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,27 @@ const { resolve: resolveColor, utils } = require('@asamuzakjp/css-color');
88
const { cssCalc, isColor, isGradient, splitValue } = utils;
99

1010
exports.TYPES = {
11-
INTEGER: 1,
12-
NUMBER: 2,
13-
LENGTH: 3,
14-
PERCENT: 4,
15-
URL: 5,
16-
COLOR: 6,
17-
STRING: 7,
18-
ANGLE: 8,
19-
KEYWORD: 9,
20-
NULL_OR_EMPTY_STR: 10,
21-
CALC: 11,
22-
VAR: 12,
23-
GRADIENT: 13,
11+
UNDEFINED: 0,
12+
NULL_OR_EMPTY_STR: 1,
13+
VAR: 2,
14+
NUMBER: 4,
15+
PERCENT: 8,
16+
LENGTH: 0x10,
17+
ANGLE: 0x20,
18+
CALC: 0x40,
19+
COLOR: 0x80,
20+
STRING: 0x100,
21+
KEYWORD: 0x200,
22+
UNIDENT: 0x8000,
2423
};
2524

2625
// regular expressions
2726
var DIGIT = '(?:0|[1-9]\\d*)';
2827
var NUMBER = `[+-]?(?:${DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${DIGIT})?`;
29-
var integerRegEx = new RegExp(`^[+-]?${DIGIT}$`);
30-
var numberRegEx = new RegExp(`^${NUMBER}$`);
31-
var lengthRegEx = new RegExp(
32-
`^${NUMBER}(?:[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic))$`
33-
);
34-
var percentRegEx = new RegExp(`^${NUMBER}%$`);
28+
var unitRegEx = new RegExp(`^(${NUMBER})([a-z]+|%)?$`);
3529
var angleRegEx = new RegExp(`^${NUMBER}(?:deg|g?rad|turn)$`);
3630
var urlRegEx = /^url\(\s*((?:[^)]|\\\))*)\s*\)$/;
31+
var keywordRegEx = /^[a-z]+(?:\-[a-z]+)*$/i;
3732
var stringRegEx = /^("[^"]*"|'[^']*')$/;
3833
var varRegEx = /^var\(|(?<=[*/\s(])var\(/;
3934
var calcRegEx =
@@ -48,46 +43,55 @@ exports.valueType = function valueType(val) {
4843
val = val.toString();
4944
}
5045
if (typeof val !== 'string') {
51-
return undefined;
52-
}
53-
if (integerRegEx.test(val)) {
54-
return exports.TYPES.INTEGER;
55-
}
56-
if (numberRegEx.test(val)) {
57-
return exports.TYPES.NUMBER;
58-
}
59-
if (lengthRegEx.test(val)) {
60-
return exports.TYPES.LENGTH;
61-
}
62-
if (percentRegEx.test(val)) {
63-
return exports.TYPES.PERCENT;
64-
}
65-
if (val.startsWith('url(') && val.endsWith(')')) {
66-
if (urlRegEx.test(val)) {
67-
return exports.TYPES.URL;
68-
}
69-
return undefined;
46+
return exports.TYPES.UNDEFINED;
7047
}
7148
if (varRegEx.test(val)) {
7249
return exports.TYPES.VAR;
7350
}
7451
if (calcRegEx.test(val)) {
7552
return exports.TYPES.CALC;
7653
}
77-
if (stringRegEx.test(val)) {
78-
return exports.TYPES.STRING;
79-
}
80-
if (angleRegEx.test(val)) {
81-
return exports.TYPES.ANGLE;
54+
if (unitRegEx.test(val)) {
55+
const [, , unit] = unitRegEx.exec(val);
56+
if (!unit) {
57+
return exports.TYPES.NUMBER;
58+
}
59+
if (unit === '%') {
60+
return exports.TYPES.PERCENT;
61+
}
62+
if (/^(?:[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic))$/.test(unit)) {
63+
return exports.TYPES.LENGTH;
64+
}
65+
if (/^(?:deg|g?rad|turn)$/.test(unit)) {
66+
return exports.TYPES.ANGLE;
67+
}
8268
}
8369
if (isColor(val)) {
8470
return exports.TYPES.COLOR;
8571
}
86-
if (isGradient(val)) {
87-
return exports.TYPES.GRADIENT;
72+
if (stringRegEx.test(val)) {
73+
return exports.TYPES.STRING;
8874
}
8975

9076
switch (val.toLowerCase()) {
77+
// system color keywords
78+
case 'accentcolor':
79+
case 'accentcolortext':
80+
case 'activetext':
81+
case 'buttonborder':
82+
case 'buttonface':
83+
case 'buttontext':
84+
case 'canvas':
85+
case 'canvastext':
86+
case 'field':
87+
case 'fieldtext':
88+
case 'graytext':
89+
case 'highlight':
90+
case 'highlighttext':
91+
case 'linktext':
92+
case 'mark':
93+
case 'marktext':
94+
case 'visitedtext':
9195
// the following are deprecated in CSS3
9296
case 'activeborder':
9397
case 'activecaption':
@@ -119,87 +123,97 @@ exports.valueType = function valueType(val) {
119123
case 'windowtext':
120124
return exports.TYPES.COLOR;
121125
default:
122-
return exports.TYPES.KEYWORD;
123-
}
124-
};
125-
126-
exports.parseInteger = function parseInteger(val) {
127-
var type = exports.valueType(val);
128-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
129-
return val;
130-
}
131-
if (type !== exports.TYPES.INTEGER) {
132-
return undefined;
126+
if (keywordRegEx.test(val)) {
127+
return exports.TYPES.KEYWORD;
128+
}
129+
return exports.TYPES.UNIDENT;
133130
}
134-
return String(parseInt(val, 10));
135131
};
136132

137133
exports.parseNumber = function parseNumber(val) {
138134
var type = exports.valueType(val);
139-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
140-
return val;
141-
}
142-
if (type !== exports.TYPES.NUMBER && type !== exports.TYPES.INTEGER) {
143-
return undefined;
135+
switch (type) {
136+
case exports.TYPES.NULL_OR_EMPTY_STR:
137+
case exports.TYPES.VAR:
138+
return val;
139+
case exports.TYPES.NUMBER:
140+
return `${parseFloat(val)}`;
141+
default:
142+
return undefined;
144143
}
145-
return String(parseFloat(val));
146144
};
147145

148146
exports.parseLength = function parseLength(val) {
149-
if (val === 0 || val === '0') {
150-
return '0px';
151-
}
152147
var type = exports.valueType(val);
153-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
154-
return val;
155-
}
156-
if (type !== exports.TYPES.LENGTH) {
157-
return undefined;
148+
switch (type) {
149+
case exports.TYPES.NULL_OR_EMPTY_STR:
150+
case exports.TYPES.VAR:
151+
return val;
152+
case exports.TYPES.CALC:
153+
return cssCalc(val, {
154+
format: 'specifiedValue',
155+
});
156+
case exports.TYPES.LENGTH: {
157+
const [, numVal, unit] = unitRegEx.exec(val);
158+
return `${parseFloat(numVal)}${unit}`;
159+
}
160+
default:
161+
if (type === exports.TYPES.NUMBER && parseFloat(val) === 0) {
162+
return '0px';
163+
}
164+
return undefined;
158165
}
159-
return val;
160166
};
161167

162168
exports.parsePercent = function parsePercent(val) {
163-
if (val === 0 || val === '0') {
164-
return '0%';
165-
}
166169
var type = exports.valueType(val);
167-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
168-
return val;
169-
}
170-
if (type !== exports.TYPES.PERCENT) {
171-
return undefined;
170+
switch (type) {
171+
case exports.TYPES.NULL_OR_EMPTY_STR:
172+
case exports.TYPES.VAR:
173+
return val;
174+
case exports.TYPES.CALC:
175+
return cssCalc(val, {
176+
format: 'specifiedValue',
177+
});
178+
case exports.TYPES.PERCENT:
179+
const [, numVal, unit] = unitRegEx.exec(val);
180+
return `${parseFloat(numVal)}${unit}`;
181+
default:
182+
if (type === exports.TYPES.NUMBER && parseFloat(val) === 0) {
183+
return '0%';
184+
}
185+
return undefined;
172186
}
173-
return val;
174187
};
175188

176189
// either a length or a percent
177190
exports.parseMeasurement = function parseMeasurement(val) {
178191
var type = exports.valueType(val);
179-
if (type === exports.TYPES.VAR) {
180-
return val;
181-
}
182-
if (type === exports.TYPES.CALC) {
183-
return cssCalc(val, {
184-
format: 'specifiedValue',
185-
});
186-
}
187-
188-
var length = exports.parseLength(val);
189-
if (length !== undefined) {
190-
return length;
192+
switch (type) {
193+
case exports.TYPES.NULL_OR_EMPTY_STR:
194+
case exports.TYPES.VAR:
195+
return val;
196+
case exports.TYPES.CALC:
197+
return cssCalc(val, {
198+
format: 'specifiedValue',
199+
});
200+
case exports.TYPES.LENGTH:
201+
case exports.TYPES.PERCENT:
202+
const [, numVal, unit] = unitRegEx.exec(val);
203+
return `${parseFloat(numVal)}${unit}`;
204+
default:
205+
if (type === exports.TYPES.NUMBER && parseFloat(val) === 0) {
206+
return '0px';
207+
}
208+
return undefined;
191209
}
192-
return exports.parsePercent(val);
193210
};
194211

195-
exports.parseInheritingMeasurement = function parseInheritingMeasurement(v) {
196-
if (String(v).toLowerCase() === 'auto') {
197-
return 'auto';
198-
}
199-
if (String(v).toLowerCase() === 'inherit') {
200-
return 'inherit';
212+
exports.parseInheritingMeasurement = function parseInheritingMeasurement(val) {
213+
if (/^(?:auto|inherit)$/i.test(val)) {
214+
return val.toLowerCase();
201215
}
202-
return exports.parseMeasurement(v);
216+
return exports.parseMeasurement(val);
203217
};
204218

205219
exports.parseUrl = function parseUrl(val) {
@@ -291,9 +305,12 @@ exports.parseString = function parseString(val) {
291305

292306
exports.parseColor = function parseColor(val) {
293307
var type = exports.valueType(val);
294-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
308+
if (type & (exports.TYPES.NULL_OR_EMPTY_STR | exports.TYPES.VAR)) {
295309
return val;
296310
}
311+
if (type === exports.TYPES.UNDEFINED) {
312+
return undefined;
313+
}
297314
if (/^[a-z]+$/i.test(val) && type === exports.TYPES.COLOR) {
298315
return val;
299316
}
@@ -306,6 +323,9 @@ exports.parseColor = function parseColor(val) {
306323
return undefined;
307324
};
308325

326+
// FIXME:
327+
// This function seems to be incorrect.
328+
// However, this has no impact so far, as this function is only used by the deprecated `azimuth` property.
309329
exports.parseAngle = function parseAngle(val) {
310330
var type = exports.valueType(val);
311331
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
@@ -331,7 +351,7 @@ exports.parseAngle = function parseAngle(val) {
331351
return flt + 'deg';
332352
};
333353

334-
exports.parseKeyword = function parseKeyword(val, valid_keywords) {
354+
exports.parseKeyword = function parseKeyword(val, validKeywords) {
335355
var type = exports.valueType(val);
336356
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
337357
return val;
@@ -341,36 +361,38 @@ exports.parseKeyword = function parseKeyword(val, valid_keywords) {
341361
}
342362
val = val.toString().toLowerCase();
343363
var i;
344-
for (i = 0; i < valid_keywords.length; i++) {
345-
if (valid_keywords[i].toLowerCase() === val) {
346-
return valid_keywords[i];
364+
for (i = 0; i < validKeywords.length; i++) {
365+
if (validKeywords[i].toLowerCase() === val) {
366+
return validKeywords[i];
347367
}
348368
}
349369
return undefined;
350370
};
351371

352372
exports.parseImage = function parseImage(val) {
353373
if (/^(?:none|inherit)$/i.test(val)) {
354-
return val;
374+
return val.toLowerCase();
355375
}
356376
var type = exports.valueType(val);
357-
if (type === exports.TYPES.NULL_OR_EMPTY_STR || type === exports.TYPES.VAR) {
377+
if (type & (exports.TYPES.NULL_OR_EMPTY_STR | exports.TYPES.VAR)) {
358378
return val;
359379
}
380+
if (type === exports.TYPES.UNDEFINED) {
381+
return undefined;
382+
}
360383
var values = splitValue(val, ',');
361384
var isImage = !!values.length;
362385
var i;
363386
for (i = 0; i < values.length; i++) {
364387
var image = values[i];
365-
var t = exports.valueType(image);
366-
if (t === exports.TYPES.NULL_OR_EMPTY_STR) {
388+
if (exports.valueType(image) === exports.TYPES.NULL_OR_EMPTY_STR) {
367389
return image;
368390
}
369-
if (t === exports.TYPES.GRADIENT || /^(?:none|inherit)$/i.test(image)) {
391+
if (isGradient(image) || /^(?:none|inherit)$/i.test(image)) {
370392
continue;
371393
}
372394
var imageUrl = exports.parseUrl(image);
373-
if (exports.valueType(imageUrl) === exports.TYPES.URL) {
395+
if (imageUrl) {
374396
values[i] = imageUrl;
375397
} else {
376398
isImage = false;

lib/properties/backgroundPosition.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,26 @@ var parse = function parse(v) {
1313
return undefined;
1414
}
1515
var types = [];
16+
var typeLengthOrPercent = parsers.TYPES.LENGTH | parsers.TYPES.PERCENT;
17+
var typeKeyword = parsers.TYPES.KEYWORD;
1618
parts.forEach(function (part, index) {
1719
types[index] = parsers.valueType(part);
1820
});
1921
if (parts.length === 1) {
20-
if (types[0] === parsers.TYPES.LENGTH || types[0] === parsers.TYPES.PERCENT) {
22+
if (types[0] & typeLengthOrPercent) {
2123
return v;
2224
}
23-
if (types[0] === parsers.TYPES.KEYWORD) {
25+
if (types[0] === typeKeyword) {
2426
if (valid_keywords.indexOf(v.toLowerCase()) !== -1 || v.toLowerCase() === 'inherit') {
2527
return v;
2628
}
2729
}
2830
return undefined;
2931
}
30-
if (
31-
(types[0] === parsers.TYPES.LENGTH || types[0] === parsers.TYPES.PERCENT) &&
32-
(types[1] === parsers.TYPES.LENGTH || types[1] === parsers.TYPES.PERCENT)
33-
) {
32+
if (types[0] & typeLengthOrPercent && types[1] & typeLengthOrPercent) {
3433
return v;
3534
}
36-
if (types[0] !== parsers.TYPES.KEYWORD || types[1] !== parsers.TYPES.KEYWORD) {
35+
if (types[0] !== typeKeyword || types[1] !== typeKeyword) {
3736
return undefined;
3837
}
3938
if (valid_keywords.indexOf(parts[0]) !== -1 && valid_keywords.indexOf(parts[1]) !== -1) {

0 commit comments

Comments
 (0)