From a87cb8808a42bd49241be574313a1fd8546ec521 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Tue, 8 Jun 2021 10:47:31 +0200 Subject: [PATCH] feat: custom var() Fixes https://github.com/jsdom/cssstyle/issues/125 --- lib/parsers.js | 139 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 27 deletions(-) diff --git a/lib/parsers.js b/lib/parsers.js index 0e07c242..0367c730 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -98,6 +98,7 @@ exports.parseInteger = function parseInteger(val) { if (numberRegEx.test(val)) { return String(parseInt(val, 10)); } + return exports.parseCustomVariable(val); }; exports.parseNumber = function parseNumber(val) { @@ -108,6 +109,7 @@ exports.parseNumber = function parseNumber(val) { if (numberRegEx.test(val)) { return String(parseFloat(val)); } + return exports.parseCustomVariable(val); }; exports.parseLength = function parseLength(val, resolve = false) { @@ -155,6 +157,7 @@ exports.parseLength = function parseLength(val, resolve = false) { } return number + unit; } + return exports.parseCustomVariable(val); }; exports.parsePercentage = function parsePercentage(val, resolve = false) { @@ -171,6 +174,7 @@ exports.parsePercentage = function parsePercentage(val, resolve = false) { if (percentageRegEx.test(val)) { return val; } + return exports.parseCustomVariable(val); }; exports.parseLengthOrPercentage = function parseLengthOrPercentage(val, resolve) { @@ -202,6 +206,7 @@ exports.parseAngle = function parseAngle(val, resolve = false) { } return number + unit; } + return exports.parseCustomVariable(val); }; exports.parseTime = function parseTime(val, resolve = false) { @@ -222,9 +227,15 @@ exports.parseTime = function parseTime(val, resolve = false) { } return number + unit; } + return exports.parseCustomVariable(val); }; exports.parseCalc = function parseCalc(val, parseOperand = exports.parseNumber) { + const variable = exports.parseCustomVariable(val); + if (variable) { + return variable; + } + const res = calcRegEx.exec(val); if (!res) { return undefined; @@ -358,47 +369,56 @@ exports.parseKeyword = function parseKeyword( if (valid.includes(lowerCaseValue)) { return lowerCaseValue; } + return exports.parseCustomVariable(val); }; exports.parseCustomIdentifier = function parseCustomIdentifier(val) { if (identRegEx.test(val) && !exports.parseKeyword(val) && val !== 'default') { return val; } + return exports.parseCustomVariable(val); +}; + +exports.parseDashedIdentifier = function parseDashedIdentifier(val) { + if (identRegEx.test(val) && val.startsWith('--')) { + return val; + } + return exports.parseCustomVariable(val); }; exports.parseUrl = function parseUrl(val) { var res = urlRegEx.exec(val); // does it match the regex? - if (!res) { - return undefined; - } - var str = res[1]; - // if it starts with single or double quotes, does it end with the same? - if ((str[0] === '"' || str[0] === "'") && str[0] !== str[str.length - 1]) { - return undefined; - } - if (str[0] === '"' || str[0] === "'") { - str = str.substr(1, str.length - 2); - } + if (res) { + var str = res[1]; + // if it starts with single or double quotes, does it end with the same? + if ((str[0] === '"' || str[0] === "'") && str[0] !== str[str.length - 1]) { + return undefined; + } + if (str[0] === '"' || str[0] === "'") { + str = str.substr(1, str.length - 2); + } - var i; - for (i = 0; i < str.length; i++) { - switch (str[i]) { - case '(': - case ')': - case ' ': - case '\t': - case '\n': - case "'": - case '"': - return undefined; - case '\\': - i++; - break; + var i; + for (i = 0; i < str.length; i++) { + switch (str[i]) { + case '(': + case ')': + case ' ': + case '\t': + case '\n': + case "'": + case '"': + return undefined; + case '\\': + i++; + break; + } } - } - return 'url(' + str + ')'; + return 'url(' + str + ')'; + } + return exports.parseCustomVariable(val); }; exports.parseString = function parseString(val) { @@ -421,9 +441,15 @@ exports.parseString = function parseString(val) { } return val; } + return exports.parseCustomVariable(val); }; exports.parseColor = function parseColor(val) { + const variable = exports.parseCustomVariable(val); + if (variable) { + return variable; + } + var red, green, blue, @@ -535,6 +561,65 @@ exports.parseColor = function parseColor(val) { return exports.parseKeyword(val, namedColors); }; +exports.parseCustomVariable = function parseCustomVariable(val) { + let before = ''; + let call = ''; + let i = -1; + let char; + while ((char = val[++i]) && call !== 'var(') { + if (/[var(]/i.test(char)) { + if ('var('.startsWith(call)) { + call += char.toLowerCase(); + } else { + before += call; + call = char; + } + } else { + before += call; + call = ''; + before += char; + } + } + + if (call !== 'var(') { + return undefined; + } + + let open = 1; + let j = i; + while ((char = val[++j]) && open > 0) { + if (char === '(') { + open++; + } else if (char === ')') { + open--; + } + } + + const splitIndex = open ? j : j - 1; + const stringArgs = val.slice(i, splitIndex); + const after = val.slice(splitIndex) || ''; + const [args] = exports.splitTokens(stringArgs, /,/); + const property = exports.parseDashedIdentifier(args.shift()); + + if (!property) { + return undefined; + } + + const parsedArgs = [property]; + for (let i = 0; i < args.length; i++) { + let arg = args[i]; + if (arg.toLowerCase().startsWith('var(')) { + arg = parseCustomVariable(arg); + if (arg === undefined) { + return undefined; + } + } + parsedArgs.push(arg); + } + + return `${before}var(${parsedArgs.join(', ')}${after}`; +}; + // utility to translate from border-width to borderWidth var dashedToCamelCase = function(dashed) { var i;