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/*"],