Skip to content

Commit b4a20af

Browse files
authored
Improve upgrade tool to pretty print --spacing(2) (#15596)
This PR improves the upgrade tool to make sure that newly upgraded `--spacing(2)` CSS functions is pretty printed to prevent unambiguous looking classes (even though it compiles correctly). If you have a class such as `m-[calc(100dvh-theme(spacing.2))]`, then we used to convert it to `m-[calc(100dvh-calc(var(--spacing)*2))]`. But recently we introduced the `--spacing(2)` CSS function which means that the output now looks like this instead: `m-[calc(100dvh---spacing(2))]`. The triple `-` is valid because the first `-` is the minus sign, the next two `-` characters are from the function. One solution is to introduce spaces via underscores: ``` m-[calc(100dvh_-_--spacing(2))] ``` But a simpler solution, is to wrap the `--spacing(2)` in parens to remove the underscores and improve the readability of the `---` characters. ``` m-[calc(100dvh-(--spacing(2)))] ```
1 parent 27f8bab commit b4a20af

File tree

4 files changed

+43
-2
lines changed

4 files changed

+43
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- Add missing `main` and `browser` fields for `@tailwindcss/browser` ([#15594](https://github.com/tailwindlabs/tailwindcss/pull/15594))
13+
- _Upgrade (experimental)_: Pretty print `--spacing(…)` to prevent ambiguity ([#15596](https://github.com/tailwindlabs/tailwindcss/pull/15596))
1314

1415
## [4.0.0-beta.9] - 2025-01-09
1516

packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ test.each([
2222
['bg-[theme(colors.red.500)]', 'bg-(--color-red-500)'], // Arbitrary value
2323
['bg-[size:theme(spacing.4)]', 'bg-[size:--spacing(4)]'], // Arbitrary value + data type hint
2424

25+
// Pretty print CSS functions preceded by an operator to prevent consecutive
26+
// operator characters.
27+
['w-[calc(100dvh-theme(spacing.2))]', 'w-[calc(100dvh-(--spacing(2)))]'],
28+
['w-[calc(100dvh+theme(spacing.2))]', 'w-[calc(100dvh+(--spacing(2)))]'],
29+
['w-[calc(100dvh/theme(spacing.2))]', 'w-[calc(100dvh/(--spacing(2)))]'],
30+
['w-[calc(100dvh*theme(spacing.2))]', 'w-[calc(100dvh*(--spacing(2)))]'],
31+
2532
// Convert to `var(…)` if we can resolve the path, but keep fallback values
2633
['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'],
2734

packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ function substituteFunctionsInValue(
237237
ast: ValueParser.ValueAstNode[],
238238
handle: (value: string, fallback?: string) => string | null,
239239
) {
240-
ValueParser.walk(ast, (node, { replaceWith }) => {
240+
ValueParser.walk(ast, (node, { parent, replaceWith }) => {
241241
if (node.kind === 'function' && node.value === 'theme') {
242242
if (node.nodes.length < 1) return
243243

@@ -275,6 +275,37 @@ function substituteFunctionsInValue(
275275
fallbackValues.length > 0 ? handle(path, ValueParser.toCss(fallbackValues)) : handle(path)
276276
if (replacement === null) return
277277

278+
if (parent) {
279+
let idx = parent.nodes.indexOf(node) - 1
280+
while (idx !== -1) {
281+
let previous = parent.nodes[idx]
282+
// Skip the space separator
283+
if (previous.kind === 'separator' && previous.value.trim() === '') {
284+
idx -= 1
285+
continue
286+
}
287+
288+
// If the previous node is a word and contains an operator, we need to
289+
// wrap the replacement in parentheses to make the output less
290+
// ambiguous.
291+
//
292+
// Input:
293+
// - `calc(100dvh-theme(spacing.2))`
294+
//
295+
// Output:
296+
// - `calc(100dvh-(--spacing(2)))`
297+
//
298+
// Not:
299+
// -`calc(100dvh---spacing(2))`
300+
//
301+
if (/^[-+*/]$/.test(previous.value.trim())) {
302+
replacement = `(${replacement})`
303+
}
304+
305+
break
306+
}
307+
}
308+
278309
replaceWith(ValueParser.parse(replacement))
279310
}
280311
})

packages/tailwindcss/src/css-functions.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,9 @@ describe('--theme(…)', () => {
177177
color: --theme(colors.red.500);
178178
}
179179
`),
180-
).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: The --theme(…) function can only be used with CSS variables from your theme.]`)
180+
).rejects.toThrowErrorMatchingInlineSnapshot(
181+
`[Error: The --theme(…) function can only be used with CSS variables from your theme.]`,
182+
)
181183
})
182184
})
183185

0 commit comments

Comments
 (0)