From 2b3812b2baf791435b3f98144c2db27dbbdca216 Mon Sep 17 00:00:00 2001
From: Alex <8125011+alex-kinokon@users.noreply.github.com>
Date: Wed, 3 Jul 2024 01:04:49 -0400
Subject: [PATCH] Bug fixes
---
.vscode/settings.json | 3 +-
package.json | 17 +-
pnpm-lock.yaml | 298 +++++++++++++++++++++++++++---
scripts/index.ts | 3 +-
src/__tests__/styleObject.test.ts | 24 ++-
src/__tests__/tw.test.ts | 3 +
src/babel-tailwind.ts | 169 ++++++++++-------
src/css-to-js.ts | 273 ++++++++++++++++-----------
src/esbuild-postcss.ts | 1 +
src/index.ts | 44 -----
src/macro.d.ts | 43 +++++
src/shared.ts | 1 +
src/vite-plugin.ts | 7 +-
tsconfig.json | 2 +-
14 files changed, 637 insertions(+), 251 deletions(-)
create mode 100644 src/macro.d.ts
diff --git a/.vscode/settings.json b/.vscode/settings.json
index ad92582..3a19d2f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
{
- "editor.formatOnSave": true
+ "editor.formatOnSave": true,
+ "typescript.tsdk": "node_modules/typescript/lib"
}
diff --git a/package.json b/package.json
index d317606..1539054 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,6 @@
{
"name": "@aet/tailwind",
- "version": "0.0.1-beta.21",
- "main": "dist/index.js",
+ "version": "0.0.1-beta.30",
"license": "MIT",
"scripts": {
"build": "./scripts/index.ts",
@@ -10,6 +9,14 @@
"files": [
"dist"
],
+ "exports": {
+ ".": "./dist/index.js",
+ "./package.json": "./package.json",
+ "./classed": "./dist/classed.mjs",
+ "./macro": {
+ "types": "./dist/macro.d.ts"
+ }
+ },
"devDependencies": {
"@aet/eslint-rules": "^0.0.34",
"@types/babel__core": "^7.20.5",
@@ -19,16 +26,15 @@
"@types/node": "^20.14.9",
"@types/postcss-safe-parser": "^5.0.4",
"@types/react": "^18.3.3",
+ "@types/stylis": "^4.2.6",
"cli-highlight": "^2.1.11",
"clsx": "^2.1.1",
"colord": "^2.9.3",
"css-what": "^6.1.0",
"dedent": "^1.5.3",
- "esbuild": "^0.21.5",
"esbuild-register": "^3.5.0",
"eslint": "^8.57.0",
"postcss-nested": "^6.0.1",
- "postcss-safe-parser": "^7.0.0",
"prettier": "^3.3.2",
"tailwindcss": "^3.4.4",
"tsup": "^8.1.0",
@@ -42,9 +48,12 @@
"dependencies": {
"@babel/core": "^7.24.7",
"@emotion/hash": "^0.9.1",
+ "esbuild": "^0.23.0",
+ "json5": "^2.2.3",
"lodash": "^4.17.21",
"postcss": "^8.4.39",
"postcss-selector-parser": "^6.1.0",
+ "stylis": "^4.3.2",
"tiny-invariant": "^1.3.3",
"type-fest": "^4.21.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4b8f366..4177272 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,12 +14,24 @@ importers:
'@emotion/hash':
specifier: ^0.9.1
version: 0.9.1
+ esbuild:
+ specifier: ^0.23.0
+ version: 0.23.0
+ json5:
+ specifier: ^2.2.3
+ version: 2.2.3
lodash:
specifier: ^4.17.21
version: 4.17.21
postcss:
specifier: ^8.4.39
version: 8.4.39
+ postcss-selector-parser:
+ specifier: ^6.1.0
+ version: 6.1.0
+ stylis:
+ specifier: ^4.3.2
+ version: 4.3.2
tiny-invariant:
specifier: ^1.3.3
version: 1.3.3
@@ -51,6 +63,9 @@ importers:
'@types/react':
specifier: ^18.3.3
version: 18.3.3
+ '@types/stylis':
+ specifier: ^4.2.6
+ version: 4.2.6
cli-highlight:
specifier: ^2.1.11
version: 2.1.11
@@ -66,24 +81,15 @@ importers:
dedent:
specifier: ^1.5.3
version: 1.5.3
- esbuild:
- specifier: ^0.21.5
- version: 0.21.5
esbuild-register:
specifier: ^3.5.0
- version: 3.5.0(esbuild@0.21.5)
+ version: 3.5.0(esbuild@0.23.0)
eslint:
specifier: ^8.57.0
version: 8.57.0
postcss-nested:
specifier: ^6.0.1
version: 6.0.1(postcss@8.4.39)
- postcss-safe-parser:
- specifier: ^7.0.0
- version: 7.0.0(postcss@8.4.39)
- postcss-selector-parser:
- specifier: ^6.1.0
- version: 6.1.0
prettier:
specifier: ^3.3.2
version: 3.3.2
@@ -249,138 +255,282 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.23.0':
+ resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/android-arm64@0.21.5':
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.23.0':
+ resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm@0.21.5':
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.23.0':
+ resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-x64@0.21.5':
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.23.0':
+ resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/darwin-arm64@0.21.5':
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.23.0':
+ resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.21.5':
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.23.0':
+ resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/freebsd-arm64@0.21.5':
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.23.0':
+ resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.21.5':
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.23.0':
+ resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/linux-arm64@0.21.5':
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.23.0':
+ resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm@0.21.5':
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.23.0':
+ resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-ia32@0.21.5':
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.23.0':
+ resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-loong64@0.21.5':
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.23.0':
+ resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.21.5':
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.23.0':
+ resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.21.5':
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.23.0':
+ resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.21.5':
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.23.0':
+ resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-s390x@0.21.5':
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.23.0':
+ resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-x64@0.21.5':
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.23.0':
+ resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/netbsd-x64@0.21.5':
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.23.0':
+ resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.23.0':
+ resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.21.5':
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.23.0':
+ resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/sunos-x64@0.21.5':
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.23.0':
+ resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/win32-arm64@0.21.5':
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.23.0':
+ resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-ia32@0.21.5':
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.23.0':
+ resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-x64@0.21.5':
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.23.0':
+ resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/eslint-utils@4.4.0':
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -586,6 +736,9 @@ packages:
'@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
+ '@types/stylis@4.2.6':
+ resolution: {integrity: sha512-4nebF2ZJGzQk0ka0O6+FZUWceyFv4vWq/0dXBMmrSeAwzOuOd/GxE5Pa64d/ndeNLG73dXoBsRzvtsVsYUv6Uw==}
+
'@types/ws@8.5.10':
resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==}
@@ -988,6 +1141,11 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ esbuild@0.23.0:
+ resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
@@ -1685,12 +1843,6 @@ packages:
peerDependencies:
postcss: ^8.2.14
- postcss-safe-parser@7.0.0:
- resolution: {integrity: sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==}
- engines: {node: '>=18.0'}
- peerDependencies:
- postcss: ^8.4.31
-
postcss-selector-parser@6.1.0:
resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
engines: {node: '>=4'}
@@ -1893,6 +2045,9 @@ packages:
strip-literal@2.1.0:
resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==}
+ stylis@4.3.2:
+ resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==}
+
sucrase@3.35.0:
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
engines: {node: '>=16 || 14 >=14.17'}
@@ -2383,72 +2538,144 @@ snapshots:
'@esbuild/aix-ppc64@0.21.5':
optional: true
+ '@esbuild/aix-ppc64@0.23.0':
+ optional: true
+
'@esbuild/android-arm64@0.21.5':
optional: true
+ '@esbuild/android-arm64@0.23.0':
+ optional: true
+
'@esbuild/android-arm@0.21.5':
optional: true
+ '@esbuild/android-arm@0.23.0':
+ optional: true
+
'@esbuild/android-x64@0.21.5':
optional: true
+ '@esbuild/android-x64@0.23.0':
+ optional: true
+
'@esbuild/darwin-arm64@0.21.5':
optional: true
+ '@esbuild/darwin-arm64@0.23.0':
+ optional: true
+
'@esbuild/darwin-x64@0.21.5':
optional: true
+ '@esbuild/darwin-x64@0.23.0':
+ optional: true
+
'@esbuild/freebsd-arm64@0.21.5':
optional: true
+ '@esbuild/freebsd-arm64@0.23.0':
+ optional: true
+
'@esbuild/freebsd-x64@0.21.5':
optional: true
+ '@esbuild/freebsd-x64@0.23.0':
+ optional: true
+
'@esbuild/linux-arm64@0.21.5':
optional: true
+ '@esbuild/linux-arm64@0.23.0':
+ optional: true
+
'@esbuild/linux-arm@0.21.5':
optional: true
+ '@esbuild/linux-arm@0.23.0':
+ optional: true
+
'@esbuild/linux-ia32@0.21.5':
optional: true
+ '@esbuild/linux-ia32@0.23.0':
+ optional: true
+
'@esbuild/linux-loong64@0.21.5':
optional: true
+ '@esbuild/linux-loong64@0.23.0':
+ optional: true
+
'@esbuild/linux-mips64el@0.21.5':
optional: true
+ '@esbuild/linux-mips64el@0.23.0':
+ optional: true
+
'@esbuild/linux-ppc64@0.21.5':
optional: true
+ '@esbuild/linux-ppc64@0.23.0':
+ optional: true
+
'@esbuild/linux-riscv64@0.21.5':
optional: true
+ '@esbuild/linux-riscv64@0.23.0':
+ optional: true
+
'@esbuild/linux-s390x@0.21.5':
optional: true
+ '@esbuild/linux-s390x@0.23.0':
+ optional: true
+
'@esbuild/linux-x64@0.21.5':
optional: true
+ '@esbuild/linux-x64@0.23.0':
+ optional: true
+
'@esbuild/netbsd-x64@0.21.5':
optional: true
+ '@esbuild/netbsd-x64@0.23.0':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.23.0':
+ optional: true
+
'@esbuild/openbsd-x64@0.21.5':
optional: true
+ '@esbuild/openbsd-x64@0.23.0':
+ optional: true
+
'@esbuild/sunos-x64@0.21.5':
optional: true
+ '@esbuild/sunos-x64@0.23.0':
+ optional: true
+
'@esbuild/win32-arm64@0.21.5':
optional: true
+ '@esbuild/win32-arm64@0.23.0':
+ optional: true
+
'@esbuild/win32-ia32@0.21.5':
optional: true
+ '@esbuild/win32-ia32@0.23.0':
+ optional: true
+
'@esbuild/win32-x64@0.21.5':
optional: true
+ '@esbuild/win32-x64@0.23.0':
+ optional: true
+
'@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
dependencies:
eslint: 8.57.0
@@ -2651,6 +2878,8 @@ snapshots:
'@types/prop-types': 15.7.12
csstype: 3.1.3
+ '@types/stylis@4.2.6': {}
+
'@types/ws@8.5.10':
dependencies:
'@types/node': 20.14.9
@@ -3034,10 +3263,10 @@ snapshots:
es-module-lexer@1.5.4: {}
- esbuild-register@3.5.0(esbuild@0.21.5):
+ esbuild-register@3.5.0(esbuild@0.23.0):
dependencies:
debug: 4.3.4
- esbuild: 0.21.5
+ esbuild: 0.23.0
transitivePeerDependencies:
- supports-color
@@ -3067,6 +3296,33 @@ snapshots:
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
+ esbuild@0.23.0:
+ 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
+
escalade@3.1.2: {}
escape-string-regexp@1.0.5: {}
@@ -3750,10 +4006,6 @@ snapshots:
postcss: 8.4.39
postcss-selector-parser: 6.1.0
- postcss-safe-parser@7.0.0(postcss@8.4.39):
- dependencies:
- postcss: 8.4.39
-
postcss-selector-parser@6.1.0:
dependencies:
cssesc: 3.0.0
@@ -3948,6 +4200,8 @@ snapshots:
dependencies:
js-tokens: 9.0.0
+ stylis@4.3.2: {}
+
sucrase@3.35.0:
dependencies:
'@jridgewell/gen-mapping': 0.3.5
diff --git a/scripts/index.ts b/scripts/index.ts
index ea768fb..1c5ded4 100755
--- a/scripts/index.ts
+++ b/scripts/index.ts
@@ -28,7 +28,7 @@ await Promise.all([
build({
...tsupConfig,
entry: ["src/index.ts"],
- external: ["postcss-selector-parser", "postcss"],
+ external: ["postcss-selector-parser", "postcss", "stylis"],
}),
Bun.write(
"dist/package.json",
@@ -44,6 +44,7 @@ await Promise.all([
await Promise.all([
fs.copyFile("README.md", "dist/README.md"),
fs.copyFile("LICENSE.md", "dist/LICENSE.md"),
+ fs.copyFile("src/macro.d.ts", "dist/macro.d.ts"),
]);
process.exit(0);
diff --git a/src/__tests__/styleObject.test.ts b/src/__tests__/styleObject.test.ts
index 33671e6..a0472bd 100644
--- a/src/__tests__/styleObject.test.ts
+++ b/src/__tests__/styleObject.test.ts
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { getBuild } from "./utils";
import { getClassName } from "../index";
-describe.only("babel-tailwind", () => {
+describe("babel-tailwind", () => {
const compileESBuild = getBuild("styleObject");
it("supports conversion into CSSProperties", async () => {
@@ -10,9 +10,11 @@ describe.only("babel-tailwind", () => {
clsx: "emotion",
expectFiles: 1,
javascript: `
+ import { tws } from "@aet/tailwind/macro";
+
export function Hello() {
return (
-
+
Hello, world!
);
@@ -20,9 +22,23 @@ describe.only("babel-tailwind", () => {
`,
});
- const clsName = getClassName("p-2 text-center").replace(/^tw-/, "tw_");
+ const clsName = getClassName("p-2 text-center hover:font-semibold sm:p-1").replace(
+ /^tw-/,
+ "tw_"
+ );
expect(files.js.text).toContain(
- `var ${clsName} = {\n "padding": "0.5rem",\n "textAlign": "center"\n}`
+ [
+ `var ${clsName} = {`,
+ ' padding: "0.5rem",',
+ ' textAlign: "center",',
+ ' "&:hover": {',
+ ' fontWeight: "600"',
+ " },",
+ ' "@media (min-width: 640px)": {',
+ ' padding: "0.25rem"',
+ " }",
+ "}",
+ ].join("\n")
);
expect(files.js.text).toContain(`style: ${clsName}`);
});
diff --git a/src/__tests__/tw.test.ts b/src/__tests__/tw.test.ts
index 5a1c705..053cea5 100644
--- a/src/__tests__/tw.test.ts
+++ b/src/__tests__/tw.test.ts
@@ -4,11 +4,14 @@ import { getBuild } from "./utils";
describe("babel-tailwind", () => {
const compileESBuild = getBuild("tw");
+
it("supports grouped tw", async () => {
const { files } = await compileESBuild({
clsx: "emotion",
expectFiles: 2,
javascript: `
+ import { tw } from "@aet/tailwind/macro";
+
export default tw("text-sm", \`flex\`, {
"group-hover": "text-center",
"[&>div]": \`font-semibold\`,
diff --git a/src/babel-tailwind.ts b/src/babel-tailwind.ts
index 24ff431..254d076 100644
--- a/src/babel-tailwind.ts
+++ b/src/babel-tailwind.ts
@@ -4,10 +4,11 @@ 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, StyleMapEntry } from "./shared";
+import { type SourceLocation, type StyleMapEntry, macroName } from "./shared";
import { type ResolveTailwindOptions, getClassName } from "./index";
export type ClassNameCollector = (path: string, entries: StyleMapEntry[]) => void;
+type BabelTypes = typeof babel.types;
type Type = "css" | "js";
export function babelTailwind(
@@ -15,8 +16,6 @@ export function babelTailwind(
styleMap,
clsx,
getClassName: getClass = getClassName,
- macroFunction,
- macroStyleFunction,
jsxAttributeAction = "delete",
jsxAttributeName = "css",
vite,
@@ -25,11 +24,7 @@ export function babelTailwind(
) {
type BabelPluginState = ReturnType
;
- function getState(
- path: NodePath,
- state: babel.PluginPass,
- t: typeof babel.types
- ) {
+ function getState(path: NodePath, state: babel.PluginPass, t: BabelTypes) {
let cx: t.Identifier;
let styleImport: t.Identifier;
@@ -118,69 +113,62 @@ export function babelTailwind(
};
}
- const getType = (fnName: string): Type | undefined =>
- fnName === macroFunction ? "css" : fnName === macroStyleFunction ? "js" : undefined;
-
return definePlugin(({ types: t }) => ({
Program: {
enter(path, state) {
- Object.assign(state, getState(path, state, t));
+ const _ = getState(path, state, t);
+ Object.assign(state, _);
+
+ for (const {
+ local: { parentPath: local },
+ imported,
+ } of getMacros(t, path, macroName)) {
+ const type = imported === "tw" ? "css" : imported === "tws" ? "js" : undefined;
+ if (!type) continue;
+
+ if (isNodePath(local, t.isTaggedTemplateExpression)) {
+ const { node } = local;
+ const { tag, quasi } = node;
+ if (!t.isIdentifier(tag)) continue;
+
+ invariant(
+ !quasi.expressions.length,
+ `Macro call should not contain expressions`
+ );
+
+ const value = quasi.quasis[0].value.cooked;
+ if (value) {
+ const trimmed = trim(value);
+ const className = _.getClass(type, trimmed);
+ _.recordIfAbsent(type, {
+ key: className,
+ className: trimmed,
+ location: _.sliceText(node),
+ });
+ _.replaceWithImport(type, local, className);
+ }
+ } else if (isNodePath(local, t.isCallExpression)) {
+ const { node } = local;
+ const { callee } = node;
+ if (!t.isIdentifier(callee)) continue;
+
+ const trimmed = local.get("arguments").flatMap(evaluateArgs).join(" ");
+ const className = getClass(trimmed);
+ _.recordIfAbsent(type, {
+ key: className,
+ className: trimmed,
+ location: _.sliceText(node),
+ });
+ _.replaceWithImport(type, local, className);
+ }
+ }
},
+
exit({ node }, _) {
_.finish(node);
},
},
- TaggedTemplateExpression(path, _) {
- if (macroFunction == null && macroStyleFunction == null) return;
- const { node } = path;
-
- const {
- tag,
- quasi: { quasis, expressions },
- } = node;
- if (!t.isIdentifier(tag)) return;
-
- invariant(
- !expressions.length,
- `${macroFunction}\`\` should not contain expressions`
- );
-
- const type = getType(tag.name);
- if (!type) return;
-
- const value = quasis[0].value.cooked;
- if (value) {
- const trimmed = trim(value);
- const className = _.getClass(type, trimmed);
- _.recordIfAbsent(type, {
- key: className,
- className: trimmed,
- location: _.sliceText(node),
- });
- _.replaceWithImport(type, path, className);
- }
- },
-
- CallExpression(path, _) {
- if (macroFunction == null) return;
- const { node } = path;
- const { callee } = node;
- if (!t.isIdentifier(callee)) return;
-
- const type = getType(callee.name);
- if (!type) return;
-
- const trimmed = path.get("arguments").flatMap(evaluateArgs).join(" ");
- const className = getClass(trimmed);
- _.recordIfAbsent(type, {
- key: className,
- className: trimmed,
- location: _.sliceText(node),
- });
- _.replaceWithImport(type, path, className);
- },
-
JSXAttribute(path, _) {
const { name } = path.node;
if (name.name !== jsxAttributeName) return;
@@ -296,7 +284,7 @@ export function babelTailwind(
}));
}
-function getClsxImport(t: typeof babel.types, cx: t.Identifier, clsx: string) {
+function getClsxImport(t: BabelTypes, cx: t.Identifier, clsx: string) {
switch (clsx) {
case "emotion":
return t.importDeclaration(
@@ -346,6 +334,56 @@ function evaluateArgs(path: NodePath) {
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,
+ importSource: string
+) {
+ const importDecs = programPath
+ .get("body")
+ .filter(x => isNodePath(x, t.isImportDeclaration))
+ .filter(x => x.node.source.value === importSource);
+
+ 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 definePlugin =
(fn: (runtime: typeof babel) => babel.Visitor) =>
(runtime: typeof babel) => {
@@ -367,6 +405,11 @@ function matchPath(
fn?.(nodePath);
}
+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 "";
diff --git a/src/css-to-js.ts b/src/css-to-js.ts
index bccc214..dfe38d1 100755
--- a/src/css-to-js.ts
+++ b/src/css-to-js.ts
@@ -3,14 +3,15 @@
import {
type AtRule,
type Builder,
- type ChildNode,
type Node,
type Root,
type Rule,
parse,
} from "postcss";
+import JSON5 from "json5";
import parseSelector from "postcss-selector-parser";
import Stringifier from "postcss/lib/stringifier";
+import { type Element, compile } from "stylis";
import { camelCase } from "lodash";
function getSelectorScope(selector: string): string {
@@ -99,10 +100,6 @@ function getCssIndexedByScope(css: string) {
}
for (const scope of scopesStack.at(-1)!) {
- if (!cssIndexedByScope.has(scope)) {
- cssIndexedByScope.set(scope, "");
- }
-
if (
flag === "start" &&
isNode(node, "rule") &&
@@ -113,7 +110,7 @@ function getCssIndexedByScope(css: string) {
.join(", ")} {`;
}
- cssIndexedByScope.set(scope, cssIndexedByScope.get(scope) + output);
+ cssIndexedByScope.set(scope, (cssIndexedByScope.get(scope) || "") + output);
}
if (flag === "end") {
@@ -124,23 +121,6 @@ function getCssIndexedByScope(css: string) {
return cssIndexedByScope;
}
-function convertSelectorForEmotion(
- selector: string,
- scope: string,
- knownScopes: Set,
- mapClassNames: (className: string) => string
-): string {
- return parseSelector(nodes => {
- nodes.first.walkClasses(node => {
- if (node.toString() === scope) {
- node.toString = () => "&";
- } else if (knownScopes.has(node.toString())) {
- node.toString = () => `.\${${mapClassNames(node.value)}}`;
- }
- });
- }).processSync(selector);
-}
-
const convertScopeToModuleName = (scope: string) =>
camelCase(scope)
.replace(/^(\d)/, "_$1")
@@ -149,141 +129,214 @@ const convertScopeToModuleName = (scope: string) =>
"_$1"
);
-function convertScopedCssForEmotion(
- scopedCss: string,
- scope: string,
- knownScopes: Set,
- mapClassNames: (className: string) => string
-): string {
- let scopedCssForEmotion = "";
-
- stringify(scopedCss, (output, node, flag) => {
- if ((flag === "start" || flag === "end") && isNode(node, "rule")) {
- if (node.selector === scope) {
- if (isNode(node.parent, "root")) {
- return;
- } else if (flag === "start") {
- output = "& {";
- }
- } else if (flag === "start") {
- const selectors = new Set(
- node.selectors.map(selector =>
- convertSelectorForEmotion(selector, scope, knownScopes, mapClassNames)
- )
- );
-
- // TODO remove join usage once https://github.com/prettier/prettier/issues/2883 is resolved
- output = `${[...selectors].join(", ")} {`;
- }
- }
-
- scopedCssForEmotion += output;
- });
-
- return scopedCssForEmotion.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
-}
-
export function convertCssToJS(
css: string,
mapClassNames: (className: string) => string = convertScopeToModuleName
): string {
- let cssForEmotion = "";
+ let res = "";
- const cssIndexedByScope = getCssIndexedByScope(css);
-
- if (cssIndexedByScope.has("root") && cssIndexedByScope.get("root")!.trim()) {
- cssForEmotion += 'import { injectGlobal } from "@emotion/css";\n';
+ const map = getCssIndexedByScope(css);
+ if (map.has("root") && map.get("root")!.trim()) {
+ res += 'import { injectGlobal } from "@emotion/css";\n';
}
- const knownScopes = new Set(cssIndexedByScope.keys());
+ const knownScopes = new Set(map.keys());
const collator = new Intl.Collator(undefined, {
numeric: true,
sensitivity: "base",
});
+ function convertScopedCss(scope: string): string {
+ let scopedCssText = "";
+ const scopedCss = map.get(scope)!;
+
+ stringify(scopedCss, (output, node, flag) => {
+ if ((flag === "start" || flag === "end") && isNode(node, "rule")) {
+ if (node.selector === scope) {
+ if (isNode(node.parent, "root")) {
+ return;
+ } else if (flag === "start") {
+ output = "& {";
+ }
+ } else if (flag === "start") {
+ const selectors = new Set(
+ node.selectors.map(selector =>
+ parseSelector(nodes => {
+ nodes.first.walkClasses(node => {
+ if (node.toString() === scope) {
+ node.toString = () => "&";
+ } else if (knownScopes.has(node.toString())) {
+ node.toString = () => `.\${${mapClassNames(node.value)}}`;
+ }
+ });
+ }).processSync(selector)
+ )
+ );
+
+ // TODO remove join usage once https://github.com/prettier/prettier/issues/2883 is resolved
+ output = `${[...selectors].join(", ")} {`;
+ }
+ }
+
+ scopedCssText += output;
+ if (node?.type === "decl" && output.at(-1) !== ";") {
+ scopedCssText += ";";
+ }
+ });
+
+ return scopedCssText.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
+ }
+
const sortedKnownScopes = [...knownScopes]
.sort((scopeA, scopeB) => (scopeA === "root" ? -1 : collator.compare(scopeA, scopeB)))
- .reduce((previousSortedKnownScopes, knownScope) => {
+ .reduce((accum, knownScope) => {
for (const requiredScope of getRequiredScopes(
- cssIndexedByScope.get(knownScope)!,
+ map.get(knownScope)!,
knownScope,
knownScopes
)) {
- previousSortedKnownScopes.add(requiredScope);
+ accum.add(requiredScope);
}
- previousSortedKnownScopes.add(knownScope);
- return previousSortedKnownScopes;
+ accum.add(knownScope);
+ return accum;
}, new Set());
for (const scope of sortedKnownScopes) {
- cssForEmotion += "\n";
+ const style = convertScopedCss(scope).trimEnd();
+ if (!style.trim()) continue;
- const convertedScopedCssForEmotion = convertScopedCssForEmotion(
- cssIndexedByScope.get(scope)!,
- scope,
- knownScopes,
- mapClassNames
- ).trimEnd();
-
- if (!convertedScopedCssForEmotion.trim()) continue;
-
- cssForEmotion +=
+ res +=
scope === "root"
- ? `injectGlobal\`${convertedScopedCssForEmotion}\n\`;\n`
+ ? `injectGlobal\`${style}\n\`;\n`
: `\nexport const ${mapClassNames(
scope
- )} = ${JSON.stringify(asJSObject(convertedScopedCssForEmotion), null, 2)};\n`;
+ )} = ${JSON5.stringify(asJSObject(style), null, 2)};\n`;
}
- return cssForEmotion.trim();
+ return res.trim();
}
+// https://github.com/facebook/react/blob/3db98c917701d59f62cf1fbe45cbf01b0b61c704/packages/react-dom-bindings/src/shared/isUnitlessNumber.js#L13
+const unitlessNumbers = new Set([
+ "animationIterationCount",
+ "aspectRatio",
+ "borderImageOutset",
+ "borderImageSlice",
+ "borderImageWidth",
+ "boxFlex",
+ "boxFlexGroup",
+ "boxOrdinalGroup",
+ "columnCount",
+ "columns",
+ "flex",
+ "flexGrow",
+ "flexPositive",
+ "flexShrink",
+ "flexNegative",
+ "flexOrder",
+ "gridArea",
+ "gridRow",
+ "gridRowEnd",
+ "gridRowSpan",
+ "gridRowStart",
+ "gridColumn",
+ "gridColumnEnd",
+ "gridColumnSpan",
+ "gridColumnStart",
+ "fontWeight",
+ "lineClamp",
+ "lineHeight",
+ "opacity",
+ "order",
+ "orphans",
+ "scale",
+ "tabSize",
+ "widows",
+ "zIndex",
+ "zoom",
+ "fillOpacity", // SVG-related properties
+ "floodOpacity",
+ "stopOpacity",
+ "strokeDasharray",
+ "strokeDashoffset",
+ "strokeMiterlimit",
+ "strokeOpacity",
+ "strokeWidth",
+ "MozAnimationIterationCount", // Known Prefixed Properties
+ "MozBoxFlex", // TODO: Remove these since they shouldn't be used in modern code
+ "MozBoxFlexGroup",
+ "MozLineClamp",
+ "msAnimationIterationCount",
+ "msFlex",
+ "msZoom",
+ "msFlexGrow",
+ "msFlexNegative",
+ "msFlexOrder",
+ "msFlexPositive",
+ "msFlexShrink",
+ "msGridColumn",
+ "msGridColumnSpan",
+ "msGridRow",
+ "msGridRowSpan",
+ "WebkitAnimationIterationCount",
+ "WebkitBoxFlex",
+ "WebKitBoxFlexGroup",
+ "WebkitBoxOrdinalGroup",
+ "WebkitColumnCount",
+ "WebkitColumns",
+ "WebkitFlex",
+ "WebkitFlexGrow",
+ "WebkitFlexPositive",
+ "WebkitFlexShrink",
+ "WebkitLineClamp",
+]);
-const candidates = new Set(["fontSize"]);
function simplifyValue(propName: string, value: string) {
const num = value.match(/^(\d+(\.\d+)?)px$/)?.[1];
- if (num != null && candidates.has(propName)) {
+ if (num != null && unitlessNumbers.has(propName)) {
return parseFloat(num);
}
return value;
}
function asJSObject(inputCssText: string) {
- const css = parse(`a{${inputCssText}}`);
+ const css = compile(inputCssText);
const result: Record = {};
- if (css.nodes.length !== 1) {
- throw new Error("Expected exactly one root node");
- }
- const node = css.first!;
- if (node.type !== "rule") return;
-
- function walk(collect: Record, node: ChildNode) {
+ function walk(collect: Record, node: Element) {
switch (node.type) {
- case "atrule":
- const obj = (collect[`@${node.name} ${node.params}`] ??= {});
- node.each(child => {
+ case "decl": {
+ const prop = node.props as string;
+ const propName = prop.startsWith("--")
+ ? prop
+ : prop.replace(/(-.)/g, v => v[1].toUpperCase());
+ collect[propName] = simplifyValue(propName, node.children as string);
+ break;
+ }
+
+ case "rule": {
+ const ruleName = node.value.replaceAll("\f", "");
+ const obj = ruleName === "&" ? collect : (collect[ruleName] ??= {});
+ for (const child of node.children as Element[]) {
walk(obj, child);
- });
+ }
+ break;
+ }
+
+ case "comm":
break;
- case "decl":
- const propName = node.prop.replace(/(-.)/g, v => v[1].toUpperCase());
- collect[propName] = simplifyValue(propName, node.value);
- break;
-
- case "rule":
- node.each(declaration => {
- walk(collect, declaration);
- });
- break;
-
- case "comment":
+ case "@media":
+ const media = (collect[node.value] ??= {});
+ for (const child of node.children as Element[]) {
+ walk(media, child);
+ }
break;
}
}
- walk(result, node);
-
+ for (const node of css) {
+ walk(result, node);
+ }
return result as React.CSSProperties;
}
diff --git a/src/esbuild-postcss.ts b/src/esbuild-postcss.ts
index a57e1fd..c511a10 100644
--- a/src/esbuild-postcss.ts
+++ b/src/esbuild-postcss.ts
@@ -59,6 +59,7 @@ export const esbuildPlugin = ({
const entry = styles.find(s => s.key === cls)!;
if (!entry) {
+ console.error(e);
throw new Error("Could not find entry for CSS");
}
diff --git a/src/index.ts b/src/index.ts
index dd5ffd0..09987e1 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -17,30 +17,6 @@ export type BuildStyleFile = (
path: string
) => Promise;
-interface RecursiveStringObject {
- [modifier: string]: string | RecursiveStringObject;
-}
-
-export type CSSAttributeValue = string | (string | RecursiveStringObject)[];
-
-/**
- * Tagged template macro function combining Tailwind classes
- * @example "tw" => tw`p-2 text-center`
- */
-export interface TailwindFunction {
- (strings: TemplateStringsArray): string;
- (...args: (string | RecursiveStringObject)[]): string;
-}
-
-/**
- * Tagged template macro function compiling Tailwind styles
- * @example "tws" => tws`p-2 text-center` // { padding: 2, textAlign: "center" }
- */
-export interface TailwindStyleFunction