diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8a6a2873..9c91a923 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,3 +1,5 @@ +'use strict'; + module.exports = { root: true, parser: '@typescript-eslint/parser', @@ -5,6 +7,7 @@ module.exports = { parserOptions: { project: true, tsconfigRootDir: __dirname, + project: ['./tsconfig.eslint.json'], }, extends: [ 'plugin:@typescript-eslint/recommended-type-checked', diff --git a/package-lock.json b/package-lock.json index 7ce260ce..acc6a8d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,11 @@ "version": "0.11.1", "license": "Apache-2.0", "dependencies": { - "glob-to-regexp": "^0.4.1" + "minimatch": "^10.0.1" }, "devDependencies": { "@types/chai": "5.0.0", "@types/glob": "^8.1.0", - "@types/glob-to-regexp": "^0.4.4", "@types/mocha": "^10.0.9", "@types/node": "^12.0.0", "@types/vscode": "^1.54.0", @@ -94,6 +93,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -118,6 +139,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -262,12 +305,6 @@ "@types/node": "*" } }, - "node_modules/@types/glob-to-regexp": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz", - "integrity": "sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==", - "dev": true - }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -435,15 +472,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -677,8 +705,7 @@ "node_modules/balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "node_modules/base64-js": { "version": "1.5.1", @@ -738,13 +765,11 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -962,7 +987,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/core-util-is": { @@ -1202,6 +1227,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -1239,6 +1274,18 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -1495,10 +1542,27 @@ "node": ">= 6" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, "node_modules/globals": { "version": "13.24.0", @@ -1874,15 +1938,17 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha": { @@ -1920,15 +1986,6 @@ "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", diff --git a/package.json b/package.json index 79788b75..4c1ff399 100644 --- a/package.json +++ b/package.json @@ -182,15 +182,15 @@ } }, "scripts": { - "vscode:prepublish": "tsc -p ./", - "compile": "tsc -watch -p ./", + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "watch": "tsc -watch -p ./", "lint": "eslint .", "test": "npm run vscode:prepublish && node ./out/test/runTest.js" }, "devDependencies": { "@types/chai": "5.0.0", "@types/glob": "^8.1.0", - "@types/glob-to-regexp": "^0.4.4", "@types/mocha": "^10.0.9", "@types/node": "^12.0.0", "@types/vscode": "^1.54.0", @@ -208,6 +208,6 @@ "typescript": "^5.6.2" }, "dependencies": { - "glob-to-regexp": "^0.4.1" + "minimatch": "^10.0.1" } } diff --git a/src/extension.ts b/src/extension.ts index 09ca4edd..61fec7cb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,7 +24,6 @@ import Queue from './lib/queue'; import VariablesManager from './lib/variables/variables-manager'; import CacheManager from './lib/cache-manager'; import EditorManager from './lib/editor-manager'; -import globToRegexp from 'glob-to-regexp'; import { getColorizeConfig, ColorizeConfig, @@ -32,6 +31,7 @@ import { } from './lib/colorize-config'; import Listeners from './listeners'; +import { minimatch } from 'minimatch'; let config: ColorizeConfig = { languages: [], @@ -213,10 +213,24 @@ function isLanguageSupported(languageId: string): boolean { * @returns {boolean} */ function isIncludedFile(fileName: string): boolean { - return ( - config.filesToIncludes.find((globPattern: string) => - globToRegexp(globPattern).test(fileName), - ) !== undefined + return config.filesToIncludes.some((globPattern: string) => + // No reason why this reports an error + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + minimatch(fileName, globPattern, { nonegate: true }), + ); +} + +/** + * Check if the file is the `colorize.exclude` setting + * + * @param {string} fileName A valid filename (path to the file) + * @returns {boolean} + */ +function isExcludedFile(fileName: string): boolean { + return config.filesToExcludes.some((globPattern: string) => + // No reason why this reports an error + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + minimatch(fileName, globPattern, { nonegate: true }), ); } @@ -229,8 +243,9 @@ function isIncludedFile(fileName: string): boolean { function canColorize(document: TextDocument): boolean { // update to use filesToExcludes. Remove `isLanguageSupported` ? checking path with file extension or include glob pattern should be enough return ( - isLanguageSupported(document.languageId) || - isIncludedFile(document.fileName) + !isExcludedFile(document.fileName) && + (isLanguageSupported(document.languageId) || + isIncludedFile(document.fileName)) ); } diff --git a/src/lib/colors/strategies/rgb-strategy.ts b/src/lib/colors/strategies/rgb-strategy.ts index c8e64582..6b7727c6 100644 --- a/src/lib/colors/strategies/rgb-strategy.ts +++ b/src/lib/colors/strategies/rgb-strategy.ts @@ -7,24 +7,63 @@ const R_RED = `(?:\\d{1,3}${DOT_VALUE}?|${DOT_VALUE})`; const R_GREEN = R_RED; const R_BLUE = R_RED; +const RGB_NEW_SYNTAX = `rgba?\\(\\s*${R_RED}%?\\s*${R_GREEN}%?\\s*${R_BLUE}%?(?:\\s*\\/\\s*(?:\\d{1,3}${DOT_VALUE}?|${ALPHA})?%?)?\\)`; +const RGB_LEGACY_SYNTAX = `rgb\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*\\)`; +const RGBA_LEGACY_SYNTAX = `rgba\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*,\\s*${ALPHA}\\s*\\)`; + export const REGEXP = new RegExp( - `((?:rgb\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*\\))|(?:rgba\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*,\\s*${ALPHA}\\s*\\)))${EOL}`, + `(${RGB_LEGACY_SYNTAX}|${RGBA_LEGACY_SYNTAX}|${RGB_NEW_SYNTAX})${EOL}`, 'gi', ); export const REGEXP_ONE = new RegExp( - `^((?:rgb\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*\\))|(?:rgba\\(\\s*${R_RED}\\s*,\\s*${R_GREEN}\\s*,\\s*${R_BLUE}\\s*,\\s*${ALPHA}\\s*\\)))${EOL}`, + `^(${RGB_LEGACY_SYNTAX}|${RGBA_LEGACY_SYNTAX}|${RGB_NEW_SYNTAX})${EOL}`, 'i', ); function extractRGBA(value: string): number[] { - const rgba_string = value.replace(/rgb(a){0,1}\(/, '').replace(/\)/, ''); - return rgba_string.split(/,/gi).map((c) => parseFloat(c)); + const rgba_string = value + .replace(/rgb(a){0,1}\(/, '') + .replace(/\)/, '') + .replace('/', ' ') + .replaceAll(',', ' '); + const values = rgba_string.split(/\s+/); + + const [r, g, b] = values.slice(0, 3).map((v) => { + const value = parseFloat(v); + + if (v.includes('%')) { + const percentage = value > 100 ? 100 : value; + + return (255 * percentage) / 100; + } + + return value; + }); + + const isRelativeAlpha = /%/.test(values[3]); + + let a = parseFloat(values[3] ?? 1); + + if (!isRelativeAlpha && a > 1) { + a = 1; + } + + if (isRelativeAlpha && a > 100) { + a = 1; + } + + if (a > 1) { + a = a / 100; + } + return [r, g, b, a]; } function getColor(match: RegExpExecArray) { const value = match[1]; const rgba = extractRGBA(value); - const alpha = rgba[3] || 1; + + const alpha = rgba[3] ?? 1; + const rgb = rgba.slice(0, 3) as [number, number, number]; // Check if it's a valid rgb(a) color if (rgb.every((c) => c <= 255)) { @@ -36,3 +75,4 @@ function getColor(match: RegExpExecArray) { const strategy = new ColorStrategy('RGB', REGEXP, REGEXP_ONE, getColor); ColorExtractor.registerStrategy(strategy); +export default strategy; diff --git a/test/extension/index.test.ts b/test/extension/index.test.ts index db877664..3139924e 100644 --- a/test/extension/index.test.ts +++ b/test/extension/index.test.ts @@ -1,6 +1,6 @@ import { assert } from 'chai'; -import { describe, it } from 'mocha'; +import { describe, it, beforeEach } from 'mocha'; // You can import and use all API from the 'vscode' module // as well as import your extension to test it @@ -21,6 +21,11 @@ const fixtureSourcePath = path.join( ); describe('Extension', () => { + beforeEach(async () => { + const settings = vscode.workspace.getConfiguration('colorize'); + await settings.update('exclude', [], true); + await settings.update('include', [], true); + }); it('is activated successfully upon opening a scss file', async () => { const fileName = `${fixtureSourcePath}/style.scss`; await vscode.workspace.openTextDocument(fileName); @@ -51,4 +56,31 @@ describe('Extension', () => { assert.equal(ext.exports.editor, editor); assert.equal(ext.exports.deco.size, 1); }); + + it('Can use "exclude" setting to not colorize file', async () => { + const settings = vscode.workspace.getConfiguration('colorize'); + await settings.update('exclude', ['**/long_style.scss'], true); + const fileName = `${fixtureSourcePath}/long_style.scss`; + + const doc = await vscode.workspace.openTextDocument(fileName); + await vscode.window.showTextDocument(doc); + await new Promise((resolve) => setTimeout(resolve, 200)); // mandatory because of the queue >< + + assert.isUndefined(ext.exports.editor); + }); + it('Can use "include" setting to colorize file', async () => { + const fileName = `${fixtureSourcePath}/file.other`; + + const doc = await vscode.workspace.openTextDocument(fileName); + const editor = await vscode.window.showTextDocument(doc); + await new Promise((resolve) => setTimeout(resolve, 200)); // mandatory because of the queue >< + + assert.isUndefined(ext.exports.editor); + + const settings = vscode.workspace.getConfiguration('colorize'); + await settings.update('include', ['**/*.other'], true); + await new Promise((resolve) => setTimeout(resolve, 200)); // mandatory because of the queue >< + + assert.equal(ext.exports.editor, editor); + }); }); diff --git a/test/fixtures/file.other b/test/fixtures/file.other new file mode 100644 index 00000000..e69de29b diff --git a/test/runTest.ts b/test/runTest.ts index 46b52600..51b234b9 100644 --- a/test/runTest.ts +++ b/test/runTest.ts @@ -17,6 +17,7 @@ async function main() { extensionDevelopmentPath, extensionTestsPath, version: vscodeVersion, + launchArgs: ['--disable-extensions'], }); } catch (err) { console.error(err); @@ -25,4 +26,4 @@ async function main() { } } -main(); +void main(); diff --git a/test/unit/color-extractor-strategies/rgb-extrator.test.ts b/test/unit/color-extractor-strategies/rgb-extrator.test.ts index 8f825d86..a4b83611 100644 --- a/test/unit/color-extractor-strategies/rgb-extrator.test.ts +++ b/test/unit/color-extractor-strategies/rgb-extrator.test.ts @@ -3,8 +3,28 @@ import { describe, it } from 'mocha'; import { REGEXP } from '../../../src/lib/colors/strategies/rgb-strategy'; import { regex_exec } from '../../test-util'; +import RGBStrategy from '../../../src/lib/colors/strategies/rgb-strategy'; +import Color from '../../../src/lib/colors/color'; describe('Test rgb(a) color Regex', () => { + it('Should match the new syntax', function () { + assert.equal(regex_exec('rgb(255 255 255)', REGEXP)[1], 'rgb(255 255 255)'); + assert.equal(regex_exec('rgb(2% 13% 255)', REGEXP)[1], 'rgb(2% 13% 255)'); + assert.equal( + regex_exec('rgb(255 255 255 / 50%)', REGEXP)[1], + 'rgb(255 255 255 / 50%)', + ); + assert.equal(regex_exec('rgba(0 255 255)', REGEXP)[1], 'rgba(0 255 255)'); + assert.equal( + regex_exec('rgba(0 255 255 / 50)', REGEXP)[1], + 'rgba(0 255 255 / 50)', + ); + + assert.equal( + regex_exec('rgba(.1 25.5 2.55 / 50)', REGEXP)[1], + 'rgba(.1 25.5 2.55 / 50)', + ); + }); it('Should match a simple rgb color', function () { assert.equal( regex_exec('rgb(123, 123, 123)', REGEXP)[1], @@ -137,3 +157,204 @@ describe('Test rgb(a) color Regex', () => { ); }); }); + +describe('Extract color', () => { + ( + [ + { + input: 'rgb(255 255 255)', + expected: { + rgb: [255, 255, 255], + alpha: 1, + }, + }, + { + input: 'rgb(255 255 255 / 50%)', + expected: { + rgb: [255, 255, 255], + alpha: 0.5, + }, + }, + { + input: 'rgb(255 255 255 / 255%)', + expected: { + rgb: [255, 255, 255], + alpha: 1, + }, + }, + { + input: 'rgba(0 255 255)', + expected: { + rgb: [0, 255, 255], + alpha: 1, + }, + }, + { + input: 'rgba(0 255 255 / 50)', + expected: { + rgb: [0, 255, 255], + alpha: 1, + }, + }, + { + input: 'rgba(.1 25.5 2.55 / 50)', + expected: { + rgb: [0.1, 25.5, 2.55], + alpha: 1, + }, + }, + { + input: 'rgb(2% 13% 255)', + expected: { + rgb: [5.1, 33.15, 255], + alpha: 1, + }, + }, + { + input: 'rgb(123, 123, 123)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgba(123, 123, 123, 0)', + expected: { + rgb: [123, 123, 123], + alpha: 0, + }, + }, + { + input: 'rgba(123, 123, 123, 0.3)', + expected: { + rgb: [123, 123, 123], + alpha: 0.3, + }, + }, + { + input: 'rgba(123, 123, 123, .3)', + expected: { + rgb: [123, 123, 123], + alpha: 0.3, + }, + }, + { + input: 'rgba(123, 123, 123, 1)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgba(123, 123, 123, 1.0)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgb(12.3, 123, 123)', + expected: { + rgb: [12.3, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgb(123, 12.3, 123)', + expected: { + rgb: [123, 12.3, 123], + alpha: 1, + }, + }, + { + input: 'rgb(123, 123, 12.3)', + expected: { + rgb: [123, 123, 12.3], + alpha: 1, + }, + }, + { + input: 'rgb(123, 123, 12.333333)', + expected: { + rgb: [123, 123, 12.333333], + alpha: 1, + }, + }, + { + input: 'rgb(12.3, 12.3, 12.3)', + expected: { + rgb: [12.3, 12.3, 12.3], + alpha: 1, + }, + }, + { + input: 'rgb(.3, 12.3, 12.3)', + expected: { + rgb: [0.3, 12.3, 12.3], + alpha: 1, + }, + }, + { + input: 'rgba(12.3, 123, 123, 0)', + expected: { + rgb: [12.3, 123, 123], + alpha: 0, + }, + }, + { + input: 'rgba(123, 12.3, 123, 0)', + expected: { + rgb: [123, 12.3, 123], + alpha: 0, + }, + }, + { + input: 'rgba(123, 123, 12.3, 0)', + expected: { + rgb: [123, 123, 12.3], + alpha: 0, + }, + }, + { + input: 'rgba(123, 123, 123, 1.0)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgba(123, 123, 123, 1.00)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgba(123, 123, 123, 1)', + expected: { + rgb: [123, 123, 123], + alpha: 1, + }, + }, + { + input: 'rgba(.123, 123, 123, 1)', + expected: { + rgb: [0.123, 123, 123], + alpha: 1, + }, + }, + ] satisfies Array<{ + input: string; + expected: { + rgb: [number, number, number]; + alpha: number; + }; + }> + ).forEach((test) => { + it(`Should correctly extract '${test.input}'`, function () { + const color = RGBStrategy.extractColor(test.input) as Color; + assert.deepEqual(color.rgb, test.expected.rgb); + assert.deepEqual(color.alpha, test.expected.alpha); + }); + }); +}); diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 00000000..e58959dd --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "types": ["@types/node"], + "noEmit": true, + "allowJs": true + }, + "extends": "./tsconfig.json", + "include": ["src/**/*.ts", "test/**/*.ts", ".eslintrc.cjs"] +}