Skip to content

Commit da3ec04

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

File tree

2 files changed

+209
-68
lines changed

2 files changed

+209
-68
lines changed

lib/parsers.js

Lines changed: 76 additions & 53 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,12 +505,12 @@ var getParts = function (str) {
489505
return parts;
490506
};
491507

492-
/*
493-
* this either returns undefined meaning that it isn't valid
494-
* or returns an object where the keys are dashed short
495-
* hand properties and the values are the values to set
496-
* on them
497-
*/
508+
// this either returns undefined meaning that it isn't valid
509+
// or returns an object where the keys are dashed short
510+
// hand properties and the values are the values to set
511+
// on them
512+
// FIXME: need additional argument which indicates syntax
513+
// and/or use Map() for shorthandFor to ensure order of the longhand properties
498514
exports.shorthandParser = function parse(v, shorthandFor) {
499515
var obj = {};
500516
var type = exports.valueType(v);
@@ -504,19 +520,19 @@ exports.shorthandParser = function parse(v, shorthandFor) {
504520
});
505521
return obj;
506522
}
507-
523+
if (type === exports.TYPES.UNDEFINED) {
524+
return undefined;
525+
}
508526
if (typeof v === 'number') {
509527
v = v.toString();
510528
}
511-
512529
if (typeof v !== 'string') {
513530
return undefined;
514531
}
515-
516532
if (v.toLowerCase() === 'inherit') {
517533
return {};
518534
}
519-
var parts = getParts(v);
535+
var parts = splitValue(v);
520536
var valid = true;
521537
parts.forEach(function (part, i) {
522538
var partValid = false;
@@ -526,21 +542,29 @@ exports.shorthandParser = function parse(v, shorthandFor) {
526542
obj[property] = part;
527543
}
528544
});
529-
valid = valid && partValid;
545+
if (valid) {
546+
valid = partValid;
547+
}
530548
});
531549
if (!valid) {
532550
return undefined;
533551
}
534552
return obj;
535553
};
536554

555+
// FIXME: check against shorthandParser and reduce Object.keys().forEach() loops
537556
exports.shorthandSetter = function (property, shorthandFor) {
538557
return function (v) {
558+
if (v === undefined) {
559+
return;
560+
}
561+
if (v === null) {
562+
v = '';
563+
}
539564
var obj = exports.shorthandParser(v, shorthandFor);
540565
if (obj === undefined) {
541566
return;
542567
}
543-
//console.log('shorthandSetter for:', property, 'obj:', obj);
544568
Object.keys(obj).forEach(function (subprop) {
545569
// in case subprop is an implicit property, this will clear
546570
// *its* subpropertiesX
@@ -572,6 +596,7 @@ exports.shorthandSetter = function (property, shorthandFor) {
572596
};
573597
};
574598

599+
// FIXME: move shorthandGetter() and shorthandSetter to CSSStyleDeclaration()
575600
exports.shorthandGetter = function (property, shorthandFor) {
576601
return function () {
577602
if (this._values[property] !== undefined) {
@@ -646,12 +671,10 @@ exports.implicitSetter = function (propertyBefore, propertyAfter, isValid, parse
646671
};
647672
};
648673

649-
//
650674
// Companion to implicitSetter, but for the individual parts.
651675
// This sets the individual value, and checks to see if all four
652676
// sub-parts are set. If so, it sets the shorthand version and removes
653677
// the individual parts from the cssText.
654-
//
655678
exports.subImplicitSetter = function (prefix, part, isValid, parser) {
656679
var property = prefix + '-' + part;
657680
var subparts = [prefix + '-top', prefix + '-right', prefix + '-bottom', prefix + '-left'];
@@ -698,12 +721,12 @@ exports.subImplicitSetter = function (prefix, part, isValid, parser) {
698721
};
699722
};
700723

701-
var camelToDashed = /[A-Z]/g;
702-
var firstSegment = /^\([^-]\)-/;
703-
var vendorPrefixes = ['o', 'moz', 'ms', 'webkit'];
704724
exports.camelToDashed = function (camelCase) {
725+
var upperCase = /[A-Z]/g;
726+
var firstSegment = /^\([^-]\)-/;
727+
var vendorPrefixes = ['o', 'moz', 'ms', 'webkit'];
705728
var match;
706-
var dashed = camelCase.replace(camelToDashed, '-$&').toLowerCase();
729+
var dashed = camelCase.replace(upperCase, '-$&').toLowerCase();
707730
match = dashed.match(firstSegment);
708731
if (match && vendorPrefixes.indexOf(match[1]) !== -1) {
709732
dashed = '-' + dashed;

0 commit comments

Comments
 (0)