From e32e6849b351fc8055ca8cae2af1ddf0dd6cc320 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 15 Oct 2024 00:48:44 +0200 Subject: [PATCH 1/3] convert arbitrary values to bare values --- .../arbitrary-value-to-bare-value.test.ts | 21 ++++++ .../codemods/arbitrary-value-to-bare-value.ts | 69 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts index 2f29c130fb67..152c6ffbd14b 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts @@ -3,6 +3,23 @@ import { expect, test } from 'vitest' import { arbitraryValueToBareValue } from './arbitrary-value-to-bare-value' test.each([ + ['aspect-[12/34]', 'aspect-12/34'], + ['aspect-[1.2/34]', 'aspect-[1.2/34]'], + ['col-start-[7]', 'col-start-7'], + ['flex-[2]', 'flex-2'], // `flex` is implemented as static and functional utilities + + // Only 50-200% (inclusive) are valid: + // https://developer.mozilla.org/en-US/docs/Web/CSS/font-stretch#percentage + ['font-stretch-[50%]', 'font-stretch-50%'], + ['font-stretch-[201%]', 'font-stretch-[201%]'], + ['font-stretch-[49%]', 'font-stretch-[49%]'], + // Should stay as-is + ['font-stretch-[1/2]', 'font-stretch-[1/2]'], + + // This test in itself is a bit flawed because `text-[1/2]` currently + // generates something. Converting it to `text-1/2` doesn't produce anything. + ['text-[1/2]', 'text-[1/2]'], + ['data-[selected]:flex', 'data-selected:flex'], ['data-[foo=bar]:flex', 'data-[foo=bar]:flex'], @@ -22,6 +39,10 @@ test.each([ ['group-has-aria-[selected]:flex', 'group-has-aria-[selected]:flex'], ['max-lg:hover:data-[selected]:flex!', 'max-lg:hover:data-selected:flex!'], + [ + 'data-[selected]:aria-[selected="true"]:aspect-[12/34]', + 'data-selected:aria-selected:aspect-12/34', + ], ])('%s => %s', async (candidate, result) => { let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { base: __dirname, diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts index 065f10807326..bae2cd856dfa 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts @@ -1,6 +1,7 @@ import type { Config } from 'tailwindcss' import { parseCandidate, type Candidate, type Variant } from '../../../../tailwindcss/src/candidate' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { isPositiveInteger } from '../../../../tailwindcss/src/utils/infer-data-type' import { segment } from '../../../../tailwindcss/src/utils/segment' import { printCandidate } from '../candidates' @@ -12,6 +13,74 @@ export function arbitraryValueToBareValue( for (let candidate of parseCandidate(rawCandidate, designSystem)) { let clone = structuredClone(candidate) let changed = false + + // Convert font-stretch-* utilities + if ( + clone.kind === 'functional' && + clone.value?.kind === 'arbitrary' && + clone.value.dataType === null && + clone.root === 'font-stretch' + ) { + if (clone.value.value.endsWith('%')) { + let percentage = parseFloat(clone.value.value) + if (percentage >= 50 && percentage <= 200) { + changed = true + clone.value = { + kind: 'named', + value: clone.value.value, + fraction: null, + } + } + } + } + + // Convert arbitrary values with positive integers to bare values + // Convert arbitrary values with fractions to bare values + else if ( + clone.kind === 'functional' && + clone.value?.kind === 'arbitrary' && + clone.value.dataType === null + ) { + let parts = segment(clone.value.value, '/') + if (parts.every((part) => isPositiveInteger(part))) { + changed = true + + let currentValue = clone.value + let currentModifier = clone.modifier + + // E.g.: `col-start-[12]` + // ^^ + if (parts.length === 1) { + clone.value = { + kind: 'named', + value: clone.value.value, + fraction: null, + } + } + + // E.g.: `aspect-[12/34]` + // ^^ ^^ + else { + clone.value = { + kind: 'named', + value: parts[0], + fraction: clone.value.value, + } + clone.modifier = { + kind: 'named', + value: parts[1], + } + } + + // Double check that the new value compiles correctly + if (designSystem.compileAstNodes(clone).length === 0) { + clone.value = currentValue + clone.modifier = currentModifier + changed = false + } + } + } + for (let variant of variants(clone)) { // Convert `data-[selected]` to `data-selected` if ( From ab397abb0ab14514e5e89c33f12ce6ab52879909 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 15 Oct 2024 11:16:11 +0200 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6586568c91b3..74ba883757a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - _Upgrade (experimental)_: Migrate `@media screen(…)` when running codemods ([#14603](https://github.com/tailwindlabs/tailwindcss/pull/14603)) - _Upgrade (experimental)_: Inject `@config "…"` when a `tailwind.config.{js,ts,…}` is detected ([#14635](https://github.com/tailwindlabs/tailwindcss/pull/14635)) - _Upgrade (experimental)_: Migrate `aria-*`, `data-*`, and `supports-*` variants from arbitrary values to bare values ([#14644](https://github.com/tailwindlabs/tailwindcss/pull/14644)) +- _Upgrade (experimental)_: Migrate arbitrary values to bare values ([#14669](https://github.com/tailwindlabs/tailwindcss/pull/14669)) ### Fixed From 0d31180b30aa337a6b44205008077c61b0ef482b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 15 Oct 2024 11:40:21 +0200 Subject: [PATCH 3/3] ensure `font-stretch-[50.5%]` stays as an arbitrary value --- .../template/codemods/arbitrary-value-to-bare-value.test.ts | 1 + .../src/template/codemods/arbitrary-value-to-bare-value.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts index 152c6ffbd14b..411f0eb9ee3a 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts @@ -11,6 +11,7 @@ test.each([ // Only 50-200% (inclusive) are valid: // https://developer.mozilla.org/en-US/docs/Web/CSS/font-stretch#percentage ['font-stretch-[50%]', 'font-stretch-50%'], + ['font-stretch-[50.5%]', 'font-stretch-[50.5%]'], ['font-stretch-[201%]', 'font-stretch-[201%]'], ['font-stretch-[49%]', 'font-stretch-[49%]'], // Should stay as-is diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts index bae2cd856dfa..44aa2675db83 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts @@ -21,8 +21,8 @@ export function arbitraryValueToBareValue( clone.value.dataType === null && clone.root === 'font-stretch' ) { - if (clone.value.value.endsWith('%')) { - let percentage = parseFloat(clone.value.value) + if (clone.value.value.endsWith('%') && isPositiveInteger(clone.value.value.slice(0, -1))) { + let percentage = parseInt(clone.value.value) if (percentage >= 50 && percentage <= 200) { changed = true clone.value = {