Skip to content

Commit a79a96e

Browse files
Fix template migration issues
1 parent c01b825 commit a79a96e

File tree

11 files changed

+151
-20
lines changed

11 files changed

+151
-20
lines changed

integrations/upgrade/index.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,97 @@ test(
261261
)
262262
},
263263
)
264+
265+
test(
266+
`migrates prefixes even if other files have unprefixed versions of the candidate`,
267+
{
268+
fs: {
269+
'package.json': json`
270+
{
271+
"dependencies": {
272+
"@tailwindcss/upgrade": "workspace:^"
273+
}
274+
}
275+
`,
276+
'tailwind.config.js': js`
277+
/** @type {import('tailwindcss').Config} */
278+
module.exports = {
279+
content: ['./src/**/*.{html,js}'],
280+
prefix: 'tw__',
281+
}
282+
`,
283+
'src/index.html': html`
284+
<div class="tw__flex flex tw__flex"></div>
285+
`,
286+
'src/other.html': html`
287+
<div class="flex tw__flex flex"></div>
288+
`,
289+
'src/input.css': css`
290+
@tailwind base;
291+
@tailwind components;
292+
@tailwind utilities;
293+
`,
294+
},
295+
},
296+
async ({ exec, fs }) => {
297+
console.log(await exec('npx @tailwindcss/upgrade -c tailwind.config.js'))
298+
299+
await fs.expectFileToContain(
300+
'src/index.html',
301+
html`
302+
<div class="tw:flex flex tw:flex"></div>
303+
`,
304+
)
305+
await fs.expectFileToContain(
306+
'src/other.html',
307+
html`
308+
<div class="flex tw:flex flex"></div>
309+
`,
310+
)
311+
},
312+
)
313+
314+
test(
315+
`prefixed variants do not cause their unprefixed counterparts to be valid`,
316+
{
317+
fs: {
318+
'package.json': json`
319+
{
320+
"dependencies": {
321+
"@tailwindcss/upgrade": "workspace:^"
322+
}
323+
}
324+
`,
325+
'tailwind.config.js': js`
326+
/** @type {import('tailwindcss').Config} */
327+
module.exports = {
328+
content: ['./src/**/*.{html,js}'],
329+
prefix: 'tw__',
330+
}
331+
`,
332+
'src/index.html': html`
333+
<div class="tw__bg-gradient-to-t"></div>
334+
`,
335+
'src/other.html': html`
336+
<div class="bg-gradient-to-t"></div>
337+
`,
338+
},
339+
},
340+
async ({ exec, fs }) => {
341+
await exec('npx @tailwindcss/upgrade -c tailwind.config.js')
342+
343+
await fs.expectFileToContain(
344+
'src/index.html',
345+
html`
346+
<div class="tw:bg-linear-to-t"></div>
347+
`,
348+
)
349+
350+
await fs.expectFileToContain(
351+
'src/other.html',
352+
html`
353+
<div class="bg-gradient-to-t"></div>
354+
`,
355+
)
356+
},
357+
)

