From edd276e59b13241a886cb3de517aa8d3f8557d18 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Fri, 11 Jul 2025 14:47:05 +0200 Subject: [PATCH] feat: is valid class name worker --- src/util/tailwindcss-api/index.ts | 6 +++ .../worker/get-sorted-class-names.spec.ts | 12 +++--- .../worker/is-valid-class-name.mjs | 40 +++++++++++++++++++ .../worker/is-valid-class-name.spec.ts | 22 ++++++++++ 4 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 src/util/tailwindcss-api/worker/is-valid-class-name.mjs create mode 100644 src/util/tailwindcss-api/worker/is-valid-class-name.spec.ts diff --git a/src/util/tailwindcss-api/index.ts b/src/util/tailwindcss-api/index.ts index 7e63951..bb39819 100644 --- a/src/util/tailwindcss-api/index.ts +++ b/src/util/tailwindcss-api/index.ts @@ -11,3 +11,9 @@ export const getSortedClassNamesWorker: ( ) => Array = createSyncFn( require.resolve("./worker/get-sorted-class-names.mjs") ); +export const isValidClassNameWorker: ( + cssConfigPath: string, + className: string +) => boolean = createSyncFn( + require.resolve("./worker/is-valid-class-name.mjs") +); diff --git a/src/util/tailwindcss-api/worker/get-sorted-class-names.spec.ts b/src/util/tailwindcss-api/worker/get-sorted-class-names.spec.ts index 2d6b722..ee7ce34 100644 --- a/src/util/tailwindcss-api/worker/get-sorted-class-names.spec.ts +++ b/src/util/tailwindcss-api/worker/get-sorted-class-names.spec.ts @@ -8,15 +8,15 @@ test(`Sort classnames based on "normal.css"`, () => { "lg:flex", "block", "top-0", - "unkown", + "unknown", "text-red-100", ]; const sorted = getSortedClassNamesWorker(path, unorderdClassNames); // Unknown classnames should be first - expect(sorted[0]).toBe("unkown"); + expect(sorted[0]).toBe("unknown"); // The rest should be sorted as well expect(sorted).toStrictEqual([ - "unkown", + "unknown", "top-0", "block", "text-red-100", @@ -28,16 +28,16 @@ test(`Sort "tw:" prefixed classnames based on "tiny-prefixed.css"`, () => { const path = require.resolve("../../../../tests/stubs/css/tiny-prefixed.css"); const unorderdClassNames = [ "tw:flex", - "tw:unkown", + "tw:unknown", "tw:hover:text-tiny", "tw:top-0", ]; const sorted = getSortedClassNamesWorker(path, unorderdClassNames); // Unknown classnames should be first - expect(sorted[0]).toBe("tw:unkown"); + expect(sorted[0]).toBe("tw:unknown"); // The rest should be sorted as well expect(sorted).toStrictEqual([ - "tw:unkown", + "tw:unknown", "tw:top-0", "tw:flex", "tw:hover:text-tiny", diff --git a/src/util/tailwindcss-api/worker/is-valid-class-name.mjs b/src/util/tailwindcss-api/worker/is-valid-class-name.mjs new file mode 100644 index 0000000..dacee2d --- /dev/null +++ b/src/util/tailwindcss-api/worker/is-valid-class-name.mjs @@ -0,0 +1,40 @@ +/** + * âš ī¸ This is a worker script which is ran in node's `worker_threads`. + * 🤓 This means that it is not executed in the main thread, but in a separate thread. + * 😅 Because of this, expect some disturbances, like: + * - `console.log` won't work `vitest`... (seems to work with `jest`). + * - You cannot pass complex objects as arguments, only serializable ones. + * - You cannot retun complex objects, only serializable ones. + * - e.g. You cannot return the `utils.context` directly, but you can return some of its properties... + * + * â„šī¸ It uses the `*.mjs` extension to indicate that it is an ES module. + * ✅ We still check the syntax with TypeScript, but it is not a TypeScript file. + */ + +// @ts-check + +import { runAsWorker } from "synckit"; +import { TailwindUtils } from "tailwind-api-utils"; + +runAsWorker( + async ( + /** + * @type {string} The path to the Tailwind CSS config file + */ + cssConfigPath, + /** + * @type {string} Class name to validate + */ + className + ) => { + const utils = new TailwindUtils(); + await utils.loadConfigV4(cssConfigPath); + if (!utils.context) { + throw new Error( + `Failed to load the Tailwind CSS theme using: "${cssConfigPath}"` + ); + } + const sorted = await utils.isValidClassName(className); + return sorted; + } +); diff --git a/src/util/tailwindcss-api/worker/is-valid-class-name.spec.ts b/src/util/tailwindcss-api/worker/is-valid-class-name.spec.ts new file mode 100644 index 0000000..0ca5cfd --- /dev/null +++ b/src/util/tailwindcss-api/worker/is-valid-class-name.spec.ts @@ -0,0 +1,22 @@ +import { expect, test } from "vitest"; + +import { isValidClassNameWorker } from ".."; + +test(`Validate classnames based on "normal.css"`, () => { + const path = require.resolve("../../../../tests/stubs/css/normal.css"); + // Unknown classnames should be invalid + expect(isValidClassNameWorker(path, "unknown")).toBe(false); + // Known classnames should be valid + expect(isValidClassNameWorker(path, "flex")).toBe(true); +}); + +test(`Validate "tw:" prefixed classnames based on "tiny-prefixed.css"`, () => { + const path = require.resolve("../../../../tests/stubs/css/tiny-prefixed.css"); + // Unknown classnames should be invalid + expect(isValidClassNameWorker(path, "tw:unknown")).toBe(false); + // Known classnames should be valid + expect(isValidClassNameWorker(path, "tw:flex")).toBe(true); + expect(isValidClassNameWorker(path, "tw:border-tiny")).toBe(true); + // Unprefixed classnames should be invalid + expect(isValidClassNameWorker(path, "flex")).toBe(false); +});