From 5a3b03b69b17bb1e217734eebd54d355ee167a07 Mon Sep 17 00:00:00 2001 From: Alex <8125011+alex-kinokon@users.noreply.github.com> Date: Sat, 17 Aug 2024 19:59:08 -0400 Subject: [PATCH] Split files --- .eslintrc.js | 1 + package.json | 14 +- pnpm-lock.yaml | 298 +++++++++++------------ src/babel-tailwind.ts | 536 ------------------------------------------ src/babel/index.ts | 389 ++++++++++++++++++++++++++++++ src/babel/macro.ts | 142 +++++++++++ src/babel/utils.ts | 51 ++++ src/index.ts | 2 +- src/macro.d.ts | 2 +- src/vite-plugin.ts | 2 +- 10 files changed, 742 insertions(+), 695 deletions(-) delete mode 100644 src/babel-tailwind.ts create mode 100644 src/babel/index.ts create mode 100644 src/babel/macro.ts create mode 100644 src/babel/utils.ts diff --git a/.eslintrc.js b/.eslintrc.js index 001a91f..93121e6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,5 +4,6 @@ const { extendConfig } = require("@aet/eslint-rules"); module.exports = extendConfig({ rules: { "class-methods-use-this": "error", + "import-x/no-unresolved": ["error", { ignore: ["react"] }], }, }); diff --git a/package.json b/package.json index ea8d5e7..b6702e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aet/tailwind", - "version": "1.0.9", + "version": "1.0.10", "license": "MIT", "scripts": { "build": "./scripts/index.ts", @@ -33,7 +33,7 @@ "@types/bun": "^1.1.6", "@types/dedent": "^0.7.2", "@types/lodash": "^4.17.7", - "@types/node": "^22.2.0", + "@types/node": "^22.4.0", "@types/postcss-safe-parser": "^5.0.4", "@types/react": "^18.3.3", "@types/stylis": "^4.2.6", @@ -47,11 +47,11 @@ "nolyfill": "^1.0.39", "postcss-nested": "^6.2.0", "prettier": "^3.3.3", - "tailwindcss": "^3.4.9", + "tailwindcss": "^3.4.10", "tslib": "^2.6.3", "tsup": "^8.2.4", "typescript": "^5.5.4", - "vite": "^5.4.0", + "vite": "^5.4.1", "vitest": "^2.0.5" }, "peerDependencies": { @@ -60,14 +60,14 @@ "dependencies": { "@babel/core": "^7.25.2", "@emotion/hash": "^0.9.2", - "esbuild": "^0.23.0", + "esbuild": "^0.23.1", "json5": "^2.2.3", "lodash": "^4.17.21", "postcss": "^8.4.41", - "postcss-selector-parser": "^6.1.1", + "postcss-selector-parser": "^6.1.2", "stylis": "^4.3.2", "tiny-invariant": "^1.3.3", - "type-fest": "^4.24.0" + "type-fest": "^4.25.0" }, "prettier": { "arrowParens": "avoid", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 34e224e..082ba0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^0.9.2 version: 0.9.2 esbuild: - specifier: ^0.23.0 - version: 0.23.0 + specifier: ^0.23.1 + version: 0.23.1 json5: specifier: ^2.2.3 version: 2.2.3 @@ -30,8 +30,8 @@ importers: specifier: ^8.4.41 version: 8.4.41 postcss-selector-parser: - specifier: ^6.1.1 - version: 6.1.1 + specifier: ^6.1.2 + version: 6.1.2 stylis: specifier: ^4.3.2 version: 4.3.2 @@ -39,8 +39,8 @@ importers: specifier: ^1.3.3 version: 1.3.3 type-fest: - specifier: ^4.24.0 - version: 4.24.0 + specifier: ^4.25.0 + version: 4.25.0 devDependencies: '@aet/eslint-rules': specifier: 1.0.1-beta.24 @@ -58,8 +58,8 @@ importers: specifier: ^4.17.7 version: 4.17.7 '@types/node': - specifier: ^22.2.0 - version: 22.2.0 + specifier: ^22.4.0 + version: 22.4.0 '@types/postcss-safe-parser': specifier: ^5.0.4 version: 5.0.4 @@ -86,7 +86,7 @@ importers: version: 1.5.3 esbuild-register: specifier: ^3.6.0 - version: 3.6.0(esbuild@0.23.0) + version: 3.6.0(esbuild@0.23.1) eslint: specifier: ^8.57.0 version: 8.57.0 @@ -100,8 +100,8 @@ importers: specifier: ^3.3.3 version: 3.3.3 tailwindcss: - specifier: ^3.4.9 - version: 3.4.9 + specifier: ^3.4.10 + version: 3.4.10 tslib: specifier: ^2.6.3 version: 2.6.3 @@ -112,11 +112,11 @@ importers: specifier: ^5.5.4 version: 5.5.4 vite: - specifier: ^5.4.0 - version: 5.4.0(@types/node@22.2.0) + specifier: ^5.4.1 + version: 5.4.1(@types/node@22.4.0) vitest: specifier: ^2.0.5 - version: 2.0.5(@types/node@22.2.0) + version: 2.0.5(@types/node@22.4.0) packages: @@ -226,8 +226,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.23.0': - resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -238,8 +238,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.23.0': - resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -250,8 +250,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.23.0': - resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -262,8 +262,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.23.0': - resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -274,8 +274,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.23.0': - resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -286,8 +286,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.23.0': - resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -298,8 +298,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.23.0': - resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -310,8 +310,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.0': - resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -322,8 +322,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.23.0': - resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -334,8 +334,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.23.0': - resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -346,8 +346,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.23.0': - resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -358,8 +358,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.23.0': - resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -370,8 +370,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.23.0': - resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -382,8 +382,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.23.0': - resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -394,8 +394,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.23.0': - resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -406,8 +406,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.23.0': - resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -418,8 +418,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.23.0': - resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -430,14 +430,14 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.23.0': - resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.0': - resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -448,8 +448,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.0': - resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -460,8 +460,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.23.0': - resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -472,8 +472,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.23.0': - resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -484,8 +484,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.23.0': - resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -496,8 +496,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.23.0': - resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -732,8 +732,8 @@ packages: '@types/node@20.12.14': resolution: {integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==} - '@types/node@22.2.0': - resolution: {integrity: sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==} + '@types/node@22.4.0': + resolution: {integrity: sha512-49AbMDwYUz7EXxKU/r7mXOsxwFr4BYbvB7tWYxVuLdb2ibd30ijjXINSMAHiEEZk5PCRBmW1gUeisn2VMKt3cQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1198,8 +1198,8 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.23.0: - resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} engines: {node: '>=18'} hasBin: true @@ -1955,8 +1955,8 @@ packages: peerDependencies: postcss: ^8.2.14 - postcss-selector-parser@6.1.1: - resolution: {integrity: sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==} + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -2181,8 +2181,8 @@ packages: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} - tailwindcss@3.4.9: - resolution: {integrity: sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==} + tailwindcss@3.4.10: + resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} engines: {node: '>=14.0.0'} hasBin: true @@ -2292,8 +2292,8 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@4.24.0: - resolution: {integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==} + type-fest@4.25.0: + resolution: {integrity: sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==} engines: {node: '>=16'} typescript@5.5.4: @@ -2304,8 +2304,8 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.13.0: - resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} + undici-types@6.19.6: + resolution: {integrity: sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==} update-browserslist-db@1.1.0: resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} @@ -2327,8 +2327,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.4.0: - resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==} + vite@5.4.1: + resolution: {integrity: sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -2624,142 +2624,142 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.23.0': + '@esbuild/aix-ppc64@0.23.1': optional: true '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.23.0': + '@esbuild/android-arm64@0.23.1': optional: true '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.23.0': + '@esbuild/android-arm@0.23.1': optional: true '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/android-x64@0.23.0': + '@esbuild/android-x64@0.23.1': optional: true '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/darwin-arm64@0.23.0': + '@esbuild/darwin-arm64@0.23.1': optional: true '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/darwin-x64@0.23.0': + '@esbuild/darwin-x64@0.23.1': optional: true '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/freebsd-arm64@0.23.0': + '@esbuild/freebsd-arm64@0.23.1': optional: true '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/freebsd-x64@0.23.0': + '@esbuild/freebsd-x64@0.23.1': optional: true '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-arm64@0.23.0': + '@esbuild/linux-arm64@0.23.1': optional: true '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.23.0': + '@esbuild/linux-arm@0.23.1': optional: true '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-ia32@0.23.0': + '@esbuild/linux-ia32@0.23.1': optional: true '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/linux-loong64@0.23.0': + '@esbuild/linux-loong64@0.23.1': optional: true '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/linux-mips64el@0.23.0': + '@esbuild/linux-mips64el@0.23.1': optional: true '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.23.0': + '@esbuild/linux-ppc64@0.23.1': optional: true '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.23.0': + '@esbuild/linux-riscv64@0.23.1': optional: true '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/linux-s390x@0.23.0': + '@esbuild/linux-s390x@0.23.1': optional: true '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/linux-x64@0.23.0': + '@esbuild/linux-x64@0.23.1': optional: true '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.23.0': + '@esbuild/netbsd-x64@0.23.1': optional: true - '@esbuild/openbsd-arm64@0.23.0': + '@esbuild/openbsd-arm64@0.23.1': optional: true '@esbuild/openbsd-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.23.0': + '@esbuild/openbsd-x64@0.23.1': optional: true '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.23.0': + '@esbuild/sunos-x64@0.23.1': optional: true '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.23.0': + '@esbuild/win32-arm64@0.23.1': optional: true '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.23.0': + '@esbuild/win32-ia32@0.23.1': optional: true '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.23.0': + '@esbuild/win32-x64@0.23.1': optional: true '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': @@ -3055,9 +3055,9 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@22.2.0': + '@types/node@22.4.0': dependencies: - undici-types: 6.13.0 + undici-types: 6.19.6 '@types/normalize-package-data@2.4.4': {} @@ -3076,7 +3076,7 @@ snapshots: '@types/ws@8.5.12': dependencies: - '@types/node': 22.2.0 + '@types/node': 22.4.0 '@typescript-eslint/eslint-plugin@8.0.1(@typescript-eslint/parser@8.0.1(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': dependencies: @@ -3365,9 +3365,9 @@ snapshots: '@types/node': 20.12.14 '@types/ws': 8.5.12 - bundle-require@5.0.0(esbuild@0.23.0): + bundle-require@5.0.0(esbuild@0.23.1): dependencies: - esbuild: 0.23.0 + esbuild: 0.23.1 load-tsconfig: 0.2.5 cac@6.7.14: {} @@ -3527,10 +3527,10 @@ snapshots: es-module-lexer@1.5.4: {} - esbuild-register@3.6.0(esbuild@0.23.0): + esbuild-register@3.6.0(esbuild@0.23.1): dependencies: debug: 4.3.6 - esbuild: 0.23.0 + esbuild: 0.23.1 transitivePeerDependencies: - supports-color @@ -3560,32 +3560,32 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.23.0: + esbuild@0.23.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.23.0 - '@esbuild/android-arm': 0.23.0 - '@esbuild/android-arm64': 0.23.0 - '@esbuild/android-x64': 0.23.0 - '@esbuild/darwin-arm64': 0.23.0 - '@esbuild/darwin-x64': 0.23.0 - '@esbuild/freebsd-arm64': 0.23.0 - '@esbuild/freebsd-x64': 0.23.0 - '@esbuild/linux-arm': 0.23.0 - '@esbuild/linux-arm64': 0.23.0 - '@esbuild/linux-ia32': 0.23.0 - '@esbuild/linux-loong64': 0.23.0 - '@esbuild/linux-mips64el': 0.23.0 - '@esbuild/linux-ppc64': 0.23.0 - '@esbuild/linux-riscv64': 0.23.0 - '@esbuild/linux-s390x': 0.23.0 - '@esbuild/linux-x64': 0.23.0 - '@esbuild/netbsd-x64': 0.23.0 - '@esbuild/openbsd-arm64': 0.23.0 - '@esbuild/openbsd-x64': 0.23.0 - '@esbuild/sunos-x64': 0.23.0 - '@esbuild/win32-arm64': 0.23.0 - '@esbuild/win32-ia32': 0.23.0 - '@esbuild/win32-x64': 0.23.0 + '@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 escalade@3.1.2: {} @@ -4358,9 +4358,9 @@ snapshots: postcss-nested@6.2.0(postcss@8.4.41): dependencies: postcss: 8.4.41 - postcss-selector-parser: 6.1.1 + postcss-selector-parser: 6.1.2 - postcss-selector-parser@6.1.1: + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -4410,7 +4410,7 @@ snapshots: remeda@2.10.1: dependencies: - type-fest: 4.24.0 + type-fest: 4.25.0 require-directory@2.1.1: {} @@ -4574,7 +4574,7 @@ snapshots: '@pkgr/core': 0.1.1 tslib: 2.6.3 - tailwindcss@3.4.9: + tailwindcss@3.4.10: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -4595,7 +4595,7 @@ snapshots: postcss-js: 4.0.1(postcss@8.4.41) postcss-load-config: 4.0.2(postcss@8.4.41) postcss-nested: 6.2.0(postcss@8.4.41) - postcss-selector-parser: 6.1.1 + postcss-selector-parser: 6.1.2 resolve: 1.22.8 sucrase: 3.35.0 transitivePeerDependencies: @@ -4652,12 +4652,12 @@ snapshots: tsup@8.2.4(jiti@1.21.6)(postcss@8.4.41)(typescript@5.5.4)(yaml@2.5.0): dependencies: - bundle-require: 5.0.0(esbuild@0.23.0) + bundle-require: 5.0.0(esbuild@0.23.1) cac: 6.7.14 chokidar: 3.6.0 consola: 3.2.3 debug: 4.3.6 - esbuild: 0.23.0 + esbuild: 0.23.1 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 @@ -4689,13 +4689,13 @@ snapshots: type-fest@0.8.1: {} - type-fest@4.24.0: {} + type-fest@4.25.0: {} typescript@5.5.4: {} undici-types@5.26.5: {} - undici-types@6.13.0: {} + undici-types@6.19.6: {} update-browserslist-db@1.1.0(browserslist@4.23.3): dependencies: @@ -4714,13 +4714,13 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-node@2.0.5(@types/node@22.2.0): + vite-node@2.0.5(@types/node@22.4.0): dependencies: cac: 6.7.14 debug: 4.3.6 pathe: 1.1.2 tinyrainbow: 1.2.0 - vite: 5.4.0(@types/node@22.2.0) + vite: 5.4.1(@types/node@22.4.0) transitivePeerDependencies: - '@types/node' - less @@ -4732,16 +4732,16 @@ snapshots: - supports-color - terser - vite@5.4.0(@types/node@22.2.0): + vite@5.4.1(@types/node@22.4.0): dependencies: esbuild: 0.21.5 postcss: 8.4.41 rollup: 4.20.0 optionalDependencies: - '@types/node': 22.2.0 + '@types/node': 22.4.0 fsevents: 2.3.3 - vitest@2.0.5(@types/node@22.2.0): + vitest@2.0.5(@types/node@22.4.0): dependencies: '@ampproject/remapping': 2.3.0 '@vitest/expect': 2.0.5 @@ -4759,11 +4759,11 @@ snapshots: tinybench: 2.9.0 tinypool: 1.0.0 tinyrainbow: 1.2.0 - vite: 5.4.0(@types/node@22.2.0) - vite-node: 2.0.5(@types/node@22.2.0) + vite: 5.4.1(@types/node@22.4.0) + vite-node: 2.0.5(@types/node@22.4.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.2.0 + '@types/node': 22.4.0 transitivePeerDependencies: - less - lightningcss diff --git a/src/babel-tailwind.ts b/src/babel-tailwind.ts deleted file mode 100644 index f86a239..0000000 --- a/src/babel-tailwind.ts +++ /dev/null @@ -1,536 +0,0 @@ -import { basename, dirname, extname, join } from "node:path"; -import type b from "@babel/core"; -import hash from "@emotion/hash"; -import { isPlainObject } from "lodash"; -import invariant from "tiny-invariant"; -import { type NodePath, type types as t } from "@babel/core"; -import { type SourceLocation, type StyleMapEntry, macroNames } from "./shared"; -import { type ResolveTailwindOptions, getClassName } from "./index"; - -export type ClassNameCollector = (path: string, entries: StyleMapEntry[]) => void; -type BabelTypes = typeof b.types; -type Type = "css" | "js"; - -export function babelTailwind( - options: ResolveTailwindOptions, - onCollect: ClassNameCollector | undefined -) { - const { - styleMap, - clsx, - getClassName: getClass = getClassName, - jsxAttributeAction = "delete", - jsxAttributeName = "css", - vite: bustCache, - } = options; - - type BabelPluginUtils = ReturnType; - - function getUtils(path: NodePath, state: b.PluginPass, t: BabelTypes) { - let cx: t.Identifier; - let tslibImport: t.Identifier; - let styleImport: t.Identifier; - - const cssMap = new Map(); - const jsMap = new Map(); - - function getStyleImport() { - styleImport ??= path.scope.generateUidIdentifier("styles"); - return t.cloneNode(styleImport); - } - - return { - getClass(type: Type, value: string) { - return type === "css" ? getClass(value) : "tw_" + hash(value); - }, - - sliceText: (node: t.Node): SourceLocation => ({ - filename: state.filename!, - start: node.loc!.start, - end: node.loc!.end, - text: state.file.code - .split("\n") - .slice(node.loc!.start.line - 1, node.loc!.end.line) - .join("\n"), - }), - - recordIfAbsent(type: Type, entry: StyleMapEntry) { - const map = type === "css" ? cssMap : jsMap; - if (!map.has(entry.key)) { - map.set(entry.key, entry); - } - }, - - replaceWithImport({ - type, - path, - className, - }: { - type: Type; - path: NodePath; - className: string; - }) { - if (type === "css") { - path.replaceWith(t.stringLiteral(className)); - } else { - const styleImportId = getStyleImport(); - path.replaceWith( - t.memberExpression(styleImportId, t.stringLiteral(className), true) - ); - } - }, - - getCx: () => { - if (cx == null) { - cx = path.scope.generateUidIdentifier("cx"); - path.node.body.unshift(getClsxImport(t, cx, clsx)); - } - return t.cloneNode(cx); - }, - - getTSlibImport: () => { - if (tslibImport == null) { - tslibImport = path.scope.generateUidIdentifier("tslib"); - path.node.body.unshift( - t.importDeclaration( - [t.importNamespaceSpecifier(tslibImport)], - t.stringLiteral("tslib") - ) - ); - } - return t.cloneNode(tslibImport); - }, - - finish(node: t.Program) { - const { filename } = state; - if (!cssMap.size && !jsMap.size) return; - invariant(filename, "babel: missing state.filename"); - - if (cssMap.size) { - const cssName = basename(filename, extname(filename)) + ".css"; - const path = join(dirname(filename), cssName); - const value = Array.from(cssMap.values()); - const importee = `tailwind:./${cssName}` + getSuffix(bustCache, value); - - node.body.unshift(t.importDeclaration([], t.stringLiteral(importee))); - - styleMap.set(path, value); - onCollect?.(path, value); - } - - if (jsMap.size) { - const jsName = basename(filename, extname(filename)) + ".tailwindStyle.js"; - const path = join(dirname(filename), jsName); - const value = Array.from(jsMap.values()); - const importee = `tailwind:./${jsName}` + getSuffix(bustCache, value); - - node.body.unshift( - t.importDeclaration( - [t.importNamespaceSpecifier(getStyleImport())], - t.stringLiteral(importee) - ) - ); - styleMap.set(path, value); - onCollect?.(path, value); - } - }, - }; - } - - return definePlugin(({ types: t }) => ({ - Program: { - enter(path, state) { - const _ = getUtils(path, state, t); - Object.assign(state, _); - - for (const { callee, imported, prefix } of getMacros(t, path, macroNames).map( - macro => mapMacro(t, macro) - )) { - const type = imported === "tw" ? "css" : imported === "tws" ? "js" : undefined; - if (!type) continue; - - if (isNodePath(callee, t.isTaggedTemplateExpression)) { - const { node } = callee; - const { quasi } = node; - - invariant( - !quasi.expressions.length, - `Macro call should not contain expressions` - ); - - const value = quasi.quasis[0].value.cooked; - if (value) { - const list = trimPrefix(value, prefix ? prefix + ":" : undefined); - const className = _.getClass(type, list.join(" ")); - _.recordIfAbsent(type, { - key: className, - classNames: list, - location: _.sliceText(node), - }); - _.replaceWithImport({ - type, - path: callee, - className: addIf(className, list.includes("group") && " group"), - }); - } - } else if (isNodePath(callee, t.isCallExpression)) { - const { node } = callee; - if (!t.isIdentifier(node.callee)) continue; - - const list = callee.get("arguments").flatMap(evaluateArgs); - const className = getClass(list.join(" ")); - _.recordIfAbsent(type, { - key: className, - classNames: list, - location: _.sliceText(node), - }); - _.replaceWithImport({ - type, - path: callee, - className: addIf(className, list.includes("group") && " group"), - }); - } - } - }, - - exit({ node }, _) { - _.finish(node); - }, - }, - - JSXAttribute(path, _) { - const { name } = path.node; - if (name.name !== jsxAttributeName) return; - - const valuePath = path.get("value"); - if (!valuePath.node) return; - - const copy = - jsxAttributeAction === "delete" ? undefined : t.cloneNode(valuePath.node, true); - - const parent = path.parent as t.JSXOpeningElement; - const classNameAttribute = parent.attributes.find( - (attr): attr is t.JSXAttribute => - t.isJSXAttribute(attr) && attr.name.name === "className" - ); - - matchPath(valuePath, go => ({ - StringLiteral(path) { - const { node } = path; - const { value } = node; - const trimmed = trim(value); - if (trimmed.length) { - const className = getClass(trimmed.join(" ")); - _.recordIfAbsent("css", { - key: className, - classNames: trimmed, - location: _.sliceText(node), - }); - path.replaceWith(t.stringLiteral(className)); - } - }, - ArrayExpression(path) { - for (const element of path.get("elements")) { - go(element); - } - }, - ObjectExpression(path) { - const trimmed = evaluateArgs(path); - const className = getClass(trimmed.join(" ")); - _.recordIfAbsent("css", { - key: className, - classNames: trimmed, - location: _.sliceText(path.node), - }); - path.replaceWith(t.stringLiteral(className)); - }, - JSXExpressionContainer(path) { - go(path.get("expression")); - }, - ConditionalExpression(path) { - go(path.get("consequent")); - go(path.get("alternate")); - }, - LogicalExpression(path) { - go(path.get("right")); - }, - CallExpression(path) { - for (const arg of path.get("arguments")) { - go(arg); - } - }, - })); - - let valuePathNode = extractJSXContainer(valuePath.node); - if ( - t.isArrayExpression(valuePathNode) && - valuePathNode.elements.every(node => t.isStringLiteral(node)) - ) { - valuePathNode = t.stringLiteral( - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - (valuePathNode.elements as t.StringLiteral[]).map(node => node.value).join(" ") - ); - } - - if (classNameAttribute) { - const attrValue = classNameAttribute.value!; - const wrap = (originalValue: b.types.Expression) => - t.callExpression(_.getCx(), [originalValue, valuePathNode]); - - // If both are string literals, we can merge them directly here - if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePathNode)) { - attrValue.value += - (attrValue.value.at(-1) === " " ? "" : " ") + valuePathNode.value; - } else { - const internalAttrValue = extractJSXContainer(attrValue); - if ( - t.isArrowFunctionExpression(internalAttrValue) && - !t.isBlockStatement(internalAttrValue.body) - ) { - internalAttrValue.body = wrap(internalAttrValue.body); - } else { - classNameAttribute.value = t.jsxExpressionContainer(wrap(internalAttrValue)); - } - } - } else { - const wrap = (originalValue: b.types.Expression) => - t.callExpression(_.getCx(), [valuePathNode, originalValue]); - - const rest = parent.attributes.filter(attr => t.isJSXSpreadAttribute(attr)); - let arg; - if (rest.length === 1 && (arg = rest[0].argument) && t.isIdentifier(arg)) { - // props from argument and not modified anywhere - const scope = path.scope.getBinding(arg.name); - let index: number; - const node = scope?.path.node; - if ( - scope && - !scope.constantViolations.length && - t.isFunctionDeclaration(scope.path.parent) && - (index = (scope.path.parent.params as t.Node[]).indexOf(node!)) !== -1 && - (t.isIdentifier(node) || t.isObjectPattern(node)) - ) { - const clsVar = path.scope.generateUidIdentifier("className"); - if (t.isIdentifier(node)) { - scope.path.parent.params[index] = t.objectPattern([ - t.objectProperty(t.identifier("className"), clsVar), - t.restElement(node), - ]); - } else { - node.properties.unshift( - t.objectProperty(t.identifier("className"), clsVar) - ); - } - - parent.attributes.push( - t.jsxAttribute( - t.jsxIdentifier("className"), - t.jsxExpressionContainer(wrap(clsVar)) - ) - ); - } else { - const tslibImport = _.getTSlibImport(); - rest[0].argument = t.callExpression( - t.memberExpression(tslibImport, t.identifier("__rest")), - [arg, t.arrayExpression([t.stringLiteral("className")])] - ); - - parent.attributes.push( - t.jsxAttribute( - t.jsxIdentifier("className"), - t.jsxExpressionContainer( - wrap(t.memberExpression(arg, t.identifier("className"))) - ) - ) - ); - } - } else { - const containerValue = t.isStringLiteral(valuePathNode) - ? valuePathNode - : t.callExpression(_.getCx(), [valuePathNode]); - - parent.attributes.push( - t.jsxAttribute( - t.jsxIdentifier("className"), - t.jsxExpressionContainer(containerValue) - ) - ); - } - } - - if (jsxAttributeAction === "delete") { - path.remove(); - } else { - path.node.value = copy!; - if (Array.isArray(jsxAttributeAction) && jsxAttributeAction[0] === "rename") { - path.node.name.name = jsxAttributeAction[1]; - } - } - }, - })); -} - -function getClsxImport(t: BabelTypes, cx: t.Identifier, clsx: string) { - switch (clsx) { - case "emotion": - return t.importDeclaration( - [t.importSpecifier(cx, t.identifier("cx"))], - t.stringLiteral("@emotion/css") - ); - case "clsx": - return t.importDeclaration([t.importDefaultSpecifier(cx)], t.stringLiteral("clsx")); - case "classnames": - return t.importDeclaration( - [t.importDefaultSpecifier(cx)], - t.stringLiteral("classnames") - ); - default: - throw new Error("Unknown clsx library"); - } -} - -function evaluateArgs(path: NodePath) { - const { confident, value } = path.evaluate(); - invariant(confident, "Argument cannot be statically evaluated"); - - if (typeof value === "string") { - return trim(value); - } - - if (isPlainObject(value)) { - return flatMapEntries(value, (classes, modifier) => { - if (modifier === "data" && isPlainObject(classes)) { - return flatMapEntries(classes as Record, (cls, key) => - typeof cls === "string" - ? trimPrefix(cls, `${modifier}-[${key}]:`) - : flatMapEntries(cls as Record, (cls, attrValue) => - trimPrefix(cls, `${modifier}-[${key}=${attrValue}]:`) - ) - ); - } - - invariant( - typeof classes === "string", - `Value for "${modifier}" should be a string` - ); - return trimPrefix(classes, modifier + ":"); - }); - } - - throw new Error("Invalid argument type"); -} - -function getName(t: BabelTypes, exp: t.Node) { - if (t.isIdentifier(exp)) { - return exp.name; - } else if (t.isStringLiteral(exp)) { - return exp.value; - } -} - -function getMacros( - t: BabelTypes, - programPath: NodePath, - importSources: string[] -) { - const importDecs = programPath - .get("body") - .filter(x => isNodePath(x, t.isImportDeclaration)) - .filter(x => importSources.includes(x.node.source.value)); - - const macros = importDecs - .flatMap(x => x.get("specifiers")) - .map(x => { - const local = x.get("local"); - if (isNodePath(x, t.isImportNamespaceSpecifier)) { - return local.scope - .getOwnBinding(local.node.name)! - .referencePaths.map(p => p.parentPath) - .filter(p => isNodePath(p, t.isMemberExpression)) - .map(p => ({ - local: p, - imported: getName(t, p.node.property)!, - })) - .filter(p => p.imported); - } else if (t.isImportSpecifier(x.node)) { - const imported = x.node.imported; - return local.scope.getOwnBinding(local.node.name)!.referencePaths.map(p => ({ - local: p as NodePath, - imported: getName(t, imported)!, - })); - } - }) - .filter(Boolean) - .flat(1); - - for (const x of importDecs) { - x.remove(); - } - - return macros; -} - -function mapMacro(t: BabelTypes, macro: ReturnType[number]) { - let callee = macro.local.parentPath; - const prefix: string[] = []; - - while (isNodePath(callee, t.isMemberExpression)) { - invariant(t.isIdentifier(callee.node.property), "Invalid member expression"); - prefix.unshift( - callee.node.property.name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase() - ); - callee = callee.parentPath; - } - - return { - callee, - imported: macro.imported, - prefix: prefix.length ? prefix.join(":") : undefined, - }; -} - -const definePlugin = - (fn: (runtime: typeof b) => b.Visitor) => - (runtime: typeof b) => { - const plugin: b.PluginObj = { - visitor: fn(runtime), - }; - return plugin as b.PluginObj; - }; - -const extractJSXContainer = (attr: NonNullable): t.Expression => - attr.type === "JSXExpressionContainer" ? (attr.expression as t.Expression) : attr; - -function matchPath( - nodePath: NodePath, - fns: (dig: (nodePath: NodePath) => void) => b.Visitor -) { - if (!nodePath.node) return; - const fn = fns(path => matchPath(path, fns))[nodePath.node.type] as any; - fn?.(nodePath); -} - -function addIf(text: string, suffix: string | false) { - return suffix ? text + suffix : text; -} - -const isNodePath = ( - nodePath: NodePath | null, - predicate: (node: t.Node) => node is T -): nodePath is NodePath => Boolean(nodePath?.node && predicate(nodePath.node)); - -function getSuffix(add: boolean | undefined, entries: StyleMapEntry[]) { - if (!add) return ""; - - const cacheKey = hash(entries.map(x => x.classNames).join(",")); - return `?${cacheKey}`; -} - -const trim = (value: string) => - value.replace(/\s+/g, " ").trim().split(" ").filter(Boolean); -const trimPrefix = (cls: string, prefix = "") => trim(cls).map(value => prefix + value); - -const flatMapEntries = ( - map: Record, - fn: (value: V, key: K) => R[] -): R[] => Object.entries(map).flatMap(([key, value]) => fn(value as V, key as K)); diff --git a/src/babel/index.ts b/src/babel/index.ts new file mode 100644 index 0000000..1a343ff --- /dev/null +++ b/src/babel/index.ts @@ -0,0 +1,389 @@ +import { basename, dirname, extname, join } from "node:path"; +import type b from "@babel/core"; +import hash from "@emotion/hash"; +import invariant from "tiny-invariant"; +import { type NodePath, type types as t } from "@babel/core"; +import { type SourceLocation, type StyleMapEntry } from "../shared"; +import { type ResolveTailwindOptions, getClassName } from "../index"; +import { handleMacro } from "./macro"; +import { evaluateArgs, trim } from "./utils"; + +export type ClassNameCollector = (path: string, entries: StyleMapEntry[]) => void; +type BabelTypes = typeof b.types; +type Type = "css" | "js"; + +export type BabelPluginUtils = ReturnType; + +function getUtils({ + path, + state, + t, + options, + onCollect, +}: { + path: NodePath; + state: b.PluginPass; + t: BabelTypes; + options: ResolveTailwindOptions; + onCollect: ClassNameCollector | undefined; +}) { + const { + styleMap, + clsx, + getClassName: getClass = getClassName, + vite: bustCache, + } = options; + + let cx: t.Identifier; + let tslibImport: t.Identifier; + let styleImport: t.Identifier; + + const cssMap = new Map(); + const jsMap = new Map(); + + function getStyleImport() { + styleImport ??= path.scope.generateUidIdentifier("styles"); + return t.cloneNode(styleImport); + } + + return { + getClass(type: Type, value: string) { + return type === "css" ? getClass(value) : "tw_" + hash(value); + }, + + sliceText: (node: t.Node): SourceLocation => ({ + filename: state.filename!, + start: node.loc!.start, + end: node.loc!.end, + text: state.file.code + .split("\n") + .slice(node.loc!.start.line - 1, node.loc!.end.line) + .join("\n"), + }), + + recordIfAbsent(type: Type, entry: StyleMapEntry) { + const map = type === "css" ? cssMap : jsMap; + if (!map.has(entry.key)) { + map.set(entry.key, entry); + } + }, + + replaceWithImport({ + type, + path, + className, + }: { + type: Type; + path: NodePath; + className: string; + }) { + if (type === "css") { + path.replaceWith(t.stringLiteral(className)); + } else { + const styleImportId = getStyleImport(); + path.replaceWith( + t.memberExpression(styleImportId, t.stringLiteral(className), true) + ); + } + }, + + getCx: () => { + if (cx == null) { + cx = path.scope.generateUidIdentifier("cx"); + path.node.body.unshift(getClsxImport(t, cx, clsx)); + } + return t.cloneNode(cx); + }, + + getTSlibImport: () => { + if (tslibImport == null) { + tslibImport = path.scope.generateUidIdentifier("tslib"); + path.node.body.unshift( + t.importDeclaration( + [t.importNamespaceSpecifier(tslibImport)], + t.stringLiteral("tslib") + ) + ); + } + return t.cloneNode(tslibImport); + }, + + finish(node: t.Program) { + const { filename } = state; + if (!cssMap.size && !jsMap.size) return; + invariant(filename, "babel: missing state.filename"); + + if (cssMap.size) { + const cssName = basename(filename, extname(filename)) + ".css"; + const path = join(dirname(filename), cssName); + const value = Array.from(cssMap.values()); + const importee = `tailwind:./${cssName}` + getSuffix(bustCache, value); + + node.body.unshift(t.importDeclaration([], t.stringLiteral(importee))); + + styleMap.set(path, value); + onCollect?.(path, value); + } + + if (jsMap.size) { + const jsName = basename(filename, extname(filename)) + ".tailwindStyle.js"; + const path = join(dirname(filename), jsName); + const value = Array.from(jsMap.values()); + const importee = `tailwind:./${jsName}` + getSuffix(bustCache, value); + + node.body.unshift( + t.importDeclaration( + [t.importNamespaceSpecifier(getStyleImport())], + t.stringLiteral(importee) + ) + ); + styleMap.set(path, value); + onCollect?.(path, value); + } + }, + }; +} + +export function babelTailwind( + options: ResolveTailwindOptions, + onCollect: ClassNameCollector | undefined +) { + const { + getClassName: getClass = getClassName, + jsxAttributeAction = "delete", + jsxAttributeName = "css", + } = options; + + return definePlugin(({ types: t }) => ({ + Program: { + enter(path, state) { + const _ = getUtils({ path, state, t, options, onCollect }); + Object.assign(state, _); + + handleMacro({ t, path, _ }); + }, + + exit({ node }, _) { + _.finish(node); + }, + }, + + JSXAttribute(path, _) { + const { name } = path.node; + if (name.name !== jsxAttributeName) return; + + const valuePath = path.get("value"); + if (!valuePath.node) return; + + const copy = + jsxAttributeAction === "delete" ? undefined : t.cloneNode(valuePath.node, true); + + const parent = path.parent as t.JSXOpeningElement; + const classNameAttribute = parent.attributes.find( + (attr): attr is t.JSXAttribute => + t.isJSXAttribute(attr) && attr.name.name === "className" + ); + + matchPath(valuePath, go => ({ + StringLiteral(path) { + const { node } = path; + const { value } = node; + const trimmed = trim(value); + if (trimmed.length) { + const className = getClass(trimmed.join(" ")); + _.recordIfAbsent("css", { + key: className, + classNames: trimmed, + location: _.sliceText(node), + }); + path.replaceWith(t.stringLiteral(className)); + } + }, + ArrayExpression(path) { + for (const element of path.get("elements")) { + go(element); + } + }, + ObjectExpression(path) { + const trimmed = evaluateArgs(path); + const className = getClass(trimmed.join(" ")); + _.recordIfAbsent("css", { + key: className, + classNames: trimmed, + location: _.sliceText(path.node), + }); + path.replaceWith(t.stringLiteral(className)); + }, + JSXExpressionContainer(path) { + go(path.get("expression")); + }, + ConditionalExpression(path) { + go(path.get("consequent")); + go(path.get("alternate")); + }, + LogicalExpression(path) { + go(path.get("right")); + }, + CallExpression(path) { + for (const arg of path.get("arguments")) { + go(arg); + } + }, + })); + + let valuePathNode = extractJSXContainer(valuePath.node); + if ( + t.isArrayExpression(valuePathNode) && + valuePathNode.elements.every(node => t.isStringLiteral(node)) + ) { + valuePathNode = t.stringLiteral( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (valuePathNode.elements as t.StringLiteral[]).map(node => node.value).join(" ") + ); + } + + if (classNameAttribute) { + const attrValue = classNameAttribute.value!; + const wrap = (originalValue: b.types.Expression) => + t.callExpression(_.getCx(), [originalValue, valuePathNode]); + + // If both are string literals, we can merge them directly here + if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePathNode)) { + attrValue.value += + (attrValue.value.at(-1) === " " ? "" : " ") + valuePathNode.value; + } else { + const internalAttrValue = extractJSXContainer(attrValue); + if ( + t.isArrowFunctionExpression(internalAttrValue) && + !t.isBlockStatement(internalAttrValue.body) + ) { + internalAttrValue.body = wrap(internalAttrValue.body); + } else { + classNameAttribute.value = t.jsxExpressionContainer(wrap(internalAttrValue)); + } + } + } else { + const wrap = (originalValue: b.types.Expression) => + t.callExpression(_.getCx(), [valuePathNode, originalValue]); + + const rest = parent.attributes.filter(attr => t.isJSXSpreadAttribute(attr)); + let arg; + if (rest.length === 1 && (arg = rest[0].argument) && t.isIdentifier(arg)) { + // props from argument and not modified anywhere + const scope = path.scope.getBinding(arg.name); + let index: number; + const node = scope?.path.node; + if ( + scope && + !scope.constantViolations.length && + t.isFunctionDeclaration(scope.path.parent) && + (index = (scope.path.parent.params as t.Node[]).indexOf(node!)) !== -1 && + (t.isIdentifier(node) || t.isObjectPattern(node)) + ) { + const clsVar = path.scope.generateUidIdentifier("className"); + if (t.isIdentifier(node)) { + scope.path.parent.params[index] = t.objectPattern([ + t.objectProperty(t.identifier("className"), clsVar), + t.restElement(node), + ]); + } else { + node.properties.unshift( + t.objectProperty(t.identifier("className"), clsVar) + ); + } + + parent.attributes.push( + t.jsxAttribute( + t.jsxIdentifier("className"), + t.jsxExpressionContainer(wrap(clsVar)) + ) + ); + } else { + const tslibImport = _.getTSlibImport(); + rest[0].argument = t.callExpression( + t.memberExpression(tslibImport, t.identifier("__rest")), + [arg, t.arrayExpression([t.stringLiteral("className")])] + ); + + parent.attributes.push( + t.jsxAttribute( + t.jsxIdentifier("className"), + t.jsxExpressionContainer( + wrap(t.memberExpression(arg, t.identifier("className"))) + ) + ) + ); + } + } else { + const containerValue = t.isStringLiteral(valuePathNode) + ? valuePathNode + : t.callExpression(_.getCx(), [valuePathNode]); + + parent.attributes.push( + t.jsxAttribute( + t.jsxIdentifier("className"), + t.jsxExpressionContainer(containerValue) + ) + ); + } + } + + if (jsxAttributeAction === "delete") { + path.remove(); + } else { + path.node.value = copy!; + if (Array.isArray(jsxAttributeAction) && jsxAttributeAction[0] === "rename") { + // eslint-disable-next-line unicorn/consistent-destructuring + path.node.name.name = jsxAttributeAction[1]; + } + } + }, + })); +} + +function getClsxImport(t: BabelTypes, cx: t.Identifier, clsx: string) { + switch (clsx) { + case "emotion": + return t.importDeclaration( + [t.importSpecifier(cx, t.identifier("cx"))], + t.stringLiteral("@emotion/css") + ); + case "clsx": + return t.importDeclaration([t.importDefaultSpecifier(cx)], t.stringLiteral("clsx")); + case "classnames": + return t.importDeclaration( + [t.importDefaultSpecifier(cx)], + t.stringLiteral("classnames") + ); + default: + throw new Error("Unknown clsx library"); + } +} + +const definePlugin = + (fn: (runtime: typeof b) => b.Visitor) => + (runtime: typeof b) => { + const plugin: b.PluginObj = { + visitor: fn(runtime), + }; + return plugin as b.PluginObj; + }; + +const extractJSXContainer = (attr: NonNullable): t.Expression => + attr.type === "JSXExpressionContainer" ? (attr.expression as t.Expression) : attr; + +function matchPath( + nodePath: NodePath, + fns: (dig: (nodePath: NodePath) => void) => b.Visitor +) { + if (!nodePath.node) return; + const fn = fns(path => matchPath(path, fns))[nodePath.node.type] as any; + fn?.(nodePath); +} + +function getSuffix(add: boolean | undefined, entries: StyleMapEntry[]) { + if (!add) return ""; + + const cacheKey = hash(entries.map(x => x.classNames).join(",")); + return `?${cacheKey}`; +} diff --git a/src/babel/macro.ts b/src/babel/macro.ts new file mode 100644 index 0000000..ab9db75 --- /dev/null +++ b/src/babel/macro.ts @@ -0,0 +1,142 @@ +import type b from "@babel/core"; +import invariant from "tiny-invariant"; +import { type NodePath, type types as t } from "@babel/core"; +import { macroNames } from "../shared"; +import type { BabelPluginUtils } from "./index"; +import { evaluateArgs, trimPrefix } from "./utils"; + +type BabelTypes = typeof b.types; + +export function handleMacro({ + t, + path, + _, +}: { + t: BabelTypes; + path: NodePath; + _: BabelPluginUtils; +}) { + for (const { callee, imported, prefix } of getMacros(t, path, macroNames).map(macro => + mapMacro(t, macro) + )) { + const type = imported === "tw" ? "css" : imported === "tws" ? "js" : undefined; + if (!type) continue; + + if (isNodePath(callee, t.isTaggedTemplateExpression)) { + const { node } = callee; + const { quasi } = node; + + invariant(!quasi.expressions.length, `Macro call should not contain expressions`); + + const value = quasi.quasis[0].value.cooked; + if (value) { + const list = trimPrefix(value, prefix ? prefix + ":" : undefined); + const className = _.getClass(type, list.join(" ")); + _.recordIfAbsent(type, { + key: className, + classNames: list, + location: _.sliceText(node), + }); + _.replaceWithImport({ + type, + path: callee, + className: addIf(className, list.includes("group") && " group"), + }); + } + } else if (isNodePath(callee, t.isCallExpression)) { + const { node } = callee; + if (!t.isIdentifier(node.callee)) continue; + + const list = callee.get("arguments").flatMap(evaluateArgs); + const className = _.getClass("css", list.join(" ")); + _.recordIfAbsent(type, { + key: className, + classNames: list, + location: _.sliceText(node), + }); + _.replaceWithImport({ + type, + path: callee, + className: addIf(className, list.includes("group") && " group"), + }); + } + } +} + +function addIf(text: string, suffix: string | false) { + return suffix ? text + suffix : text; +} + +function mapMacro(t: BabelTypes, macro: ReturnType[number]) { + let callee = macro.local.parentPath; + const prefix: string[] = []; + + while (isNodePath(callee, t.isMemberExpression)) { + invariant(t.isIdentifier(callee.node.property), "Invalid member expression"); + prefix.unshift( + callee.node.property.name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase() + ); + callee = callee.parentPath; + } + + return { + callee, + imported: macro.imported, + prefix: prefix.length ? prefix.join(":") : undefined, + }; +} + +function getName(t: BabelTypes, exp: t.Node) { + if (t.isIdentifier(exp)) { + return exp.name; + } else if (t.isStringLiteral(exp)) { + return exp.value; + } +} + +function getMacros( + t: BabelTypes, + programPath: NodePath, + importSources: string[] +) { + const importDecs = programPath + .get("body") + .filter(x => isNodePath(x, t.isImportDeclaration)) + .filter(x => importSources.includes(x.node.source.value)); + + const macros = importDecs + .flatMap(x => x.get("specifiers")) + .map(x => { + const local = x.get("local"); + if (isNodePath(x, t.isImportNamespaceSpecifier)) { + return local.scope + .getOwnBinding(local.node.name)! + .referencePaths.map(p => p.parentPath) + .filter(p => isNodePath(p, t.isMemberExpression)) + .map(p => ({ + local: p, + imported: getName(t, p.node.property)!, + })) + .filter(p => p.imported); + } else if (t.isImportSpecifier(x.node)) { + const imported = x.node.imported; + return local.scope.getOwnBinding(local.node.name)!.referencePaths.map(p => ({ + local: p as NodePath, + imported: getName(t, imported)!, + })); + } + }) + .filter(Boolean) + .flat(1); + + for (const x of importDecs) { + x.remove(); + } + + return macros; +} + +const isNodePath = ( + nodePath: NodePath | null, + predicate: (node: t.Node) => node is T +): nodePath is NodePath => Boolean(nodePath?.node && predicate(nodePath.node)); diff --git a/src/babel/utils.ts b/src/babel/utils.ts new file mode 100644 index 0000000..cad4296 --- /dev/null +++ b/src/babel/utils.ts @@ -0,0 +1,51 @@ +import { basename, dirname, extname, join } from "node:path"; +import type b from "@babel/core"; +import hash from "@emotion/hash"; +import { isPlainObject } from "lodash"; +import invariant from "tiny-invariant"; +import { type NodePath, type types as t } from "@babel/core"; +import { type SourceLocation, type StyleMapEntry } from "../shared"; +import { type ResolveTailwindOptions, getClassName } from "../index"; +import { handleMacro } from "./macro"; + +export function evaluateArgs(path: NodePath) { + const { confident, value } = path.evaluate(); + invariant(confident, "Argument cannot be statically evaluated"); + + if (typeof value === "string") { + return trim(value); + } + + if (isPlainObject(value)) { + return flatMapEntries(value, (classes, modifier) => { + if (modifier === "data" && isPlainObject(classes)) { + return flatMapEntries(classes as Record, (cls, key) => + typeof cls === "string" + ? trimPrefix(cls, `${modifier}-[${key}]:`) + : flatMapEntries(cls as Record, (cls, attrValue) => + trimPrefix(cls, `${modifier}-[${key}=${attrValue}]:`) + ) + ); + } + + invariant( + typeof classes === "string", + `Value for "${modifier}" should be a string` + ); + return trimPrefix(classes, modifier + ":"); + }); + } + + throw new Error("Invalid argument type"); +} + +export const trim = (value: string) => + value.replace(/\s+/g, " ").trim().split(" ").filter(Boolean); + +export const trimPrefix = (cls: string, prefix = "") => + trim(cls).map(value => prefix + value); + +const flatMapEntries = ( + map: Record, + fn: (value: V, key: K) => R[] +): R[] => Object.entries(map).flatMap(([key, value]) => fn(value as V, key as K)); diff --git a/src/index.ts b/src/index.ts index 04ba9fc..af34ddf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import type { SetRequired } from "type-fest"; import { transformSync } from "esbuild"; import type postcss from "postcss"; import { memoize, without } from "lodash"; -import { type ClassNameCollector, babelTailwind } from "./babel-tailwind"; +import { type ClassNameCollector, babelTailwind } from "./babel/index"; import { esbuildPlugin } from "./esbuild-postcss"; import { vitePlugin } from "./vite-plugin"; import { type StyleMap, createPostCSS } from "./shared"; diff --git a/src/macro.d.ts b/src/macro.d.ts index 9a3a8c0..827bc51 100644 --- a/src/macro.d.ts +++ b/src/macro.d.ts @@ -99,5 +99,5 @@ type TailwindStyleFunctionReturn = Config extends { tws: infer T } ? T : never; * } * ``` */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface +// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type export interface Config {} diff --git a/src/vite-plugin.ts b/src/vite-plugin.ts index 74361f6..91ed68a 100644 --- a/src/vite-plugin.ts +++ b/src/vite-plugin.ts @@ -17,7 +17,7 @@ export const vitePlugin = ({ name: "tailwind", config(config) { - ((config.optimizeDeps ?? {}).exclude ?? []).push(...macroNames, `${pkgName}/base`); + ((config.optimizeDeps ??= {}).exclude ??= []).push(...macroNames, `${pkgName}/base`); }, resolveId(id, importer) {