diff --git a/.cspell.json b/.cspell.json index 9c20f76..b5ae54e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -25,6 +25,7 @@ "objstr", "OBJSTR", "quasis", - "shadcn" + "shadcn", + "synckit" ] } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18e9cce..8235e21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/setup-node@v4 with: cache: npm - node-version: 22 + node-version: 23 - name: Install dependencies run: npm ci @@ -40,16 +40,19 @@ jobs: - name: Install dependencies run: npm ci - - name: Run tests - run: npm test + - name: Run tests with tailwindcss v3 + run: npm run test:v3 + + - name: Run tests with tailwindcss v4 + run: npm run test:v4 strategy: fail-fast: true matrix: node: - - 18 - 20 - 22 + - 23 os: - ubuntu-latest - windows-latest diff --git a/build/index.ts b/build/index.ts index 2034285..4f26fd5 100644 --- a/build/index.ts +++ b/build/index.ts @@ -1,14 +1,30 @@ -import { writeFile } from "fs/promises"; -import { $ } from "readable-tailwind:build:utils.js"; +import { mkdir, writeFile } from "fs/promises"; + import { transformImports } from "readable-tailwind:build:transform.js"; + import { $ } from "readable-tailwind:build:utils.js"; -const esmDir = "lib/esm" -const cjsDir = "lib/cjs" + async function build(){ -await $`npx tsc --module preserve --project tsconfig.build.esm.json --outDir ${esmDir}` -await $`npx tsc-alias --outDir ${esmDir}` -await writeFile(`${esmDir}/package.json`, JSON.stringify({ type: "module" }), "utf-8") + const esmDir = "lib/esm" + const cjsDir = "lib/cjs" -await $`npx tsc --module commonjs --moduleResolution node --project tsconfig.build.cjs.json --verbatimModuleSyntax false --outDir ${cjsDir}` -await $`npx tsc-alias --outDir ${cjsDir}` -await writeFile(`${cjsDir}/package.json`, JSON.stringify({ type: "commonjs" }), "utf-8") + console.info("Building ESM...") + await mkdir(esmDir, { recursive: true }); + await $`npx tsc --project tsconfig.build.esm.json --outDir ${esmDir}` + await $`npx tsc-alias --outDir ${esmDir}` + await writeFile(`${esmDir}/package.json`, JSON.stringify({ type: "module" }), "utf-8") + await transformImports([`${esmDir}/**/*.js`], "tailwindcss3", "tailwindcss") + await transformImports([`${esmDir}/**/*.js`], "tailwindcss4", "tailwindcss") + console.info("Building CJS...") + await mkdir(cjsDir, { recursive: true }); + await $`npx tsc --project tsconfig.build.cjs.json --outDir ${cjsDir}` + await $`npx tsc-alias --outDir ${cjsDir}` + await writeFile(`${cjsDir}/package.json`, JSON.stringify({ type: "commonjs" }), "utf-8") + await transformImports([`${cjsDir}/**/*.js`], "tailwindcss3", "tailwindcss") + await transformImports([`${cjsDir}/**/*.js`], "tailwindcss4", "tailwindcss") + + console.info("Build complete") + + } + + build().catch(console.error); \ No newline at end of file diff --git a/build/transform.ts b/build/transform.ts new file mode 100644 index 0000000..b807e33 --- /dev/null +++ b/build/transform.ts @@ -0,0 +1,13 @@ +import { readFile, writeFile } from 'fs/promises'; + import { glob } from 'glob' + +export async function transformImports(globPatterns: string[], search: string, replace: string) { + const files = await glob(globPatterns); + + for(const file of files) { + const content = await readFile(file, 'utf-8'); + const transformed = content.replaceAll(search, replace); + + await writeFile(file, transformed); + } +} \ No newline at end of file diff --git a/docs/rules/sort-classes.md b/docs/rules/sort-classes.md index e4270c7..ead93c6 100644 --- a/docs/rules/sort-classes.md +++ b/docs/rules/sort-classes.md @@ -21,9 +21,19 @@ Enforce the order of tailwind classes. It is possible to sort classes alphabetic
+- `entryPoint` + + The path to the entry file of the tailwind css config. If not specified, the plugin will fall back to the default configuration. + The tailwind config is used to determine the sorting order. + + **Type**: `string` + **Default**: `undefined` + +
+ - `tailwindConfig` - The path to the tailwind config file. If not specified, the plugin will try to find it automatically or falls back to the default configuration. + The path to the `tailwind.config.js` file. If not specified, the plugin will try to find it automatically or falls back to the default configuration. The tailwind config is used to determine the sorting order. **Type**: `string` diff --git a/package-lock.json b/package-lock.json index 408c6df..16fc566 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,24 @@ { "name": "eslint-plugin-readable-tailwind", - "version": "1.8.2", + "version": "2.0.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "eslint-plugin-readable-tailwind", - "version": "1.8.2", + "version": "2.0.0-beta.0", "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.18.0", + "postcss": "^8.5.1", + "postcss-import": "^16.1.0" + }, "devDependencies": { - "@html-eslint/parser": "^0.32.0", - "@schoero/configs": "^1.2.3", + "@html-eslint/parser": "^0.33.0", + "@schoero/configs": "^1.2.5", "@types/estree-jsx": "^1.0.5", - "@types/node": "^22.10.7", - "@typescript-eslint/parser": "^8.20.0", + "@types/node": "^22.10.10", + "@typescript-eslint/parser": "^8.21.0", "changelogen": "^0.5.7", "cspell": "^8.17.2", "es-html-parser": "^0.0.10", @@ -23,13 +28,18 @@ "json-schema": "^0.4.0", "markdownlint": "^0.37.4", "proper-tags": "^2.0.2", - "svelte": "^5.19.0", + "svelte": "^5.19.2", "svelte-eslint-parser": "^0.43.0", - "tailwindcss": "^3.4.17", + "synckit": "^0.9.2", + "tailwindcss": "^4.0.0", + "tailwindcss3": "npm:tailwindcss@^3.0.0", + "tailwindcss4": "npm:tailwindcss@^4.0.0", + "ts-node": "^10.9.2", "tsc-alias": "^1.8.10", + "tsx": "^4.19.2", "typescript": "^5.7.3", - "vite-node": "^3.0.2", - "vitest": "^3.0.2", + "vite-node": "^3.0.4", + "vitest": "^3.0.4", "vue-eslint-parser": "^9.4.3" }, "engines": { @@ -37,7 +47,7 @@ }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", - "tailwindcss": ">=3.3.0" + "tailwindcss": "^3.3.0 || ^4.0.0" } }, "node_modules/@actions/core": { @@ -740,6 +750,30 @@ "node": ">=18.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.49.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz", @@ -1367,9 +1401,9 @@ } }, "node_modules/@html-eslint/parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.32.0.tgz", - "integrity": "sha512-XSrc3rlIakRlJmFO3EpcVAiwJMfTFvjRZrpFr2jhX1E/Zjd/jPuYbKKXaY6ZLpeRQDtexFiKU+r8pa9DT2pd0A==", + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.33.0.tgz", + "integrity": "sha512-vYH6MtSIt79ufObABZuvRtemuSJGXtRWBVHCIfGnskJ+cAypq7HXQo/Lv03dI6PwcOfrPrCwBLW662411HHoNg==", "dev": true, "license": "MIT", "dependencies": { @@ -1852,9 +1886,9 @@ ] }, "node_modules/@schoero/configs": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@schoero/configs/-/configs-1.2.4.tgz", - "integrity": "sha512-APWo1WFOXdndyMlBRsBISTM9VNcfVTAojn/YIluX99LFKu+ydzyX322rGmCcF6/yxclot8RvWMlq2xto690lVA==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@schoero/configs/-/configs-1.2.5.tgz", + "integrity": "sha512-F0zKu/ObQVuqyzrjHf4dq3Q8IVgig3RVcQ5GnhnhU2DPKc8Ue+MAI8ZVLnrIPadOmpRdf/JylgNUIX5VNh2hhw==", "dev": true, "license": "MIT", "dependencies": { @@ -1879,8 +1913,8 @@ "@stylistic/eslint-plugin-jsx": "^2.13.0", "@stylistic/eslint-plugin-plus": "^2.13.0", "@stylistic/eslint-plugin-ts": "^2.13.0", - "@typescript-eslint/eslint-plugin": "^8.20.0", - "@typescript-eslint/parser": "^8.20.0", + "@typescript-eslint/eslint-plugin": "^8.21.0", + "@typescript-eslint/parser": "^8.21.0", "cspell-lib": "^8.17.2", "eslint-plugin-import-newlines": "^1.4.0", "eslint-plugin-import-x": "^4.6.1", @@ -1897,7 +1931,7 @@ "vitest-github-actions-reporter": "^0.11.1" }, "optionalDependencies": { - "eslint-plugin-readable-tailwind": "^1.8.2" + "eslint-plugin-readable-tailwind": "^1.9.0" }, "peerDependencies": { "@stylistic/eslint-plugin-jsx": "^2.13.0", @@ -2013,6 +2047,34 @@ "eslint": ">=8.40.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2079,9 +2141,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", - "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "version": "22.10.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", + "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", "dev": true, "license": "MIT", "dependencies": { @@ -2103,17 +2165,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz", - "integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz", + "integrity": "sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.20.0", - "@typescript-eslint/type-utils": "8.20.0", - "@typescript-eslint/utils": "8.20.0", - "@typescript-eslint/visitor-keys": "8.20.0", + "@typescript-eslint/scope-manager": "8.21.0", + "@typescript-eslint/type-utils": "8.21.0", + "@typescript-eslint/utils": "8.21.0", + "@typescript-eslint/visitor-keys": "8.21.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2133,16 +2195,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz", - "integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.21.0.tgz", + "integrity": "sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.20.0", - "@typescript-eslint/types": "8.20.0", - "@typescript-eslint/typescript-estree": "8.20.0", - "@typescript-eslint/visitor-keys": "8.20.0", + "@typescript-eslint/scope-manager": "8.21.0", + "@typescript-eslint/types": "8.21.0", + "@typescript-eslint/typescript-estree": "8.21.0", + "@typescript-eslint/visitor-keys": "8.21.0", "debug": "^4.3.4" }, "engines": { @@ -2158,14 +2220,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.20.0.tgz", - "integrity": "sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.21.0.tgz", + "integrity": "sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.20.0", - "@typescript-eslint/visitor-keys": "8.20.0" + "@typescript-eslint/types": "8.21.0", + "@typescript-eslint/visitor-keys": "8.21.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2176,14 +2238,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz", - "integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.21.0.tgz", + "integrity": "sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.20.0", - "@typescript-eslint/utils": "8.20.0", + "@typescript-eslint/typescript-estree": "8.21.0", + "@typescript-eslint/utils": "8.21.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.0" }, @@ -2200,9 +2262,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.20.0.tgz", - "integrity": "sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.21.0.tgz", + "integrity": "sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==", "dev": true, "license": "MIT", "engines": { @@ -2214,14 +2276,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.20.0.tgz", - "integrity": "sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz", + "integrity": "sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.20.0", - "@typescript-eslint/visitor-keys": "8.20.0", + "@typescript-eslint/types": "8.21.0", + "@typescript-eslint/visitor-keys": "8.21.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2241,16 +2303,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.20.0.tgz", - "integrity": "sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.21.0.tgz", + "integrity": "sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.20.0", - "@typescript-eslint/types": "8.20.0", - "@typescript-eslint/typescript-estree": "8.20.0" + "@typescript-eslint/scope-manager": "8.21.0", + "@typescript-eslint/types": "8.21.0", + "@typescript-eslint/typescript-estree": "8.21.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2265,13 +2327,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.20.0.tgz", - "integrity": "sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz", + "integrity": "sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/types": "8.21.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2283,14 +2345,14 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.2.tgz", - "integrity": "sha512-dKSHLBcoZI+3pmP5hiZ7I5grNru2HRtEW8Z5Zp4IXog8QYcxhlox7JUPyIIFWfN53+3HW3KPLIl6nSzUGgKSuQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.4.tgz", + "integrity": "sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.2", - "@vitest/utils": "3.0.2", + "@vitest/spy": "3.0.4", + "@vitest/utils": "3.0.4", "chai": "^5.1.2", "tinyrainbow": "^2.0.0" }, @@ -2299,13 +2361,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.2.tgz", - "integrity": "sha512-Hr09FoBf0jlwwSyzIF4Xw31OntpO3XtZjkccpcBf8FeVW3tpiyKlkeUzxS/txzHqpUCNIX157NaTySxedyZLvA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.4.tgz", + "integrity": "sha512-gEef35vKafJlfQbnyOXZ0Gcr9IBUsMTyTLXsEQwuyYAerpHqvXhzdBnDFuHLpFqth3F7b6BaFr4qV/Cs1ULx5A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.2", + "@vitest/spy": "3.0.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -2326,9 +2388,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.2.tgz", - "integrity": "sha512-yBohcBw/T/p0/JRgYD+IYcjCmuHzjC3WLAKsVE4/LwiubzZkE8N49/xIQ/KGQwDRA8PaviF8IRO8JMWMngdVVQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.4.tgz", + "integrity": "sha512-ts0fba+dEhK2aC9PFuZ9LTpULHpY/nd6jhAQ5IMU7Gaj7crPCTdCFfgvXxruRBLFS+MLraicCuFXxISEq8C93g==", "dev": true, "license": "MIT", "dependencies": { @@ -2339,14 +2401,14 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.2.tgz", - "integrity": "sha512-GHEsWoncrGxWuW8s405fVoDfSLk6RF2LCXp6XhevbtDjdDme1WV/eNmUueDfpY1IX3MJaCRelVCEXsT9cArfEg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.4.tgz", + "integrity": "sha512-dKHzTQ7n9sExAcWH/0sh1elVgwc7OJ2lMOBrAm73J7AH6Pf9T12Zh3lNE1TETZaqrWFXtLlx3NVrLRb5hCK+iw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.2", - "pathe": "^2.0.1" + "@vitest/utils": "3.0.4", + "pathe": "^2.0.2" }, "funding": { "url": "https://opencollective.com/vitest" @@ -2360,15 +2422,15 @@ "license": "MIT" }, "node_modules/@vitest/snapshot": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.2.tgz", - "integrity": "sha512-h9s67yD4+g+JoYG0zPCo/cLTabpDqzqNdzMawmNPzDStTiwxwkyYM1v5lWE8gmGv3SVJ2DcxA2NpQJZJv9ym3g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.4.tgz", + "integrity": "sha512-+p5knMLwIk7lTQkM3NonZ9zBewzVp9EVkVpvNta0/PlFWpiqLaRcF4+33L1it3uRUCh0BGLOaXPPGEjNKfWb4w==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.2", + "@vitest/pretty-format": "3.0.4", "magic-string": "^0.30.17", - "pathe": "^2.0.1" + "pathe": "^2.0.2" }, "funding": { "url": "https://opencollective.com/vitest" @@ -2382,9 +2444,9 @@ "license": "MIT" }, "node_modules/@vitest/spy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.2.tgz", - "integrity": "sha512-8mI2iUn+PJFMT44e3ISA1R+K6ALVs47W6eriDTfXe6lFqlflID05MB4+rIFhmDSLBj8iBsZkzBYlgSkinxLzSQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.4.tgz", + "integrity": "sha512-sXIMF0oauYyUy2hN49VFTYodzEAu744MmGcPR3ZBsPM20G+1/cSW/n1U+3Yu/zHxX2bIDe1oJASOkml+osTU6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2395,13 +2457,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.2.tgz", - "integrity": "sha512-Qu01ZYZlgHvDP02JnMBRpX43nRaZtNpIzw3C1clDXmn8eakgX6iQVGzTQ/NjkIr64WD8ioqOjkaYRVvHQI5qiw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.4.tgz", + "integrity": "sha512-8BqC1ksYsHtbWH+DfpOAKrFw3jl3Uf9J7yeFh85Pz52IWuh1hBBtyfEbRNNZNjl8H8A5yMLH9/t+k7HIKzQcZQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.2", + "@vitest/pretty-format": "3.0.4", "loupe": "^3.1.2", "tinyrainbow": "^2.0.0" }, @@ -2442,6 +2504,19 @@ "acorn": ">=8.9.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3117,6 +3192,13 @@ "dev": true, "license": "MIT" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3465,6 +3547,16 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3546,7 +3638,6 @@ "version": "5.18.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -3982,9 +4073,9 @@ } }, "node_modules/eslint-plugin-readable-tailwind": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-readable-tailwind/-/eslint-plugin-readable-tailwind-1.8.2.tgz", - "integrity": "sha512-YJ0nDFhuahZZNPgEMwSw4/Ri87qg7Z6YFLTOUam3PBDFomIXAJG89cvFmZg1R2InpEmHAvVRh3QqcoKbkZZM3g==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-readable-tailwind/-/eslint-plugin-readable-tailwind-1.9.0.tgz", + "integrity": "sha512-GrAAVpnii49FdC3YeJ7jy3mTwgPuHVJB2JpV4zLfJGWFNcxKJTz8qs3/vpixedq/LnQ1eN2IY+h+IN91g7D9HA==", "dev": true, "license": "MIT", "optional": true, @@ -4744,7 +4835,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4933,7 +5023,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -4967,7 +5056,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5150,7 +5238,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5614,6 +5701,13 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -6576,7 +6670,6 @@ "version": "3.3.8", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, "funding": [ { "type": "github", @@ -6946,7 +7039,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -7007,7 +7099,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -7027,7 +7118,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7089,7 +7179,6 @@ "version": "8.5.1", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7115,10 +7204,9 @@ } }, "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", + "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -7126,7 +7214,7 @@ "resolve": "^1.1.7" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "postcss": "^8.0.0" @@ -7259,7 +7347,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { @@ -7348,7 +7435,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -7526,7 +7612,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -7737,7 +7822,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8065,7 +8149,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8075,9 +8158,9 @@ } }, "node_modules/svelte": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.0.tgz", - "integrity": "sha512-qvd2GvvYnJxS/MteQKFSMyq8cQrAAut28QZ39ySv9k3ggmhw4Au4Rfcsqva74i0xMys//OhbhVCNfXPrDzL/Bg==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.2.tgz", + "integrity": "sha512-Ww1uLgdX5MdQrAO5zfU1dWUh6zqiPR6uIbwqm8a+4eQ+tNEYHRPgypvKKfHh9lmTkmJ30PWZ2O5qX8aS+PblRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8194,6 +8277,14 @@ } }, "node_modules/tailwindcss": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0.tgz", + "integrity": "sha512-ULRPI3A+e39T7pSaf1xoi58AqqJxVCLg8F/uM5A3FadUbnyDTgltVnXJvdkTjwCOGA6NazqHVcwPJC5h2vRYVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss3": { + "name": "tailwindcss", "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", @@ -8231,7 +8322,7 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/glob-parent": { + "node_modules/tailwindcss3/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", @@ -8244,11 +8335,36 @@ "node": ">=10.13.0" } }, + "node_modules/tailwindcss3/node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/tailwindcss4": { + "name": "tailwindcss", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0.tgz", + "integrity": "sha512-ULRPI3A+e39T7pSaf1xoi58AqqJxVCLg8F/uM5A3FadUbnyDTgltVnXJvdkTjwCOGA6NazqHVcwPJC5h2vRYVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8396,6 +8512,57 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/tsc-alias": { "version": "1.8.10", "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.10.tgz", @@ -8483,6 +8650,474 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -8639,6 +9274,13 @@ "dev": true, "license": "MIT" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -8734,16 +9376,16 @@ } }, "node_modules/vite-node": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.2.tgz", - "integrity": "sha512-hsEQerBAHvVAbv40m3TFQe/lTEbOp7yDpyqMJqr2Tnd+W58+DEYOt+fluQgekOePcsNBmR77lpVAnIU2Xu4SvQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.4.tgz", + "integrity": "sha512-7JZKEzcYV2Nx3u6rlvN8qdo3QV7Fxyt6hx+CCKz9fbWxdX5IvUOmTWEAxMrWxaiSf7CKGLJQ5rFu8prb/jBjOA==", "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.6.0", - "pathe": "^2.0.1", + "pathe": "^2.0.2", "vite": "^5.0.0 || ^6.0.0" }, "bin": { @@ -8784,31 +9426,31 @@ } }, "node_modules/vitest": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.2.tgz", - "integrity": "sha512-5bzaHakQ0hmVVKLhfh/jXf6oETDBtgPo8tQCHYB+wftNgFJ+Hah67IsWc8ivx4vFL025Ow8UiuTf4W57z4izvQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.4.tgz", + "integrity": "sha512-6XG8oTKy2gnJIFTHP6LD7ExFeNLxiTkK3CfMvT7IfR8IN+BYICCf0lXUQmX7i7JoxUP8QmeP4mTnWXgflu4yjw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.2", - "@vitest/mocker": "3.0.2", - "@vitest/pretty-format": "^3.0.2", - "@vitest/runner": "3.0.2", - "@vitest/snapshot": "3.0.2", - "@vitest/spy": "3.0.2", - "@vitest/utils": "3.0.2", + "@vitest/expect": "3.0.4", + "@vitest/mocker": "3.0.4", + "@vitest/pretty-format": "^3.0.4", + "@vitest/runner": "3.0.4", + "@vitest/snapshot": "3.0.4", + "@vitest/spy": "3.0.4", + "@vitest/utils": "3.0.4", "chai": "^5.1.2", "debug": "^4.4.0", "expect-type": "^1.1.0", "magic-string": "^0.30.17", - "pathe": "^2.0.1", + "pathe": "^2.0.2", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.2", + "vite-node": "3.0.4", "why-is-node-running": "^2.3.0" }, "bin": { @@ -8822,9 +9464,10 @@ }, "peerDependencies": { "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.2", - "@vitest/ui": "3.0.2", + "@vitest/browser": "3.0.4", + "@vitest/ui": "3.0.4", "happy-dom": "*", "jsdom": "*" }, @@ -8832,6 +9475,9 @@ "@edge-runtime/vm": { "optional": true }, + "@types/debug": { + "optional": true + }, "@types/node": { "optional": true }, @@ -9164,6 +9810,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 5c05a0f..160cdd1 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "1.9.0", + "version": "2.0.0-beta.0", "type": "module", "name": "eslint-plugin-readable-tailwind", "description": "auto-wraps tailwind classes after a certain print width or class count into multiple lines to improve readability.", @@ -53,25 +53,32 @@ "release:latest": "changelogen --bump --output --no-tag", "spellcheck": "cspell lint", "spellcheck:ci": "npm run spellcheck -- --no-progress", - "test": "vitest -c ./vite.config.ts", + "test": "npm run test:v3 -- --run && npm run test:v4 -- --run", + "test:v3": "npm i tailwindcss@^3 --no-save && vitest -c ./vite.config.ts", + "test:v4": "npm i tailwindcss@^4 --no-save && vitest -c ./vite.config.ts", "typecheck": "tsc --noEmit" }, "engines": { - "node": ">=16" + "node": ">=19" }, "files": [ "lib" ], "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", - "tailwindcss": ">=3.3.0" + "tailwindcss": "^3.3.0 || ^4.0.0" + }, + "dependencies": { + "enhanced-resolve": "^5.18.0", + "postcss": "^8.5.1", + "postcss-import": "^16.1.0" }, "devDependencies": { - "@html-eslint/parser": "^0.32.0", - "@schoero/configs": "^1.2.3", + "@html-eslint/parser": "^0.33.0", + "@schoero/configs": "^1.2.5", "@types/estree-jsx": "^1.0.5", - "@types/node": "^22.10.7", - "@typescript-eslint/parser": "^8.20.0", + "@types/node": "^22.10.10", + "@typescript-eslint/parser": "^8.21.0", "changelogen": "^0.5.7", "cspell": "^8.17.2", "es-html-parser": "^0.0.10", @@ -81,13 +88,18 @@ "json-schema": "^0.4.0", "markdownlint": "^0.37.4", "proper-tags": "^2.0.2", - "svelte": "^5.19.0", + "svelte": "^5.19.2", "svelte-eslint-parser": "^0.43.0", - "tailwindcss": "^3.4.17", + "synckit": "^0.9.2", + "tailwindcss": "^4.0.0", + "tailwindcss3": "npm:tailwindcss@^3.0.0", + "tailwindcss4": "npm:tailwindcss@^4.0.0", + "ts-node": "^10.9.2", "tsc-alias": "^1.8.10", + "tsx": "^4.19.2", "typescript": "^5.7.3", - "vite-node": "^3.0.2", - "vitest": "^3.0.2", + "vite-node": "^3.0.4", + "vitest": "^3.0.4", "vue-eslint-parser": "^9.4.3" }, "keywords": [ @@ -120,6 +132,6 @@ "tailwind-classes" ], "volta": { - "node": "22.5.1" + "node": "22.13.1" } } diff --git a/src/rules/tailwind-sort-classes.ts b/src/rules/tailwind-sort-classes.ts index b686df3..cfcb2f9 100644 --- a/src/rules/tailwind-sort-classes.ts +++ b/src/rules/tailwind-sort-classes.ts @@ -1,10 +1,4 @@ -import { resolve } from "node:path"; - -import defaultConfig from "tailwindcss/defaultConfig.js"; -import * as setupContextUtils from "tailwindcss/lib/lib/setupContextUtils.js"; -import loadConfig from "tailwindcss/loadConfig.js"; -import resolveConfig from "tailwindcss/resolveConfig.js"; - +import { getClassOrder } from "readable-tailwind:async:class-order.sync.js"; import { DEFAULT_ATTRIBUTE_NAMES, DEFAULT_CALLEE_NAMES, @@ -34,7 +28,6 @@ import type { Rule } from "eslint"; import type { CallExpression, Node, TaggedTemplateExpression, VariableDeclarator } from "estree"; import type { JSXOpeningElement } from "estree-jsx"; import type { SvelteStartTag } from "svelte-eslint-parser/lib/ast/index.js"; -import type { Config } from "tailwindcss/types/config.js"; import type { AST } from "vue-eslint-parser"; import type { Literal } from "readable-tailwind:types:ast.js"; @@ -49,11 +42,13 @@ import type { export type Options = [ Partial< - AttributeOption & + AttributeOption + & CalleeOption & TagOption & VariableOption & { + entryPoint?: string; order?: "asc" | "desc" | "improved" | "official" ; tailwindConfig?: string; } @@ -68,9 +63,6 @@ const defaultOptions = { variables: DEFAULT_VARIABLE_NAMES } as const satisfies Options[0]; -const TAILWIND_CONFIG_CACHE = new Map>>(); -const TAILWIND_CONTEXT_CACHE = new Map, TailwindContext>(); - export const tailwindSortClasses: ESLintRule = { name: "sort-classes" as const, rule: { @@ -78,9 +70,6 @@ export const tailwindSortClasses: ESLintRule = { const { attributes, callees, tags, variables } = getOptions(ctx); - const tailwindConfig = findTailwindConfig(ctx); - const tailwindContext = createTailwindContext(tailwindConfig); - const lintLiterals = (ctx: Rule.RuleContext, literals: Literal[]) => { for(const literal of literals){ @@ -100,7 +89,7 @@ export const tailwindSortClasses: ESLintRule = { unsortableClasses[1] = classChunks.pop() ?? ""; } - const sortedClassChunks = sortClasses(ctx, tailwindContext, classChunks); + const sortedClassChunks = sortClasses(ctx, classChunks); const classes: string[] = []; @@ -263,6 +252,10 @@ export const tailwindSortClasses: ESLintRule = { ...getAttributesSchema(defaultOptions.attributes), ...getVariableSchema(defaultOptions.variables), ...getTagsSchema(defaultOptions.tags), + entryPoint: { + description: "The path to the css entry point of the project. If not specified, the plugin will fall back to the default tailwind classes.", + type: "string" + }, order: { default: defaultOptions.order, description: "The algorithm to use when sorting classes.", @@ -288,9 +281,9 @@ export const tailwindSortClasses: ESLintRule = { }; -function sortClasses(ctx: Rule.RuleContext, tailwindContext: TailwindContext, classes: string[]): string[] { +function sortClasses(ctx: Rule.RuleContext, classes: string[]): string[] { - const { order } = getOptions(ctx); + const { order, tailwindConfig } = getOptions(ctx); if(order === "asc"){ return [...classes].sort((a, b) => a.localeCompare(b)); @@ -300,7 +293,7 @@ function sortClasses(ctx: Rule.RuleContext, tailwindContext: TailwindContext, cl return [...classes].sort((a, b) => b.localeCompare(a)); } - const officialClassOrder = tailwindContext.getClassOrder(classes) as [string, bigint | null][]; + const officialClassOrder = getClassOrder({ classes, configPath: tailwindConfig, cwd: ctx.cwd }); const officiallySortedClasses = [...officialClassOrder] .sort(([, a], [, z]) => { if(a === z){ return 0; } @@ -336,46 +329,6 @@ function sortClasses(ctx: Rule.RuleContext, tailwindContext: TailwindContext, cl } -function findTailwindConfig(ctx: Rule.RuleContext, directory: string = ctx.cwd) { - - const { tailwindConfig } = getOptions(ctx); - - const cacheKey = JSON.stringify({ config: tailwindConfig, cwd: ctx.cwd }); - - if(TAILWIND_CONFIG_CACHE.has(cacheKey)){ - return TAILWIND_CONFIG_CACHE.get(cacheKey)!; - } - - let userConfig: Config | undefined; - - userConfig ??= tailwindConfig - ? loadTailwindConfig(resolve(directory, tailwindConfig)) - : undefined; - - userConfig ??= loadTailwindConfig(resolve(directory, "tailwind.config.js")); - userConfig ??= loadTailwindConfig(resolve(directory, "tailwind.config.ts")); - - if(userConfig){ - const loadedConfig = resolveConfig(userConfig); - TAILWIND_CONFIG_CACHE.set(cacheKey, loadedConfig); - return loadedConfig; - } - - const parentDirectory = resolve(directory, ".."); - - if(directory === parentDirectory){ - return resolveConfig(defaultConfig); - } - - return findTailwindConfig(ctx, parentDirectory); - -} - -function loadTailwindConfig(path: string) { - try { - return loadConfig(path); - } catch (error){} -} export function getOptions(ctx?: Rule.RuleContext) { @@ -403,7 +356,11 @@ export function getOptions(ctx?: Rule.RuleContext) { ctx?.settings["readable-tailwind"]?.tags ?? defaultOptions.tags; - const tailwindConfig = options.tailwindConfig; + const tailwindConfig = options.tailwindConfig ?? options.entryPoint ?? + ctx?.settings["eslint-plugin-readable-tailwind"]?.tailwindConfig ?? + ctx?.settings["readable-tailwind"]?.tailwindConfig ?? + ctx?.settings["eslint-plugin-readable-tailwind"]?.entryPoint ?? + ctx?.settings["readable-tailwind"]?.entryPoint; return { attributes, @@ -415,20 +372,3 @@ export function getOptions(ctx?: Rule.RuleContext) { }; } - -interface TailwindContext { - getClassOrder: (classes: string[]) => [className: string, order: bigint | null][]; - tailwindConfig: Config; -} - -function createTailwindContext(tailwindConfig: ReturnType): TailwindContext { - if(TAILWIND_CONTEXT_CACHE.has(tailwindConfig)){ - return TAILWIND_CONTEXT_CACHE.get(tailwindConfig)!; - } - - const createContext = setupContextUtils.createContext ?? setupContextUtils.default.createContext; - - const context = createContext(tailwindConfig); - TAILWIND_CONTEXT_CACHE.set(tailwindConfig, context); - return context; -} diff --git a/src/tailwind/api/interface.ts b/src/tailwind/api/interface.ts new file mode 100644 index 0000000..b710dc7 --- /dev/null +++ b/src/tailwind/api/interface.ts @@ -0,0 +1,7 @@ +export interface GetClassOrderRequest { + classes: string[]; + cwd: string; + configPath?: string; +} + +export type GetClassOrderResponse = [className: string, order: bigint | null][]; diff --git a/src/tailwind/async/class-order.async.ts b/src/tailwind/async/class-order.async.ts new file mode 100644 index 0000000..f8ed2f1 --- /dev/null +++ b/src/tailwind/async/class-order.async.ts @@ -0,0 +1,10 @@ +import { runAsWorker } from "synckit"; + +import type { GetClassOrderRequest } from "../api/interface.js"; +import type { SupportedTailwindVersion } from "../utils/version.js"; + + +runAsWorker(async (version: SupportedTailwindVersion, request: GetClassOrderRequest) => { + const { getClassOrder } = await import(`../v${version}/index.js`); + return getClassOrder(request); +}); diff --git a/src/tailwind/async/class-order.sync.ts b/src/tailwind/async/class-order.sync.ts new file mode 100644 index 0000000..ecf087e --- /dev/null +++ b/src/tailwind/async/class-order.sync.ts @@ -0,0 +1,33 @@ +// runner.js +import { resolve } from "node:path"; +import { env } from "node:process"; + +import { createSyncFn, TsRunner } from "synckit"; + +import { getTailwindcssVersion, isSupportedVersion } from "../utils/version.js"; + +import type { GetClassOrderRequest, GetClassOrderResponse } from "../api/interface.js"; +import type { SupportedTailwindVersion } from "../utils/version.js"; + + +const getClassOrderSync = createSyncFn<(version: SupportedTailwindVersion, request: GetClassOrderRequest) => any>(resolve(getDirName(), "./class-order.async.js"), { + ...env.NODE_ENV === "test" && { execArgv: ["--import", TsRunner.TSX] } +}); + + +export function getClassOrder(request: GetClassOrderRequest): GetClassOrderResponse { + + const version = getTailwindcssVersion(); + + if(!isSupportedVersion(version.major)){ + throw new Error(`Unsupported Tailwind CSS version: ${version.major}`); + } + + return getClassOrderSync(version.major, request) as GetClassOrderResponse; +} + +function getDirName() { + // eslint-disable-next-line eslint-plugin-typescript/ban-ts-comment, eslint-plugin-typescript/prefer-ts-expect-error + // @ts-ignore + return import.meta.dirname ?? __dirname; +} diff --git a/src/tailwind/utils/config.ts b/src/tailwind/utils/config.ts new file mode 100644 index 0000000..048d3d0 --- /dev/null +++ b/src/tailwind/utils/config.ts @@ -0,0 +1,25 @@ +import { existsSync } from "node:fs"; +import { basename, dirname, resolve } from "node:path"; + + +export function findFileRecursive(cwd: string, paths: string[]) { + const resolvedPaths = paths.map(p => resolve(cwd, p)); + + for(let resolvedPath = resolvedPaths.shift(); resolvedPath !== undefined; resolvedPath = resolvedPaths.shift()){ + if(existsSync(resolvedPath)){ + return resolvedPath; + } + + const fileName = basename(resolvedPath); + const directory = dirname(resolvedPath); + + const parentDirectory = resolve(directory, ".."); + const parentPath = resolve(parentDirectory, fileName); + + if(parentDirectory === directory || directory === cwd){ + continue; + } + + resolvedPaths.push(parentPath); + } +} diff --git a/src/tailwind/utils/module.ts b/src/tailwind/utils/module.ts new file mode 100644 index 0000000..d29b557 --- /dev/null +++ b/src/tailwind/utils/module.ts @@ -0,0 +1,3 @@ +export function isCommonJSModule(): boolean { + return typeof __dirname === "string"; +} diff --git a/src/tailwind/utils/resolvers.ts b/src/tailwind/utils/resolvers.ts new file mode 100644 index 0000000..3b9c800 --- /dev/null +++ b/src/tailwind/utils/resolvers.ts @@ -0,0 +1,37 @@ +import fs from "node:fs"; + +import enhancedResolve from "enhanced-resolve"; + + +const fileSystem = new enhancedResolve.CachedInputFileSystem(fs, 30_000); + +export const esmResolver = enhancedResolve.ResolverFactory.createResolver({ + conditionNames: ["node", "import"], + extensions: [".mjs", ".js"], + fileSystem, + mainFields: ["module"], + useSyncFileSystemCalls: true +}); + +export const cjsResolver = enhancedResolve.ResolverFactory.createResolver({ + conditionNames: ["node", "require"], + extensions: [".js", ".cjs"], + fileSystem, + mainFields: ["main"], + useSyncFileSystemCalls: true +}); + +export const cssResolver = enhancedResolve.ResolverFactory.createResolver({ + conditionNames: ["style"], + extensions: [".css"], + fileSystem, + mainFields: ["style"], + useSyncFileSystemCalls: true +}); + +export const jsonResolver = enhancedResolve.ResolverFactory.createResolver({ + conditionNames: ["json"], + extensions: [".json"], + fileSystem, + useSyncFileSystemCalls: true +}); diff --git a/src/tailwind/utils/version.ts b/src/tailwind/utils/version.ts new file mode 100644 index 0000000..caaa4af --- /dev/null +++ b/src/tailwind/utils/version.ts @@ -0,0 +1,29 @@ +import { readFileSync } from "node:fs"; + +import { jsonResolver } from "../utils/resolvers.js"; + + +export type SupportedTailwindVersion = 3 | 4; + +export function isSupportedVersion(version: number): version is SupportedTailwindVersion { + return version === 3 || version === 4; +} + + +export function getTailwindcssVersion() { + const packageJsonPath = jsonResolver.resolveSync({}, process.cwd(), "tailwindcss/package.json"); + const packageJson = packageJsonPath && JSON.parse(readFileSync(packageJsonPath, "utf-8")); + + if(!packageJson){ + throw new Error("Could not find a Tailwind CSS package.json"); + } + + return parseSemanticVersion(packageJson.version); +} + +function parseSemanticVersion(version: string): { major: number; minor: number; patch: number; identifier?: string; } { + const [major, minor, patchString] = version.split("."); + const [patch, identifier] = patchString.split("-"); + + return { identifier, major: +major, minor: +minor, patch: +patch }; +} diff --git a/src/tailwind/v3/class-order.ts b/src/tailwind/v3/class-order.ts new file mode 100644 index 0000000..48101f7 --- /dev/null +++ b/src/tailwind/v3/class-order.ts @@ -0,0 +1,19 @@ +import { findFileRecursive } from "../utils/config.js"; +import { createTailwindContextFromConfigFile } from "./config.js"; + +import type { GetClassOrderRequest, GetClassOrderResponse } from "../api/interface.js"; + + +export async function getClassOrder({ classes, configPath, cwd }: GetClassOrderRequest): Promise { + const potentialPaths = [ + ...configPath ? [configPath] : [], + "tailwind.config.js", + "tailwind.config.cjs", + "tailwind.config.mjs", + "tailwind.config.ts" + ]; + + const foundPath = findFileRecursive(cwd, potentialPaths); + const context = createTailwindContextFromConfigFile(foundPath); + return context.getClassOrder(classes); +} diff --git a/src/tailwind/v3/config.ts b/src/tailwind/v3/config.ts new file mode 100644 index 0000000..e424396 --- /dev/null +++ b/src/tailwind/v3/config.ts @@ -0,0 +1,27 @@ +import defaultConfig from "tailwindcss3/defaultConfig.js"; +import setupContextUtils from "tailwindcss3/lib/lib/setupContextUtils.js"; +import loadConfig from "tailwindcss3/loadConfig.js"; +import resolveConfig from "tailwindcss3/resolveConfig.js"; + + +export function loadTailwindConfig(path: string | undefined) { + const config = path ? loadConfig(path) : defaultConfig; + return resolveConfig(config); +} + +const CACHE = new Map>(); + +export function createTailwindContextFromConfigFile(path?: string) { + const cacheKey = path ?? "default"; + + if(CACHE.has(cacheKey)){ + return CACHE.get(cacheKey); + } + + const tailwindConfig = loadTailwindConfig(path); + const context = setupContextUtils.createContext?.(tailwindConfig) ?? setupContextUtils.default?.createContext?.(tailwindConfig); + + CACHE.set(cacheKey, context); + + return context; +} diff --git a/src/tailwind/v3/index.ts b/src/tailwind/v3/index.ts new file mode 100644 index 0000000..4d7dda0 --- /dev/null +++ b/src/tailwind/v3/index.ts @@ -0,0 +1 @@ +export { getClassOrder } from "./class-order.js"; diff --git a/src/tailwind/v4/class-order.ts b/src/tailwind/v4/class-order.ts new file mode 100644 index 0000000..ab712d8 --- /dev/null +++ b/src/tailwind/v4/class-order.ts @@ -0,0 +1,32 @@ +import { findFileRecursive } from "../utils/config.js"; +import { cssResolver } from "../utils/resolvers.js"; +import { createTailwindContextFromEntryPoint } from "./config.js"; + +import type { GetClassOrderRequest, GetClassOrderResponse } from "../api/interface.js"; + + +export async function getClassOrder({ classes, configPath, cwd }: GetClassOrderRequest): Promise { + const potentialStylesheetPaths = [ + ...configPath ? [configPath] : [] + ]; + const potentialConfigPaths = [ + ...configPath ? [configPath] : [], + "tailwind.config.js", + "tailwind.config.cjs", + "tailwind.config.mjs", + "tailwind.config.ts" + ]; + + const foundStylesheetPath = findFileRecursive(cwd, potentialStylesheetPaths); + const foundConfigPath = findFileRecursive(cwd, potentialConfigPaths); + const defaultStyleSheetPath = cssResolver.resolveSync({}, cwd, "tailwindcss/theme.css"); + + const path = foundStylesheetPath ?? foundConfigPath ?? defaultStyleSheetPath; + + if(!path){ + throw new Error("Could not find a valid Tailwind CSS configuration"); + } + + const context = await createTailwindContextFromEntryPoint(path); + return context.getClassOrder(classes); +} diff --git a/src/tailwind/v4/config.ts b/src/tailwind/v4/config.ts new file mode 100644 index 0000000..3e76183 --- /dev/null +++ b/src/tailwind/v4/config.ts @@ -0,0 +1,139 @@ +import { readFile } from "node:fs/promises"; +import path, { dirname } from "node:path"; +import { pathToFileURL } from "node:url"; + +import postcss from "postcss"; +import postcssImport from "postcss-import"; + +import { isCommonJSModule } from "../utils/module.js"; +import { cjsResolver, cssResolver, esmResolver } from "../utils/resolvers.js"; + + +function resolveJsFrom(base: string, id: string): string { + try { + return esmResolver.resolveSync({}, base, id) || id; + } catch (err){ + return cjsResolver.resolveSync({}, base, id) || id; + } +} + +function resolveCssFrom(base: string, id: string) { + return cssResolver.resolveSync({}, base, id) || id; +} + +function createLoader({ + filepath, + legacy, + onError +}: { + filepath: string; + legacy: boolean; + onError: (id: string, error: unknown, resourceType: string) => T; +}) { + const cacheKey = `${+Date.now()}`; + + async function loadFile(id: string, base: string, resourceType: string) { + try { + const resolved = resolveJsFrom(base, id); + + const url = pathToFileURL(resolved); + url.searchParams.append("t", cacheKey); + + return await import(url.href).then(m => m.default ?? m); + } catch (err){ + return onError(id, err, resourceType); + } + } + + if(legacy){ + const baseDir = path.dirname(filepath); + return async (id: string) => loadFile(id, baseDir, "module"); + } + + return async (id: string, base: string, resourceType: string) => { + return { + base, + module: await loadFile(id, base, resourceType) + }; + }; +} + +const CACHE = new Map>>(); + +export async function createTailwindContextFromEntryPoint(entryPoint: string) { + if(CACHE.has(entryPoint)){ + return CACHE.get(entryPoint); + } + + const importBasePath = dirname(entryPoint); + + const tailwindPath = isCommonJSModule() + ? cjsResolver.resolveSync({}, importBasePath, "tailwindcss") + : esmResolver.resolveSync({}, importBasePath, "tailwindcss"); + + if(!tailwindPath){ + throw new Error("Could not find Tailwind CSS"); + } + + const tailwindUrl = pathToFileURL(tailwindPath).toString(); + // eslint-disable-next-line eslint-plugin-typescript/naming-convention + const { __unstable__loadDesignSystem } = await import(tailwindUrl); + + let css = await readFile(entryPoint, "utf-8"); + + // Determine if the v4 API supports resolving `@import` + let supportsImports = false; + try { + await __unstable__loadDesignSystem('@import "./empty";', { + loadStylesheet: async () => { + supportsImports = true; + return { + base: importBasePath, + content: "" + }; + } + }); + } catch {} + + if(!supportsImports){ + const resolveImports = postcss([postcssImport()]); + const result = await resolveImports.process(css, { from: entryPoint }); + css = result.css; + } + + // Load the design system and set up a compatible context object that is + // usable by the rest of the plugin + const design = await __unstable__loadDesignSystem(css, { + base: importBasePath, + loadModule: createLoader({ + filepath: entryPoint, + legacy: false, + onError: (id, err, resourceType) => { + console.error(`Unable to load ${resourceType}: ${id}`, err); + + if(resourceType === "config"){ + return {}; + } else if(resourceType === "plugin"){ + return () => {}; + } + } + }), + + loadStylesheet: async (id: string, base: string) => { + const resolved = resolveCssFrom(base, id); + + return { + base: path.dirname(resolved), + content: await readFile(resolved, "utf-8") + }; + } + }); + + const context = { + getClassOrder: (classList: string[]) => design.getClassOrder(classList) + }; + + CACHE.set(entryPoint, context); + + return context; +} diff --git a/src/tailwind/v4/index.ts b/src/tailwind/v4/index.ts new file mode 100644 index 0000000..4d7dda0 --- /dev/null +++ b/src/tailwind/v4/index.ts @@ -0,0 +1 @@ +export { getClassOrder } from "./class-order.js"; diff --git a/tsconfig.build.cjs.json b/tsconfig.build.cjs.json index 84e7d09..5717700 100644 --- a/tsconfig.build.cjs.json +++ b/tsconfig.build.cjs.json @@ -1,6 +1,9 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "module": "CommonJS", + "moduleResolution": "node", + "verbatimModuleSyntax": false, "declaration": true, "declarationMap": true, "noEmit": false, @@ -9,6 +12,9 @@ "target": "ES2020" }, "include": [ + "src/tailwind/v3/**/*.ts", + "src/tailwind/v4/**/*.ts", + "src/tailwind/async/**/*.ts", "src/configs/cjs.ts", "src/api/defaults.ts", "src/api/types.ts" diff --git a/tsconfig.build.esm.json b/tsconfig.build.esm.json index d645e15..04cf759 100644 --- a/tsconfig.build.esm.json +++ b/tsconfig.build.esm.json @@ -1,6 +1,8 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "nodenext", "declaration": true, "declarationMap": true, "noEmit": false, @@ -9,6 +11,9 @@ "target": "ES2020" }, "include": [ + "src/tailwind/v3/**/*.ts", + "src/tailwind/v4/**/*.ts", + "src/tailwind/async/**/*.ts", "src/configs/esm.ts", "src/api/defaults.ts", "src/api/types.ts" diff --git a/tsconfig.json b/tsconfig.json index 9eb4285..b60db75 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,8 @@ "noImplicitAny": false, "paths": { "readable-tailwind:build:*": ["build/*"], + "readable-tailwind:async:*": ["src/tailwind/async/*"], + "readable-tailwind:tailwindcss:*": ["src/tailwindcss/*"], "readable-tailwind:options:*": ["src/options/*"], "readable-tailwind:configs:*": ["src/configs/*"], "readable-tailwind:parsers:*": ["src/parsers/*"],