From cd7a423323efad7d55542cf03589a378bc44613f Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 14 Dec 2024 10:37:39 +0900 Subject: [PATCH] Update valueType(), parseColor() --- lib/parsers.js | 165 +----------------------------------- lib/utils/colorSpace.js | 19 ----- test/CSSStyleDeclaration.js | 12 ++- test/parsers.js | 7 ++ 4 files changed, 20 insertions(+), 183 deletions(-) delete mode 100644 lib/utils/colorSpace.js diff --git a/lib/parsers.js b/lib/parsers.js index bacd50e..78d0214 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -4,9 +4,7 @@ ********************************************************************/ 'use strict'; -const { resolve } = require('@asamuzakjp/css-color'); -const namedColors = require('./named_colors.json'); -const { hslToRgb } = require('./utils/colorSpace'); +const { isColor, resolve } = require('@asamuzakjp/css-color'); exports.TYPES = { INTEGER: 1, @@ -29,12 +27,7 @@ var lengthRegEx = /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch var percentRegEx = /^[-+]?[0-9]*\.?[0-9]+%$/; var urlRegEx = /^url\(\s*([^)]*)\s*\)$/; var stringRegEx = /^("[^"]*"|'[^']*')$/; -var colorRegEx1 = /^#([0-9a-fA-F]{3,4}){1,2}$/; -var colorRegEx2 = /^rgb\(([^)]*)\)$/; -var colorRegEx3 = /^rgba\(([^)]*)\)$/; var calcRegEx = /^calc\(([^)]*)\)$/; -var colorRegEx4 = - /^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/; var angleRegEx = /^([-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/; // This will return one of the above types based on the passed in string @@ -74,53 +67,12 @@ exports.valueType = function valueType(val) { if (angleRegEx.test(val)) { return exports.TYPES.ANGLE; } - if (colorRegEx1.test(val)) { + if (isColor(val)) { return exports.TYPES.COLOR; } - var res = colorRegEx2.exec(val); - var parts; - if (res !== null) { - parts = res[1].split(/\s*,\s*/); - if (parts.length !== 3) { - return undefined; - } - if ( - parts.every(percentRegEx.test.bind(percentRegEx)) || - parts.every(integerRegEx.test.bind(integerRegEx)) - ) { - return exports.TYPES.COLOR; - } - return undefined; - } - res = colorRegEx3.exec(val); - if (res !== null) { - parts = res[1].split(/\s*,\s*/); - if (parts.length !== 4) { - return undefined; - } - if ( - parts.slice(0, 3).every(percentRegEx.test.bind(percentRegEx)) || - parts.slice(0, 3).every(integerRegEx.test.bind(integerRegEx)) - ) { - if (numberRegEx.test(parts[3])) { - return exports.TYPES.COLOR; - } - } - return undefined; - } - - if (colorRegEx4.test(val)) { - return exports.TYPES.COLOR; - } - - // could still be a color, one of the standard keyword colors val = val.toLowerCase(); - if (namedColors.includes(val)) { - return exports.TYPES.COLOR; - } - switch (val) { // the following are deprecated in CSS3 case 'activeborder': @@ -292,119 +244,10 @@ exports.parseColor = function parseColor(val) { if (type === exports.TYPES.NULL_OR_EMPTY_STR) { return val; } - var red, - green, - blue, - hue, - saturation, - lightness, - alpha = 1; - var parts; - var res = colorRegEx1.exec(val); - // is it #aaa, #ababab, #aaaa, #abababaa - if (res) { - var defaultHex = val.substr(1); - var hex = val.substr(1); - if (hex.length === 3 || hex.length === 4) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - - if (defaultHex.length === 4) { - hex = hex + defaultHex[3] + defaultHex[3]; - } - } - red = parseInt(hex.substr(0, 2), 16); - green = parseInt(hex.substr(2, 2), 16); - blue = parseInt(hex.substr(4, 2), 16); - if (hex.length === 8) { - var hexAlpha = hex.substr(6, 2); - var hexAlphaToRgbaAlpha = Number((parseInt(hexAlpha, 16) / 255).toFixed(3)); - - return 'rgba(' + red + ', ' + green + ', ' + blue + ', ' + hexAlphaToRgbaAlpha + ')'; - } - return 'rgb(' + red + ', ' + green + ', ' + blue + ')'; - } - - res = val.includes(',') && colorRegEx2.exec(val); - if (res) { - parts = res[1].split(/\s*,\s*/); - if (parts.length !== 3) { - return undefined; - } - if (parts.every(percentRegEx.test.bind(percentRegEx))) { - red = Math.floor((parseFloat(parts[0].slice(0, -1)) * 255) / 100); - green = Math.floor((parseFloat(parts[1].slice(0, -1)) * 255) / 100); - blue = Math.floor((parseFloat(parts[2].slice(0, -1)) * 255) / 100); - } else if (parts.every(integerRegEx.test.bind(integerRegEx))) { - red = parseInt(parts[0], 10); - green = parseInt(parts[1], 10); - blue = parseInt(parts[2], 10); - } else { - return undefined; - } - red = Math.min(255, Math.max(0, red)); - green = Math.min(255, Math.max(0, green)); - blue = Math.min(255, Math.max(0, blue)); - return 'rgb(' + red + ', ' + green + ', ' + blue + ')'; - } - - res = val.includes(',') && colorRegEx3.exec(val); - if (res) { - parts = res[1].split(/\s*,\s*/); - if (parts.length !== 4) { - return undefined; - } - if (parts.slice(0, 3).every(percentRegEx.test.bind(percentRegEx))) { - red = Math.floor((parseFloat(parts[0].slice(0, -1)) * 255) / 100); - green = Math.floor((parseFloat(parts[1].slice(0, -1)) * 255) / 100); - blue = Math.floor((parseFloat(parts[2].slice(0, -1)) * 255) / 100); - alpha = parseFloat(parts[3]); - } else if (parts.slice(0, 3).every(integerRegEx.test.bind(integerRegEx))) { - red = parseInt(parts[0], 10); - green = parseInt(parts[1], 10); - blue = parseInt(parts[2], 10); - alpha = parseFloat(parts[3]); - } else { - return undefined; - } - if (isNaN(alpha)) { - alpha = 1; - } - red = Math.min(255, Math.max(0, red)); - green = Math.min(255, Math.max(0, green)); - blue = Math.min(255, Math.max(0, blue)); - alpha = Math.min(1, Math.max(0, alpha)); - if (alpha === 1) { - return 'rgb(' + red + ', ' + green + ', ' + blue + ')'; - } - return 'rgba(' + red + ', ' + green + ', ' + blue + ', ' + alpha + ')'; - } - - res = colorRegEx4.exec(val); - if (res) { - const [, _hue, _saturation, _lightness, _alphaString = ''] = res; - const _alpha = parseFloat(_alphaString.replace(',', '').trim()); - if (!_hue || !_saturation || !_lightness) { - return undefined; - } - hue = parseFloat(_hue); - saturation = parseInt(_saturation, 10); - lightness = parseInt(_lightness, 10); - if (_alpha && numberRegEx.test(_alpha)) { - alpha = parseFloat(_alpha); - } - - const [r, g, b] = hslToRgb(hue, saturation / 100, lightness / 100); - if (!_alphaString || alpha === 1) { - return 'rgb(' + r + ', ' + g + ', ' + b + ')'; - } - return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')'; - } - - if (type === exports.TYPES.COLOR) { + if (/^[a-z]+$/i.test(val) && type === exports.TYPES.COLOR) { return val; } - - res = resolve(val, { + var res = resolve(val, { format: 'specifiedValue', }); if (res) { diff --git a/lib/utils/colorSpace.js b/lib/utils/colorSpace.js deleted file mode 100644 index 83be60a..0000000 --- a/lib/utils/colorSpace.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; - -const MAX_HUE = 360; -const COLOR_NB = 12; -const MAX_RGB_VALUE = 255; - -// https://www.w3.org/TR/css-color-4/#hsl-to-rgb -exports.hslToRgb = (hue, sat, light) => { - hue = hue % MAX_HUE; - if (hue < 0) { - hue += MAX_HUE; - } - function f(n) { - const k = (n + hue / (MAX_HUE / COLOR_NB)) % COLOR_NB; - const a = sat * Math.min(light, 1 - light); - return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); - } - return [f(0), f(8), f(4)].map((value) => Math.round(value * MAX_RGB_VALUE)); -}; diff --git a/test/CSSStyleDeclaration.js b/test/CSSStyleDeclaration.js index b2f20a2..62f35d0 100644 --- a/test/CSSStyleDeclaration.js +++ b/test/CSSStyleDeclaration.js @@ -183,9 +183,9 @@ describe('CSSStyleDeclaration', () => { style.color = 'rgba(0,0,0,0)'; assert.strictEqual(style.color, 'rgba(0, 0, 0, 0)'); style.color = 'rgba(5%, 10%, 20%, 0.4)'; - assert.strictEqual(style.color, 'rgba(12, 25, 51, 0.4)'); + assert.strictEqual(style.color, 'rgba(13, 26, 51, 0.4)'); style.color = 'rgb(33%, 34%, 33%)'; - assert.strictEqual(style.color, 'rgb(84, 86, 84)'); + assert.strictEqual(style.color, 'rgb(84, 87, 84)'); style.color = 'rgba(300, 200, 100, 1.5)'; assert.strictEqual(style.color, 'rgb(255, 200, 100)'); style.color = 'hsla(0, 1%, 2%, 0.5)'; @@ -199,13 +199,19 @@ describe('CSSStyleDeclaration', () => { style.color = 'currentcolor'; assert.strictEqual(style.color, 'currentcolor'); style.color = '#ffffffff'; - assert.strictEqual(style.color, 'rgba(255, 255, 255, 1)'); + assert.strictEqual(style.color, 'rgb(255, 255, 255)'); style.color = '#fffa'; assert.strictEqual(style.color, 'rgba(255, 255, 255, 0.667)'); style.color = '#ffffff66'; assert.strictEqual(style.color, 'rgba(255, 255, 255, 0.4)'); }); + it('invalid hex color value', () => { + var style = new CSSStyleDeclaration(); + style.color = '#1234567'; + assert.strictEqual(style.color, ''); + }); + it('short hand properties with embedded spaces', () => { var style = new CSSStyleDeclaration(); style.background = 'rgb(0, 0, 0) url(/something/somewhere.jpg)'; diff --git a/test/parsers.js b/test/parsers.js index 2b73fcb..a5acf4a 100644 --- a/test/parsers.js +++ b/test/parsers.js @@ -167,6 +167,13 @@ describe('parseColor', () => { assert.strictEqual(output, 'color-mix(in srgb, rgb(255, 0, 0), rgb(0, 0, 255))'); }); + it('should not remove comments, trim or lower case letters if var() is used', () => { + let input = 'var( --custom-Color /* comment */)'; + let output = parsers.parseColor(input); + + assert.strictEqual(output, 'var( --custom-Color /* comment */)'); + }); + it.todo('Add more tests'); }); describe('parseAngle', () => {