Robin Malfait d325e70496
Convert , to in grid-cols-[…], grid-rows-[…], and object-[…] (#14927)
This PR converts legacy commas in arbitrary values to spaces.

In Tailwind CSS v3, we allowed commas in arbitrary values for
`grid-cols-[…]`, `grid-rows-[…]`, and `object-[…]` for backwards
compatibility. The underlying CSS value did use spaces instead of
commas.

This PR adds a code mod where convert the commas to spaces when we see
them.


Test plan:
---

Running this on Catalyst it goes from this:

<img width="393" alt="image"
src="https://github.com/user-attachments/assets/03cbda73-41f9-4601-b77a-5b511226b876">

To the expected value of:

<img width="376" alt="image"
src="https://github.com/user-attachments/assets/dd9bbe01-5eb1-4340-937b-70c435e7e4f0">

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-11-11 10:26:37 -05:00

101 lines
2.9 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 { 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
export const DEFAULT_MIGRATIONS: Migration[] = [
prefix,
important,
bgGradient,
simpleLegacyClasses,
maxWidthScreen,
themeToVar,
variantOrder, // Has to happen before migrations that modify variants
automaticVarInjection,
legacyArbitraryValues,
arbitraryValueToBareValue,
modernizeArbitraryValues,
]
export 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
},
): string {
for (let migration of DEFAULT_MIGRATIONS) {
rawCandidate = 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 = 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)),
)
}