integrations/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function test(
7474
) {
7575
return (only || (!process.env.CI && debug) ? defaultTest.only : defaultTest)(
7676
name,
77-
{ timeout: TEST_TIMEOUT, retry: 3 },
77+
{ timeout: TEST_TIMEOUT, retry: debug ? 0 : 3 },
7878
async (options) => {
7979
let rootDir = debug ? path.join(REPO_ROOT, '.debug') : TMP_ROOT
8080
await fs.mkdir(rootDir, { recursive: true })

packages/@tailwindcss-upgrade/src/template/candidates.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ test('extracts candidates with positions from a template', async () => {
1414
base: __dirname,
1515
})
1616

17-
let candidates = await extractRawCandidates(content)
17+
let candidates = await extractRawCandidates(content, 'html')
1818
let validCandidates = candidates.filter(
1919
({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0,
2020
)
@@ -60,7 +60,7 @@ test('replaces the right positions for a candidate', async () => {
6060
base: __dirname,
6161
})
6262

63-
let candidates = await extractRawCandidates(content)
63+
let candidates = await extractRawCandidates(content, 'html')
6464

6565
let candidate = candidates.find(
6666
({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0,

packages/@tailwindcss-upgrade/src/template/candidates.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,24 @@ import type { DesignSystem } from '../../../tailwindcss/src/design-system'
55

66
export async function extractRawCandidates(
77
content: string,
8+
extension: string,
89
): Promise<{ rawCandidate: string; start: number; end: number }[]> {
910
let scanner = new Scanner({})
10-
let result = scanner.getCandidatesWithPositions({ content, extension: 'html' })
11+
let result = scanner.getCandidatesWithPositions({ content, extension })
12+
13+
// Create a map to remove duplicates
14+
let candidatesMap = new Map<string, { rawCandidate: string; start: number; end: number }>()
1115

12-
let candidates: { rawCandidate: string; start: number; end: number }[] = []
1316
for (let { candidate: rawCandidate, position: start } of result) {
14-
candidates.push({ rawCandidate, start, end: start + rawCandidate.length })
17+
let end = start + rawCandidate.length
18+
candidatesMap.set(`${start}:${end}:${rawCandidate}`, {
19+
rawCandidate,
20+
start,
21+
end: start + rawCandidate.length,
22+
})
1523
}
16-
return candidates
24+
25+
return [...candidatesMap.values()]
1726
}
1827

1928
export function printCandidate(designSystem: DesignSystem, candidate: Candidate) {

packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Config } from 'tailwindcss'
22
import { walk, WalkAction } from '../../../../tailwindcss/src/ast'
3-
import type { Candidate, Variant } from '../../../../tailwindcss/src/candidate'
3+
import { type Candidate, type Variant } from '../../../../tailwindcss/src/candidate'
44
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
55
import { printCandidate } from '../candidates'
66

@@ -9,7 +9,11 @@ export function automaticVarInjection(
99
_userConfig: Config,
1010
rawCandidate: string,
1111
): string {
12-
for (let candidate of designSystem.parseCandidate(rawCandidate)) {
12+
for (let readonlyCandidate of designSystem.parseCandidate(rawCandidate)) {
13+
// The below logic makes extended use of mutation. Since candidates in the
14+
// DesignSystem are cached, we can't mutate them directly.
15+
let candidate = structuredClone(readonlyCandidate) as Candidate
16+
1317
let didChange = false
1418

1519
// Add `var(…)` in modifier position, e.g.:

packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ export function bgGradient(
99
_userConfig: Config,
1010
rawCandidate: string,
1111
): string {
12+
/**
13+
* Iterates over the candidates parsed from the raw candidate string, and processes each candidate that represents a Tailwind CSS background gradient utility.
14+
*
15+
* For each candidate that starts with "bg-gradient-to-", this function checks if the direction is valid, and if so, updates the candidate's root to use the "bg-linear-to-" prefix instead.
16+
* The updated candidate is then returned for further processing.
17+
*
18+
* @param designSystem - The design system configuration object.
19+
* @param rawCandidate - The raw candidate string to be parsed and processed.
20+
* @returns The updated candidate string, or the original rawCandidate if no processing was done.
21+
*/
1222
for (let candidate of designSystem.parseCandidate(rawCandidate)) {
1323
if (candidate.kind === 'static' && candidate.root.startsWith('bg-gradient-to-')) {
1424
let direction = candidate.root.slice(15)
@@ -17,8 +27,10 @@ export function bgGradient(
1727
continue
1828
}
1929

20-
candidate.root = `bg-linear-to-${direction}`
21-
return printCandidate(designSystem, candidate)
30+
return printCandidate(designSystem, {
31+
...candidate,
32+
root: `bg-linear-to-${direction}`,
33+
})
2234
}
2335
}
2436
return rawCandidate

packages/@tailwindcss-upgrade/src/template/codemods/important.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Config } from 'tailwindcss'
2+
import { parseCandidate } from '../../../../tailwindcss/src/candidate'
23
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
34
import { printCandidate } from '../candidates'
45

@@ -19,7 +20,7 @@ export function important(
1920
_userConfig: Config,
2021
rawCandidate: string,
2122
): string {
22-
for (let candidate of designSystem.parseCandidate(rawCandidate)) {
23+
for (let candidate of parseCandidate(rawCandidate, designSystem)) {
2324
if (candidate.important && candidate.raw[candidate.raw.length - 1] !== '!') {
2425
// The printCandidate function will already put the exclamation mark in
2526
// the right place, so we just need to mark this candidate as requiring a

packages/@tailwindcss-upgrade/src/template/codemods/prefix.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Config } from 'tailwindcss'
2-
import type { Candidate } from '../../../../tailwindcss/src/candidate'
2+
import { parseCandidate, type Candidate } from '../../../../tailwindcss/src/candidate'
33
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
44
import { segment } from '../../../../tailwindcss/src/utils/segment'
55
import { printCandidate } from '../candidates'
@@ -24,7 +24,10 @@ export function prefix(
2424
let unprefixedCandidate =
2525
rawCandidate.slice(0, v3Base.start) + v3Base.base + rawCandidate.slice(v3Base.end)
2626

27-
let candidates = designSystem.parseCandidate(unprefixedCandidate)
27+
// Note: This is not a valid candidate in the original DesignSystem, so we
28+
// can not use the `DesignSystem#parseCandidate` API here or otherwise this
29+
// invalid candidate will be cached.
30+
let candidates = [...parseCandidate(unprefixedCandidate, designSystem)]
2831
if (candidates.length > 0) {
2932
candidate = candidates[0]
3033
}

packages/@tailwindcss-upgrade/src/template/codemods/variant-order.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Config } from 'tailwindcss'
22
import { walk, type AstNode } from '../../../../tailwindcss/src/ast'
3-
import type { Variant } from '../../../../tailwindcss/src/candidate'
3+
import { type Variant } from '../../../../tailwindcss/src/candidate'
44
import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
55
import { printCandidate } from '../candidates'
66

packages/@tailwindcss-upgrade/src/template/migrate.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import fs from 'node:fs/promises'
2-
import path from 'node:path'
2+
import path, { extname } from 'node:path'
33
import type { Config } from 'tailwindcss'
44
import type { DesignSystem } from '../../../tailwindcss/src/design-system'
55
import { extractRawCandidates, replaceCandidateInContent } from './candidates'
@@ -38,8 +38,9 @@ export default async function migrateContents(
3838
designSystem: DesignSystem,
3939
userConfig: Config,
4040
contents: string,
41+
extension: string,
4142
): Promise<string> {
42-
let candidates = await extractRawCandidates(contents)
43+
let candidates = await extractRawCandidates(contents, extension)
4344

4445
// Sort candidates by starting position desc
4546
candidates.sort((a, z) => z.start - a.start)
@@ -49,6 +50,8 @@ export default async function migrateContents(
4950
let migratedCandidate = migrateCandidate(designSystem, userConfig, rawCandidate)
5051

5152
if (migratedCandidate !== rawCandidate) {
53+
console.error('DOING WORK!!!!!!!!!!!')
54+
console.log('start', start, 'end', end, migratedCandidate, rawCandidate)
5255
output = replaceCandidateInContent(output, migratedCandidate, start, end)
5356
}
5457
}
@@ -60,5 +63,10 @@ export async function migrate(designSystem: DesignSystem, userConfig: Config, fi
6063
let fullPath = path.resolve(process.cwd(), file)
6164
let contents = await fs.readFile(fullPath, 'utf-8')
6265

63-
await fs.writeFile(fullPath, await migrateContents(designSystem, userConfig, contents))
66+
console.log('> ', fullPath)
67+
68+
await fs.writeFile(
69+
fullPath,
70+
await migrateContents(designSystem, userConfig, contents, extname(file)),
71+
)
6472
}

0 commit comments

Comments
 (0)