From b5dc4ed540de341ee9d7ddad95e95cf803c8c25f Mon Sep 17 00:00:00 2001 From: jaywcjlove <398188662@qq.com> Date: Sun, 10 Jul 2022 14:56:58 +0800 Subject: [PATCH] fix: enhanced hsl matching. --- src/__tests__/index.test.ts | 89 ++++++++++++++++++++++++++++++++++--- src/index.ts | 34 ++++---------- 2 files changed, 93 insertions(+), 30 deletions(-) diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 86fa4fa..9ee8de0 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -4,14 +4,23 @@ it('=> gradsToDegrees("200")', () => expect(gradsToDegrees('200')).toEqual(180)) it('=> gradsToDegrees(200)', () => expect(gradsToDegrees(200)).toEqual(180)); it('=> gradsToDegrees(-200)', () => expect(gradsToDegrees(200)).toEqual(180)); it('=> gradsToDegrees(+200)', () => expect(gradsToDegrees(200)).toEqual(180)); - it('=> radiansToDegrees(3.14)', () => expect(radiansToDegrees(3.14)).toEqual(180)); - it('=> hsl() ❌ ', () => expect(hslMatcher('')).toBeUndefined()); it('=> hsl() ❌ ', () => expect(hslMatcher('hsl()')).toBeUndefined()); it('=> hsl("") ❌ ', () => expect(hslMatcher('hsl("")')).toBeUndefined()); it('=> hsl("~~~~") ❌ ', () => expect(hslMatcher('hsl("~~~")')).toBeUndefined()); -it('=> hsl(240, 100%, 50%, 23x) ❌ ', () => expect(hslMatcher('hsl(240, 100%, 50%, 23x)')).toBeFalsy()); +it('=> hsl(240, 100%, 50%, 23x) ❌ ', () => expect(hslMatcher('hsl(240, 100%, 50%, 23x)')).toBeUndefined()); +it('=> hsl(.9 .99% .999%/ ) ❌ ', () => expect(hslMatcher('hsl(.9 .99% .999%/ )')).toBeUndefined()); +it('=> hsl(.9 .99% .999%, ) ❌ ', () => expect(hslMatcher('hsl(.9 .99% .999%, )')).toBeUndefined()); +it('=> hsl(.9, .99% .999% ) ❌ ', () => expect(hslMatcher('hsl(.9, .99% .999% )')).toBeUndefined()); + +it('=> hsl(.9, .99%, -.999% ) ✅ ', () => + expect(hslMatcher('hsl(.9, .99%, -.999% )')).toEqual({ + h: '.9', + s: '.99%', + l: '-.999%', + a: undefined, + })); it('=> hsl(240, 100%, 50% ) ✅ ', () => expect(hslMatcher('hsl(240, 100%, 50% )')).toEqual({ @@ -109,8 +118,6 @@ it('=> hsl(.9, .99%, .999%, .9999) ✅ ', () => s: '.99%', })); -it('=> hsl(.9, .99%, .999%, ) ❌ ', () => expect(hslMatcher('hsl(.9, .99%, .999%, )')).toBeUndefined()); - it('=> hsl(0240, 0100%, 0050%, 01) ✅ ', () => expect(hslMatcher('hsl(0240, 0100%, 0050%, 01)')).toEqual({ a: '01', @@ -151,6 +158,14 @@ it('=> hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3) ✅ ', () => a: '1E-3', })); +it('=> hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3%) ✅ ', () => + expect(hslMatcher('hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3%)')).toEqual({ + h: '2.40e+2', + s: '1.00e+2%', + l: '5.00e+1%', + a: '1E-3%', + })); + // space separated (CSS Color Level 4) it('=> hsl(240 100% 50%) ✅ ', () => expect(hslMatcher('hsl(240 100% 50%)')).toEqual({ @@ -229,6 +244,30 @@ it('=> hlsStringToRGB("hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3)")', () => a: 0.001, })); +it('=> hlsStringToRGB("hsl(2.40e+2turn, 1.00e+2%, 5.00e+1%, 1E-3)")', () => + expect(hlsStringToRGB('hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3)')).toEqual({ + r: 0, + g: 0, + b: 255, + a: 0.001, + })); + +it('=> hlsStringToRGB("hsl(2.40e+2 1.00e+2% 5.00e+1% / 1E-3)")', () => + expect(hlsStringToRGB('hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3)')).toEqual({ + r: 0, + g: 0, + b: 255, + a: 0.001, + })); + +it('=> hlsStringToRGB("hsl(2.40e+2deg 1.00e+2% 5.00e+1% / 1E-3)")', () => + expect(hlsStringToRGB('hsl(2.40e+2deg 1.00e+2% 5.00e+1% / 1E-3)')).toEqual({ + r: 0, + g: 0, + b: 255, + a: 0.001, + })); + it('=> hlsStringToRGB("hsl(180deg, 100%, 50%, 0.1)")', () => expect(hlsStringToRGB('hsl(180deg, 100%, 50%, 0.1)')).toEqual({ r: 0, @@ -237,6 +276,14 @@ it('=> hlsStringToRGB("hsl(180deg, 100%, 50%, 0.1)")', () => a: 0.1, })); +it('=> hlsStringToRGB("hsl(180deg 100% 50% / 0.1)")', () => + expect(hlsStringToRGB('hsl(180deg, 100%, 50%, 0.1)')).toEqual({ + r: 0, + g: 255, + b: 255, + a: 0.1, + })); + it('=> hlsStringToRGB("hsl(0.5turn, 100%, 50%, 0.1)")', () => expect(hlsStringToRGB('hsl(0.5turn, 100%, 50%, 0.1)')).toEqual({ r: 0, @@ -245,6 +292,14 @@ it('=> hlsStringToRGB("hsl(0.5turn, 100%, 50%, 0.1)")', () => a: 0.1, })); +it('=> hlsStringToRGB("hsl(190deg 100% 36% / 53%)")', () => + expect(hlsStringToRGB('hsl(190deg 100% 36% / 53%)')).toEqual({ + r: 0, + g: 153, + b: 184, + a: 0.53, + })); + it('=> hlsStringToRGB("hsl(-240, -100%, -50%, -0.1)")', () => expect(hlsStringToRGB('hsl(-240, -100%, -50%, -0.1)')).toEqual({ r: 0, @@ -316,6 +371,30 @@ it('=> hlsStringToRGB("hsl(.9, .99%, .999%, .9999)")', () => a: 0.9999, })); +it('=> hlsStringToRGB("hsl(.9deg, .99%, .999%, .9999)")', () => + expect(hlsStringToRGB('hsl(.9deg, .99%, .999%, .9999)')).toEqual({ + r: 3, + g: 3, + b: 3, + a: 0.9999, + })); + +it('=> hlsStringToRGB("hsl(-.9deg, .99%, .999%, .9999)")', () => + expect(hlsStringToRGB('hsl(.9deg, .99%, .999%, .9999)')).toEqual({ + r: 3, + g: 3, + b: 3, + a: 0.9999, + })); + +it('=> hlsStringToRGB("hsl(+.9deg, .99%, .999%, .9999)")', () => + expect(hlsStringToRGB('hsl(.9deg, .99%, .999%, .9999)')).toEqual({ + r: 3, + g: 3, + b: 3, + a: 0.9999, + })); + it('=> hlsStringToRGB("hsl(240.5, 99.99%, 49.999%, 0.9999)")', () => expect(hlsStringToRGB('hsl(240.5, 99.99%, 49.999%, 0.9999)')).toEqual({ r: 2, diff --git a/src/index.ts b/src/index.ts index fb764ea..0378a58 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,7 @@ const MATCHER = - /hsla?\(\s*(\+?-?\d+\.?\d+(?:e\+)?(\d+)?(?:deg|rad|grad|turn)?)\s*,\s*(\+?\-?\d+\.?\d*?%)\s*,\s*(\+?\-?\d+\.?\d*?%)\s*(,\s*?\d*%|,\s*\+?-?\d*\.?\d*)?\s*\)/i; -// hsl(.9, .99%, .999%) // ✅✅✅✅ -// hsl(.9, .99%, .999%, .9999) // fraction w/o leading zero -const MATCHER2 = /hsla?\(\s*(\.\d*)\s*,\s*(\.\d*%)\s*,\s*(\.\d*%)\s*(,\s*\.\d*\s*)?\)/i; -// hsl(240 100% 50%) // ✅✅✅✅ -// hsl(240 100% 50% / 0.1) // space separated with opacity -const MATCHER3 = /hsla?\(\s*(\d*)\s\s*(\d*%)\s\s*(\d*%)\s*(\/\s*\d*.\d*\s*)?\)/i; -// hsl(2.40e+2, 1.00e+2%, 5.00e+1%, 1E-3) -const MATCHER4 = /hsla?\(\s*(\d*.\d*e\+\d*)\s*,\s*(\d*.\d*e\+\d*%),\s*(\d*.\d*e\+\d*%)\s*(,\s*\d*E-\d*)?/i; + /hsla?\(\s*(\+?-?\d*\.?\d*(?:e\+)?(?:\d*)?(?:deg|rad|grad|turn)?)\s*,\s*(\+?\-?\d*\.?\d*(?:e\+)?(?:\d*)?%)\s*,\s*(\+?\-?\d*\.?\d*(?:e\+)?(?:\d*)?%)\s*(,\s*\+?\-?\s*(?:\d*\.?\d*(?:E-\d*)?%?)?)?\s*\)/i; +const MATCHER_SPACE = + /hsla?\(\s*(\+?-?\d*\.?\d*(?:e\+)?(?:\d*)?(?:deg|rad|grad|turn)?)\s*(\+?\-?\d*\.?\d*(?:e\+)?(?:\d*)?%)\s*(\+?\-?\d*\.?\d*(?:e\+)?(?:\d*)?%)\s*(\/\s*\+?\-?\s*(?:\d*\.?\d*(?:E-\d*)?%?)?)?\s*\)/i; const aStr = (a?: string) => (a ? a.replace(/^(,|\/)\s*/, '').trim() : a); @@ -33,22 +27,11 @@ export interface HSLAObjectStringColor extends HSLObjectStringColor { /** Convert HLS string to HLS object or verify whether hls is valid */ export default function hslMatcher(hsl: string = ''): HSLAObjectStringColor | undefined { - const match = MATCHER.exec(hsl); + const match = MATCHER.exec(hsl) || MATCHER_SPACE.exec(hsl); if (!!match) { - const [_, h, __, s, l, a] = match; - return { - h, - s, - l, - a: aStr(a), - }; - } - const match2 = MATCHER2.exec(hsl); - const match3 = MATCHER3.exec(hsl); - const match4 = MATCHER4.exec(hsl); - const arr = match2 || match3 || match4; - if (!!arr) { - const [_, h, s, l, a] = arr; + const [_, h, s, l, a] = match; + if (a && a.trim() === ',') return; + if (a && a.trim() === '/') return; return { h, s, @@ -144,7 +127,8 @@ export function hlsStringToRGB(hls: string): RGBColor | RGBAColor | undefined { * Values outside the range [0,1] are not invalid, but are clamped to that range when computed. */ if (alphaStr && /^\+?-?\d*(E-\d*|.\d*%?)?$/.test(alphaStr)) { - return { r: toFixed(255 * f(0)), g: toFixed(255 * f(8)), b: toFixed(255 * f(4)), a: Number(alphaStr) }; + const alpha = /%/g.test(alphaStr) ? Number(alphaStr.replace(/%/g, '')) / 100 : Number(alphaStr); + return { r: toFixed(255 * f(0)), g: toFixed(255 * f(8)), b: toFixed(255 * f(4)), a: alpha }; } return { r: toFixed(255 * f(0)), g: toFixed(255 * f(8)), b: toFixed(255 * f(4)) }; }