From bd3d6bc09b0eead6ba3dc648688b9489f0d417dc Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 11 Oct 2024 14:22:55 +0200 Subject: [PATCH] Migrate legacy classes to the v4 alternative (#14643) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a mapping from legacy classes to new classes. For example, the `flex-shrink-0` is still used in our projects, but is deprecated in v3. The migration does a tiny bit of parsing because we can't rely on `designSystem.parseCandidate(…)` because this requires the utility to be defined which is not the case for legacy classes. This migration runs _after_ the migration where we handle prefixes, so we don't have to worry about that. We do have to worry about the `!` location, because the `important` migration also relies on the `designSystem`. | Old | New | | ------------------- | ---------------------- | | `overflow-clip` | `text-clip` | | `overflow-ellipsis` | `text-ellipsis` | | `flex-grow-0` | `grow-0` | | `flex-shrink-0` | `shrink-0` | | `decoration-clone` | `box-decoration-clone` | | `decoration-slice` | `box-decoration-slice` | --- CHANGELOG.md | 1 + .../src/template/candidates.ts | 3 +- .../codemods/simple-legacy-classes.test.ts | 22 ++++++++++ .../codemods/simple-legacy-classes.ts | 41 +++++++++++++++++++ .../src/template/migrate.ts | 2 + 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts create mode 100644 packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b5434b04..88314a4ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support `keyframes` in JS config file themes ([#14594](https://github.com/tailwindlabs/tailwindcss/pull/14594)) - _Upgrade (experimental)_: Migrate v3 PostCSS setups to v4 in some cases ([#14612](https://github.com/tailwindlabs/tailwindcss/pull/14612)) - _Upgrade (experimental)_: The upgrade tool now automatically discovers your JavaScript config ([#14597](https://github.com/tailwindlabs/tailwindcss/pull/14597)) +- _Upgrade (experimental)_: Migrate legacy classes to the v4 alternative ([#14643](https://github.com/tailwindlabs/tailwindcss/pull/14643)) ### Fixed diff --git a/packages/@tailwindcss-upgrade/src/template/candidates.ts b/packages/@tailwindcss-upgrade/src/template/candidates.ts index bc422d188..be08477ee 100644 --- a/packages/@tailwindcss-upgrade/src/template/candidates.ts +++ b/packages/@tailwindcss-upgrade/src/template/candidates.ts @@ -5,9 +5,10 @@ import type { DesignSystem } from '../../../tailwindcss/src/design-system' export async function extractRawCandidates( content: string, + extension: string = 'html', ): Promise<{ rawCandidate: string; start: number; end: number }[]> { let scanner = new Scanner({}) - let result = scanner.getCandidatesWithPositions({ content, extension: 'html' }) + let result = scanner.getCandidatesWithPositions({ content, extension }) let candidates: { rawCandidate: string; start: number; end: number }[] = [] for (let { candidate: rawCandidate, position: start } of result) { diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts new file mode 100644 index 000000000..d0a89da58 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts @@ -0,0 +1,22 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { simpleLegacyClasses } from './simple-legacy-classes' + +test.each([ + ['overflow-clip', 'text-clip'], + ['overflow-ellipsis', 'text-ellipsis'], + ['flex-grow-0', 'grow-0'], + ['flex-shrink-0', 'shrink-0'], + ['decoration-clone', 'box-decoration-clone'], + ['decoration-slice', 'box-decoration-slice'], + + ['max-lg:hover:decoration-slice', 'max-lg:hover:box-decoration-slice'], + ['max-lg:hover:decoration-slice!', 'max-lg:hover:box-decoration-slice!'], + ['max-lg:hover:!decoration-slice', 'max-lg:hover:box-decoration-slice!'], +])('%s => %s', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect(simpleLegacyClasses(designSystem, {}, candidate)).toEqual(result) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts new file mode 100644 index 000000000..94a4121f8 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts @@ -0,0 +1,41 @@ +import type { Config } from 'tailwindcss' +import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { printCandidate } from '../candidates' + +// Classes that used to exist in Tailwind CSS v3, but do not exist in Tailwind +// CSS v4 anymore. +const LEGACY_CLASS_MAP = { + 'overflow-clip': 'text-clip', + 'overflow-ellipsis': 'text-ellipsis', + 'flex-grow-0': 'grow-0', + 'flex-shrink-0': 'shrink-0', + 'decoration-clone': 'box-decoration-clone', + 'decoration-slice': 'box-decoration-slice', +} + +const SEEDED = new WeakSet() + +export function simpleLegacyClasses( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, +): string { + // Prepare design system with the legacy classes + if (!SEEDED.has(designSystem)) { + for (let old in LEGACY_CLASS_MAP) { + designSystem.utilities.static(old, () => []) + } + SEEDED.add(designSystem) + } + + for (let candidate of designSystem.parseCandidate(rawCandidate)) { + if (candidate.kind === 'static' && Object.hasOwn(LEGACY_CLASS_MAP, candidate.root)) { + return printCandidate(designSystem, { + ...candidate, + root: LEGACY_CLASS_MAP[candidate.root as keyof typeof LEGACY_CLASS_MAP], + }) + } + } + + return rawCandidate +} diff --git a/packages/@tailwindcss-upgrade/src/template/migrate.ts b/packages/@tailwindcss-upgrade/src/template/migrate.ts index 5fd710d4f..df9d22b15 100644 --- a/packages/@tailwindcss-upgrade/src/template/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/template/migrate.ts @@ -7,6 +7,7 @@ import { automaticVarInjection } from './codemods/automatic-var-injection' import { bgGradient } from './codemods/bg-gradient' import { important } from './codemods/important' import { prefix } from './codemods/prefix' +import { simpleLegacyClasses } from './codemods/simple-legacy-classes' import { variantOrder } from './codemods/variant-order' export type Migration = ( @@ -20,6 +21,7 @@ export const DEFAULT_MIGRATIONS: Migration[] = [ important, automaticVarInjection, bgGradient, + simpleLegacyClasses, variantOrder, ]