diff --git a/.gitignore b/.gitignore index 1f45d3a..99eb95b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +*.draft *.draft.* +src/converts # Logs logs diff --git a/package.json b/package.json index c1773f2..fad5b20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@aet/babel-tailwind", - "version": "0.0.1-beta.8", + "name": "@aet/tailwind", + "version": "0.0.1-beta.5", "main": "dist/index.js", "license": "MIT", "private": true, @@ -12,9 +12,9 @@ "dist" ], "devDependencies": { - "@aet/eslint-rules": "^0.0.22", + "@aet/eslint-rules": "^0.0.25", "@types/babel__core": "^7.20.5", - "@types/bun": "^1.0.12", + "@types/bun": "^1.1.0", "@types/dedent": "^0.7.2", "@types/lodash": "^4.17.0", "@types/node": "^20.12.7", @@ -32,8 +32,8 @@ "tailwindcss": "^3.4.3", "tsup": "^8.0.2", "typescript": "^5.4.5", - "vite": "^5.2.8", - "vitest": "^1.4.0" + "vite": "^5.2.10", + "vitest": "^1.5.0" }, "peerDependencies": { "tailwindcss": "^3.4.3" @@ -52,4 +52,4 @@ "singleQuote": false, "trailingComma": "es5" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2dbbd2f..d2bd03f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,14 +20,14 @@ dependencies: devDependencies: '@aet/eslint-rules': - specifier: ^0.0.22 - version: 0.0.22(eslint@8.57.0)(typescript@5.4.5) + specifier: ^0.0.25 + version: 0.0.25(eslint@8.57.0)(typescript@5.4.5) '@types/babel__core': specifier: ^7.20.5 version: 7.20.5 '@types/bun': - specifier: ^1.0.12 - version: 1.0.12 + specifier: ^1.1.0 + version: 1.1.0 '@types/dedent': specifier: ^0.7.2 version: 0.7.2 @@ -80,11 +80,11 @@ devDependencies: specifier: ^5.4.5 version: 5.4.5 vite: - specifier: ^5.2.8 - version: 5.2.8(@types/node@20.12.7) + specifier: ^5.2.10 + version: 5.2.10(@types/node@20.12.7) vitest: - specifier: ^1.4.0 - version: 1.4.0(@types/node@20.12.7) + specifier: ^1.5.0 + version: 1.5.0(@types/node@20.12.7) packages: @@ -93,18 +93,18 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@aet/eslint-rules@0.0.22(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-PLAnaYlb6GdG6gKjQP5B8XckOa7driZL1rbw51wGTYTl/0Etqu5R/u4TkQSYePZab7xCIrJuPSC3PsBEhI5pvQ==} + /@aet/eslint-rules@0.0.25(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-6F6iSb5Oc8DAqUVIPzXMQuAgzPceowZMh/lGfV++sk9t36nVefy+8UDWoDixVyHjoAbGPWjV4xx1EHi2xawk9g==} peerDependencies: eslint: ^8.57.0 typescript: ^5.4.4 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@types/eslint': 8.56.7 - '@typescript-eslint/eslint-plugin': 7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/type-utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5) + '@types/eslint': 8.56.10 + '@typescript-eslint/eslint-plugin': 7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/type-utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) aria-query: 5.3.0 axe-core: 4.9.0 axobject-query: 4.0.0 @@ -117,10 +117,12 @@ packages: eslint-config-prettier: 9.1.0(eslint@8.57.0) eslint-define-config: 1.24.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) eslint-plugin-es-x: 7.6.0(eslint@8.57.0) eslint-plugin-jsdoc: 48.2.3(eslint@8.57.0) eslint-plugin-unicorn: 52.0.0(eslint@8.57.0) + esprima: 4.0.1 + esquery: 1.5.0 estraverse: 5.3.0 fast-glob: 3.3.2 get-tsconfig: 4.7.3 @@ -1057,18 +1059,18 @@ packages: '@babel/types': 7.24.0 dev: true - /@types/bun@1.0.12: - resolution: {integrity: sha512-qPb5FcygbpSS1NDBjWyQCWeI9kKXwSYSR1Enu7yb+gMXgFwGMhlyOvgV/7FGrdvAjlSXWRY6IDepos7k8WzAtQ==} + /@types/bun@1.1.0: + resolution: {integrity: sha512-QGK0yU4jh0OK1A7DyhPkQuKjHQCC5jSJa3dpWIEhHv/rPfb6zLfdArc4/uUUZBMTcjilsafRXnPWO+1owb572Q==} dependencies: - bun-types: 1.0.36 + bun-types: 1.1.0 dev: true /@types/dedent@0.7.2: resolution: {integrity: sha512-kRiitIeUg1mPV9yH4VUJ/1uk2XjyANfeL8/7rH1tsjvHeO9PJLBHJIYsFWmAvmGj5u8rj+1TZx7PZzW2qLw3Lw==} dev: true - /@types/eslint@8.56.7: - resolution: {integrity: sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==} + /@types/eslint@8.56.10: + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 @@ -1118,8 +1120,8 @@ packages: '@types/node': 20.12.7 dev: true - /@typescript-eslint/eslint-plugin@7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==} + /@typescript-eslint/eslint-plugin@7.7.0(@typescript-eslint/parser@7.7.0)(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -1130,11 +1132,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.5.0 - '@typescript-eslint/type-utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.5.0 + '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.7.0 + '@typescript-eslint/type-utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.7.0 debug: 4.3.4 eslint: 8.57.0 graphemer: 1.4.0 @@ -1147,8 +1149,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==} + /@typescript-eslint/parser@7.7.0(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1157,10 +1159,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 7.5.0 - '@typescript-eslint/types': 7.5.0 - '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.5.0 + '@typescript-eslint/scope-manager': 7.7.0 + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 7.7.0 debug: 4.3.4 eslint: 8.57.0 typescript: 5.4.5 @@ -1168,16 +1170,16 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager@7.5.0: - resolution: {integrity: sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==} + /@typescript-eslint/scope-manager@7.7.0: + resolution: {integrity: sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==} engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.5.0 - '@typescript-eslint/visitor-keys': 7.5.0 + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/visitor-keys': 7.7.0 dev: true - /@typescript-eslint/type-utils@7.5.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==} + /@typescript-eslint/type-utils@7.7.0(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1186,8 +1188,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) + '@typescript-eslint/utils': 7.7.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) @@ -1196,13 +1198,13 @@ packages: - supports-color dev: true - /@typescript-eslint/types@7.5.0: - resolution: {integrity: sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==} + /@typescript-eslint/types@7.7.0: + resolution: {integrity: sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==} engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/typescript-estree@7.5.0(typescript@5.4.5): - resolution: {integrity: sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==} + /@typescript-eslint/typescript-estree@7.7.0(typescript@5.4.5): + resolution: {integrity: sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -1210,12 +1212,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 7.5.0 - '@typescript-eslint/visitor-keys': 7.5.0 + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/visitor-keys': 7.7.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.3 + minimatch: 9.0.4 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 @@ -1223,8 +1225,8 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@7.5.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==} + /@typescript-eslint/utils@7.7.0(eslint@8.57.0)(typescript@5.4.5): + resolution: {integrity: sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1232,9 +1234,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.5.0 - '@typescript-eslint/types': 7.5.0 - '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.7.0 + '@typescript-eslint/types': 7.7.0 + '@typescript-eslint/typescript-estree': 7.7.0(typescript@5.4.5) eslint: 8.57.0 semver: 7.6.0 transitivePeerDependencies: @@ -1242,11 +1244,11 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys@7.5.0: - resolution: {integrity: sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==} + /@typescript-eslint/visitor-keys@7.7.0: + resolution: {integrity: sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==} engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.5.0 + '@typescript-eslint/types': 7.7.0 eslint-visitor-keys: 3.4.3 dev: true @@ -1254,38 +1256,38 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@vitest/expect@1.4.0: - resolution: {integrity: sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==} + /@vitest/expect@1.5.0: + resolution: {integrity: sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==} dependencies: - '@vitest/spy': 1.4.0 - '@vitest/utils': 1.4.0 + '@vitest/spy': 1.5.0 + '@vitest/utils': 1.5.0 chai: 4.4.1 dev: true - /@vitest/runner@1.4.0: - resolution: {integrity: sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==} + /@vitest/runner@1.5.0: + resolution: {integrity: sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==} dependencies: - '@vitest/utils': 1.4.0 + '@vitest/utils': 1.5.0 p-limit: 5.0.0 pathe: 1.1.2 dev: true - /@vitest/snapshot@1.4.0: - resolution: {integrity: sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==} + /@vitest/snapshot@1.5.0: + resolution: {integrity: sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==} dependencies: magic-string: 0.30.8 pathe: 1.1.2 pretty-format: 29.7.0 dev: true - /@vitest/spy@1.4.0: - resolution: {integrity: sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==} + /@vitest/spy@1.5.0: + resolution: {integrity: sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==} dependencies: tinyspy: 2.2.1 dev: true - /@vitest/utils@1.4.0: - resolution: {integrity: sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==} + /@vitest/utils@1.5.0: + resolution: {integrity: sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==} dependencies: diff-sequences: 29.6.3 estree-walker: 3.0.3 @@ -1449,8 +1451,8 @@ packages: engines: {node: '>=6'} dev: true - /bun-types@1.0.36: - resolution: {integrity: sha512-gaIb1SyhB0JZfIEg73/kSFhqolUqJXC68peguhXGwqr27HuvI8nkD0LTIHp/1DY4cNadfXHYgYrZIWX7oEoXlg==} + /bun-types@1.1.0: + resolution: {integrity: sha512-GhMDD7TosdJzQPGUOcQD5PZshvXVxDfwGAZs2dq+eSaPsRn3iUCzvpFlsg7Q51bXVzLAUs+FWHlnmpgZ5UggIg==} dependencies: '@types/node': 20.11.30 '@types/ws': 8.5.10 @@ -1865,7 +1867,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: @@ -1886,7 +1888,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.7.0(eslint@8.57.0)(typescript@5.4.5) debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 @@ -2022,6 +2024,12 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} @@ -2636,13 +2644,6 @@ packages: brace-expansion: 1.1.11 dev: true - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimatch@9.0.4: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} @@ -3555,8 +3556,8 @@ packages: spdx-expression-parse: 3.0.1 dev: true - /vite-node@1.4.0(@types/node@20.12.7): - resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} + /vite-node@1.5.0(@types/node@20.12.7): + resolution: {integrity: sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true dependencies: @@ -3564,7 +3565,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.2.8(@types/node@20.12.7) + vite: 5.2.10(@types/node@20.12.7) transitivePeerDependencies: - '@types/node' - less @@ -3576,8 +3577,8 @@ packages: - terser dev: true - /vite@5.2.8(@types/node@20.12.7): - resolution: {integrity: sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==} + /vite@5.2.10(@types/node@20.12.7): + resolution: {integrity: sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -3612,15 +3613,15 @@ packages: fsevents: 2.3.3 dev: true - /vitest@1.4.0(@types/node@20.12.7): - resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==} + /vitest@1.5.0(@types/node@20.12.7): + resolution: {integrity: sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.4.0 - '@vitest/ui': 1.4.0 + '@vitest/browser': 1.5.0 + '@vitest/ui': 1.5.0 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -3638,11 +3639,11 @@ packages: optional: true dependencies: '@types/node': 20.12.7 - '@vitest/expect': 1.4.0 - '@vitest/runner': 1.4.0 - '@vitest/snapshot': 1.4.0 - '@vitest/spy': 1.4.0 - '@vitest/utils': 1.4.0 + '@vitest/expect': 1.5.0 + '@vitest/runner': 1.5.0 + '@vitest/snapshot': 1.5.0 + '@vitest/spy': 1.5.0 + '@vitest/utils': 1.5.0 acorn-walk: 8.3.2 chai: 4.4.1 debug: 4.3.4 @@ -3655,8 +3656,8 @@ packages: strip-literal: 2.1.0 tinybench: 2.6.0 tinypool: 0.8.3 - vite: 5.2.8(@types/node@20.12.7) - vite-node: 1.4.0(@types/node@20.12.7) + vite: 5.2.10(@types/node@20.12.7) + vite-node: 1.5.0(@types/node@20.12.7) why-is-node-running: 2.2.2 transitivePeerDependencies: - less diff --git a/src/babel-tailwind.ts b/src/babel-tailwind.ts index dd30437..8ecfdd2 100644 --- a/src/babel-tailwind.ts +++ b/src/babel-tailwind.ts @@ -1,8 +1,8 @@ import { basename, dirname, extname, join } from "node:path"; import type babel from "@babel/core"; import { type NodePath, type types as t } from "@babel/core"; -import type { SourceLocation, StyleMap, StyleMapEntry } from "./shared"; -import { type TailwindPluginOptions, getClassName } from "./index"; +import type { SourceLocation, StyleMapEntry } from "./shared"; +import { type ResolveTailwindOptions, getClassName } from "./index"; const definePlugin = (fn: (runtime: typeof babel) => babel.Visitor) => @@ -32,15 +32,18 @@ interface BabelPluginState { tailwindMap: Map; } +export type ClassNameCollector = (path: string, entries: StyleMapEntry[]) => void; + export function babelTailwind( - styleMap: StyleMap, { + styleMap, clsx, getClassName: getClass = getClassName, taggedTemplateName, jsxAttributeAction = "delete", jsxAttributeName = "css", - }: TailwindPluginOptions + }: ResolveTailwindOptions, + onCollect: ClassNameCollector | undefined ) { function getClsxImport(t: typeof babel.types, cx: t.Identifier) { switch (clsx) { @@ -103,7 +106,10 @@ export function babelTailwind( t.importDeclaration([], t.stringLiteral(`tailwind:./${cssName}`)) ); - styleMap.set(join(dirname(filename), cssName), Array.from(tailwindMap.values())); + const path = join(dirname(filename), cssName); + const value = Array.from(tailwindMap.values()); + styleMap.set(path, value); + onCollect?.(path, value); }, }, @@ -185,18 +191,24 @@ export function babelTailwind( if (classNameAttribute) { const attrValue = classNameAttribute.value!; + const valuePathNode = valuePath.node; + const wrap = (originalValue: babel.types.Expression) => + t.callExpression(getCx(), [originalValue, extractJSXContainer(valuePathNode)]); // If both are string literals, we can merge them directly here - if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePath.node)) { + if (t.isStringLiteral(attrValue) && t.isStringLiteral(valuePathNode)) { attrValue.value += - (attrValue.value.at(-1) === " " ? "" : " ") + valuePath.node.value; + (attrValue.value.at(-1) === " " ? "" : " ") + valuePathNode.value; } else { - classNameAttribute.value = t.jsxExpressionContainer( - t.callExpression(getCx(), [ - extractJSXContainer(attrValue), - extractJSXContainer(valuePath.node), - ]) - ); + 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 { parent.attributes.push( diff --git a/src/converts/LICENSE b/src/converts/LICENSE deleted file mode 100644 index e69de29..0000000 diff --git a/src/converts/NodesManager.ts b/src/converts/NodesManager.ts deleted file mode 100644 index 90519c6..0000000 --- a/src/converts/NodesManager.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { type AtRule, type ChildNode, type Node, Rule } from "postcss"; -import { isAtRuleNode, isChildNode } from "./utils"; - -export interface ResolvedTailwindNode { - rule: Rule; - tailwindClasses: string[]; -} - -interface UnresolvedTailwindNode { - key: string; - rootRuleSelector?: string | null; - originalRule: Rule; - classesPrefix: string; - tailwindClasses: string[]; -} - -export type TailwindNode = ResolvedTailwindNode | UnresolvedTailwindNode; - -function isResolvedTailwindNode(node: TailwindNode): node is ResolvedTailwindNode { - return "rule" in node; -} - -export class TailwindNodesManager { - protected nodesMap: Map; - - constructor(initialNodes?: TailwindNode[]) { - this.nodesMap = new Map(); - if (initialNodes?.length) { - this.mergeNodes(initialNodes); - } - } - - mergeNode(node: TailwindNode) { - const nodeIsResolved = isResolvedTailwindNode(node); - const nodeKey = nodeIsResolved - ? TailwindNodesManager.convertRuleToKey(node.rule) - : node.key; - const foundNode = this.nodesMap.get(nodeKey); - - if (foundNode) { - foundNode.tailwindClasses = foundNode.tailwindClasses.concat( - nodeIsResolved - ? node.tailwindClasses - : node.tailwindClasses.map(className => `${node.classesPrefix}${className}`) - ); - - return; - } - - if (nodeIsResolved) { - this.nodesMap.set(nodeKey, node); - } else { - let rule; - - if (node.rootRuleSelector) { - rule = new Rule({ - selector: node.rootRuleSelector, - }); - - const rootChild = this.upToRootChild(node.originalRule); - if (rootChild) { - node.originalRule.root().insertBefore(rootChild, rule); - } - } else { - rule = node.originalRule; - } - - this.nodesMap.set(nodeKey, { - rule, - tailwindClasses: node.tailwindClasses.map( - className => `${node.classesPrefix}${className}` - ), - }); - } - } - - mergeNodes(nodes: TailwindNode[]) { - for (const node of nodes) { - this.mergeNode(node); - } - } - - hasNode(key: string) { - return this.nodesMap.has(key); - } - - getNode(key: string) { - return this.nodesMap.get(key) || null; - } - - getNodes() { - return Array.from(this.nodesMap.values()); - } - - protected upToRootChild(node: Node) { - let childNode: ChildNode | null = null; - - while (node.parent && node.parent.type !== "root" && isChildNode(node.parent)) { - childNode = node = node.parent; - continue; - } - - return childNode; - } - - static convertRuleToKey(rule: Rule, overriddenSelector: string | null = null) { - let currentParent = rule.parent; - let parentKey = ""; - - while (isChildNode(currentParent)) { - parentKey += - (isAtRuleNode(currentParent) - ? this.makeSingleAtRuleKey(currentParent) - : this.makeSingleRuleKey(currentParent)) + "__"; - - currentParent = currentParent.parent; - } - - return parentKey + (overriddenSelector == null ? rule.selector : overriddenSelector); - } - - protected static makeSingleAtRuleKey(atRule: AtRule) { - return `a(${atRule.name}|${atRule.params})`; - } - - protected static makeSingleRuleKey(atRule: Rule) { - return `r(${atRule.selector})`; - } -} diff --git a/src/converts/README.md b/src/converts/README.md deleted file mode 100644 index 1a1b092..0000000 --- a/src/converts/README.md +++ /dev/null @@ -1,230 +0,0 @@ -# Convert CSS to TailwindCSS 3.x - -[![npm package][npm-img]][npm-url] -[![Build Status][build-img]][build-url] -[![Downloads][downloads-img]][downloads-url] -[![Issues][issues-img]][issues-url] -[![Semantic Release][semantic-release-img]][semantic-release-url] - -> Convert your CSS to TailwindCSS 3.x respecting TailwindCSS configuration - -**[🔗 Demo](https://transform.tools/css-to-tailwind)** - -**[🔗 VS Code Extension already available 🎉](https://github.com/Jackardios/vscode-css-to-tailwindcss)** - -![VSCode demo](.github/demo.gif) - -## Features: - -- supports almost all the features (except custom plugins) currently available in TailwindCSS -- the ability to set your own TailwindCSS configuration -- colors are matched regardless of the format used -- rem is converted to px (it is possible to configure the rem size) -- non-convertible CSS declarations are simply skipped -- [ambiguities](https://tailwindcss.com/docs/adding-custom-styles#resolving-ambiguities) when using css variables are resolved automatically - -## Install - -```bash -npm install css-to-tailwindcss -``` - -## Usage - -```ts -import { TailwindConverter } from 'css-to-tailwindcss'; - -const converter = new TailwindConverter({ - remInPx: 16, // set null if you don't want to convert rem to pixels - postCSSPlugins: [require('postcss-nested')], // add any postcss plugins to this array - tailwindConfig: { - // your tailwind config here - content: [], - theme: { - extend: { - colors: { - 'custom-color': { - 100: '#123456', - 200: 'hsla(210, 100%, 51.0%, 0.016)', - 300: '#654321', - gold: 'hsl(41, 28.3%, 79.8%)', - marine: 'rgb(4, 55, 242, 0.75)', - }, - }, - screens: { - 'custom-screen': { min: '768px', max: '1024px' }, - }, - }, - supports: { - grid: 'display: grid', - flex: 'display: flex', - }, - }, - }, -}); - -const inputCSS = ` -:root { - --some-color: #090909; -} - -.foo { - padding: 0.875em 256px; - margin-left: 16px; - text-align: center; - font-size: 12px; - transition: color, background-color, border-color, text-decoration-color, fill, - stroke 200ms cubic-bezier(0, 0, 0.2, 1); - animation-delay: 200ms; - - &:hover { - filter: blur(4px) brightness(0.5) sepia(100%) contrast(1) hue-rotate(30deg) - invert(0) opacity(0.05) saturate(1.5); - color: hsl(41, 28.3%, 79.8%); - font-size: 1.25rem; - } - - &[aria-disabled="true"] { - width: 25%; - color: var(--some-color); - font-size: 1em; - } - - @media screen and (min-width: 768px) { - top: auto; - bottom: auto; - left: 25%; - right: 25%; - } - - @media (min-width: 768px) and (max-width: 1024px) { - min-width: 100%; - margin-right: -24px; - } - - @supports (display: grid) { - display: grid; - grid-column: span 1 / span 1; - } -} - -.foo.bar { - padding: 0.875rem 256px 15%; - transform: translateX(12px) translateY(-0.5em) skew(1deg, 3deg) - scale(-0.75, 1.05) rotate(-0.25turn); - - &::after { - content: "*"; - animation: spin 1s linear infinite; - } -} -`; - -converter.convertCSS(inputCSS).then(({ convertedRoot, nodes }) => { - console.log(convertedRoot.toString()); - console.log(nodes); -}); -``` - -Console output - -`convertedRoot.toString()`: - -```css -:root { - --some-color: #090909; -} - -.foo { - @apply text-center text-xs transition-colors duration-200 ease-out ml-4 px-64 py-[0.875em] hover:blur-sm hover:brightness-50 hover:sepia hover:contrast-100 hover:hue-rotate-30 hover:invert-0 hover:opacity-5 hover:saturate-150 hover:text-custom-color-gold hover:text-xl disabled:w-3/12 disabled:text-[color:var(--some-color)] disabled:text-[1em] md:inset-x-1/4 md:inset-y-auto custom-screen:min-w-full custom-screen:-mr-6 supports-grid:grid supports-grid:col-span-1; - animation-delay: 200ms; -} - -.foo.bar { - @apply translate-x-3 translate-y-[-0.5em] skew-x-1 skew-y-3 rotate-[-0.25turn] pt-3.5 pb-[15%] px-64 -scale-x-75 scale-y-105 after:content-["*"] after:animate-spin; -} -``` - -`nodes`: - -```js -[ - { - rule: { - selector: '.foo', - // ... - }, - tailwindClasses: [ - 'text-center', - 'text-xs', - 'transition-colors', - 'duration-200', - 'ease-out', - 'ml-4', - 'px-64', - 'py-[0.875em]', - 'hover:blur-sm', - 'hover:brightness-50', - 'hover:sepia', - 'hover:contrast-100', - 'hover:hue-rotate-30', - 'hover:invert-0', - 'hover:opacity-5', - 'hover:saturate-150', - 'hover:text-custom-color-gold', - 'hover:text-xl', - 'disabled:w-3/12', - 'disabled:text-[color:var(--some-color)]', - 'disabled:text-[1em]', - 'md:inset-x-1/4', - 'md:inset-y-auto', - 'custom-screen:min-w-full', - 'custom-screen:-mr-6', - 'supports-grid:grid', - 'supports-grid:col-span-1', - ], - }, - { - rule: { - selector: '.foo.bar', - // ... - }, - tailwindClasses: [ - 'translate-x-3', - 'translate-y-[-0.5em]', - 'skew-x-1', - 'skew-y-3', - 'rotate-[-0.25turn]', - 'pt-3.5', - 'pb-[15%]', - 'px-64', - '-scale-x-75', - 'scale-y-105', - 'after:content-["*"]', - 'after:animate-spin', - ], - }, -]; -``` - -## API - -### TailwindConverter(options?) - -| Option | Type | Default | Description | -| ---------------------------- | ------------------ | ------- | ---------------------------------------------------------------------------------------- | -| remInPx | `number` \| `null` | `null` | `rem` in `px` unit. Set null if you don't want to convert rem to pixels | -| arbitraryPropertiesIsEnabled | `boolean` | `false` | defines whether non-convertible properties should be converted as "arbitrary properties" | -| tailwindConfig | `Config` | {} | Set your tailwind config here | -| postCSSPlugins | `AcceptedPlugin[]` | [] | Array of acceptable postcss plugins | - -[build-img]: https://github.com/jackardios/css-to-tailwindcss/actions/workflows/release.yml/badge.svg -[build-url]: https://github.com/jackardios/css-to-tailwindcss/actions/workflows/release.yml -[downloads-img]: https://img.shields.io/npm/dt/css-to-tailwindcss -[downloads-url]: https://www.npmtrends.com/css-to-tailwindcss -[npm-img]: https://img.shields.io/npm/v/css-to-tailwindcss -[npm-url]: https://www.npmjs.com/package/css-to-tailwindcss -[issues-img]: https://img.shields.io/github/issues/jackardios/css-to-tailwindcss -[issues-url]: https://github.com/jackardios/css-to-tailwindcss/issues -[semantic-release-img]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg -[semantic-release-url]: https://github.com/semantic-release/semantic-release diff --git a/src/converts/index.ts b/src/converts/index.ts deleted file mode 100644 index 45dda45..0000000 --- a/src/converts/index.ts +++ /dev/null @@ -1,405 +0,0 @@ -import { - type AttributeSelector, - type Selector, - isTraversal, - parse, - stringify, -} from "css-what"; -import type { Config } from "tailwindcss"; -import type { Expand } from "tailwindcss/types/config"; -import type { CorePluginList } from "tailwindcss/types/generated/corePluginList"; -import baseResolveConfig from "tailwindcss/resolveConfig"; -import postcss, { AtRule } from "postcss"; -import type { - AcceptedPlugin, - Container, - Declaration, - Document, - Root, - Rule, -} from "postcss"; -import postcssSafeParser from "postcss-safe-parser"; -import type { ConverterMapping } from "./types"; -import { type TailwindNode, TailwindNodesManager } from "./NodesManager"; -import { - detectIndent, - isAtRuleNode, - isChildNode, - removeUnnecessarySpaces, -} from "./utils"; -import { - converterMappingByTailwindTheme, - normalizeAtRuleParams, -} from "./utils/converterMappingByTailwindTheme"; -import { - DECLARATION_CONVERTERS_MAPPING, - convertDeclarationValue, - prepareArbitraryValue, -} from "./mappings/declaration-converters-mapping"; -import MEDIA_PARAMS_MAPPING from "./mappings/media-params-mapping.json"; -import PSEUDOS_MAPPING from "./mappings/pseudos-mapping.json"; -import { reduceTailwindClasses } from "./utils/reduceTailwindClasses"; - -export interface TailwindConverterConfig { - remInPx?: number | null; - tailwindConfig?: Config; - postCSSPlugins: AcceptedPlugin[]; - arbitraryPropertiesIsEnabled: boolean; -} - -export const DEFAULT_CONVERTER_CONFIG: Omit = { - postCSSPlugins: [], - arbitraryPropertiesIsEnabled: false, -}; - -export interface ResolvedTailwindConfig extends Config { - prefix: string; - separator: string; - corePlugins: Expand>>; -} - -export type ResolvedConfig = ReturnType; -export type CorePlugins = ResolvedTailwindConfig["corePlugins"]; - -export function resolveConfig(config: Config) { - const resolved = baseResolveConfig(config); - const corePlugins: CorePlugins = {}; - for (const current of resolved["corePlugins"] as CorePluginList[]) { - corePlugins[current] = true; - } - - return { - ...resolved, - prefix: resolved.prefix || "", - separator: resolved.separator || ":", - corePlugins, - }; -} - -export class TailwindConverter { - protected config: TailwindConverterConfig; - private tailwindConfig: ResolvedConfig; - private mapping: ConverterMapping; - - constructor({ - tailwindConfig, - ...converterConfig - }: Partial = {}) { - const resolvedTailwindConfig = resolveConfig( - tailwindConfig || ({ content: [] } as Config) - ); - this.tailwindConfig = resolvedTailwindConfig; - this.mapping = converterMappingByTailwindTheme( - resolvedTailwindConfig.theme, - converterConfig.remInPx - ); - - this.config = { - ...DEFAULT_CONVERTER_CONFIG, - ...converterConfig, - }; - } - - async convertCSS(css: string) { - const nodesManager = new TailwindNodesManager(); - const parsed = await postcss(this.config.postCSSPlugins).process(css, { - parser: postcssSafeParser, - }); - - parsed.root.walkRules(rule => { - const converted = this.convertRule(rule); - if (converted) { - nodesManager.mergeNode(converted); - } - }); - - const nodes = nodesManager.getNodes(); - for (const node of nodes) { - if (node.tailwindClasses.length) { - node.rule.prepend( - new AtRule({ - name: "apply", - params: node.tailwindClasses.join(" "), - }) - ); - } - } - - this.cleanRaws(parsed.root); - - return { - nodes, - convertedRoot: parsed.root, - }; - } - - protected cleanRaws(root: Root | Document) { - root.raws.indent = detectIndent(root); - - root.walkRules(node => { - if (node.nodes?.length === 0) { - node.remove(); - } else { - node.cleanRaws(true); - } - }); - - root.walkAtRules(node => { - if (node.nodes?.length === 0) { - node.remove(); - } else { - node.cleanRaws(true); - } - }); - } - - protected convertRule(rule: Rule): TailwindNode | null { - let tailwindClasses: string[] = []; - - rule.walkDecls(declaration => { - const converted = this.convertDeclarationToClasses(declaration); - - if (converted?.length) { - declaration.remove(); - tailwindClasses = tailwindClasses.concat(converted); - } - }); - - if (tailwindClasses.length) { - tailwindClasses = reduceTailwindClasses(tailwindClasses); - - if (this.tailwindConfig.prefix) { - tailwindClasses = tailwindClasses.map(className => - className[0] === "[" // is "arbitrary property" class - ? className - : `${this.tailwindConfig.prefix}${className}` - ); - } - - return this.makeTailwindNode(rule, tailwindClasses); - } - - return null; - } - - protected convertDeclarationToClasses(declaration: Declaration) { - const converter = DECLARATION_CONVERTERS_MAPPING[declaration.prop]; - const classes = - !converter.flag || this.tailwindConfig.corePlugins[converter.flag] - ? converter?.map(declaration, this.mapping, this.config, this.tailwindConfig) - : []; - - if (classes.length === 0 && this.config.arbitraryPropertiesIsEnabled) { - return [`[${declaration.prop}:${prepareArbitraryValue(declaration.value)}]`]; - } - - return classes; - } - - protected makeTailwindNode(rule: Rule, tailwindClasses: string[]): TailwindNode { - const { baseSelector, classPrefix } = this.parseSelector(rule.selector); - - const classPrefixByParentNodes = this.convertContainerToClassPrefix(rule.parent); - - if (classPrefixByParentNodes) { - return { - key: baseSelector, - rootRuleSelector: baseSelector, - originalRule: rule, - classesPrefix: classPrefixByParentNodes + classPrefix, - tailwindClasses, - }; - } - - if (classPrefix) { - const key = TailwindNodesManager.convertRuleToKey(rule, baseSelector); - const isRootRule = key === baseSelector; - - return { - key, - rootRuleSelector: isRootRule ? baseSelector : null, - originalRule: rule, - classesPrefix: classPrefix, - tailwindClasses, - }; - } - - return { rule, tailwindClasses }; - } - - protected parseSelector(rawSelector: string) { - const parsedSelectors = parse(rawSelector); - - if (parsedSelectors.length !== 1) { - return { baseSelector: rawSelector, classPrefix: "" }; - } - - const parsedSelector = parsedSelectors[0]; - let baseSelectors: Array = []; - let classPrefixes: Array = []; - parsedSelector?.forEach((selectorItem, index) => { - if (isTraversal(selectorItem)) { - baseSelectors = parsedSelector.slice(0, index + 1); - classPrefixes = []; - - return; - } - - const classPrefix = this.convertSelectorToClassPrefix(selectorItem); - - if (classPrefix) { - classPrefixes.push(classPrefix); - } else { - baseSelectors.push(selectorItem); - } - }); - - return { - baseSelector: stringify([baseSelectors]), - classPrefix: classPrefixes.join(""), - }; - } - - protected convertSelectorToClassPrefix(selector: Selector) { - if (selector.type === "pseudo" || selector.type === "pseudo-element") { - const mapped = (PSEUDOS_MAPPING as any)[selector.name]; - - return mapped ? `${mapped}${this.tailwindConfig.separator}` : null; - } - - if (selector.type === "attribute") { - if (selector.name.startsWith("aria-")) { - const mappingKey = this.attributeSelectorToMappingKey(selector, 6); - const mapped = this.mapping.aria?.[mappingKey]; - - if (!mapped) { - return null; - } - - return `${mapped}${this.tailwindConfig.separator}`; - } - - if (selector.name.startsWith("data-")) { - const mappingKey = this.attributeSelectorToMappingKey(selector, 6); - const mapped = this.mapping.data?.[mappingKey]; - - if (!mapped) { - return null; - } - - return `${mapped}${this.tailwindConfig.separator}`; - } - } - - return null; - } - - protected attributeSelectorToMappingKey(selector: AttributeSelector, from = 1) { - const stringifiedSelector = stringify([[selector]]); - - return stringifiedSelector.substring(from, stringifiedSelector.length - 1); - } - - protected convertContainerToClassPrefix(container: Container | undefined) { - let currentContainer: Document | Container | undefined = container; - const mediaParams: string[] = []; - const supportsParams: string[] = []; - - while (isChildNode(currentContainer)) { - if (!isAtRuleNode(currentContainer)) { - // do not convert if parent is not at-rule - return ""; - } - - if (currentContainer.name === "media") { - mediaParams.push(currentContainer.params); - } else if (currentContainer.name === "supports") { - supportsParams.push(currentContainer.params); - } else { - return ""; - } - - currentContainer = currentContainer.parent; - } - - let mediaPrefixes = ""; - let supportsPrefixes = ""; - if (mediaParams.length) { - mediaPrefixes = this.convertMediaParamsToClassPrefix(mediaParams.reverse()); - if (!mediaPrefixes) { - return ""; - } - } - - if (supportsParams.length) { - supportsPrefixes = this.convertSupportsParamsToClassPrefix( - supportsParams.reverse() - ); - if (!supportsPrefixes) { - return ""; - } - } - - return mediaPrefixes + supportsPrefixes; - } - - protected convertMediaParamsToClassPrefix(mediaParams: string[]) { - const modifiers: string[] = []; - const screens: string[] = []; - - for (let i = 0; i < mediaParams.length; i++) { - const splitted = mediaParams[i].split(" and "); - for (let j = 0; j < splitted.length; j++) { - const param = normalizeAtRuleParams(splitted[j].trim()); - - if (param === "screen") { - continue; - } - - if (param.includes("width") || param.includes("height")) { - screens.push(param); - continue; - } - - const mapped = (MEDIA_PARAMS_MAPPING as any)[param.replace(/\s+/g, "")]; - if (mapped) { - modifiers.push(mapped); - continue; - } - - // do not convert if not convertable media - return ""; - } - } - - if (screens.length > 0) { - const mappedScreen = this.mapping.screens[screens.join(" and ")]; - - if (!mappedScreen) { - return ""; - } - - modifiers.push(mappedScreen); - } - - const classPrefix = modifiers.join(this.tailwindConfig.separator); - - return classPrefix ? classPrefix + this.tailwindConfig.separator : ""; - } - - protected convertSupportsParamsToClassPrefix(supportParams: string[]) { - const buildParams = supportParams.join(" and "); - const classPrefix = convertDeclarationValue({ - value: { - value: - supportParams.length > 1 - ? removeUnnecessarySpaces(buildParams) - : normalizeAtRuleParams(buildParams), - valuesMap: this.mapping.supports || {}, - classPrefix: "supports", - }, - }); - - return classPrefix ? classPrefix.join(",") + this.tailwindConfig.separator : ""; - } -} diff --git a/src/converts/mappings/declaration-converters-mapping.ts b/src/converts/mappings/declaration-converters-mapping.ts deleted file mode 100644 index 1740c08..0000000 --- a/src/converts/mappings/declaration-converters-mapping.ts +++ /dev/null @@ -1,2206 +0,0 @@ -import type { Declaration } from "postcss"; -import type { ResolvedTailwindConverterConfig } from "../index"; - -import UTILITIES_MAPPING from "./utilities-mapping.json"; -import { - normalizeColorValue, - normalizeSizeValue, - normalizeValue, -} from "../utils/converterMappingByTailwindTheme"; -import { isCSSVariable, removeUnnecessarySpaces } from "../utils"; - -function parseCSSFunction(string: string) { - const { name, value } = string.match(/(?[\w-]+)\((?.*?)\)/)?.groups || {}; - return { name: name || null, value: value || null }; -} - -const parseCSSFunctions = (value: string) => - value - .trim() - .match(/(?[\w-]+)\((?.*?)\)/gm) - ?.map((cssFunction: string) => parseCSSFunction(cssFunction)) || []; - -export function prepareArbitraryValue(value: string) { - return normalizeValue(value).replace(/_/g, "\\_").replace(/\s+/g, "_"); -} - -type CSSDataType = "color" | "length" | "number" | "image" | "position" | "family-name"; - -export function convertDeclarationValue({ - value, - valuesMap, - classPrefix, - fallbackValue = value, - fallbackClassPrefix = classPrefix, - cssDataType = null, -}: { - value: string; - valuesMap: Record; - classPrefix: string; - fallbackValue?: string; - fallbackClassPrefix?: string; - cssDataType?: CSSDataType | null; -}) { - const normalizedValue = normalizeValue(value); - const mappedValue = valuesMap[normalizedValue]; - if (mappedValue) { - if (mappedValue === "DEFAULT") { - return [classPrefix]; - } - - return [`${classPrefix}-${mappedValue}`]; - } - - const arbitraryValue = prepareArbitraryValue(fallbackValue); - - if (!arbitraryValue) { - return []; - } - - if (cssDataType && isCSSVariable(arbitraryValue)) { - return [ - `${fallbackClassPrefix}-[${cssDataType ? `${cssDataType}:` : ""}${arbitraryValue}]`, - ]; - } - - return [`${fallbackClassPrefix}-[${arbitraryValue}]`]; -} - -export function strictConvertDeclarationValue( - value: string, - valuesMap: Record -) { - return valuesMap[value] ? [valuesMap[value]] : []; -} - -function convertColorDeclarationValue({ - declValue, - valuesMap, - classPrefix, - cssDataType = null, -}: { - declValue: string; - valuesMap: Record; - classPrefix: string; - cssDataType?: CSSDataType | null; -}) { - return convertDeclarationValue({ - value: normalizeColorValue(declValue), - valuesMap, - classPrefix, - fallbackValue: declValue, - fallbackClassPrefix: classPrefix, - cssDataType, - }); -} - -function convertSizeDeclarationValue({ - declValue, - valuesMap, - classPrefix, - remInPx, - supportsNegativeValues = false, - cssDataType = null, -}: { - declValue: string; - valuesMap: Record; - classPrefix: string; - remInPx: number | null | undefined; - supportsNegativeValues?: boolean; - cssDataType?: CSSDataType | null; -}) { - const normalizedValue = normalizeSizeValue(declValue, remInPx); - const isNegativeValue = supportsNegativeValues && normalizedValue.startsWith("-"); - - return convertDeclarationValue({ - value: isNegativeValue ? normalizedValue.slice(1) : normalizedValue, - valuesMap, - classPrefix: isNegativeValue ? `-${classPrefix}` : classPrefix, - fallbackValue: declValue, - fallbackClassPrefix: classPrefix, - cssDataType, - }); -} - -function convertBorderDeclarationValue({ - value, - config, - classPrefix, -}: { - value: string; - config: ResolvedTailwindConverterConfig; - classPrefix: string; -}) { - const [width, style, ...colorArray] = value.split(/\s+/m); - const color = colorArray.join(" "); - - let classes: string[] = []; - - if (width) { - if (!config.tailwindConfig.corePlugins.borderWidth) { - return []; - } - classes = classes.concat( - convertSizeDeclarationValue({ - declValue: width, - valuesMap: config.mapping.borderWidth, - classPrefix, - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - ); - } - - if (style) { - if (!config.tailwindConfig.corePlugins.borderStyle) { - return []; - } - classes = classes.concat( - strictConvertDeclarationValue(style, UTILITIES_MAPPING["border-style"]) - ); - } - - if (color) { - if (!config.tailwindConfig.corePlugins.borderColor) { - return []; - } - classes = classes.concat( - convertColorDeclarationValue({ - declValue: color, - valuesMap: config.mapping.borderColor, - classPrefix, - cssDataType: "color", - }) - ); - } - - return classes; -} - -function parseComposedSpacingValue(value: string) { - const values = value.split(/\s+/m); - - if (values.length > 4) { - return { top: null, right: null, bottom: null, left: null }; - } - - return { - top: values[0], - right: values[1] || values[0], - bottom: values[2] || values[0], - left: values[3] || values[1] || values[0], - }; -} - -export function convertComposedSpacingDeclarationValue( - value: string, - mapping: { - top: { valuesMapping: Record; classPrefix: string }; - right: { valuesMapping: Record; classPrefix: string }; - bottom: { valuesMapping: Record; classPrefix: string }; - left: { valuesMapping: Record; classPrefix: string }; - }, - remInPx: number | null | undefined -) { - const parsed = parseComposedSpacingValue(value); - let classes: string[] = []; - - for (const [key, value] of Object.entries(parsed) as [ - "top" | "right" | "bottom" | "left", - any, - ][]) { - const { valuesMapping, classPrefix } = mapping[key] || {}; - - if (value && valuesMapping && classPrefix) { - classes = classes.concat( - convertSizeDeclarationValue({ - declValue: value, - valuesMap: valuesMapping, - classPrefix, - remInPx, - supportsNegativeValues: true, - }) - ); - } - } - - return classes; -} - -interface DeclarationConvertersMapping { - [property: string]: ( - declaration: Declaration, - config: ResolvedTailwindConverterConfig - ) => string[]; -} - -export const DECLARATION_CONVERTERS_MAPPING: DeclarationConvertersMapping = { - "accent-color": (declaration, config) => - config.tailwindConfig.corePlugins.accentColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.accentColor, - classPrefix: "accent", - cssDataType: "color", - }) - : [], - - "align-content": (declaration, config) => - config.tailwindConfig.corePlugins.alignContent - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["align-content"] - ) - : [], - - "align-items": (declaration, config) => - config.tailwindConfig.corePlugins.alignItems - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["align-items"]) - : [], - - "align-self": (declaration, config) => - config.tailwindConfig.corePlugins.alignSelf - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["align-self"]) - : [], - - animation: (declaration, config) => - config.tailwindConfig.corePlugins.animation - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.animation, - classPrefix: "animate", - }) - : [], - - appearance: (declaration, config) => - config.tailwindConfig.corePlugins.appearance - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["appearance"]) - : [], - - "aspect-ratio": (declaration, config) => - config.tailwindConfig.corePlugins.aspectRatio - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.aspectRatio, - classPrefix: "aspect", - }) - : [], - - "backdrop-filter": (declaration, config) => { - if (!config.tailwindConfig.corePlugins.backdropFilter) { - return []; - } - - let classes: string[] = []; - const mappings: Record = { - blur: config.tailwindConfig.corePlugins.backdropBlur && config.mapping.backdropBlur, - brightness: - config.tailwindConfig.corePlugins.backdropBrightness && - config.mapping.backdropBrightness, - contrast: - config.tailwindConfig.corePlugins.backdropContrast && - config.mapping.backdropContrast, - grayscale: - config.tailwindConfig.corePlugins.backdropGrayscale && - config.mapping.backdropGrayscale, - "hue-rotate": - config.tailwindConfig.corePlugins.backdropHueRotate && - config.mapping.backdropHueRotate, - invert: - config.tailwindConfig.corePlugins.backdropInvert && config.mapping.backdropInvert, - opacity: - config.tailwindConfig.corePlugins.backdropOpacity && - config.mapping.backdropOpacity, - saturate: - config.tailwindConfig.corePlugins.backdropSaturate && - config.mapping.backdropSaturate, - sepia: - config.tailwindConfig.corePlugins.backdropSepia && config.mapping.backdropSepia, - }; - - parseCSSFunctions(declaration.value).every(({ name, value }) => { - if (name == null || value == null) { - classes = []; - return false; - } - - const mapping = mappings[name]; - - if (mapping) { - delete mappings[name]; - - const currentClasses = convertSizeDeclarationValue({ - declValue: value, - valuesMap: mapping, - classPrefix: `backdrop-${name}`, - remInPx: config.remInPx, - supportsNegativeValues: name === "hue-rotate", - }); - - if (currentClasses?.length) { - classes = classes.concat(currentClasses); - return true; - } - } - - classes = []; - return false; - }); - - return classes; - }, - - "background-attachment": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundAttachment - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["background-attachment"] - ) - : [], - - "background-blend-mode": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundBlendMode - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["background-blend-mode"] - ) - : [], - - "background-clip": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundClip - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["background-clip"] - ) - : [], - - "background-color": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.backgroundColor, - classPrefix: "bg", - cssDataType: "color", - }) - : [], - - "background-image": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundImage - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.backgroundImage, - classPrefix: "bg", - fallbackValue: declaration.value, - fallbackClassPrefix: "bg", - cssDataType: "image", - }) - : [], - - "background-origin": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundOrigin - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["background-origin"] - ) - : [], - - "background-position": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundPosition - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.backgroundPosition, - classPrefix: "bg", - fallbackValue: declaration.value, - fallbackClassPrefix: "bg", - cssDataType: "position", - }) - : [], - - "background-repeat": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundRepeat - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["background-repeat"] - ) - : [], - - "background-size": (declaration, config) => - config.tailwindConfig.corePlugins.backgroundSize - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.backgroundSize, - classPrefix: "bg", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - border: (declaration, config) => - convertBorderDeclarationValue({ - value: declaration.value, - config, - classPrefix: "border", - }), - - "border-bottom": (declaration, config) => - convertBorderDeclarationValue({ - value: declaration.value, - config, - classPrefix: "border-b", - }), - - "border-bottom-color": (declaration, config) => - config.tailwindConfig.corePlugins.borderColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderColor, - classPrefix: "border-b", - cssDataType: "color", - }) - : [], - - "border-bottom-left-radius": (declaration, config) => - config.tailwindConfig.corePlugins.borderRadius - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderRadius, - classPrefix: "rounded-bl", - remInPx: config.remInPx, - }) - : [], - - "border-bottom-right-radius": (declaration, config) => - config.tailwindConfig.corePlugins.borderRadius - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderRadius, - classPrefix: "rounded-br", - remInPx: config.remInPx, - }) - : [], - - // 'border-bottom-style': (declaration, config) => - // strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING['border-style']), - - "border-bottom-width": (declaration, config) => - config.tailwindConfig.corePlugins.borderWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderWidth, - classPrefix: "border-b", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "border-collapse": (declaration, config) => - config.tailwindConfig.corePlugins.borderCollapse - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["border-collapse"] - ) - : [], - - "border-color": (declaration, config) => - config.tailwindConfig.corePlugins.borderColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderColor, - classPrefix: "border", - cssDataType: "color", - }) - : [], - - "border-left": (declaration, config) => - convertBorderDeclarationValue({ - value: declaration.value, - config, - classPrefix: "border-l", - }), - - "border-left-color": (declaration, config) => - config.tailwindConfig.corePlugins.borderColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderColor, - classPrefix: "border-l", - cssDataType: "color", - }) - : [], - - // 'border-left-style': (declaration, config) => - // strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING['border-style']), - - "border-left-width": (declaration, config) => - config.tailwindConfig.corePlugins.borderWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderWidth, - classPrefix: "border-l", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "border-radius": (declaration, config) => - config.tailwindConfig.corePlugins.borderRadius - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderRadius, - classPrefix: "rounded", - remInPx: config.remInPx, - }) - : [], - - "border-right": (declaration, config) => - convertBorderDeclarationValue({ - value: declaration.value, - config, - classPrefix: "border-r", - }), - - "border-right-color": (declaration, config) => - config.tailwindConfig.corePlugins.borderColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderColor, - classPrefix: "border-r", - cssDataType: "color", - }) - : [], - - // 'border-right-style': (declaration, config) => - // strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING['border-style']), - - "border-right-width": (declaration, config) => - config.tailwindConfig.corePlugins.borderWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderWidth, - classPrefix: "border-r", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "border-spacing": (declaration, config) => - config.tailwindConfig.corePlugins.borderSpacing - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderSpacing, - classPrefix: "border-spacing", - remInPx: config.remInPx, - }) - : [], - - "border-style": (declaration, config) => - config.tailwindConfig.corePlugins.borderStyle - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["border-style"] - ) - : [], - - "border-top": (declaration, config) => - convertBorderDeclarationValue({ - value: declaration.value, - config, - classPrefix: "border-t", - }), - - "border-top-color": (declaration, config) => - config.tailwindConfig.corePlugins.borderColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderColor, - classPrefix: "border-t", - cssDataType: "color", - }) - : [], - - "border-top-left-radius": (declaration, config) => - config.tailwindConfig.corePlugins.borderRadius - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderRadius, - classPrefix: "rounded-tl", - remInPx: config.remInPx, - }) - : [], - - "border-top-right-radius": (declaration, config) => - config.tailwindConfig.corePlugins.borderRadius - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderRadius, - classPrefix: "rounded-tr", - remInPx: config.remInPx, - }) - : [], - - // 'border-top-style': (declaration, config) => - // strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING['border-style']), - - "border-top-width": (declaration, config) => - config.tailwindConfig.corePlugins.borderWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderWidth, - classPrefix: "border-t", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "border-width": (declaration, config) => - config.tailwindConfig.corePlugins.borderWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.borderWidth, - classPrefix: "border", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - bottom: (declaration, config) => - config.tailwindConfig.corePlugins.position - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.inset, - classPrefix: "bottom", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "box-decoration-break": (declaration, config) => - config.tailwindConfig.corePlugins.position - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["box-decoration-break"] - ) - : [], - - "box-shadow": (declaration, config) => - config.tailwindConfig.corePlugins.boxShadow - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.boxShadow, - classPrefix: "shadow", - }) - : [], - - "box-sizing": (declaration, config) => - config.tailwindConfig.corePlugins.boxSizing - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["box-sizing"]) - : [], - - "break-after": (declaration, config) => - config.tailwindConfig.corePlugins.breakAfter - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["break-after"]) - : [], - - "break-before": (declaration, config) => - config.tailwindConfig.corePlugins.breakBefore - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["break-before"] - ) - : [], - - "break-inside": (declaration, config) => - config.tailwindConfig.corePlugins.breakInside - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["break-inside"] - ) - : [], - - "caret-color": (declaration, config) => - config.tailwindConfig.corePlugins.caretColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.caretColor, - classPrefix: "caret", - cssDataType: "color", - }) - : [], - - clear: (declaration, config) => - config.tailwindConfig.corePlugins.clear - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["clear"]) - : [], - - color: (declaration, config) => - config.tailwindConfig.corePlugins.textColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.textColor, - classPrefix: "text", - cssDataType: "color", - }) - : [], - - "column-gap": (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap-x", - remInPx: config.remInPx, - }) - : [], - - columns: (declaration, config) => - config.tailwindConfig.corePlugins.columns - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.columns, - classPrefix: "columns", - remInPx: config.remInPx, - }) - : [], - - content: (declaration, config) => - config.tailwindConfig.corePlugins.content - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.content, - classPrefix: "content", - }) - : [], - - cursor: (declaration, config) => - config.tailwindConfig.corePlugins.cursor - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.cursor, - classPrefix: "cursor", - }) - : [], - - display: (declaration, config) => - config.tailwindConfig.corePlugins.display - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["display"]) - : [], - - fill: (declaration, config) => - config.tailwindConfig.corePlugins.fill - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.fill, - classPrefix: "fill", - }) - : [], - - filter: (declaration, config) => { - if (!config.tailwindConfig.corePlugins.filter) { - return []; - } - - let classes: string[] = []; - const mappings: Record = { - blur: config.tailwindConfig.corePlugins.blur && config.mapping.blur, - brightness: - config.tailwindConfig.corePlugins.brightness && config.mapping.brightness, - contrast: config.tailwindConfig.corePlugins.contrast && config.mapping.contrast, - grayscale: config.tailwindConfig.corePlugins.grayscale && config.mapping.grayscale, - "hue-rotate": - config.tailwindConfig.corePlugins.hueRotate && config.mapping.hueRotate, - invert: config.tailwindConfig.corePlugins.invert && config.mapping.invert, - opacity: config.tailwindConfig.corePlugins.opacity && config.mapping.opacity, - saturate: config.tailwindConfig.corePlugins.saturate && config.mapping.saturate, - sepia: config.tailwindConfig.corePlugins.sepia && config.mapping.sepia, - // 'drop-shadow': config.tailwindConfig.corePlugins.dropShadow && config.mapping.dropShadow, - }; - - parseCSSFunctions(declaration.value).every(({ name, value }) => { - if (name == null || value == null) { - classes = []; - return false; - } - - const mapping = mappings[name]; - - if (mapping) { - delete mapping[name]; - - const currentClasses = convertSizeDeclarationValue({ - declValue: value, - valuesMap: mapping, - classPrefix: name, - remInPx: config.remInPx, - supportsNegativeValues: name === "hue-rotate", - }); - - if (currentClasses?.length) { - classes = classes.concat(currentClasses); - return true; - } - } - - classes = []; - return false; - }); - - return classes; - }, - - flex: (declaration, config) => { - if (!config.tailwindConfig.corePlugins.flex) { - return []; - } - - const classes = convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.flex, - classPrefix: "flex", - fallbackValue: "", - }); - - if (classes.length) { - return classes; - } - - const [flexGrow, flexShrink = "1", flexBasis = "0%"] = declaration.value - .trim() - .split(/\s+/m); - - return convertDeclarationValue({ - value: `${flexGrow} ${flexShrink} ${flexBasis}`, - valuesMap: config.mapping.flex, - classPrefix: "flex", - fallbackValue: declaration.value, - }); - }, - - "flex-basis": (declaration, config) => - config.tailwindConfig.corePlugins.flexBasis - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.flexBasis, - classPrefix: "basis", - remInPx: config.remInPx, - }) - : [], - - "flex-direction": (declaration, config) => - config.tailwindConfig.corePlugins.flexDirection - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["flex-direction"] - ) - : [], - - "flex-grow": (declaration, config) => - config.tailwindConfig.corePlugins.flexGrow - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.flexGrow, - classPrefix: "grow", - }) - : [], - - "flex-shrink": (declaration, config) => - config.tailwindConfig.corePlugins.flexShrink - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.flexShrink, - classPrefix: "shrink", - }) - : [], - - "flex-wrap": (declaration, config) => - config.tailwindConfig.corePlugins.flexWrap - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["flex-wrap"]) - : [], - - float: (declaration, config) => - config.tailwindConfig.corePlugins.float - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["float"]) - : [], - - "font-size": (declaration, config) => - config.tailwindConfig.corePlugins.fontSize - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.fontSize, - classPrefix: "text", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "font-smoothing": (declaration, config) => - config.tailwindConfig.corePlugins.fontSmoothing - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["font-smoothing"] - ) - : [], - - "font-style": (declaration, config) => - config.tailwindConfig.corePlugins.fontStyle - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["font-style"]) - : [], - - "font-variant-numeric": (declaration, config) => - config.tailwindConfig.corePlugins.fontVariantNumeric - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["font-variant-numeric"] - ) - : [], - - "font-weight": (declaration, config) => - config.tailwindConfig.corePlugins.fontWeight - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.fontWeight, - classPrefix: "font", - fallbackValue: declaration.value, - fallbackClassPrefix: "font", - cssDataType: "number", - }) - : [], - - gap: (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap", - remInPx: config.remInPx, - }) - : [], - - "grid-auto-columns": (declaration, config) => - config.tailwindConfig.corePlugins.gridAutoColumns - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridAutoColumns, - classPrefix: "auto-cols", - }) - : [], - - "grid-auto-flow": (declaration, config) => - config.tailwindConfig.corePlugins.gridAutoFlow - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["grid-auto-flow"] - ) - : [], - - "grid-auto-rows": (declaration, config) => - config.tailwindConfig.corePlugins.gridAutoRows - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridAutoRows, - classPrefix: "auto-rows", - }) - : [], - - "grid-column": (declaration, config) => - config.tailwindConfig.corePlugins.gridColumn - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridColumn, - classPrefix: "col", - }) - : [], - - "grid-column-end": (declaration, config) => - config.tailwindConfig.corePlugins.gridColumnEnd - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridColumnEnd, - classPrefix: "col-end", - }) - : [], - - "grid-column-gap": (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap-x", - remInPx: config.remInPx, - }) - : [], - - "grid-column-start": (declaration, config) => - config.tailwindConfig.corePlugins.gridColumnStart - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridColumnStart, - classPrefix: "col-start", - }) - : [], - - "grid-gap": (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap", - remInPx: config.remInPx, - }) - : [], - - "grid-row": (declaration, config) => - config.tailwindConfig.corePlugins.gridRow - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridRow, - classPrefix: "row", - }) - : [], - - "grid-row-end": (declaration, config) => - config.tailwindConfig.corePlugins.gridRowEnd - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridRowEnd, - classPrefix: "row-end", - }) - : [], - - "grid-row-gap": (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap-y", - remInPx: config.remInPx, - }) - : [], - - "grid-row-start": (declaration, config) => - config.tailwindConfig.corePlugins.gridRowStart - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridRowStart, - classPrefix: "row-start", - }) - : [], - - "grid-template-columns": (declaration, config) => - config.tailwindConfig.corePlugins.gridTemplateColumns - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridTemplateColumns, - classPrefix: "grid-cols", - }) - : [], - - "grid-template-rows": (declaration, config) => - config.tailwindConfig.corePlugins.gridTemplateRows - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.gridTemplateRows, - classPrefix: "grid-rows", - }) - : [], - - height: (declaration, config) => - config.tailwindConfig.corePlugins.height - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.height, - classPrefix: "h", - remInPx: config.remInPx, - }) - : [], - - inset: (declaration, config) => - config.tailwindConfig.corePlugins.inset - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.inset, - classPrefix: "inset", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - isolation: (declaration, config) => - config.tailwindConfig.corePlugins.isolation - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["isolation"]) - : [], - - "justify-content": (declaration, config) => - config.tailwindConfig.corePlugins.justifyContent - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["justify-content"] - ) - : [], - - "justify-items": (declaration, config) => - config.tailwindConfig.corePlugins.justifyItems - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["justify-items"] - ) - : [], - - "justify-self": (declaration, config) => - config.tailwindConfig.corePlugins.justifySelf - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["justify-self"] - ) - : [], - - left: (declaration, config) => - config.tailwindConfig.corePlugins.position - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.inset, - classPrefix: "left", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "letter-spacing": (declaration, config) => - config.tailwindConfig.corePlugins.letterSpacing - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.letterSpacing, - classPrefix: "tracking", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "line-height": (declaration, config) => - config.tailwindConfig.corePlugins.lineHeight - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.lineHeight, - classPrefix: "leading", - remInPx: config.remInPx, - }) - : [], - - "list-style-position": (declaration, config) => - config.tailwindConfig.corePlugins.listStylePosition - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["list-style-position"] - ) - : [], - - "list-style-type": (declaration, config) => - config.tailwindConfig.corePlugins.listStyleType - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.listStyleType, - classPrefix: "list", - }) - : [], - - margin: (declaration, config) => - config.tailwindConfig.corePlugins.margin - ? convertComposedSpacingDeclarationValue( - declaration.value, - { - top: { valuesMapping: config.mapping.margin, classPrefix: "mt" }, - right: { valuesMapping: config.mapping.margin, classPrefix: "mr" }, - bottom: { valuesMapping: config.mapping.margin, classPrefix: "mb" }, - left: { valuesMapping: config.mapping.margin, classPrefix: "ml" }, - }, - config.remInPx - ) - : [], - - "margin-bottom": (declaration, config) => - config.tailwindConfig.corePlugins.margin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.margin, - classPrefix: "mb", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "margin-left": (declaration, config) => - config.tailwindConfig.corePlugins.margin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.margin, - classPrefix: "ml", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "margin-right": (declaration, config) => - config.tailwindConfig.corePlugins.margin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.margin, - classPrefix: "mr", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "margin-top": (declaration, config) => - config.tailwindConfig.corePlugins.margin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.margin, - classPrefix: "mt", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "max-height": (declaration, config) => - config.tailwindConfig.corePlugins.maxHeight - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.maxHeight, - classPrefix: "max-h", - remInPx: config.remInPx, - }) - : [], - - "max-width": (declaration, config) => - config.tailwindConfig.corePlugins.maxWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.maxWidth, - classPrefix: "max-w", - remInPx: config.remInPx, - }) - : [], - - "min-height": (declaration, config) => - config.tailwindConfig.corePlugins.minHeight - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.minHeight, - classPrefix: "min-h", - remInPx: config.remInPx, - }) - : [], - - "min-width": (declaration, config) => - config.tailwindConfig.corePlugins.minWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.minWidth, - classPrefix: "min-w", - remInPx: config.remInPx, - }) - : [], - - "mix-blend-mode": (declaration, config) => - config.tailwindConfig.corePlugins.mixBlendMode - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["mix-blend-mode"] - ) - : [], - - "object-fit": (declaration, config) => - config.tailwindConfig.corePlugins.objectFit - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["object-fit"]) - : [], - - "object-position": (declaration, config) => - config.tailwindConfig.corePlugins.objectPosition - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.objectPosition, - classPrefix: "object", - }) - : [], - - opacity: (declaration, config) => - config.tailwindConfig.corePlugins.opacity - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.opacity, - classPrefix: "opacity", - }) - : [], - - order: (declaration, config) => - config.tailwindConfig.corePlugins.order - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.order, - classPrefix: "order", - remInPx: null, - supportsNegativeValues: true, - }) - : [], - - outline: (declaration, config) => - config.tailwindConfig.corePlugins.outlineStyle - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["outline"]) - : [], - - "outline-color": (declaration, config) => - config.tailwindConfig.corePlugins.outlineColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.outlineColor, - classPrefix: "outline", - cssDataType: "color", - }) - : [], - - "outline-offset": (declaration, config) => - config.tailwindConfig.corePlugins.outlineOffset - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.outlineOffset, - classPrefix: "outline-offset", - remInPx: config.remInPx, - supportsNegativeValues: true, - cssDataType: "length", - }) - : [], - - "outline-style": (declaration, config) => - config.tailwindConfig.corePlugins.outlineStyle - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["outline-style"] - ) - : [], - - "outline-width": (declaration, config) => - config.tailwindConfig.corePlugins.outlineWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.outlineWidth, - classPrefix: "outline", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - overflow: (declaration, config) => - config.tailwindConfig.corePlugins.overflow - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["overflow"]) - : [], - - "overflow-wrap": (declaration, config) => - config.tailwindConfig.corePlugins.wordBreak - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["overflow-wrap"] - ) - : [], - - "overflow-x": (declaration, config) => - config.tailwindConfig.corePlugins.overflow - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["overflow-x"]) - : [], - - "overflow-y": (declaration, config) => - config.tailwindConfig.corePlugins.overflow - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["overflow-y"]) - : [], - - "overscroll-behavior": (declaration, config) => - config.tailwindConfig.corePlugins.overscrollBehavior - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["overscroll-behavior"] - ) - : [], - "overscroll-behavior-x": (declaration, config) => - config.tailwindConfig.corePlugins.overscrollBehavior - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["overscroll-behavior-x"] - ) - : [], - "overscroll-behavior-y": (declaration, config) => - config.tailwindConfig.corePlugins.overscrollBehavior - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["overscroll-behavior-y"] - ) - : [], - - padding: (declaration, config) => - config.tailwindConfig.corePlugins.padding - ? convertComposedSpacingDeclarationValue( - declaration.value, - { - top: { valuesMapping: config.mapping.padding, classPrefix: "pt" }, - right: { valuesMapping: config.mapping.padding, classPrefix: "pr" }, - bottom: { - valuesMapping: config.mapping.padding, - classPrefix: "pb", - }, - left: { valuesMapping: config.mapping.padding, classPrefix: "pl" }, - }, - config.remInPx - ) - : [], - - "padding-bottom": (declaration, config) => - config.tailwindConfig.corePlugins.padding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.padding, - classPrefix: "pb", - remInPx: config.remInPx, - }) - : [], - - "padding-left": (declaration, config) => - config.tailwindConfig.corePlugins.padding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.padding, - classPrefix: "pl", - remInPx: config.remInPx, - }) - : [], - - "padding-right": (declaration, config) => - config.tailwindConfig.corePlugins.padding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.padding, - classPrefix: "pr", - remInPx: config.remInPx, - }) - : [], - - "padding-top": (declaration, config) => - config.tailwindConfig.corePlugins.padding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.padding, - classPrefix: "pt", - remInPx: config.remInPx, - }) - : [], - - "page-break-after": (declaration, config) => - config.tailwindConfig.corePlugins.breakAfter - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["break-after"]) - : [], - - "page-break-before": (declaration, config) => - config.tailwindConfig.corePlugins.breakBefore - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["break-before"] - ) - : [], - - "page-break-inside": (declaration, config) => - config.tailwindConfig.corePlugins.breakInside - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["break-inside"] - ) - : [], - - "place-content": (declaration, config) => - config.tailwindConfig.corePlugins.placeContent - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["place-content"] - ) - : [], - - "place-items": (declaration, config) => - config.tailwindConfig.corePlugins.placeItems - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["place-items"]) - : [], - - "place-self": (declaration, config) => - config.tailwindConfig.corePlugins.placeSelf - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["place-self"]) - : [], - - "pointer-events": (declaration, config) => - config.tailwindConfig.corePlugins.pointerEvents - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["pointer-events"] - ) - : [], - - position: (declaration, config) => - config.tailwindConfig.corePlugins.position - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["position"]) - : [], - - resize: (declaration, config) => - config.tailwindConfig.corePlugins.resize - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["resize"]) - : [], - - right: (declaration, config) => - config.tailwindConfig.corePlugins.position - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.inset, - classPrefix: "right", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "row-gap": (declaration, config) => - config.tailwindConfig.corePlugins.gap - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.gap, - classPrefix: "gap-y", - remInPx: config.remInPx, - }) - : [], - - "scroll-behavior": (declaration, config) => - config.tailwindConfig.corePlugins.scrollBehavior - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["scroll-behavior"] - ) - : [], - - "scroll-margin": (declaration, config) => - config.tailwindConfig.corePlugins.scrollMargin - ? convertComposedSpacingDeclarationValue( - declaration.value, - { - top: { - valuesMapping: config.mapping.scrollMargin, - classPrefix: "scroll-mt", - }, - right: { - valuesMapping: config.mapping.scrollMargin, - classPrefix: "scroll-mr", - }, - bottom: { - valuesMapping: config.mapping.scrollMargin, - classPrefix: "scroll-mb", - }, - left: { - valuesMapping: config.mapping.scrollMargin, - classPrefix: "scroll-ml", - }, - }, - config.remInPx - ) - : [], - - "scroll-margin-bottom": (declaration, config) => - config.tailwindConfig.corePlugins.scrollMargin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollMargin, - classPrefix: "scroll-mb", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "scroll-margin-left": (declaration, config) => - config.tailwindConfig.corePlugins.scrollMargin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollMargin, - classPrefix: "scroll-ml", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "scroll-margin-right": (declaration, config) => - config.tailwindConfig.corePlugins.scrollMargin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollMargin, - classPrefix: "scroll-mr", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "scroll-margin-top": (declaration, config) => - config.tailwindConfig.corePlugins.scrollMargin - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollMargin, - classPrefix: "scroll-mt", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "scroll-padding": (declaration, config) => - config.tailwindConfig.corePlugins.scrollPadding - ? convertComposedSpacingDeclarationValue( - declaration.value, - { - top: { - valuesMapping: config.mapping.scrollPadding, - classPrefix: "scroll-pt", - }, - right: { - valuesMapping: config.mapping.scrollPadding, - classPrefix: "scroll-pr", - }, - bottom: { - valuesMapping: config.mapping.scrollPadding, - classPrefix: "scroll-pb", - }, - left: { - valuesMapping: config.mapping.scrollPadding, - classPrefix: "scroll-pl", - }, - }, - config.remInPx - ) - : [], - - "scroll-padding-bottom": (declaration, config) => - config.tailwindConfig.corePlugins.scrollPadding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollPadding, - classPrefix: "scroll-pb", - remInPx: config.remInPx, - }) - : [], - - "scroll-padding-left": (declaration, config) => - config.tailwindConfig.corePlugins.scrollPadding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollPadding, - classPrefix: "scroll-pl", - remInPx: config.remInPx, - }) - : [], - - "scroll-padding-right": (declaration, config) => - config.tailwindConfig.corePlugins.scrollPadding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollPadding, - classPrefix: "scroll-pr", - remInPx: config.remInPx, - }) - : [], - - "scroll-padding-top": (declaration, config) => - config.tailwindConfig.corePlugins.scrollPadding - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.scrollPadding, - classPrefix: "scroll-pt", - remInPx: config.remInPx, - }) - : [], - - "scroll-snap-align": (declaration, config) => - config.tailwindConfig.corePlugins.scrollSnapAlign - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["scroll-snap-align"] - ) - : [], - - "scroll-snap-type": (declaration, config) => - config.tailwindConfig.corePlugins.scrollSnapType - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["scroll-snap-type"] - ) - : [], - - "scroll-snap-stop": (declaration, config) => - config.tailwindConfig.corePlugins.scrollSnapStop - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["scroll-snap-stop"] - ) - : [], - - stroke: (declaration, config) => - config.tailwindConfig.corePlugins.stroke - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.stroke, - classPrefix: "stroke", - cssDataType: "color", - }) - : [], - - "stroke-width": (declaration, config) => - config.tailwindConfig.corePlugins.strokeWidth - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.strokeWidth, - classPrefix: "stroke", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "table-layout": (declaration, config) => - config.tailwindConfig.corePlugins.tableLayout - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["table-layout"] - ) - : [], - - "text-align": (declaration, config) => - config.tailwindConfig.corePlugins.textAlign - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["text-align"]) - : [], - - "text-decoration": (declaration, config) => { - if (!config.tailwindConfig.corePlugins.textDecoration) { - return []; - } - - const parsed = declaration.value.trim().split(/\s+/m); - return parsed.length === 1 - ? strictConvertDeclarationValue( - parsed[0], - UTILITIES_MAPPING["text-decoration-line"] - ) - : []; - }, - - "text-decoration-color": (declaration, config) => - config.tailwindConfig.corePlugins.textDecorationColor - ? convertColorDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.textDecorationColor, - classPrefix: "decoration", - cssDataType: "color", - }) - : [], - - "text-decoration-line": (declaration, config) => - config.tailwindConfig.corePlugins.textDecoration - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["text-decoration-line"] - ) - : [], - - "text-decoration-style": (declaration, config) => - config.tailwindConfig.corePlugins.textDecorationStyle - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["text-decoration-style"] - ) - : [], - - "text-decoration-thickness": (declaration, config) => - config.tailwindConfig.corePlugins.textDecorationThickness - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.textDecorationThickness, - classPrefix: "decoration", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - "text-indent": (declaration, config) => - config.tailwindConfig.corePlugins.textIndent - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.textIndent, - classPrefix: "indent", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "text-overflow": (declaration, config) => - config.tailwindConfig.corePlugins.textOverflow - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["text-overflow"] - ) - : [], - - "text-transform": (declaration, config) => - config.tailwindConfig.corePlugins.textTransform - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["text-transform"] - ) - : [], - - "text-underline-offset": (declaration, config) => - config.tailwindConfig.corePlugins.textUnderlineOffset - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.textUnderlineOffset, - classPrefix: "underline-offset", - remInPx: config.remInPx, - supportsNegativeValues: false, - cssDataType: "length", - }) - : [], - - top: (declaration, config) => - config.tailwindConfig.corePlugins.position - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.inset, - classPrefix: "top", - remInPx: config.remInPx, - supportsNegativeValues: true, - }) - : [], - - "touch-action": (declaration, config) => - config.tailwindConfig.corePlugins.touchAction - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["touch-action"] - ) - : [], - - transform: (declaration, config) => { - if (!config.tailwindConfig.corePlugins.transform) { - return []; - } - - let classes: string[] = []; - - function convertTranslate( - value: string, - axis: "x" | "y" | "both" = "both" - ): string[] { - if (axis === "both") { - const splitted = split(value); - return splitted.length > 2 - ? [] - : [ - ...(splitted[0] ? convertTranslate(splitted[0], "x") : []), - ...(splitted[1] ? convertTranslate(splitted[1], "y") : []), - ]; - } - - return convertSizeDeclarationValue({ - declValue: value, - valuesMap: config.mapping.translate, - classPrefix: `translate-${axis}`, - remInPx: config.remInPx, - supportsNegativeValues: true, - }); - } - - function convertSkew(value: string, axis: "x" | "y" | "both" = "both"): string[] { - if (axis === "both") { - const splitted = split(value); - return splitted.length > 2 - ? [] - : [ - ...(splitted[0] ? convertSkew(splitted[0], "x") : []), - ...(splitted[1] ? convertSkew(splitted[1], "y") : []), - ]; - } - - return convertSizeDeclarationValue({ - declValue: value, - valuesMap: config.mapping.skew, - classPrefix: `skew-${axis}`, - remInPx: config.remInPx, - supportsNegativeValues: true, - }); - } - - function convertScale(value: string, axis: "x" | "y" | "both" = "both"): string[] { - if (axis === "both") { - const splitted = split(value); - - if (splitted.length > 2) { - return []; - } - - if (splitted[0]) { - return [ - ...convertScale(splitted[0], "x"), - ...convertScale(splitted[1] || splitted[0], "y"), - ]; - } - } - - return convertSizeDeclarationValue({ - declValue: value, - valuesMap: config.mapping.scale, - classPrefix: `scale-${axis}`, - remInPx: config.remInPx, - supportsNegativeValues: true, - }); - } - - parseCSSFunctions(declaration.value).every(({ name, value }) => { - if (name == null || value == null) { - classes = []; - return false; - } - - let converted: string[] = []; - - if (config.tailwindConfig.corePlugins.translate) { - if (name === "translate") { - converted = convertTranslate(value, "both"); - } else if (name === "translateX") { - converted = convertTranslate(value, "x"); - } else if (name === "translateY") { - converted = convertTranslate(value, "y"); - } - } - - if (config.tailwindConfig.corePlugins.skew) { - if (name === "skew") { - converted = convertSkew(value, "both"); - } else if (name === "skewX") { - converted = convertSkew(value, "x"); - } else if (name === "skewY") { - converted = convertSkew(value, "y"); - } - } - - if (config.tailwindConfig.corePlugins.scale) { - if (name === "scale") { - converted = convertScale(value, "both"); - } else if (name === "scaleX") { - converted = convertScale(value, "x"); - } else if (name === "scaleY") { - converted = convertScale(value, "y"); - } - } - - if (config.tailwindConfig.corePlugins.rotate && name === "rotate") { - converted = convertSizeDeclarationValue({ - declValue: value, - valuesMap: config.mapping.rotate, - classPrefix: "rotate", - remInPx: config.remInPx, - supportsNegativeValues: true, - }); - } - - if (converted.length) { - classes = classes.concat(converted); - return true; - } - - classes = []; - return false; - }); - - return classes; - }, - - "transform-origin": (declaration, config) => - config.tailwindConfig.corePlugins.transformOrigin - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.transformOrigin, - classPrefix: "origin", - }) - : [], - - transition: (declaration, config) => { - let classes: string[] = []; - let hasDelay = false; - - removeUnnecessarySpaces(declaration.value.trim()) - .split(/\s+/m) - .map(v => v.trim()) - .every((value, index) => { - let itemClasses: string[] = []; - - if (index === 0) { - itemClasses = config.tailwindConfig.corePlugins.transitionProperty - ? convertDeclarationValue({ - value, - valuesMap: config.mapping.transitionProperty, - classPrefix: "transition", - }) - : []; - } else if (index === 1) { - itemClasses = config.tailwindConfig.corePlugins.transitionDuration - ? convertDeclarationValue({ - value, - valuesMap: config.mapping.transitionDuration, - classPrefix: "duration", - }) - : []; - } else if (index === 2) { - const isTimingFunction = isNaN(parseFloat(value)); - - if (isTimingFunction) { - itemClasses = config.tailwindConfig.corePlugins.transitionTimingFunction - ? convertDeclarationValue({ - value, - valuesMap: config.mapping.transitionTimingFunction, - classPrefix: "ease", - }) - : []; - } else { - hasDelay = true; - itemClasses = config.tailwindConfig.corePlugins.transitionDelay - ? convertDeclarationValue({ - value, - valuesMap: config.mapping.transitionDelay, - classPrefix: "delay", - }) - : []; - } - } else if (index === 3) { - itemClasses = - config.tailwindConfig.corePlugins.transitionDelay && !hasDelay - ? convertDeclarationValue({ - value, - valuesMap: config.mapping.transitionDelay, - classPrefix: "delay", - }) - : []; - - hasDelay = true; - } - - if (!itemClasses.length) { - classes = []; - return false; - } - - classes = classes.concat(itemClasses); - return true; - }); - - return classes; - }, - - "transition-delay": (declaration, config) => - config.tailwindConfig.corePlugins.transitionDelay - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.transitionDelay, - classPrefix: "delay", - }) - : [], - - "transition-duration": (declaration, config) => - config.tailwindConfig.corePlugins.transitionDuration - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.transitionDuration, - classPrefix: "duration", - }) - : [], - - "transition-property": (declaration, config) => - config.tailwindConfig.corePlugins.transitionProperty - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.transitionProperty, - classPrefix: "transition", - }) - : [], - - "transition-timing-function": (declaration, config) => - config.tailwindConfig.corePlugins.transitionTimingFunction - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.transitionTimingFunction, - classPrefix: "ease", - }) - : [], - - "user-select": (declaration, config) => - config.tailwindConfig.corePlugins.userSelect - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["user-select"]) - : [], - - "vertical-align": (declaration, config) => - config.tailwindConfig.corePlugins.verticalAlign - ? strictConvertDeclarationValue( - declaration.value, - UTILITIES_MAPPING["vertical-align"] - ) - : [], - - visibility: (declaration, config) => - config.tailwindConfig.corePlugins.visibility - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["visibility"]) - : [], - - "white-space": (declaration, config) => - config.tailwindConfig.corePlugins.whitespace - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["white-space"]) - : [], - - width: (declaration, config) => - config.tailwindConfig.corePlugins.width - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.width, - classPrefix: "w", - remInPx: config.remInPx, - }) - : [], - - "will-change": (declaration, config) => - config.tailwindConfig.corePlugins.willChange - ? convertDeclarationValue({ - value: declaration.value, - valuesMap: config.mapping.willChange, - classPrefix: "will-change", - }) - : [], - - "word-break": (declaration, config) => - config.tailwindConfig.corePlugins.wordBreak - ? strictConvertDeclarationValue(declaration.value, UTILITIES_MAPPING["word-break"]) - : [], - - "z-index": (declaration, config) => - config.tailwindConfig.corePlugins.zIndex - ? convertSizeDeclarationValue({ - declValue: declaration.value, - valuesMap: config.mapping.zIndex, - classPrefix: "z", - remInPx: null, - supportsNegativeValues: true, - }) - : [], -}; - -function split(value: string) { - return value.split(/\s*,\s*/m).map(v => v.trim()); -} diff --git a/src/converts/mappings/media-params-mapping.json b/src/converts/mappings/media-params-mapping.json deleted file mode 100644 index b9b3331..0000000 --- a/src/converts/mappings/media-params-mapping.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "print": "print", - "orientation:portrait": "portrait", - "orientation:landscape": "landscape", - "prefers-contrast:more": "contrast-more", - "prefers-contrast:less": "contrast-less", - "prefers-color-scheme:dark": "dark", - "prefers-reduced-motion:no-preference": "motion-safe", - "prefers-reduced-motion:reduce": "motion-reduce" -} diff --git a/src/converts/mappings/pseudos-mapping.json b/src/converts/mappings/pseudos-mapping.json deleted file mode 100644 index 3509318..0000000 --- a/src/converts/mappings/pseudos-mapping.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "hover": "hover", - "focus": "focus", - "focus-within": "focus-within", - "focus-visible": "focus-visible", - "active": "active", - "visited": "visited", - "target": "target", - "first-child": "first", - "last-child": "last", - "only-child": "only", - "nth-child(odd)": "odd", - "nth-child(2n+1)": "odd", - "nth-child(even)": "even", - "nth-child(2n)": "even", - "first-of-type": "first-of-type", - "last-of-type": "last-of-type", - "only-of-type": "only-of-type", - "empty": "empty", - "disabled": "disabled", - "enabled": "enabled", - "checked": "checked", - "indeterminate": "indeterminate", - "default": "default", - "required": "required", - "valid": "valid", - "invalid": "invalid", - "in-range": "in-range", - "out-of-range": "out-of-range", - "autofill": "autofill", - "read-only": "read-only", - "before": "before", - "after": "after", - "first-letter": "first-letter", - "first-line": "first-line", - "marker": "marker", - "selection": "selection", - "file-selector-button": "file", - "backdrop": "backdrop" -} diff --git a/src/converts/mappings/utilities-mapping.json b/src/converts/mappings/utilities-mapping.json deleted file mode 100644 index f8de0f8..0000000 --- a/src/converts/mappings/utilities-mapping.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "alignContent": { - "center": "content-center", - "flex-start": "content-start", - "flex-end": "content-end", - "space-between": "content-between", - "space-around": "content-around", - "space-evenly": "content-evenly", - "baseline": "content-baseline" - }, - "alignItems": { - "flex-start": "items-start", - "flex-end": "items-end", - "center": "items-center", - "baseline": "items-baseline", - "stretch": "items-stretch" - }, - "alignSelf": { - "auto": "self-auto", - "flex-start": "self-start", - "flex-end": "self-end", - "center": "self-center", - "stretch": "self-stretch", - "baseline": "self-baseline" - }, - "appearance": { - "none": "appearance-none" - }, - "backgroundAttachment": { - "fixed": "bg-fixed", - "local": "bg-local", - "scroll": "bg-scroll" - }, - "backgroundBlendMode": { - "normal": "bg-blend-normal", - "multiply": "bg-blend-multiply", - "screen": "bg-blend-screen", - "overlay": "bg-blend-overlay", - "darken": "bg-blend-darken", - "lighten": "bg-blend-lighten", - "color-dodge": "bg-blend-color-dodge", - "color-burn": "bg-blend-color-burn", - "hard-light": "bg-blend-hard-light", - "soft-light": "bg-blend-soft-light", - "difference": "bg-blend-difference", - "exclusion": "bg-blend-exclusion", - "hue": "bg-blend-hue", - "saturation": "bg-blend-saturation", - "color": "bg-blend-color", - "luminosity": "bg-blend-luminosity" - }, - "backgroundClip": { - "border-box": "bg-clip-border", - "padding-box": "bg-clip-padding", - "content-box": "bg-clip-content", - "text": "bg-clip-text" - }, - "backgroundOrigin": { - "border-box": "bg-origin-border", - "padding-box": "bg-origin-padding", - "content-box": "bg-origin-content" - }, - "backgroundRepeat": { - "repeat": "bg-repeat", - "no-repeat": "bg-no-repeat", - "repeat-x": "bg-repeat-x", - "repeat-y": "bg-repeat-y", - "round": "bg-repeat-round", - "space": "bg-repeat-space" - }, - "borderStyle": { - "solid": "border-solid", - "dashed": "border-dashed", - "dotted": "border-dotted", - "double": "border-double", - "hidden": "border-hidden", - "none": "border-none" - }, - "borderCollapse": { - "collapse": "border-collapse", - "separate": "border-separate" - }, - "boxDecorationBreak": { - "slice": "box-decoration-slice", - "clone": "box-decoration-clone" - }, - "boxSizing": { - "border-box": "box-border", - "content-box": "box-content" - }, - "breakAfter": { - "auto": "break-after-auto", - "avoid": "break-after-avoid", - "all": "break-after-all", - "avoid-page": "break-after-avoid-page", - "page": "break-after-page", - "left": "break-after-left", - "right": "break-after-right", - "column": "break-after-column" - }, - "breakBefore": { - "auto": "break-before-auto", - "avoid": "break-before-avoid", - "all": "break-before-all", - "avoid-page": "break-before-avoid-page", - "page": "break-before-page", - "left": "break-before-left", - "right": "break-before-right", - "column": "break-before-column" - }, - "breakInside": { - "auto": "break-inside-auto", - "avoid": "break-inside-avoid", - "avoid-page": "break-inside-avoid-page", - "avoid-column": "break-inside-avoid-column" - }, - "clear": { - "left": "clear-left", - "right": "clear-right", - "both": "clear-both", - "none": "clear-none" - }, - "display": { - "block": "block", - "inline-block": "inline-block", - "inline": "inline", - "flex": "flex", - "inline-flex": "inline-flex", - "table": "table", - "inline-table": "inline-table", - "table-caption": "table-caption", - "table-cell": "table-cell", - "table-column": "table-column", - "table-column-group": "table-column-group", - "table-footer-group": "table-footer-group", - "table-header-group": "table-header-group", - "table-row-group": "table-row-group", - "table-row": "table-row", - "flow-root": "flow-root", - "grid": "grid", - "inline-grid": "inline-grid", - "contents": "contents", - "list-item": "list-item", - "none": "hidden" - }, - "flexDirection": { - "row": "flex-row", - "row-reverse": "flex-row-reverse", - "column": "flex-col", - "column-reverse": "flex-col-reverse" - }, - "flexWrap": { - "wrap": "flex-wrap", - "wrap-reverse": "flex-wrap-reverse", - "nowrap": "flex-nowrap" - }, - "float": { - "right": "float-right", - "left": "float-left", - "none": "float-none" - }, - "fontSmoothing": { - "antialiased": "antialiased", - "grayscale": "antialiased", - "auto": "subpixel-antialiased" - }, - "fontStyle": { - "italic": "italic", - "normal": "not-italic" - }, - "fontVariantNumeric": { - "normal": "normal-nums", - "ordinal": "ordinal", - "slashed-zero": "slashed-zero", - "lining-nums": "lining-nums", - "oldstyle-nums": "oldstyle-nums", - "proportional-nums": "proportional-nums", - "tabular-nums": "tabular-nums", - "diagonal-fractions": "diagonal-fractions", - "stacked-fractions": "stacked-fractions" - }, - "gridAutoFlow": { - "row": "grid-flow-row", - "column": "grid-flow-col", - "dense": "grid-flow-dense", - "row dense": "grid-flow-row-dense", - "column dense": "grid-flow-col-dense" - }, - "isolation": { - "isolate": "isolate", - "auto": "isolation-auto" - }, - "justifyContent": { - "flex-start": "justify-start", - "flex-end": "justify-end", - "center": "justify-center", - "space-between": "justify-between", - "space-around": "justify-around", - "space-evenly": "justify-evenly" - }, - "justifyItems": { - "flex-start": "justify-items-start", - "flex-end": "justify-items-end", - "start": "justify-items-start", - "end": "justify-items-end", - "center": "justify-items-center", - "stretch": "justify-items-stretch" - }, - "justifySelf": { - "auto": "justify-self-auto", - "flex-start": "justify-self-start", - "flex-end": "justify-self-end", - "start": "justify-self-start", - "end": "justify-self-end", - "center": "justify-self-center", - "stretch": "justify-self-stretch" - }, - "listStylePosition": { - "inside": "list-inside", - "outside": "list-outside" - }, - "mixBlendMode": { - "normal": "mix-blend-normal", - "multiply": "mix-blend-multiply", - "screen": "mix-blend-screen", - "overlay": "mix-blend-overlay", - "darken": "mix-blend-darken", - "lighten": "mix-blend-lighten", - "color-dodge": "mix-blend-color-dodge", - "color-burn": "mix-blend-color-burn", - "hard-light": "mix-blend-hard-light", - "soft-light": "mix-blend-soft-light", - "difference": "mix-blend-difference", - "exclusion": "mix-blend-exclusion", - "hue": "mix-blend-hue", - "saturation": "mix-blend-saturation", - "color": "mix-blend-color", - "luminosity": "mix-blend-luminosity", - "plus-lighter": "mix-blend-plus-lighter" - }, - "objectFit": { - "contain": "object-contain", - "cover": "object-cover", - "fill": "object-fill", - "none": "object-none", - "scale-down": "object-scale-down" - }, - "outlineStyle": { - "solid": "outline", - "dashed": "outline-dashed", - "dotted": "outline-dotted", - "double": "outline-double" - }, - "outline": { - "2px solid transparent": "outline-none" - }, - "overflow": { - "auto": "overflow-auto", - "hidden": "overflow-hidden", - "clip": "overflow-clip", - "visible": "overflow-visible", - "scroll": "overflow-scroll" - }, - "overflowWrap": { - "break-word": "break-words" - }, - "overflowX": { - "auto": "overflow-x-auto", - "hidden": "overflow-x-hidden", - "clip": "overflow-x-clip", - "visible": "overflow-x-visible", - "scroll": "overflow-x-scroll" - }, - "overflowY": { - "auto": "overflow-y-auto", - "hidden": "overflow-y-hidden", - "clip": "overflow-y-clip", - "visible": "overflow-y-visible", - "scroll": "overflow-y-scroll" - }, - "overscrollBehavior": { - "auto": "overscroll-auto", - "contain": "overscroll-contain", - "none": "overscroll-none" - }, - "overscrollBehaviorX": { - "auto": "overscroll-x-auto", - "contain": "overscroll-x-contain", - "none": "overscroll-x-none" - }, - "overscrollBehaviorY": { - "auto": "overscroll-y-auto", - "contain": "overscroll-y-contain", - "none": "overscroll-y-none" - }, - "placeContent": { - "center": "place-content-center", - "start": "place-content-start", - "end": "place-content-end", - "space-between": "place-content-between", - "space-around": "place-content-around", - "space-evenly": "place-content-evenly", - "baseline": "place-content-baseline", - "stretch": "place-content-stretch" - }, - "placeItems": { - "start": "place-items-start", - "end": "place-items-end", - "center": "place-items-center", - "baseline": "place-items-baseline", - "stretch": "place-items-stretch" - }, - "placeSelf": { - "auto": "place-self-auto", - "start": "place-self-start", - "end": "place-self-end", - "center": "place-self-center", - "stretch": "place-self-stretch" - }, - "pointerEvents": { - "none": "pointer-events-none", - "auto": "pointer-events-auto" - }, - "position": { - "static": "static", - "fixed": "fixed", - "absolute": "absolute", - "relative": "relative", - "sticky": "sticky" - }, - "resize": { - "none": "resize-none", - "vertical": "resize-y", - "horizontal": "resize-x", - "both": "resize" - }, - "scrollBehavior": { - "auto": "scroll-auto", - "smooth": "scroll-smooth" - }, - "scrollSnapAlign": { - "start": "snap-start", - "end": "snap-end", - "center": "snap-center", - "none": "snap-align-none" - }, - "scrollSnapType": { - "none": "snap-none", - "x var(--tw-scroll-snap-strictness)": "snap-x", - "x": "snap-x", - "y var(--tw-scroll-snap-strictness)": "snap-y", - "y": "snap-y", - "both var(--tw-scroll-snap-strictness)": "snap-both", - "both": "snap-both" - }, - "scrollSnapStop": { - "normal": "snap-normal", - "always": "snap-always" - }, - "tableLayout": { - "auto": "table-auto", - "fixed": "table-fixed" - }, - "textAlign": { - "left": "text-left", - "center": "text-center", - "right": "text-right", - "justify": "text-justify", - "start": "text-start", - "end": "text-end" - }, - "textDecorationLine": { - "underline": "underline", - "overline": "overline", - "line-through": "line-through", - "none": "no-underline" - }, - "textDecorationStyle": { - "solid": "decoration-solid", - "double": "decoration-double", - "dotted": "decoration-dotted", - "dashed": "decoration-dashed", - "wavy": "decoration-wavy" - }, - "textTransform": { - "uppercase": "uppercase", - "lowercase": "lowercase", - "capitalize": "capitalize", - "none": "normal-case" - }, - "textOverflow": { - "ellipsis": "text-ellipsis", - "clip": "text-clip" - }, - "touchAction": { - "auto": "touch-auto", - "none": "touch-none", - "pan-x": "touch-pan-x", - "pan-left": "touch-pan-left", - "pan-right": "touch-pan-right", - "pan-y": "touch-pan-y", - "pan-up": "touch-pan-up", - "pan-down": "touch-pan-down", - "pinch-zoom": "touch-pinch-zoom", - "manipulation": "touch-manipulation" - }, - "transform": { - "translateZ(0)": "transform-gpu", - "translate3d(0,0,0)": "transform-gpu", - "none": "transform-none" - }, - "userSelect": { - "none": "select-none", - "text": "select-text", - "all": "select-all", - "auto": "select-auto" - }, - "verticalAlign": { - "baseline": "align-baseline", - "top": "align-top", - "middle": "align-middle", - "bottom": "align-bottom", - "text-top": "align-text-top", - "text-bottom": "align-text-bottom", - "sub": "align-sub", - "super": "align-super" - }, - "visibility": { - "visible": "visible", - "hidden": "invisible", - "collapse": "collapse" - }, - "whitespace": { - "normal": "whitespace-normal", - "nowrap": "whitespace-nowrap", - "pre": "whitespace-pre", - "pre-line": "whitespace-pre-line", - "pre-wrap": "whitespace-pre-wrap" - }, - "wordBreak": { - "normal": "break-normal", - "break-all": "break-all", - "keep-all": "break-keep" - } -} diff --git a/src/converts/types.d.ts b/src/converts/types.d.ts deleted file mode 100644 index cb1f02c..0000000 --- a/src/converts/types.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { ThemeConfig } from "tailwindcss/types/config"; - -export type RemoveIndex = { - [P in keyof T as string extends P ? never : number extends P ? never : P]: T[P]; -}; - -export type KnownKeys = keyof RemoveIndex; - -export type SetPartialProps = Partial> & - Omit; - -export type SetRequiredProps = Required< - Pick -> & - Type; - -export type ConverterMappingKey = Exclude< - KnownKeys, - "keyframes" | "container" | "fontFamily" ->; - -export type ConverterMapping = Record> & - Record<"aria" | "data" | "supports", Record | undefined>; diff --git a/src/converts/utils.ts b/src/converts/utils.ts deleted file mode 100644 index bd0aec7..0000000 --- a/src/converts/utils.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { AtRule, ChildNode, Container, Node } from "postcss"; -import type { Screen } from "tailwindcss/types/config"; - -export function isCSSVariable(value: string) { - return /^var\((--.+?)\)$/.test(value.trim()); -} - -export function isAtRuleNode(node: Node | undefined): node is AtRule { - return !!(node?.type === "atrule"); -} - -export function isChildNode(node: Node | undefined): node is ChildNode { - return !!( - node && - (node.type === "atrule" || - node.type === "rule" || - node.type === "decl" || - node.type === "comment") - ); -} - -export function buildMediaQueryByScreen(screens: string | Screen | Screen[]) { - if (typeof screens === "string") { - return `(min-width: ${screens})`; - } - - screens = Array.isArray(screens) ? screens : [screens]; - - return screens - .map(screen => { - if ("raw" in screen && screen["raw"]) { - return screen["raw"]; - } - - const conditions: string[] = []; - if ("min" in screen && screen["min"]) { - conditions.push(`(min-width: ${screen["min"]})`); - } - - if ("max" in screen && screen["max"]) { - conditions.push(`(max-width: ${screen["max"]})`); - } - - if (conditions.length) { - return conditions.join(" and "); - } - - return null; - }) - .filter(Boolean) - .join(", "); -} - -export function detectIndent(root: Container) { - if (root.raws.indent) return root.raws.indent; - - let detectedIndent = " "; - root.walk(node => { - const p = node.parent; - if ( - p && - p !== root && - p.parent && - p.parent === root && - node.raws.before !== undefined - ) { - const parts = node.raws.before.split("\n"); - detectedIndent = parts.at(-1)!; - detectedIndent = detectedIndent.replace(/\S/g, ""); - return false; - } - }); - - return detectedIndent; -} - -export function flattenObject( - object: Record, - separator = "-" -) { - const flatObject: Record = {}; - - for (const [prop, value] of Object.entries(object)) { - if (typeof value === "object" && value !== null) { - const nestedFlatObject = flattenObject(value, separator); - - for (const [nestedProp, nestedValue] of Object.entries(nestedFlatObject)) { - flatObject[prop + separator + nestedProp] = nestedValue; - } - } else { - flatObject[prop] = value; - } - } - return flatObject; -} - -export function removeUnnecessarySpaces(string: string) { - return string.replace(/(\s+)?([,:;])(\s+)?/gm, "$2"); -} diff --git a/src/converts/utils/converterMappingByTailwindTheme.ts b/src/converts/utils/converterMappingByTailwindTheme.ts deleted file mode 100644 index 318d79f..0000000 --- a/src/converts/utils/converterMappingByTailwindTheme.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { colord } from "colord"; -import type { Config } from "tailwindcss"; -import type { - KeyValuePair, - RecursiveKeyValuePair, - ScreensConfig, -} from "tailwindcss/types/config"; -import type { ConverterMapping } from "../types"; -import { - buildMediaQueryByScreen, - flattenObject, - removeUnnecessarySpaces, -} from "../utils"; - -const remValueRegexp = /^(\d+)?\.?\d+rem$/; - -function remValueToPx(value: string, remInPx: number) { - if (remValueRegexp.test(value.trim())) { - const number = parseFloat(value); - - return isNaN(number) ? value : `${number * remInPx}px`; - } - - return value; -} - -function normalizeNumbersInString(string: string) { - return string.replace(/(^|[\s*+-/;])(\.\d+)/g, "$10$2"); -} - -export function normalizeValue(value: string) { - return removeUnnecessarySpaces(normalizeNumbersInString(value)); -} - -export function normalizeColorValue(colorValue: string) { - const parsed = colord(colorValue); - return parsed.isValid() ? parsed.toHex() : colorValue; -} - -export function normalizeZeroSizeValue(value: string) { - return value.trim() === "0px" ? "0" : value; -} - -export function normalizeSizeValue( - sizeValue: string, - remInPx: number | undefined | null -) { - return normalizeZeroSizeValue( - normalizeNumbersInString( - remInPx != null ? remValueToPx(sizeValue, remInPx) : sizeValue - ) - ); -} - -export function normalizeAtRuleParams(atRuleParam: string) { - return removeUnnecessarySpaces(atRuleParam.replace(/\(|\)/g, "")); -} - -function mapThemeTokens( - tokens: KeyValuePair, - valueConverterFn: (tokenValue: V, tokenKey: string) => string | null -) { - const result: Record = {}; - - for (const [tokenKey, tokenValue] of Object.entries(tokens)) { - const convertedTokenValue = valueConverterFn(tokenValue, tokenKey); - - if (convertedTokenValue) { - result[convertedTokenValue] = tokenKey; - } - } - - return result; -} - -function isColorKey(key: string) { - return ["fill", "stroke"].includes(key) || key.toLowerCase().includes("color"); -} - -function isSizeKey(key: string) { - return [ - "backdropBlur", - "backgroundSize", - "blur", - "borderRadius", - "borderSpacing", - "borderWidth", - "columns", - "divideWidth", - "flexBasis", - "gap", - "height", - "inset", - "letterSpacing", - "lineHeight", - "margin", - "maxHeight", - "maxWidth", - "minHeight", - "minWidth", - "outlineOffset", - "outlineWidth", - "padding", - "ringOffsetWidth", - "ringWidth", - "scrollMargin", - "scrollPadding", - "space", - "spacing", - "strokeWidth", - "textDecorationThickness", - "textUnderlineOffset", - "translate", - "width", - ].includes(key); -} - -function convertFontSizes( - fontSizes: KeyValuePair< - string, - | string - | [fontSize: string, lineHeight: string] - | [ - fontSize: string, - configuration: Partial<{ - lineHeight: string; - letterSpacing: string; - fontWeight: string | number; - }>, - ] - >, - remInPx?: number | null -) { - return mapThemeTokens(fontSizes, fontSizeValue => { - if (!fontSizeValue) { - return null; - } - - if (Array.isArray(fontSizeValue)) { - fontSizeValue = fontSizeValue[0]; - } - - return normalizeSizeValue(fontSizeValue, remInPx); - }); -} - -function convertScreens(screens: ScreensConfig) { - if (Array.isArray(screens)) { - return {} as Record; - } - - return mapThemeTokens(screens, screenValue => - screenValue ? normalizeAtRuleParams(buildMediaQueryByScreen(screenValue)) : null - ); -} - -function convertColors(colors: RecursiveKeyValuePair) { - const flatColors = flattenObject(colors); - - return mapThemeTokens(flatColors, (colorValue: string) => { - colorValue = colorValue?.toString(); - - return colorValue ? normalizeColorValue(colorValue) : null; - }); -} - -function convertSizes(sizes: KeyValuePair, remInPx: number | null | undefined) { - return mapThemeTokens(sizes, (sizeValue: string) => { - sizeValue = sizeValue?.toString(); - - return sizeValue ? normalizeSizeValue(sizeValue, remInPx) : null; - }); -} - -function convertOtherThemeTokens(tokens: KeyValuePair | null | undefined) { - return tokens - ? mapThemeTokens(tokens, (tokenValue: string) => { - tokenValue = tokenValue?.toString(); - - return tokenValue ? normalizeValue(tokenValue) : null; - }) - : tokens; -} - -export function converterMappingByTailwindTheme( - resolvedTailwindTheme: Config["theme"], - remInPx?: number | null -) { - const converterMapping = {} as ConverterMapping; - - if (!resolvedTailwindTheme) { - return converterMapping; - } - - for (const [key, themeItem] of Object.entries( - resolvedTailwindTheme as Record - )) { - if (["keyframes", "container", "fontFamily"].includes(key)) { - continue; - } - - if (key === "fontSize") { - converterMapping[key] = convertFontSizes(themeItem, remInPx); - } else if (key === "screens") { - converterMapping[key] = convertScreens(themeItem); - } else if (isColorKey(key)) { - (converterMapping as any)[key] = convertColors(themeItem); - } else if (isSizeKey(key)) { - (converterMapping as any)[key] = convertSizes(themeItem, remInPx); - } else { - (converterMapping as any)[key] = convertOtherThemeTokens(themeItem); - } - } - - return converterMapping; -} diff --git a/src/converts/utils/reduceTailwindClasses.ts b/src/converts/utils/reduceTailwindClasses.ts deleted file mode 100644 index 9a75b1b..0000000 --- a/src/converts/utils/reduceTailwindClasses.ts +++ /dev/null @@ -1,228 +0,0 @@ -class TailwindClassesReductionManager { - protected resolvedClasses: string[] = []; - protected map: Record = { - m: { mx: { ml: [], mr: [] }, my: { mt: [], mb: [] } }, - p: { px: { pl: [], pr: [] }, py: { pt: [], pb: [] } }, - "scroll-m": { - "scroll-mx": { - "scroll-ml": [], - "scroll-mr": [], - }, - "scroll-my": { - "scroll-mt": [], - "scroll-mb": [], - }, - }, - "scroll-p": { - "scroll-px": { - "scroll-pl": [], - "scroll-pr": [], - }, - "scroll-py": { - "scroll-pt": [], - "scroll-pb": [], - }, - }, - rounded: { - "rounded-t": { - "rounded-tl": [], - "rounded-tr": [], - }, - "rounded-r": { - "rounded-tr": [], - "rounded-br": [], - }, - "rounded-b": { - "rounded-bl": [], - "rounded-br": [], - }, - "rounded-l": { - "rounded-tl": [], - "rounded-bl": [], - }, - }, - border: { - "border-x": { - "border-l": [], - "border-r": [], - }, - "border-y": { - "border-t": [], - "border-b": [], - }, - }, - scale: { - "scale-x": [], - "scale-y": [], - }, - inset: { - "inset-x": { - left: [], - right: [], - }, - "inset-y": { - top: [], - bottom: [], - }, - }, - }; - - appendClassName(className: string) { - const { value, classPrefix } = this.parseTailwindClass(className); - - if (!value || !this.recursiveSetValue(classPrefix, value, this.map)) { - this.resolvedClasses.push(className); - } - } - - reduce() { - for (const [mapKey, mapValue] of Object.entries(this.map)) { - for (const value of this.recursiveResolveClasses( - mapValue, - this.resolvedClasses - ).keys()) { - this.resolvedClasses.push(this.toTailwindClass(mapKey, value)); - } - } - - return this.resolvedClasses; - } - - protected recursiveSetValue( - key: string, - value: string, - targetObject: Record - ) { - for (const objectKey in targetObject) { - if (!Object.prototype.hasOwnProperty.call(targetObject, objectKey)) continue; - - const objectValue = targetObject[objectKey]; - - if (objectKey === key) { - if (isObject(objectValue)) { - this.recursiveSetValueToAllKeys(value, objectValue); - } else if (Array.isArray(objectValue)) { - objectValue.push(value); - } - - return true; - } - - if (isObject(objectValue)) { - const isSet = this.recursiveSetValue(key, value, objectValue); - - if (isSet) { - return true; - } - } - } - - return false; - } - - protected recursiveSetValueToAllKeys(value: string, targetObject: Record) { - for (const key of Object.keys(targetObject)) { - this.recursiveSetValue(key, value, targetObject); - } - } - - protected recursiveResolveClasses( - targetObject: Record, - resolvedClasses: string[] - ) { - let commonValuesMap: null | Map = null; - - const intersectCommonValues = (valuesMap: Map) => { - if (commonValuesMap == null) { - commonValuesMap = valuesMap; - } else { - for (const [commonValue, commonClassPrefix] of commonValuesMap) { - const classPrefix = valuesMap.get(commonValue); - if (classPrefix) { - commonValuesMap?.set(commonValue, classPrefix); - } else { - commonValuesMap?.delete(commonValue); - resolvedClasses.push(this.toTailwindClass(commonClassPrefix, commonValue)); - } - } - - for (const [value, classPrefix] of valuesMap) { - if (commonValuesMap?.has(value)) { - commonValuesMap.set(value, classPrefix); - } else { - resolvedClasses.push(this.toTailwindClass(classPrefix, value)); - } - } - } - }; - - for (const [currentClassPrefix, objectValue] of Object.entries(targetObject)) { - if (isObject(objectValue)) { - const commonValuesMap = this.recursiveResolveClasses( - objectValue, - resolvedClasses - ); - for (const key of commonValuesMap.keys()) { - commonValuesMap.set(key, currentClassPrefix); - } - intersectCommonValues(commonValuesMap); - } else if (Array.isArray(objectValue)) { - intersectCommonValues( - new Map(objectValue.map(value => [value, currentClassPrefix])) - ); - } - } - - return commonValuesMap || new Map(); - } - - protected toTailwindClass(classPrefix: string, value: any) { - if (typeof value !== "string") { - value = value == null ? "" : value.toString(); - } - - if (value.startsWith("-")) { - value = value.slice(1); - classPrefix = `-${classPrefix}`; - } - - return `${classPrefix}-${value}`; - } - - protected parseTailwindClass(tailwindClass: string) { - const isNegativeValue = tailwindClass.startsWith("-"); - if (isNegativeValue) { - tailwindClass = tailwindClass.slice(1); - } - - const lastDashIndex = tailwindClass.lastIndexOf("-"); - if (lastDashIndex === -1) { - return { - value: null, - classPrefix: tailwindClass, - }; - } - - const classPrefix = tailwindClass.slice(0, lastDashIndex); - const absoluteValue = tailwindClass.slice(lastDashIndex + 1); - - return { - value: isNegativeValue ? `-${absoluteValue}` : absoluteValue, - classPrefix, - }; - } -} - -export function reduceTailwindClasses(tailwindClasses: string[]) { - const manager = new TailwindClassesReductionManager(); - - for (const className of tailwindClasses) { - manager.appendClassName(className); - } - - return manager.reduce(); -} - -function isObject(value: any): value is Record { - return value && typeof value === "object" && !Array.isArray(value); -} diff --git a/src/esbuild-babel.ts b/src/esbuild-babel.ts index 4f3c794..9711da0 100644 --- a/src/esbuild-babel.ts +++ b/src/esbuild-babel.ts @@ -6,7 +6,7 @@ import type * as esbuild from "esbuild"; import { transformSync } from "@babel/core"; /** - * An esbuild plugin that processes files with Babel if `getPlugins` returns any plugins. + * An esbuild plugin that processes files with Babel if `plugins` is not empty. */ export const babelPlugin = ({ filter = /\.[jt]sx?$/, @@ -36,6 +36,7 @@ export const babelPlugin = ({ const { code } = transformSync(load(), { parserOpts: { + createImportExpressions: true, plugins: [ "jsx", "decorators", diff --git a/src/esbuild-postcss.ts b/src/esbuild-postcss.ts index 750d9c3..96ed10d 100644 --- a/src/esbuild-postcss.ts +++ b/src/esbuild-postcss.ts @@ -28,7 +28,7 @@ export const esbuildPlugin = (styleMap: StyleMap, compile: Compile): esbuild.Plu build.onLoad({ filter: /.*/, namespace: ESBUILD_NAMESPACE }, async ({ path }) => { if (path === "directive:base") { return { - contents: (await compile("@tailwind base")).css, + contents: await compile("@tailwind base"), loader: "css", }; } @@ -40,7 +40,7 @@ export const esbuildPlugin = (styleMap: StyleMap, compile: Compile): esbuild.Plu try { const result = await compile(toCSSText(styles)); return { - contents: result.css, + contents: result, loader: "css", }; } catch (e) { diff --git a/src/index.test.ts b/src/index.test.ts index 8f96698..9cc0566 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,7 +1,8 @@ +/* eslint-disable unicorn/string-content */ import { promises as fs } from "node:fs"; import { resolve } from "node:path"; -import { type BuildOptions, type OutputFile, build, transformSync } from "esbuild"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import * as esbuild from "esbuild"; import dedent from "dedent"; import { name } from "../package.json" with { type: "json" }; import { @@ -24,8 +25,9 @@ describe("babel-tailwind", () => { }); it("supports ESBuild", async () => { - const outputFiles = await compileESBuild({ + const { files } = await compileESBuild({ clsx: "emotion", + expectFiles: 2, javascript: /* tsx */ ` export function Hello() { return ( @@ -36,20 +38,17 @@ describe("babel-tailwind", () => { } `, }); - expect(outputFiles).toHaveLength(2); - - const js = findByExt(outputFiles, ".js"); - const css = findByExt(outputFiles, ".css"); const clsName = getClassName("text-center"); - expect(js.text).toContain(`className: "${clsName}"`); - expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); + expect(files.js.text).toContain(`className: "${clsName}"`); + expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); }); it("does not remove the attribute if `preserveAttribute` is true", async () => { - const outputFiles = await compileESBuild({ + const { files } = await compileESBuild({ clsx: "emotion", jsxAttributeAction: "preserve", + expectFiles: 2, javascript: /* tsx */ ` export function Hello() { return ( @@ -60,10 +59,52 @@ describe("babel-tailwind", () => { } `, }); - expect(outputFiles).toHaveLength(2); - const js = findByExt(outputFiles, ".js"); - expect(js.text).toContain(`css: "text-center"`); + expect(files.js.text).toContain(`css: "text-center"`); + }); + + describe('merges with existing "className" attribute', () => { + it("string literal", async () => { + const { files } = await compileESBuild({ + clsx: "emotion", + expectFiles: 2, + javascript: /* tsx */ ` + export function Hello() { + return ( +
+ Hello, world! +
+ ); + } + `, + }); + + const clsName = getClassName("text-center"); + expect(files.js.text).toContain(`className: "text-center ${clsName}"`); + expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); + }); + + it("existing function", async () => { + const { files } = await compileESBuild({ + clsx: "emotion", + expectFiles: 2, + javascript: /* tsx */ ` + export function Hello() { + return ( +
isEntering ? "enter" : "exit"} css="text-center"> + Hello, world! +
+ ); + } + `, + }); + + const clsName = getClassName("text-center"); + expect(files.js.text).toContain( + `className: ({\n isEntering\n }) => _cx(isEntering ? "enter" : "exit", "${clsName}")` + ); + expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); + }); }); it("reports errors with correct position", async () => { @@ -98,9 +139,10 @@ describe("babel-tailwind", () => { }); it("supports custom jsxAttributeName", async () => { - const outputFiles = await compileESBuild({ + const { files } = await compileESBuild({ clsx: "emotion", jsxAttributeName: "tw", + expectFiles: 2, javascript: /* tsx */ ` export function Hello() { return ( @@ -111,34 +153,29 @@ describe("babel-tailwind", () => { } `, }); - expect(outputFiles).toHaveLength(2); - - const js = findByExt(outputFiles, ".js"); - const css = findByExt(outputFiles, ".css"); const clsName = getClassName("text-center"); - expect(js.text).toContain(`className: "${clsName}"`); - expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); + expect(files.js.text).toContain(`className: "${clsName}"`); + expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`); }); it("supports importing tailwind/base", async () => { - const postcss = createPostCSS({ tailwindConfig: {} }); - const base = (await postcss("@tailwind base;")).css; - const outputFiles = await compileESBuild({ + const postcss = createPostCSS({ + tailwindConfig: {}, + postCSSPlugins: [], + directives: [], + }); + const base = await postcss("@tailwind base;"); + const { files } = await compileESBuild({ clsx: "emotion", + expectFiles: 2, javascript: /* tsx */ ` import "${name}/base"; `, }); - expect(outputFiles).toHaveLength(2); - const js = findByExt(outputFiles, ".js"); - const css = findByExt(outputFiles, ".css"); - - // expect(js.text).toContain(`import "./base.css";`); - expect(js.text).toBe(""); - - expect(minCSS(css.text)).toContain(minCSS(base)); + expect(files.js.text).toBe(""); + expect(minCSS(files.css.text)).toContain(minCSS(base)); }); }); @@ -149,37 +186,48 @@ async function write(path: string, content: string) { } const minCSS = (text: string) => - transformSync(text, { minify: true, loader: "css" }).code; + esbuild.transformSync(text, { minify: true, loader: "css" }).code; -const findByExt = (outputFiles: OutputFile[], ext: string) => +const findByExt = (outputFiles: esbuild.OutputFile[], ext: string) => outputFiles.find(file => file.path.endsWith(ext))!; async function compileESBuild({ javascript, - esbuild, + esbuild: esbuildOptions, + expectFiles, ...options }: TailwindPluginOptions & { - esbuild?: BuildOptions; + esbuild?: esbuild.BuildOptions; javascript: string; + expectFiles?: number; }) { const tailwind = getTailwindPlugins({ tailwindConfig: {}, ...options, }); - const result = await build({ + const result = await esbuild.build({ bundle: true, write: false, - external: ["react/jsx-runtime"], + external: ["react/jsx-runtime", "@emotion/css", "clsx"], outdir: "dist", format: "esm", entryPoints: [await write("index.tsx", dedent(javascript))], - plugins: [babelPlugin({ plugins: [tailwind.babel] }), tailwind.esbuild], - ...esbuild, + plugins: [babelPlugin({ plugins: [tailwind.babel()] }), tailwind.esbuild()], + ...esbuildOptions, }); const { errors, warnings, outputFiles } = result; expect(errors).toHaveLength(0); expect(warnings).toHaveLength(0); - return outputFiles!; + if (expectFiles != null) { + expect(outputFiles).toHaveLength(expectFiles); + } + + return { + outputFiles: outputFiles!, + files: new Proxy({} as Record, { + get: (_, ext: string) => findByExt(outputFiles!, ext), + }), + }; } diff --git a/src/index.ts b/src/index.ts index 8ea1e35..b88c960 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import hash from "@emotion/hash"; import type { Config } from "tailwindcss"; import type postcss from "postcss"; import { memoize } from "lodash"; -import { babelTailwind } from "./babel-tailwind"; +import { type ClassNameCollector, babelTailwind } from "./babel-tailwind"; import { esbuildPlugin } from "./esbuild-postcss"; import { vitePlugin } from "./vite-plugin"; import { type StyleMap, createPostCSS, type tailwindDirectives } from "./shared"; @@ -27,7 +27,7 @@ export interface TailwindPluginOptions { /** * Directives to prefix to all Tailwind stylesheets */ - directives?: (typeof tailwindDirectives)[number][] | "all"; + directives?: (typeof tailwindDirectives)[number][] | "all" | undefined; /** * Additional PostCSS plugins (optional) @@ -53,7 +53,7 @@ export interface TailwindPluginOptions { * declare const tw: TaggedTailwindFunction; * "tw" => tw`p-2 text-center` */ - taggedTemplateName?: string; + taggedTemplateName?: string | undefined; /** * The prefix to use for the generated class names. @@ -65,8 +65,22 @@ export interface TailwindPluginOptions { * Preferred library for classnames */ clsx: "clsx" | "classnames" | "emotion"; + + /** + * @internal + */ + styleMap?: StyleMap; + + /** + * Custom CSS compile function + * @example + * async css => (await postcss.process(css, { plugins: [tailwindcss()] })).css + */ + compile(css: string): Promise; } +export type ResolveTailwindOptions = Required; + /** * Hashes and prefixes a string of Tailwind class names. * @example getClassName("p-2 text-center") // "tw-1r6fxxz" @@ -90,15 +104,31 @@ export const getClassName: GetClassName = cls => "tw-" + hash(cls); * }); */ export function getTailwindPlugins(options: TailwindPluginOptions) { - const styleMap: StyleMap = new Map(); - const compile = memoize(createPostCSS(options)); + const resolvedOptions: ResolveTailwindOptions = { + directives: undefined, + getClassName, + jsxAttributeAction: "delete", + jsxAttributeName: "css", + postCSSPlugins: [], + styleMap: new Map(), + taggedTemplateName: undefined, + tailwindConfig: {}, + ...options, + }; + + const getCompiler = () => createPostCSS(resolvedOptions); + + const { styleMap } = resolvedOptions; + const compile = options.compile ?? memoize(getCompiler()); return { compile, - babel: babelTailwind(styleMap, options), - esbuild: esbuildPlugin(styleMap, compile), - vite: vitePlugin(styleMap, compile), + babel: (onCollect?: ClassNameCollector) => babelTailwind(resolvedOptions, onCollect), + esbuild: () => esbuildPlugin(styleMap, compile), + vite: () => vitePlugin(styleMap, compile), styleMap, + options, + getCompiler, [Symbol.dispose]() { styleMap.clear(); }, diff --git a/src/shared.ts b/src/shared.ts index d964edd..df733ad 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -1,6 +1,6 @@ import tailwind from "tailwindcss"; import postcss from "postcss"; -import type { TailwindPluginOptions } from "./index"; +import type { ResolveTailwindOptions } from "./index"; export const { name: pkgName } = [require][0]( process.env.BABEL_TAILWIND_BUILD ? "./package.json" : "../package.json" @@ -30,9 +30,9 @@ export type StyleMap = Map; export function createPostCSS({ tailwindConfig, - postCSSPlugins = [], + postCSSPlugins, directives, -}: Pick) { +}: Pick) { const post = postcss([ tailwind({ ...tailwindConfig, @@ -44,7 +44,10 @@ export function createPostCSS({ const appliedDirectives = directives === "all" ? tailwindDirectives : directives; const directiveTexts = appliedDirectives?.map(d => `@tailwind ${d};\n`).join("") ?? ""; - return (css: string) => post.process(directiveTexts + css, { from: undefined }); + return async (css: string) => { + const result = await post.process(directiveTexts + css, { from: undefined }); + return result.css; + }; } export type Compile = ReturnType; diff --git a/src/vite-plugin.ts b/src/vite-plugin.ts index 1a486d9..b6ac55d 100644 --- a/src/vite-plugin.ts +++ b/src/vite-plugin.ts @@ -1,6 +1,5 @@ import { dirname, join } from "node:path"; import type * as vite from "vite"; -import { memoize } from "lodash"; import { type Compile, type StyleMap, pkgName, toCSSText } from "./shared"; const ROLLUP_PREFIX = "\0tailwind:"; @@ -29,12 +28,11 @@ export const vitePlugin = (styleMap: StyleMap, compile: Compile): vite.Plugin => if (id.startsWith(ROLLUP_PREFIX)) { const resolved = id.slice(ROLLUP_PREFIX.length); if (resolved === "directive:base") { - return (await compile("@tailwind base")).css; + return await compile("@tailwind base"); } if (styleMap.has(resolved)) { - const result = await compile(toCSSText(styleMap.get(resolved)!)); - return result.css; + return await compile(toCSSText(styleMap.get(resolved)!)); } } }, diff --git a/tsconfig.json b/tsconfig.json index 46bd661..6845890 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "allowArbitraryExtensions": true, "esModuleInterop": true, "experimentalDecorators": true, + "exactOptionalPropertyTypes": true, "jsx": "react-jsx", "module": "esnext", "moduleResolution": "node",