Repository: tailwindlabs/tailwindcss

Problem statement:
Subtraction in `calc()` arbitrary values not always normalized properly
<!-- Please provide all of the information requested below. We're a small team and without all of this information it's not possible for us to help and your bug report will be closed. -->

**What version of Tailwind CSS are you using?**

v3.2.4

**What build tool (or framework if it abstracts the build tool) are you using?**

Tailwind Play, Webpack v5

**What version of Node.js are you using?**

v16.13.0

**What browser are you using?**

Chrome

**What operating system are you using?**

Ubuntu 18.04 via WSL

**Reproduction URL**

https://play.tailwindcss.com/KnpyuskR45

**Describe your issue**

A value like `calc(1-(var(--something)*0.5))` or `calc(1-var(--something)*0.5)` in an arbitrary variant is not normalized properly, with spaces missing around the subtraction operator:
```css
.mt-\[calc\(1-var\(--something\)\*0\.5\)\] {
  margin-top: calc(1-var(--something) * 0.5);
  /* expected margin-top: calc(1 - var(--something) * 0.5); */
}
```
I would have expected this function consistently akin to the other mathematical operators which seem to be fine:
```css
.mt-\[calc\(1\+\(var\(--something\)\*0\.5\)\)\] {
  margin-top: calc(1 + (var(--something) * 0.5));
}
```


Hints:
The only place you can use the calc() function is in values. See these examples where we’re setting the value for a number of different properties.

.el {
  font-size: calc(3vw + 2px);
  width:     calc(100% - 20px);
  height:    calc(100vh - 20px);
  padding:   calc(1vw + 5px);
}

Patch:
diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js
--- a/src/util/dataTypes.js
+++ b/src/util/dataTypes.js
@@ -10,6 +10,9 @@ 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) {
@@ -49,10 +52,14 @@ export function normalize(value, isRoot = true) {
   // Add spaces around operators inside math functions like calc() that do not follow an operator
   // or '('.
   value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => {
-    return match.replace(
-      /(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
-      '$1 $2 '
-    )
+    let vars = []
+    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())
   })
 
   return value


Test patch:
diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css
--- a/tests/arbitrary-values.test.css
+++ b/tests/arbitrary-values.test.css
@@ -191,6 +191,15 @@
 .w-\[\'\}\{\}\'\] {
   width: '}{}';
 }
+.min-w-\[calc\(1-var\(--something\)\*0\.5\)\] {
+  min-width: calc(1 - var(--something) * 0.5);
+}
+.min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] {
+  min-width: calc(1 - (var(--something) * 0.5));
+}
+.min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] {
+  min-width: calc(1 - ((12 - 3) * 0.5));
+}
 .min-w-\[3\.23rem\] {
   min-width: 3.23rem;
 }
diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html
--- a/tests/arbitrary-values.test.html
+++ b/tests/arbitrary-values.test.html
@@ -67,6 +67,9 @@
     <div class="w-[var(--width)]"></div>
     <div class="w-[var(--width,calc(100%+1rem))]"></div>
     <div class="w-[calc(100%/3-1rem*2)]"></div>
+    <div class="min-w-[calc(1-var(--something)*0.5)]"></div>
+    <div class="min-w-[calc(1-(var(--something)*0.5))]"></div>
+    <div class="min-w-[calc(1-((12-3)*0.5))]"></div>
 
     <div class="min-w-[3.23rem]"></div>
     <div class="min-w-[calc(100%+1rem)]"></div>