From 39d6a7b23d8b6ce2c1b9d7f21f8b4accdb3ad494 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sun, 17 May 2026 14:34:48 +0900 Subject: [PATCH] Move isColor --- src/index.ts | 2 +- src/js/css-gradient.ts | 4 +- src/js/css-var.ts | 2 +- src/js/resolve.ts | 39 ++++++++++++++++ src/js/util.ts | 39 ---------------- test/resolve.test.ts | 101 +++++++++++++++++++++++++++++++++++++++++ test/util.test.ts | 101 ----------------------------------------- 7 files changed, 144 insertions(+), 144 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9516d40..72304de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,9 +8,9 @@ import { cssCalc } from './js/css-calc'; import { isGradient, resolveGradient } from './js/css-gradient'; import { cssVar } from './js/css-var'; +import { isColor } from './js/resolve'; import { extractDashedIdent, - isColor, resolveLengthInPixels, splitValue } from './js/util'; diff --git a/src/js/css-gradient.ts b/src/js/css-gradient.ts index 8693131..96a5ebe 100644 --- a/src/js/css-gradient.ts +++ b/src/js/css-gradient.ts @@ -3,10 +3,10 @@ */ import { createCacheKey, getCache, setCache } from './cache'; -import { resolveColor } from './resolve'; import { isString } from './common'; +import { isColor, resolveColor } from './resolve'; import { MatchedRegExp, Options } from './typedef'; -import { isColor, splitValue } from './util'; +import { splitValue } from './util'; /* constants */ import { diff --git a/src/js/css-var.ts b/src/js/css-var.ts index c97ef6f..764789b 100644 --- a/src/js/css-var.ts +++ b/src/js/css-var.ts @@ -6,7 +6,7 @@ import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer'; import { createCacheKey, getCache, setCache } from './cache'; import { isString } from './common'; import { cssCalc } from './css-calc'; -import { isColor } from './util'; +import { isColor } from './resolve'; import { Options } from './typedef'; /* constants */ diff --git a/src/js/resolve.ts b/src/js/resolve.ts index 74be6f9..fbda5f7 100644 --- a/src/js/resolve.ts +++ b/src/js/resolve.ts @@ -4,6 +4,7 @@ import { createCacheKey, getCache, setCache } from './cache'; import { + NAMED_COLORS, convertRgbToHex, resolveColorFunc, resolveColorMix, @@ -24,10 +25,12 @@ import { import { FN_COLOR, FN_MIX, + SYN_COLOR_TYPE, SYN_FN_CALC, SYN_FN_LIGHT_DARK, SYN_FN_REL, SYN_FN_VAR, + SYN_MIX, VAL_COMP, VAL_SPEC } from './constant'; @@ -35,10 +38,14 @@ const NAMESPACE = 'resolve'; const RGB_TRANSPARENT = 'rgba(0, 0, 0, 0)'; /* regexp */ +const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`); const REG_FN_CALC = new RegExp(SYN_FN_CALC); +const REG_FN_COLOR = + /^(?:(?:ok)?l(?:ab|ch)|color(?:-mix)?|hsla?|hwb|rgba?|var)\(/; const REG_FN_LIGHT_DARK = new RegExp(SYN_FN_LIGHT_DARK); const REG_FN_REL = new RegExp(SYN_FN_REL); const REG_FN_VAR = new RegExp(SYN_FN_VAR); +const REG_MIX = new RegExp(SYN_MIX); /** * resolve color @@ -311,3 +318,35 @@ export const resolve = (value: string, opt: Options = {}): string | null => { opt.nullable = false; return resolveColor(value, opt); }; + +/** + * is color + * @param value - CSS value + * @param [opt] - options + * @returns result + */ +export const isColor = (value: unknown, opt: Options = {}): boolean => { + if (!isString(value)) { + return false; + } + const str = value.toLowerCase().trim(); + if (!str) { + return false; + } + if (/^[a-z]+$/.test(str)) { + return ( + str === 'currentcolor' || + str === 'transparent' || + Object.hasOwn(NAMED_COLORS, str) + ); + } + if (REG_COLOR.test(str) || REG_MIX.test(str)) { + return true; + } + if (REG_FN_COLOR.test(str)) { + const colorOpt = { ...opt, nullable: true }; + if (!colorOpt.format) colorOpt.format = VAL_SPEC; + return !!resolveColor(str, colorOpt); + } + return false; +}; diff --git a/src/js/util.ts b/src/js/util.ts index 2ce3ce5..1c2d703 100644 --- a/src/js/util.ts +++ b/src/js/util.ts @@ -5,12 +5,9 @@ import { TokenType, tokenize } from '@csstools/css-tokenizer'; import { CacheItem, createCacheKey, getCache, setCache } from './cache'; import { isString } from './common'; -import { resolveColor } from './resolve'; import { Options } from './typedef'; /* constants */ -import { NAMED_COLORS } from './color'; -import { SYN_COLOR_TYPE, SYN_MIX, VAL_SPEC } from './constant'; const { CloseParen: PAREN_CLOSE, Comma: COMMA, @@ -30,10 +27,6 @@ const DEG = 360; const DEG_HALF = 180; /* regexp */ -const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`); -const REG_FN_COLOR = - /^(?:(?:ok)?l(?:ab|ch)|color(?:-mix)?|hsla?|hwb|rgba?|var)\(/; -const REG_MIX = new RegExp(SYN_MIX); const REG_DASHED_IDENT = /--[\w-]+/g; const REG_COMMA = /^,$/; const REG_SLASH = /^\/$/; @@ -166,38 +159,6 @@ export const extractDashedIdent = (value: string): string[] => { return res; }; -/** - * is color - * @param value - CSS value - * @param [opt] - options - * @returns result - */ -export const isColor = (value: unknown, opt: Options = {}): boolean => { - if (!isString(value)) { - return false; - } - const str = value.toLowerCase().trim(); - if (!str) { - return false; - } - if (/^[a-z]+$/.test(str)) { - return ( - str === 'currentcolor' || - str === 'transparent' || - Object.hasOwn(NAMED_COLORS, str) - ); - } - if (REG_COLOR.test(str) || REG_MIX.test(str)) { - return true; - } - if (REG_FN_COLOR.test(str)) { - const colorOpt = { ...opt, nullable: true }; - if (!colorOpt.format) colorOpt.format = VAL_SPEC; - return !!resolveColor(str, colorOpt); - } - return false; -}; - /** * round to specified precision * @param value - numeric value diff --git a/test/resolve.test.ts b/test/resolve.test.ts index 09fdc9d..076bd55 100644 --- a/test/resolve.test.ts +++ b/test/resolve.test.ts @@ -1840,3 +1840,104 @@ describe('resolve', () => { assert.strictEqual(res2, '', 'result'); }); }); + +describe('is color', () => { + const func = api.isColor; + + it('should get false', () => { + const res = func(); + assert.strictEqual(res, false, 'result'); + }); + + it('should get false', () => { + const res = func(''); + assert.strictEqual(res, false, 'result'); + }); + + it('should get false', () => { + const res = func('foo'); + assert.strictEqual(res, false, 'result'); + }); + + it('should get true', () => { + const res = func('red'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func('currentcolor'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func('transparent'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func('color(srgb 0 127.5 0)'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func('color-mix(in oklab, red, blue)'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func('rgb(from rebeccapurple r g b)'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get false', () => { + const res = func('rgb(from rebeccapurple l a b)'); + assert.strictEqual(res, false, 'result'); + }); + + it('should get true', () => { + const res = func('var(--foo)'); + assert.strictEqual(res, true, 'result'); + }); + + it('should get true', () => { + const res = func( + 'color-mix(in oklab, green, color-mix(in srgb, red, transparent))', + { + format: 'computedColor' + } + ); + assert.strictEqual(res, true, 'result'); + }); + + it('should get false', () => { + const res = func( + // Invalid color space + 'color-mix(in oklab, green, color-mix(in rgb, red, transparent))', + { + format: 'computedColor' + } + ); + assert.strictEqual(res, false, 'result'); + }); + + it('should get true', () => { + const res = func( + // Missing close paren should be okay + 'color-mix(in oklab, green, color-mix(in srgb, red, transparent)', + { + format: 'computedColor' + } + ); + assert.strictEqual(res, true, 'result'); + }); + + it('should get false', () => { + const res = func('url(var(--foo))'); + assert.strictEqual(res, false, 'result'); + }); + + it('should get false', () => { + const res = func('radial-gradient(transparent, var(--custom-color))'); + assert.strictEqual(res, false, 'result'); + }); +}); diff --git a/test/util.test.ts b/test/util.test.ts index c750f8f..bf687f2 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -221,107 +221,6 @@ describe('extract dashed-ident tokens', () => { }); }); -describe('is color', () => { - const func = util.isColor; - - it('should get false', () => { - const res = func(); - assert.strictEqual(res, false, 'result'); - }); - - it('should get false', () => { - const res = func(''); - assert.strictEqual(res, false, 'result'); - }); - - it('should get false', () => { - const res = func('foo'); - assert.strictEqual(res, false, 'result'); - }); - - it('should get true', () => { - const res = func('red'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func('currentcolor'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func('transparent'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func('color(srgb 0 127.5 0)'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func('color-mix(in oklab, red, blue)'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func('rgb(from rebeccapurple r g b)'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get false', () => { - const res = func('rgb(from rebeccapurple l a b)'); - assert.strictEqual(res, false, 'result'); - }); - - it('should get true', () => { - const res = func('var(--foo)'); - assert.strictEqual(res, true, 'result'); - }); - - it('should get true', () => { - const res = func( - 'color-mix(in oklab, green, color-mix(in srgb, red, transparent))', - { - format: 'computedColor' - } - ); - assert.strictEqual(res, true, 'result'); - }); - - it('should get false', () => { - const res = func( - // Invalid color space - 'color-mix(in oklab, green, color-mix(in rgb, red, transparent))', - { - format: 'computedColor' - } - ); - assert.strictEqual(res, false, 'result'); - }); - - it('should get true', () => { - const res = func( - // Missing close paren should be okay - 'color-mix(in oklab, green, color-mix(in srgb, red, transparent)', - { - format: 'computedColor' - } - ); - assert.strictEqual(res, true, 'result'); - }); - - it('should get false', () => { - const res = func('url(var(--foo))'); - assert.strictEqual(res, false, 'result'); - }); - - it('should get false', () => { - const res = func('radial-gradient(transparent, var(--custom-color))'); - assert.strictEqual(res, false, 'result'); - }); -}); - describe('round to specified precision', () => { const func = util.roundToPrecision;