Skip to content

Commit 54d12b2

Browse files
committed
Update parser
* add global values * scope variables * fix some functions
1 parent 4d19a92 commit 54d12b2

File tree

2 files changed

+203
-60
lines changed

2 files changed

+203
-60
lines changed

lib/parsers.js

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ exports.TYPES = {
2222
UNIDENT: 0x8000,
2323
};
2424

25+
// CSS global values
26+
exports.GLOBAL_VALUES = Object.freeze(['initial', 'inherit', 'unset', 'revert', 'revert-layer']);
27+
2528
// regular expressions
2629
var DIGIT = '(?:0|[1-9]\\d*)';
2730
var NUMBER = `[+-]?(?:${DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${DIGIT})?`;
@@ -37,6 +40,7 @@ var calcRegEx =
3740

3841
// This will return one of the above types based on the passed in string
3942
exports.valueType = function valueType(val) {
43+
// see https://webidl.spec.whatwg.org/#LegacyNullToEmptyString
4044
if (val === '' || val === null) {
4145
return exports.TYPES.NULL_OR_EMPTY_STR;
4246
}
@@ -53,7 +57,7 @@ exports.valueType = function valueType(val) {
5357
return exports.TYPES.CALC;
5458
}
5559
if (unitRegEx.test(val)) {
56-
const [, , unit] = unitRegEx.exec(val);
60+
var [, , unit] = unitRegEx.exec(val);
5761
if (!unit) {
5862
return exports.TYPES.NUMBER;
5963
}
@@ -162,7 +166,7 @@ exports.parseLength = function parseLength(val) {
162166
format: 'specifiedValue',
163167
});
164168
case exports.TYPES.LENGTH: {
165-
const [, numVal, unit] = unitRegEx.exec(val);
169+
var [, numVal, unit] = unitRegEx.exec(val);
166170
return `${parseFloat(numVal)}${unit}`;
167171
}
168172
default:
@@ -186,9 +190,10 @@ exports.parsePercent = function parsePercent(val) {
186190
return cssCalc(val, {
187191
format: 'specifiedValue',
188192
});
189-
case exports.TYPES.PERCENT:
190-
const [, numVal, unit] = unitRegEx.exec(val);
193+
case exports.TYPES.PERCENT: {
194+
var [, numVal, unit] = unitRegEx.exec(val);
191195
return `${parseFloat(numVal)}${unit}`;
196+
}
192197
default:
193198
if (varContainedRegEx.test(val)) {
194199
return val;
@@ -212,9 +217,10 @@ exports.parseMeasurement = function parseMeasurement(val) {
212217
format: 'specifiedValue',
213218
});
214219
case exports.TYPES.LENGTH:
215-
case exports.TYPES.PERCENT:
216-
const [, numVal, unit] = unitRegEx.exec(val);
220+
case exports.TYPES.PERCENT: {
221+
var [, numVal, unit] = unitRegEx.exec(val);
217222
return `${parseFloat(numVal)}${unit}`;
223+
}
218224
default:
219225
if (varContainedRegEx.test(val)) {
220226
return val;
@@ -236,7 +242,7 @@ exports.parseInheritingMeasurement = function parseInheritingMeasurement(val) {
236242
exports.parseUrl = function parseUrl(val) {
237243
var type = exports.valueType(val);
238244
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
239-
return val;
245+
return '';
240246
}
241247
var res = urlRegEx.exec(val);
242248
// does it match the regex?
@@ -293,10 +299,11 @@ exports.parseUrl = function parseUrl(val) {
293299
return 'url("' + urlstr + '")';
294300
};
295301

302+
// NOTE: seems not in use?
296303
exports.parseString = function parseString(val) {
297304
var type = exports.valueType(val);
298305
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
299-
return val;
306+
return '';
300307
}
301308
if (type !== exports.TYPES.STRING) {
302309
return undefined;
@@ -320,14 +327,38 @@ exports.parseString = function parseString(val) {
320327
return val;
321328
};
322329

323-
exports.parseColor = function parseColor(val) {
330+
exports.parseKeyword = function parseKeyword(val, validKeywords = []) {
324331
var type = exports.valueType(val);
325-
if (type === exports.TYPES.NULL_OR_EMPTY_STR || type === exports.TYPES.VAR) {
332+
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
333+
return '';
334+
}
335+
if (type === exports.TYPES.VAR) {
336+
return val;
337+
}
338+
if (type !== exports.TYPES.KEYWORD) {
339+
return undefined;
340+
}
341+
val = val.toString().toLowerCase();
342+
if (validKeywords.includes(val) || exports.GLOBAL_VALUES.includes(val)) {
326343
return val;
327344
}
345+
return undefined;
346+
};
347+
348+
exports.parseColor = function parseColor(val) {
349+
var type = exports.valueType(val);
350+
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
351+
return '';
352+
}
328353
if (type === exports.TYPES.UNDEFINED) {
329354
return undefined;
330355
}
356+
if (type === exports.TYPES.VAR) {
357+
return val;
358+
}
359+
if (type === exports.TYPES.KEYWORD) {
360+
return exports.parseKeyword(val);
361+
}
331362
if (/^[a-z]+$/i.test(val) && type === exports.TYPES.COLOR) {
332363
return val;
333364
}
@@ -346,7 +377,7 @@ exports.parseColor = function parseColor(val) {
346377
exports.parseAngle = function parseAngle(val) {
347378
var type = exports.valueType(val);
348379
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
349-
return val;
380+
return '';
350381
}
351382
if (type !== exports.TYPES.ANGLE) {
352383
return undefined;
@@ -368,34 +399,19 @@ exports.parseAngle = function parseAngle(val) {
368399
return flt + 'deg';
369400
};
370401

371-
exports.parseKeyword = function parseKeyword(val, validKeywords) {
402+
exports.parseImage = function parseImage(val) {
372403
var type = exports.valueType(val);
373404
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
374-
return val;
405+
return '';
375406
}
376-
if (type !== exports.TYPES.KEYWORD) {
407+
if (type === exports.TYPES.UNDEFINED) {
377408
return undefined;
378409
}
379-
val = val.toString().toLowerCase();
380-
var i;
381-
for (i = 0; i < validKeywords.length; i++) {
382-
if (validKeywords[i].toLowerCase() === val) {
383-
return validKeywords[i];
384-
}
385-
}
386-
return undefined;
387-
};
388-
389-
exports.parseImage = function parseImage(val) {
390-
if (/^(?:none|inherit)$/i.test(val)) {
391-
return val.toLowerCase();
392-
}
393-
var type = exports.valueType(val);
394-
if (type === exports.TYPES.NULL_OR_EMPTY_STR || type === exports.TYPES.VAR) {
410+
if (type === exports.TYPES.VAR) {
395411
return val;
396412
}
397-
if (type === exports.TYPES.UNDEFINED) {
398-
return undefined;
413+
if (type === exports.TYPES.KEYWORD) {
414+
return exports.parseKeyword(val, ['none']);
399415
}
400416
var values = splitValue(val, {
401417
delimiter: ',',
@@ -445,11 +461,11 @@ exports.dashedToCamelCase = function (dashed) {
445461
return camel;
446462
};
447463

448-
var isSpace = /\s/;
449-
var openingDeliminators = ['"', "'", '('];
450-
var closingDeliminators = ['"', "'", ')'];
451464
// this splits on whitespace, but keeps quoted and parened parts together
452465
var getParts = function (str) {
466+
var isSpace = /\s/;
467+
var openingDeliminators = ['"', "'", '('];
468+
var closingDeliminators = ['"', "'", ')'];
453469
var deliminatorStack = [];
454470
var length = str.length;
455471
var i;
@@ -489,6 +505,8 @@ var getParts = function (str) {
489505
return parts;
490506
};
491507

508+
// FIXME: need additional argument which indicates syntax
509+
// and/or use Map() for shorthandFor to ensure order of the longhand properties
492510
/*
493511
* this either returns undefined meaning that it isn't valid
494512
* or returns an object where the keys are dashed short
@@ -504,19 +522,19 @@ exports.shorthandParser = function parse(v, shorthandFor) {
504522
});
505523
return obj;
506524
}
507-
525+
if (type === exports.TYPES.UNDEFINED) {
526+
return undefined;
527+
}
508528
if (typeof v === 'number') {
509529
v = v.toString();
510530
}
511-
512531
if (typeof v !== 'string') {
513532
return undefined;
514533
}
515-
516534
if (v.toLowerCase() === 'inherit') {
517535
return {};
518536
}
519-
var parts = getParts(v);
537+
var parts = splitValue(v);
520538
var valid = true;
521539
parts.forEach(function (part, i) {
522540
var partValid = false;
@@ -526,7 +544,9 @@ exports.shorthandParser = function parse(v, shorthandFor) {
526544
obj[property] = part;
527545
}
528546
});
529-
valid = valid && partValid;
547+
if (valid) {
548+
valid = partValid;
549+
}
530550
});
531551
if (!valid) {
532552
return undefined;
@@ -536,11 +556,16 @@ exports.shorthandParser = function parse(v, shorthandFor) {
536556

537557
exports.shorthandSetter = function (property, shorthandFor) {
538558
return function (v) {
559+
if (v === undefined) {
560+
return;
561+
}
562+
if (v === null) {
563+
v = '';
564+
}
539565
var obj = exports.shorthandParser(v, shorthandFor);
540566
if (obj === undefined) {
541567
return;
542568
}
543-
//console.log('shorthandSetter for:', property, 'obj:', obj);
544569
Object.keys(obj).forEach(function (subprop) {
545570
// in case subprop is an implicit property, this will clear
546571
// *its* subpropertiesX
@@ -698,12 +723,12 @@ exports.subImplicitSetter = function (prefix, part, isValid, parser) {
698723
};
699724
};
700725

701-
var camelToDashed = /[A-Z]/g;
702-
var firstSegment = /^\([^-]\)-/;
703-
var vendorPrefixes = ['o', 'moz', 'ms', 'webkit'];
704726
exports.camelToDashed = function (camelCase) {
727+
var upperCase = /[A-Z]/g;
728+
var firstSegment = /^\([^-]\)-/;
729+
var vendorPrefixes = ['o', 'moz', 'ms', 'webkit'];
705730
var match;
706-
var dashed = camelCase.replace(camelToDashed, '-$&').toLowerCase();
731+
var dashed = camelCase.replace(upperCase, '-$&').toLowerCase();
707732
match = dashed.match(firstSegment);
708733
if (match && vendorPrefixes.indexOf(match[1]) !== -1) {
709734
dashed = '-' + dashed;

0 commit comments

Comments
 (0)