From 90f653699404750926f42896605cf545273c7212 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 21 Feb 2022 19:23:34 +0100 Subject: [PATCH] Use Tailwind's `context.getClassOrder(classes)` (#57) * prefer Tailwind's `context.getClassOrder()` if it exists We have to keep the existing code for now, since the plugin will prefer the user's tailwind version. Hopefully we can remove this in future versions. * bump tailwindcss dependency * add full getClassOrder polyfill This will also add the `group` and `peer` for older versions of Tailwind CSS * Update `getClassOrder` polyfill to support all Tailwind v3 releases * Add "parasite utilities" test Co-authored-by: Brad Cornes --- package-lock.json | 162 +++++++++++++++++++++++----------------------- package.json | 2 +- src/index.js | 48 +++++++++++--- tests/test.js | 6 ++ 4 files changed, 129 insertions(+), 89 deletions(-) diff --git a/package-lock.json b/package-lock.json index ab9161a..5014b23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "prettier-plugin-svelte": "^2.6.0", "recast": "^0.20.5", "rimraf": "^3.0.2", - "tailwindcss": "^3.0.15" + "tailwindcss": "^3.0.23" }, "engines": { "node": ">=12.17.0" @@ -1702,10 +1702,16 @@ } }, "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2947,9 +2953,9 @@ } }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2959,7 +2965,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-glob/node_modules/glob-parent": { @@ -2987,9 +2993,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", - "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -5199,11 +5205,10 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.0.tgz", + "integrity": "sha512-JzxqqT5u/x+/KOFSd7JP15DOo9nOoHpx6DYatqIHUW2+flybkm+mdcraotSQR5WcnZr+qhGVh8Ted0KdfSMxlg==", "dev": true, - "peer": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5798,15 +5803,14 @@ } }, "node_modules/postcss": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", - "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dev": true, - "peer": true, "dependencies": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" + "nanoid": "^3.2.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -5881,9 +5885,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -6212,12 +6216,12 @@ } }, "node_modules/resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6667,11 +6671,10 @@ } }, "node_modules/source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -7016,31 +7019,32 @@ "dev": true }, "node_modules/tailwindcss": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.15.tgz", - "integrity": "sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz", + "integrity": "sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==", "dev": true, "dependencies": { "arg": "^5.0.1", "chalk": "^4.1.2", - "chokidar": "^3.5.2", + "chokidar": "^3.5.3", "color-name": "^1.1.4", "cosmiconfig": "^7.0.1", "detective": "^5.2.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "normalize-path": "^3.0.0", "object-hash": "^2.2.0", + "postcss": "^8.4.6", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.0", "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.8", + "postcss-selector-parser": "^6.0.9", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", - "resolve": "^1.21.0" + "resolve": "^1.22.0" }, "bin": { "tailwind": "lib/cli.js", @@ -8919,9 +8923,9 @@ "dev": true }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -9839,9 +9843,9 @@ } }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -9875,9 +9879,9 @@ "dev": true }, "fastq": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", - "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -11583,11 +11587,10 @@ "dev": true }, "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true, - "peer": true + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.0.tgz", + "integrity": "sha512-JzxqqT5u/x+/KOFSd7JP15DOo9nOoHpx6DYatqIHUW2+flybkm+mdcraotSQR5WcnZr+qhGVh8Ted0KdfSMxlg==", + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -12042,15 +12045,14 @@ "dev": true }, "postcss": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz", - "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dev": true, - "peer": true, "requires": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" + "nanoid": "^3.2.0", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" } }, "postcss-js": { @@ -12083,9 +12085,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -12330,12 +12332,12 @@ "dev": true }, "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -12678,11 +12680,10 @@ "dev": true }, "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true, - "peer": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true }, "source-map-resolve": { "version": "0.5.3", @@ -12965,31 +12966,32 @@ "dev": true }, "tailwindcss": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.15.tgz", - "integrity": "sha512-bT2iy7FtjwgsXik4ZoJnHXR+SRCiGR1W95fVqpLZebr64m4ahwUwRbIAc5w5+2fzr1YF4Ct2eI7dojMRRl8sVQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz", + "integrity": "sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==", "dev": true, "requires": { "arg": "^5.0.1", "chalk": "^4.1.2", - "chokidar": "^3.5.2", + "chokidar": "^3.5.3", "color-name": "^1.1.4", "cosmiconfig": "^7.0.1", "detective": "^5.2.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.7", + "fast-glob": "^3.2.11", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "normalize-path": "^3.0.0", "object-hash": "^2.2.0", + "postcss": "^8.4.6", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.0", "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.8", + "postcss-selector-parser": "^6.0.9", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", - "resolve": "^1.21.0" + "resolve": "^1.22.0" } }, "terminal-link": { diff --git a/package.json b/package.json index 5499fdf..ad37a74 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "prettier-plugin-svelte": "^2.6.0", "recast": "^0.20.5", "rimraf": "^3.0.2", - "tailwindcss": "^3.0.15" + "tailwindcss": "^3.0.23" }, "peerDependencies": { "prettier": ">=2.2.0" diff --git a/src/index.js b/src/index.js index 168b9bc..c665584 100644 --- a/src/index.js +++ b/src/index.js @@ -26,6 +26,43 @@ function bigSign(bigIntValue) { return (bigIntValue > 0n) - (bigIntValue < 0n) } +function prefixCandidate(context, selector) { + let prefix = context.tailwindConfig.prefix + return typeof prefix === 'function' ? prefix(selector) : prefix + selector +} + +// Polyfill for older Tailwind CSS versions +function getClassOrderPolyfill(classes, { env }) { + // A list of utilities that are used by certain Tailwind CSS utilities but + // that don't exist on their own. This will result in them "not existing" and + // sorting could be weird since you still require them in order to make the + // host utitlies work properly. (Thanks Biology) + let parasiteUtilities = new Set([ + prefixCandidate(env.context, 'group'), + prefixCandidate(env.context, 'peer'), + ]) + + let classNamesWithOrder = [] + + for (let className of classes) { + let order = + env + .generateRules(new Set([className]), env.context) + .sort(([a], [z]) => bigSign(z - a))[0]?.[0] ?? null + + if (order === null && parasiteUtilities.has(className)) { + // This will make sure that it is at the very beginning of the + // `components` layer which technically means 'before any + // components'. + order = env.context.layerOrder.components + } + + classNamesWithOrder.push([className, order]) + } + + return classNamesWithOrder +} + function sortClasses( classStr, { env, ignoreFirst = false, ignoreLast = false } @@ -59,14 +96,9 @@ function sortClasses( suffix = `${whitespace.pop() ?? ''}${classes.pop() ?? ''}` } - let classNamesWithOrder = [] - for (let className of classes) { - let order = - env - .generateRules(new Set([className]), env.context) - .sort(([a], [z]) => bigSign(z - a))[0]?.[0] ?? null - classNamesWithOrder.push([className, order]) - } + let classNamesWithOrder = env.context.getClassOrder + ? env.context.getClassOrder(classes) + : getClassOrderPolyfill(classes, { env }) classes = classNamesWithOrder .sort(([, a], [, z]) => { diff --git a/tests/test.js b/tests/test.js index b5888da..e441e35 100644 --- a/tests/test.js +++ b/tests/test.js @@ -193,6 +193,12 @@ test('non-tailwind classes', () => { ).toEqual('
') }) +test('parasite utilities', () => { + expect( + format('
') + ).toEqual('
') +}) + test('inferred config path', () => { expect(formatFixture('basic')).toEqual( '
'