From 1cd5753ceb17399ff3b867e840d4d65528437572 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 26 Jul 2023 11:45:56 +0200 Subject: [PATCH 1/3] parse the `calc()`-like expressions and format them --- src/util/dataTypes.js | 63 ++++++++++++++++++++++++------ tests/normalize-data-types.test.js | 19 +++++++++ 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js index 2f01aa3d20d0..03f6994e75ed 100644 --- a/src/util/dataTypes.js +++ b/src/util/dataTypes.js @@ -10,9 +10,6 @@ function isCSSFunction(value) { return cssFunctions.some((fn) => new RegExp(`^${fn}\\(.*\\)`).test(value)) } -const placeholder = '--tw-placeholder' -const placeholderRe = new RegExp(placeholder, 'g') - // This is not a data type, but rather a function that can normalize the // correct values. export function normalize(value, isRoot = true) { @@ -63,15 +60,59 @@ export function normalize(value, isRoot = true) { */ function normalizeMathOperatorSpacing(value) { return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { - let vars = [] + let result = '' - return match - .replace(/var\((--.+?)[,)]/g, (match, g1) => { - vars.push(g1) - return match.replace(g1, placeholder) - }) - .replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ') - .replace(placeholderRe, () => vars.shift()) + function lastChar() { + let char = result.trimEnd() + return char[char.length - 1] + } + + for (let i = 0; i < match.length; i++) { + function peek(word) { + return word.split('').every((char, j) => match[i + j] === char) + } + + function consumeUntil(chars) { + let minIndex = Infinity + for (let char of chars) { + let index = match.indexOf(char, i) + if (index !== -1 && index < minIndex) { + minIndex = index + } + } + + let result = match.slice(i, minIndex) + i += result.length - 1 + return result + } + + let char = match[i] + + // Handle `var(--variable)` + if (peek('var')) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([')', ',']) + } + + // Handle operators + else if ( + ['+', '-', '*', '/'].includes(char) && + !['(', '+', '-', '*', '/'].includes(lastChar()) + ) { + result += ` ${char} ` + } else { + result += char + } + } + + // Simplify multiple spaces + return result.replace(/\s+/g, ' ') }) } diff --git a/tests/normalize-data-types.test.js b/tests/normalize-data-types.test.js index d99ce1c1875b..1d2a8aed758c 100644 --- a/tests/normalize-data-types.test.js +++ b/tests/normalize-data-types.test.js @@ -41,6 +41,25 @@ let table = [ ['var(--my-var-with-more-than-3-words)', 'var(--my-var-with-more-than-3-words)'], ['var(--width, calc(100%+1rem))', 'var(--width, calc(100% + 1rem))'], + ['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'], + ['calc((7-3)/(1400-782))', 'calc((7 - 3) / (1400 - 782))'], + ['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'], + ['calc((70-3)/(1400-782))', 'calc((70 - 3) / (1400 - 782))'], + ['calc((70-32)/(1400-782))', 'calc((70 - 32) / (1400 - 782))'], + ['calc((704-3)/(1400-782))', 'calc((704 - 3) / (1400 - 782))'], + ['calc((704-320))', 'calc((704 - 320))'], + ['calc((704-320)/1)', 'calc((704 - 320) / 1)'], + ['calc((704-320)/(1400-782))', 'calc((704 - 320) / (1400 - 782))'], + ['calc(24px+-1rem)', 'calc(24px + -1rem)'], + ['calc(24px+(-1rem))', 'calc(24px + (-1rem))'], + ['calc(24px_+_-1rem)', 'calc(24px + -1rem)'], + ['calc(24px+(-1rem))', 'calc(24px + (-1rem))'], + ['calc(24px_+_(-1rem))', 'calc(24px + (-1rem))'], + [ + 'calc(var(--10-10px,calc(-20px-(-30px--40px)-50px)', + 'calc(var(--10-10px,calc(-20px - (-30px - -40px) - 50px)', + ], + // Misc ['color(0_0_0/1.0)', 'color(0 0 0/1.0)'], ['color(0_0_0_/_1.0)', 'color(0 0 0 / 1.0)'], From 4bf575cb4011dacd813c4d8d491aadc56ff50c02 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 26 Jul 2023 12:08:33 +0200 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3897a901548..51ca1d6aff35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump `jiti`, `lightningcss`, `fast-glob` and `browserlist` dependencies and reflect `lightningcss` related improvements in tests ([#11550](https://github.com/tailwindlabs/tailwindcss/pull/11550)) - Make PostCSS plugin async to improve performance ([#11548](https://github.com/tailwindlabs/tailwindcss/pull/11548)) - Allow variant to be an at-rule without a prelude ([#11589](https://github.com/tailwindlabs/tailwindcss/pull/11589)) +- Improve normalisation of `calc()`-like functions ([#11686](https://github.com/tailwindlabs/tailwindcss/pull/11686)) ### Added From c3b779c5a03338aca356c0d7b5be3bf676e21155 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 26 Jul 2023 09:09:52 -0400 Subject: [PATCH 3/3] Add test case for double negatives wanted to be sure this worked --- tests/normalize-data-types.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/normalize-data-types.test.js b/tests/normalize-data-types.test.js index 1d2a8aed758c..d72005589b5b 100644 --- a/tests/normalize-data-types.test.js +++ b/tests/normalize-data-types.test.js @@ -41,6 +41,7 @@ let table = [ ['var(--my-var-with-more-than-3-words)', 'var(--my-var-with-more-than-3-words)'], ['var(--width, calc(100%+1rem))', 'var(--width, calc(100% + 1rem))'], + ['calc(1px*(7--12/24))', 'calc(1px * (7 - -12 / 24))'], ['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'], ['calc((7-3)/(1400-782))', 'calc((7 - 3) / (1400 - 782))'], ['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'],