Robin Malfait 49484f0491
Do not migrate legacy classes with custom values (#14976)
This PR fixes an issue where we migrated classes such as `rounded` to
`rounded-sm` (see:
https://github.com/tailwindlabs/tailwindcss/pull/14875)

However, if you override the values in your `tailwind.config.js` file,
then the migration might not be correct.

This PR makes sure to only migrate the classes if you haven't overridden
the values in your `tailwind.config.js` file.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-11-14 11:31:05 +01:00

103 lines
3.0 KiB
TypeScript

import fs from 'node:fs/promises'
import path, { extname } from 'node:path'
import type { Config } from 'tailwindcss'
import type { DesignSystem } from '../../../tailwindcss/src/design-system'
import { extractRawCandidates } from './candidates'
import { arbitraryValueToBareValue } from './codemods/arbitrary-value-to-bare-value'
import { automaticVarInjection } from './codemods/automatic-var-injection'
import { bgGradient } from './codemods/bg-gradient'
import { important } from './codemods/important'
import { legacyArbitraryValues } from './codemods/legacy-arbitrary-values'
import { legacyClasses } from './codemods/legacy-classes'
import { maxWidthScreen } from './codemods/max-width-screen'
import { modernizeArbitraryValues } from './codemods/modernize-arbitrary-values'
import { prefix } from './codemods/prefix'
import { simpleLegacyClasses } from './codemods/simple-legacy-classes'
import { themeToVar } from './codemods/theme-to-var'
import { variantOrder } from './codemods/variant-order'
import { spliceChangesIntoString, type StringChange } from './splice-changes-into-string'
export type Migration = (
designSystem: DesignSystem,
userConfig: Config,
rawCandidate: string,
location?: {
contents: string
start: number
end: number
},
) => string | Promise<string>
export const DEFAULT_MIGRATIONS: Migration[] = [
prefix,
important,
bgGradient,
simpleLegacyClasses,
legacyClasses,
maxWidthScreen,
themeToVar,
variantOrder, // Has to happen before migrations that modify variants
automaticVarInjection,
legacyArbitraryValues,
arbitraryValueToBareValue,
modernizeArbitraryValues,
]
export async function migrateCandidate(
designSystem: DesignSystem,
userConfig: Config,
rawCandidate: string,
// Location is only set when migrating a candidate from a source file
location?: {
contents: string
start: number
end: number
},
): Promise<string> {
for (let migration of DEFAULT_MIGRATIONS) {
rawCandidate = await migration(designSystem, userConfig, rawCandidate, location)
}
return rawCandidate
}
export default async function migrateContents(
designSystem: DesignSystem,
userConfig: Config,
contents: string,
extension: string,
): Promise<string> {
let candidates = await extractRawCandidates(contents, extension)
let changes: StringChange[] = []
for (let { rawCandidate, start, end } of candidates) {
let migratedCandidate = await migrateCandidate(designSystem, userConfig, rawCandidate, {
contents,
start,
end,
})
if (migratedCandidate === rawCandidate) {
continue
}
changes.push({
start,
end,
replacement: migratedCandidate,
})
}
return spliceChangesIntoString(contents, changes)
}
export async function migrate(designSystem: DesignSystem, userConfig: Config, file: string) {
let fullPath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file)
let contents = await fs.readFile(fullPath, 'utf-8')
await fs.writeFile(
fullPath,
await migrateContents(designSystem, userConfig, contents, extname(file)),
)
}