From 8e60a3c7e81ea0e44f127aa30df6d5676c60133d Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 23 Jan 2023 20:44:31 +0100 Subject: [PATCH] Use `Lightning CSS` in the `PostCSS` Plugin (#10399) * bump lightningcss * use `lightningcss` in the main PostCss Plugin * use lightningcss in our custom matchers Now that we are using `lightningcss` and nesting in the new `oxide` engine, the generated output _will_ be different in the majority of test cases. Using a combination of `prettier` and `lightningcss` will make the output consistent. The moment we are fully using the `oxide` engine, we can drop `lightningcss` or `prettier` again to improve the performance of the tests. * update tests to apply `lightningcss` related changes * update changelog * add `lightningcss` and `browserslist` as dev dependencies to stable package.json * only use `lightningcss` in tests (without prettier) We will only fallback to prettier if lightningcss fails somehow. * apply side effect chagnes due to only using lightningcss for tests * make CI happy (integration tests) Apply changes to integration tests now that we are using lightningcss * transform `lightningcss` for Node 12 when running tests * run prettier on failing tests for `toMatchFormattedCss` This will result in better diffs because diffs are typically per block and/or per line. But lightningcss will simplify certain selectors and the diff won't be as clear. We will only apply the prettier formatting for failing tests in the diff view so that diffs are cleaner and we don't pay for the additional prettier calls when tests pass. --- CHANGELOG.md | 1 + .../postcss-cli/tests/integration.test.js | 6 +- .../rollup-sass/tests/integration.test.js | 12 +- integrations/rollup/tests/integration.test.js | 6 +- .../tailwindcss-cli/tests/integration.test.js | 5 +- integrations/vite/tests/integration.test.js | 6 +- .../webpack-4/tests/integration.test.js | 6 +- .../webpack-5/tests/integration.test.js | 6 +- jest/customMatchers.js | 204 ++++++------ package-lock.json | 4 +- package-lock.stable.json | 279 +++++++++++++++++ package.json | 2 +- package.stable.json | 7 +- src/plugin.js | 60 ++++ tests/arbitrary-values.oxide.test.css | 20 +- tests/arbitrary-values.test.css | 18 +- tests/arbitrary-values.test.html | 2 +- tests/arbitrary-variants.test.js | 293 +++++++----------- tests/basic-usage.test.js | 12 +- tests/preflight.test.js | 6 +- tests/source-maps.test.js | 108 ++++--- tests/util/source-maps.js | 2 +- 22 files changed, 650 insertions(+), 415 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2039b711..0e338fdc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add standalone CLI build for 64-bit Windows on ARM (`node16-win-arm64`) ([#10001](https://github.com/tailwindlabs/tailwindcss/pull/10001)) - Add `delay-0` and `duration-0` by default ([#10294](https://github.com/tailwindlabs/tailwindcss/pull/10294)) - Add logical properties support for inline direction ([#10166](https://github.com/tailwindlabs/tailwindcss/pull/10166)) +- Use `Lightning CSS` in the PostCSS Plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) ### Fixed diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index 929be5c50..964c57b82 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -222,11 +222,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index 0c15ecedc..cdf9a11fb 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -220,11 +220,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } @@ -307,11 +305,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index 65f813ff5..63a28bcb5 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -220,11 +220,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index ddba060bc..42e35a895 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -472,10 +472,7 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } .font-bold { font-weight: 700; diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index 43a3052d8..b2d08bc27 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -263,11 +263,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index 68b43b9a0..63ab3cbbf 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -227,11 +227,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index 3eafb767a..95f3d5f5f 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -227,11 +227,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/jest/customMatchers.js b/jest/customMatchers.js index 385faf7bd..1ea532f0c 100644 --- a/jest/customMatchers.js +++ b/jest/customMatchers.js @@ -1,85 +1,127 @@ const prettier = require('prettier') const { diff } = require('jest-diff') +const lightningcss = require('lightningcss') -function format(input) { +function formatPrettier(input) { return prettier.format(input, { parser: 'css', printWidth: 100, }) } +function format(input) { + try { + return lightningcss + .transform({ + filename: 'input.css', + code: Buffer.from(input), + minify: false, + targets: { chrome: 106 << 16 }, + drafts: { + nesting: true, + customMedia: true, + }, + }) + .code.toString('utf8') + } catch (err) { + try { + // Lightning CSS is pretty strict, so it will fail for `@media screen(md) {}` for example, + // in that case we can fallback to prettier since it doesn't really care. However if an + // actual syntax error is made, then we still want to show the proper error. + return formatPrettier(input.replace(/\n/g, '')) + } catch { + let lines = err.source.split('\n') + let e = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) + if (Error.captureStackTrace) { + Error.captureStackTrace(e, toMatchFormattedCss) + } + throw e + } + } +} + +function toMatchFormattedCss(received = '', argument = '') { + let options = { + comment: 'formatCSS(received) === formatCSS(argument)', + isNot: this.isNot, + promise: this.promise, + } + + let formattedReceived = format(received) + let formattedArgument = format(argument) + + let pass = formattedReceived === formattedArgument + + let message = pass + ? () => { + return ( + this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) + + '\n\n' + + `Expected: not ${this.utils.printExpected(formattedReceived)}\n` + + `Received: ${this.utils.printReceived(formattedArgument)}` + ) + } + : () => { + let actual = formatPrettier(formattedReceived) + let expected = formatPrettier(formattedArgument) + + let diffString = diff(expected, actual, { + expand: this.expand, + }) + + return ( + this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) + + '\n\n' + + (diffString && diffString.includes('- Expect') + ? `Difference:\n\n${diffString}` + : `Expected: ${this.utils.printExpected(expected)}\n` + + `Received: ${this.utils.printReceived(actual)}`) + ) + } + + return { actual: received, message, pass } +} + expect.extend({ // Compare two CSS strings with all whitespace removed // This is probably naive but it's fast and works well enough. - toMatchCss(received, argument) { - function stripped(str) { - return str.replace(/\s/g, '').replace(/;/g, '') - } - - const options = { - comment: 'stripped(received) === stripped(argument)', - isNot: this.isNot, - promise: this.promise, - } - - const pass = stripped(received) === stripped(argument) - - const message = pass - ? () => { - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - `Expected: not ${this.utils.printExpected(format(received))}\n` + - `Received: ${this.utils.printReceived(format(argument))}` - ) - } - : () => { - const actual = format(received) - const expected = format(argument) - - const diffString = diff(expected, actual, { - expand: this.expand, - }) - - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - (diffString && diffString.includes('- Expect') - ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) - ) - } - - return { actual: received, message, pass } - }, + toMatchCss: toMatchFormattedCss, + toMatchFormattedCss: toMatchFormattedCss, toIncludeCss(received, argument) { - function stripped(str) { - return str.replace('/* prettier-ignore */', '').replace(/\s/g, '').replace(/;/g, '') - } - - const options = { + let options = { comment: 'stripped(received).includes(stripped(argument))', isNot: this.isNot, promise: this.promise, } - const pass = stripped(received).includes(stripped(argument)) + let pass = format(received).includes(format(argument)) - const message = pass + let message = pass ? () => { return ( this.utils.matcherHint('toIncludeCss', undefined, undefined, options) + '\n\n' + - `Expected: not ${this.utils.printExpected(format(received))}\n` + - `Received: ${this.utils.printReceived(format(argument))}` + `Expected: not ${this.utils.printExpected(formatPrettier(received))}\n` + + `Received: ${this.utils.printReceived(formatPrettier(argument))}` ) } : () => { - const actual = format(received) - const expected = format(argument) + let actual = formatPrettier(received) + let expected = formatPrettier(argument) - const diffString = diff(expected, actual, { + let diffString = diff(expected, actual, { expand: this.expand, }) @@ -96,55 +138,3 @@ expect.extend({ return { actual: received, message, pass } }, }) - -expect.extend({ - // Compare two CSS strings with all whitespace removed - // This is probably naive but it's fast and works well enough. - toMatchFormattedCss(received = '', argument = '') { - function format(input) { - return prettier.format(input.replace(/\n/g, ''), { - parser: 'css', - printWidth: 100, - }) - } - const options = { - comment: 'stripped(received) === stripped(argument)', - isNot: this.isNot, - promise: this.promise, - } - - let formattedReceived = format(received) - let formattedArgument = format(argument) - - const pass = formattedReceived === formattedArgument - - const message = pass - ? () => { - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - `Expected: not ${this.utils.printExpected(formattedReceived)}\n` + - `Received: ${this.utils.printReceived(formattedArgument)}` - ) - } - : () => { - const actual = formattedReceived - const expected = formattedArgument - - const diffString = diff(expected, actual, { - expand: this.expand, - }) - - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - (diffString && diffString.includes('- Expect') - ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) - ) - } - - return { actual: received, message, pass } - }, -}) diff --git a/package-lock.json b/package-lock.json index 2bd976cbf..1bec10384 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -25284,7 +25284,7 @@ "is-glob": "^4.0.3", "jest": "^28.1.3", "jest-diff": "^28.1.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", diff --git a/package-lock.stable.json b/package-lock.stable.json index ff0e0dcf5..6c40c1957 100644 --- a/package-lock.stable.json +++ b/package-lock.stable.json @@ -44,6 +44,7 @@ "@swc/jest": "0.2.24", "@swc/register": "0.1.10", "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", "concurrently": "^7.5.0", "cssnano": "^5.1.14", "esbuild": "^0.16.10", @@ -52,6 +53,7 @@ "eslint-plugin-prettier": "^4.2.1", "jest": "^28.1.3", "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", "prettier": "^2.8.1", "rimraf": "^3.0.0", "source-map-js": "^1.0.2", @@ -3518,6 +3520,18 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "dev": true, @@ -5876,6 +5890,192 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", + "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "dev": true, + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.18.0", + "lightningcss-darwin-x64": "1.18.0", + "lightningcss-linux-arm-gnueabihf": "1.18.0", + "lightningcss-linux-arm64-gnu": "1.18.0", + "lightningcss-linux-arm64-musl": "1.18.0", + "lightningcss-linux-x64-gnu": "1.18.0", + "lightningcss-linux-x64-musl": "1.18.0", + "lightningcss-win32-x64-msvc": "1.18.0" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", + "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", + "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", + "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", + "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", + "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", + "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", + "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "2.0.6", "license": "MIT", @@ -10238,6 +10438,12 @@ "defined": { "version": "1.0.0" }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "dev": true @@ -11842,6 +12048,79 @@ } } }, + "lightningcss": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", + "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "lightningcss-darwin-arm64": "1.18.0", + "lightningcss-darwin-x64": "1.18.0", + "lightningcss-linux-arm-gnueabihf": "1.18.0", + "lightningcss-linux-arm64-gnu": "1.18.0", + "lightningcss-linux-arm64-musl": "1.18.0", + "lightningcss-linux-x64-gnu": "1.18.0", + "lightningcss-linux-x64-musl": "1.18.0", + "lightningcss-win32-x64-msvc": "1.18.0" + } + }, + "lightningcss-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "dev": true, + "optional": true + }, + "lightningcss-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", + "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm-gnueabihf": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", + "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", + "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", + "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", + "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", + "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "dev": true, + "optional": true + }, + "lightningcss-win32-x64-msvc": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", + "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "dev": true, + "optional": true + }, "lilconfig": { "version": "2.0.6" }, diff --git a/package.json b/package.json index 14a5d5977..0a4cd90e1 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", diff --git a/package.stable.json b/package.stable.json index 15eefa949..7161e4c54 100644 --- a/package.stable.json +++ b/package.stable.json @@ -52,6 +52,7 @@ "@swc/jest": "0.2.24", "@swc/register": "0.1.10", "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", "concurrently": "^7.5.0", "cssnano": "^5.1.14", "esbuild": "^0.16.10", @@ -60,6 +61,7 @@ "eslint-plugin-prettier": "^4.2.1", "jest": "^28.1.3", "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", "prettier": "^2.8.1", "rimraf": "^3.0.0", "source-map-js": "^1.0.2", @@ -84,7 +86,7 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.21", + "postcss": "^8.0.9", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", @@ -104,6 +106,9 @@ "/standalone-cli/", "\\.test\\.skip\\.js$" ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], "transform": { "\\.js$": "@swc/jest", "\\.ts$": "@swc/jest" diff --git a/src/plugin.js b/src/plugin.js index 7dc41c317..4fa8ce757 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -34,6 +34,66 @@ module.exports = function tailwindcss(configOrPath) { processTailwindFeatures(context)(root, result) }, + env.OXIDE && + function lightningCssPlugin(_root, result) { + let postcss = require('postcss') + let lightningcss = require('lightningcss') + let browserslist = require('browserslist') + + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: + typeof process !== 'undefined' && process.env.JEST_WORKER_ID + ? { chrome: 106 << 16 } + : lightningcss.browserslistToTargets( + browserslist(require('../package.json').browserslist) + ), + + drafts: { + nesting: true, + customMedia: true, + }, + }) + + result.map = Object.assign(result.map ?? {}, { + toJSON() { + return transformed.map.toJSON() + }, + toString() { + return transformed.map.toString() + }, + }) + + result.root = postcss.parse(transformed.code.toString('utf8')) + } catch (err) { + if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { + let lines = err.source.split('\n') + err = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) + } + + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin) + } + throw err + } + }, env.DEBUG && function (root) { console.timeEnd('JIT TOTAL') diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css index 34bb93bc6..326149b90 100644 --- a/tests/arbitrary-values.oxide.test.css +++ b/tests/arbitrary-values.oxide.test.css @@ -182,20 +182,16 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: { - { - } - } + width: {{} }; } .w-\[\{\}\] { - width: { - } + width: {}; } .min-w-\[3\.23rem\] { min-width: 3.23rem; } .min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: calc(1 - ((12 - 3) * 0.5)); + min-width: -3.5px; } .min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { min-width: calc(1 - (var(--something) * 0.5)); @@ -420,7 +416,7 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '\1F44D'; + list-style-type: '\1f44d'; } .list-\[var\(--value\)\] { list-style-type: var(--value); @@ -685,13 +681,7 @@ .bg-\[image\:var\(--value\)\2c var\(--value\)\] { background-image: var(--value), var(--value); } -.bg-\[linear-gradient\(\#eee\2c - \#fff\)\2c - conic-gradient\(red\2c - orange\2c - yellow\2c - green\2c - blue\)\] { +.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue); } .bg-\[linear-gradient\(\#eee\2c \#fff\)\] { diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 3098a954a..e446fcab3 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -182,14 +182,10 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: { - { - } - } + width: {{} }; } .w-\[\{\}\] { - width: { - } + width: {}; } .min-w-\[3\.23rem\] { min-width: 3.23rem; @@ -420,7 +416,7 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '\1F44D'; + list-style-type: '\1f44d'; } .list-\[var\(--value\)\] { list-style-type: var(--value); @@ -685,13 +681,7 @@ .bg-\[image\:var\(--value\)\2c var\(--value\)\] { background-image: var(--value), var(--value); } -.bg-\[linear-gradient\(\#eee\2c - \#fff\)\2c - conic-gradient\(red\2c - orange\2c - yellow\2c - green\2c - blue\)\] { +.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue); } .bg-\[linear-gradient\(\#eee\2c \#fff\)\] { diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index 56a9d3ae6..047dae8ca 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -123,7 +123,7 @@
-
+
diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index af29b4927..1b7c08290 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -644,15 +644,15 @@ crosscheck(({ stable, oxide }) => {
-
+
-
-
+
+
@@ -667,43 +667,37 @@ crosscheck(({ stable, oxide }) => { ` return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .aria-checked\:underline[aria-checked='true'] { - text-decoration-line: underline; - } - .aria-\[labelledby\=a_b\]\:underline[aria-labelledby='a b'] { - text-decoration-line: underline; - } - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'] { - text-decoration-line: underline; - } - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline { - text-decoration-line: underline; - } - .group[aria-checked='true'] .group-aria-checked\:underline { - text-decoration-line: underline; - } - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=a_b\]\:underline { - text-decoration-line: underline; - } - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline { - text-decoration-line: underline; - } - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline { - text-decoration-line: underline; - } - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline { - text-decoration-line: underline; - } - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=a_b\]\:underline { - text-decoration-line: underline; - } - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline { + stable.expect(result.css).toMatchFormattedCss(css` + .underline, + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { text-decoration-line: underline; } + `) + oxide.expect(result.css).toMatchFormattedCss(css` + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { text-decoration-line: underline; } @@ -724,15 +718,15 @@ crosscheck(({ stable, oxide }) => {
-
+
-
-
+
+
@@ -747,43 +741,37 @@ crosscheck(({ stable, oxide }) => { ` return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .data-checked\:underline[data-ui~='checked'] { - text-decoration-line: underline; - } - .data-\[foo\=bar_baz\]\:underline[data-foo='bar baz'] { - text-decoration-line: underline; - } - .data-\[position\=top\]\:underline[data-position='top'] { - text-decoration-line: underline; - } - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline { - text-decoration-line: underline; - } - .group[data-ui~='checked'] .group-data-checked\:underline { - text-decoration-line: underline; - } - .group[data-foo='bar baz'] .group-data-\[foo\=bar_baz\]\:underline { - text-decoration-line: underline; - } - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline { - text-decoration-line: underline; - } - .group[data-position='top'] .group-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline { - text-decoration-line: underline; - } - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline { - text-decoration-line: underline; - } - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=bar_baz\]\:underline { - text-decoration-line: underline; - } - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline { + stable.expect(result.css).toMatchFormattedCss(css` + .underline, + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { text-decoration-line: underline; } + `) + oxide.expect(result.css).toMatchFormattedCss(css` + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { text-decoration-line: underline; } @@ -807,7 +795,7 @@ crosscheck(({ stable, oxide }) => {
-
+
@@ -835,37 +823,42 @@ crosscheck(({ stable, oxide }) => { .supports-grid\:underline { text-decoration-line: underline; } - } - @supports (display: grid) { + .supports-\[display\:grid\]\:grid { display: grid; } } + @supports (foo: bar) and (bar: baz) { .supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline { text-decoration-line: underline; } } + @supports (foo: bar) or (bar: baz) { .supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline { text-decoration-line: underline; } } + @supports (container-type: var(--tw)) { .supports-\[container-type\]\:underline { text-decoration-line: underline; } } + @supports not (foo: bar) { .supports-\[not\(foo\:bar\)\]\:underline { text-decoration-line: underline; } } + @supports selector(A > B) { - .supports-\[selector\(A\>B\)\]\:underline { + .supports-\[selector\(A_\>_B\)\]\:underline { text-decoration-line: underline; } } + @supports (transform-origin: 5% 5%) { .supports-\[transform-origin\:5\%_5\%\]\:underline { text-decoration-line: underline; @@ -1229,22 +1222,22 @@ crosscheck(({ stable, oxide }) => { corePlugins: { preflight: false }, plugins: [ function ({ addVariant, matchVariant }) { - addVariant('foo1', '&[data-foo=1]') - addVariant('foo2', '&[data-foo=2]') + addVariant('foo1', "&[data-foo='1']") + addVariant('foo2', "&[data-foo='2']") - matchVariant('bar', (value) => `&[data-bar=${value}]`, { + matchVariant('bar', (value) => `&[data-bar='${value}']`, { sort: (a, b) => b.value - a.value, }) - addVariant('baz1', '&[data-baz=1]') - addVariant('baz2', '&[data-baz=2]') + addVariant('baz1', "&[data-baz='1']") + addVariant('baz2', "&[data-baz='2']") - matchVariant('qux', (value) => `&[data-qux=${value}]`, { + matchVariant('qux', (value) => `&[data-qux='${value}']`, { sort: (a, b) => b.value - a.value, }) - addVariant('fred1', '&[data-fred=1]') - addVariant('fred2', '&[data-fred=2]') + addVariant('fred1', "&[data-fred='1']") + addVariant('fred2', "&[data-fred='2']") }, ], } @@ -1255,99 +1248,37 @@ crosscheck(({ stable, oxide }) => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'], .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { padding: 0.25rem; } diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 11f8c30b7..b64878032 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -505,7 +505,7 @@ crosscheck(({ stable, oxide }) => { content: [{ raw: html`
` }], theme: { boxShadow: { - lg: 'var(-a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', + lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', }, }, corePlugins: { preflight: false }, @@ -518,7 +518,7 @@ crosscheck(({ stable, oxide }) => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .shadow-lg { - --tw-shadow: var(-a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0); + --tw-shadow: var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0); --tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color), 0 0 1px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), @@ -571,12 +571,8 @@ crosscheck(({ stable, oxide }) => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .bg-\[url\(\'\/images\/one-two-three\.png\'\)\2c - linear-gradient\(to_right\2c - _\#eeeeee\2c - _\#000000\)\] { - background-image: url('/images/one-two-three.png'), - linear-gradient(to right, #eeeeee, #000000); + .bg-\[url\(\'\/images\/one-two-three\.png\'\)\,linear-gradient\(to_right\,_\#eeeeee\,_\#000000\)\] { + background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000); } `) }) diff --git a/tests/preflight.test.js b/tests/preflight.test.js index 76b5ab93a..4f6f722c7 100644 --- a/tests/preflight.test.js +++ b/tests/preflight.test.js @@ -1,6 +1,6 @@ import { crosscheck, run, html, css } from './util/run' -crosscheck(() => { +crosscheck(({ stable, oxide }) => { it('preflight has a correct border color fallback', () => { let config = { content: [{ raw: html`
` }], @@ -17,7 +17,9 @@ crosscheck(() => { ` return run(input, config).then((result) => { - expect(result.css).toContain(`border-color: currentColor;`) + stable.expect(result.css).toContain(`border-color: currentColor;`) + // Lightning CSS optimizes this to just `border-color: 0 solid;` based on the br value. + oxide.expect(result.css).toContain(`border: 0 solid;`) }) }) }) diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index 39ce7555c..cb7d5f1af 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -2,8 +2,9 @@ import postcss from 'postcss' import { parseSourceMaps } from './util/source-maps' import { crosscheck, runWithSourceMaps as run, html, css, map } from './util/run' -crosscheck(() => { - it('apply generates source maps', async () => { +crosscheck(({ stable, oxide }) => { + oxide.test.todo('apply generates source maps') + stable.test('apply generates source maps', async () => { let config = { content: [ { @@ -65,7 +66,8 @@ crosscheck(() => { ]) }) - it('preflight + base have source maps', async () => { + oxide.test.todo('preflight + base have source maps') + stable.test('preflight + base have source maps', async () => { let config = { content: [], } @@ -386,7 +388,8 @@ crosscheck(() => { ]) }) - test('utilities have source maps', async () => { + oxide.test.todo('utilities have source maps') + stable.test('utilities have source maps', async () => { let config = { content: [{ raw: `text-red-500` }], } @@ -411,7 +414,8 @@ crosscheck(() => { ]) }) - it('components have source maps', async () => { + oxide.test.todo('components have source maps') + stable.test('components have source maps', async () => { let config = { content: [{ raw: `container` }], } @@ -460,58 +464,62 @@ crosscheck(() => { ]) }) - it('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { - let config = { - content: [{ raw: `font-normal foo hover:foo` }], - } + oxide.test.todo('source maps for layer rules are not rewritten to point to @tailwind directives') + stable.test( + 'source maps for layer rules are not rewritten to point to @tailwind directives', + async () => { + let config = { + content: [{ raw: `font-normal foo hover:foo` }], + } - let utilitiesFile = postcss.parse( - css` - @tailwind utilities; - `, - { from: 'components.css', map: { prev: map } } - ) + let utilitiesFile = postcss.parse( + css` + @tailwind utilities; + `, + { from: 'components.css', map: { prev: map } } + ) - let mainCssFile = postcss.parse( - css` - @layer utilities { - .foo { - background-color: red; + let mainCssFile = postcss.parse( + css` + @layer utilities { + .foo { + background-color: red; + } } - } - `, - { from: 'input.css', map: { prev: map } } - ) + `, + { from: 'input.css', map: { prev: map } } + ) - // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` - let input = postcss.root({ - nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], - source: mainCssFile.source, - }) + // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` + let input = postcss.root({ + nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], + source: mainCssFile.source, + }) - let result = await run(input, config) + let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) + let { sources, annotations } = parseSourceMaps(result) - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') - // And we should see that the source map for the layer rule is not rewritten - // to point to the @tailwind directive but instead points to the original - expect(sources.length).toBe(2) - expect(sources).toEqual(['components.css', 'input.css']) + // And we should see that the source map for the layer rule is not rewritten + // to point to the @tailwind directive but instead points to the original + expect(sources.length).toBe(2) + expect(sources).toEqual(['components.css', 'input.css']) - expect(annotations).toEqual([ - '2:8 -> 1:0', - '2:8 -> 2:12', - '2:27 -> 3:0', - '3:10 -> 4:10', - '4:12-33 -> 5:12-33', - '5:10 -> 6:10', - '3:10 -> 7:10', - '4:12-33 -> 8:12-33', - '5:10 -> 9:10', - ]) - }) + expect(annotations).toEqual([ + '2:10 -> 1:0', + '2:10 -> 2:14', + '2:29 -> 3:0', + '3:12 -> 4:12', + '4:14-35 -> 5:14-35', + '5:12 -> 6:12', + '3:12 -> 7:12', + '4:14-35 -> 8:14-35', + '5:12 -> 9:12', + ]) + } + ) }) diff --git a/tests/util/source-maps.js b/tests/util/source-maps.js index 695ba91f6..4ed263126 100644 --- a/tests/util/source-maps.js +++ b/tests/util/source-maps.js @@ -6,7 +6,7 @@ import { SourceMapConsumer } from 'source-map-js' * @param {import('postcss').Result} result */ export function parseSourceMaps(result) { - const map = result.map.toJSON() + let map = result.map.toJSON() return { sources: map.sources,