From a910242b4dd15daa726ee1abcd3d41b93c2e732f Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 14 Nov 2024 17:47:47 +0100 Subject: [PATCH 01/20] improve deterministic sorting when dumping files 1. Sort by depth first 2. Sort by alphabetical folders 3. Prefer files starting with `index` 4. Sort alphabetically Before this change, when comparing two files, if they both started with `index`, then the sort was non-deterministic. --- integrations/upgrade/index.test.ts | 32 +++++++++++++++--------------- integrations/utils.ts | 12 ++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index ebc251a66c92..e32f299789b3 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1662,14 +1662,14 @@ test( expect(await fs.dumpFiles('./src/**/*.{html,css}')).toMatchInlineSnapshot(` " + --- ./src/index.css --- + @import './tailwind-setup.css'; + --- ./src/index.html ---
- --- ./src/index.css --- - @import './tailwind-setup.css'; - --- ./src/base.css --- @import 'tailwindcss/theme' layer(theme); @import 'tailwindcss/preflight' layer(base); @@ -1797,14 +1797,14 @@ test( expect(await fs.dumpFiles('./src/**/*.{html,css}')).toMatchInlineSnapshot(` " + --- ./src/index.css --- + @import './tailwind-setup.css'; + --- ./src/index.html ---
- --- ./src/index.css --- - @import './tailwind-setup.css'; - --- ./src/base.css --- @import 'tailwindcss/theme' layer(theme); @import 'tailwindcss/preflight' layer(base); @@ -2105,13 +2105,6 @@ test( // Files should not be modified expect(await fs.dumpFiles('./*.{js,css,html}')).toMatchInlineSnapshot(` " - --- index.html --- -
-
-
-
-
- --- index.css --- @import 'tailwindcss'; @@ -2141,6 +2134,13 @@ test( border-color: var(--color-gray-200, currentColor); } } + + --- index.html --- +
+
+
+
+
" `) }, @@ -2196,9 +2196,6 @@ test( // Files should not be modified expect(await fs.dumpFiles('./*.{js,css,html,tsx}')).toMatchInlineSnapshot(` " - --- index.html --- -
- --- index.css --- @import 'tailwindcss'; @@ -2220,6 +2217,9 @@ test( } } + --- index.html --- +
+ --- example-component.tsx --- type Star = [ x: number, diff --git a/integrations/utils.ts b/integrations/utils.ts index 44ee3c6fc66d..7ac7a1147839 100644 --- a/integrations/utils.ts +++ b/integrations/utils.ts @@ -346,15 +346,21 @@ export function test( let zParts = z[0].split('/') let aFile = aParts.at(-1) - let zFile = aParts.at(-1) + let zFile = zParts.at(-1) // Sort by depth, shallow first if (aParts.length < zParts.length) return -1 if (aParts.length > zParts.length) return 1 + // Sort by folder names, alphabetically + for (let i = 0; i < aParts.length - 1; i++) { + let diff = aParts[i].localeCompare(zParts[i]) + if (diff !== 0) return diff + } + // Sort by filename, sort files named `index` before others - if (aFile?.startsWith('index')) return -1 - if (zFile?.startsWith('index')) return 1 + if (aFile?.startsWith('index') && !zFile?.startsWith('index')) return -1 + if (zFile?.startsWith('index') && !aFile?.startsWith('index')) return 1 // Sort by filename, alphabetically return a[0].localeCompare(z[0]) From d6574448ea9ebae708e6b3a2e3e320966b07193c Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 14 Nov 2024 17:48:35 +0100 Subject: [PATCH 02/20] find config file from stylesheet while crawling up This ensures that the closest config file for a stylesheet is linked. We also write some information to the user so they can verify that the paths are correct (and adjust if necessary). --- packages/@tailwindcss-upgrade/src/migrate.ts | 60 +++++++++++++++---- .../src/template/prepare-config.ts | 39 +++++++++--- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index e01ba201defe..8969213ca3ee 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -19,7 +19,7 @@ import { migrateVariantsDirective } from './codemods/migrate-variants-directive' import type { JSConfigMigration } from './migrate-js-config' import { Stylesheet, type StylesheetConnection, type StylesheetId } from './stylesheet' import { detectConfigPath } from './template/prepare-config' -import { error } from './utils/renderer' +import { error, info, relative } from './utils/renderer' import { resolveCssId } from './utils/resolve' import { walk, WalkAction } from './utils/walk' @@ -364,16 +364,54 @@ export async function linkConfigs( // All stylesheets have a `@config` directives if (withoutAtConfig.length === 0) return - try { + // Find the config file path for each stylesheet + let configPathBySheet = new Map() + let sheetByConfigPath = new DefaultMap>(() => new Set()) + for (let sheet of withoutAtConfig) { + if (!sheet.file) continue + + let localConfigPath = configPath as string if (configPath === null) { - configPath = await detectConfigPath(base) - } else if (!path.isAbsolute(configPath)) { - configPath = path.resolve(base, configPath) + localConfigPath = await detectConfigPath(path.dirname(sheet.file), base) + } else if (!path.isAbsolute(localConfigPath)) { + localConfigPath = path.resolve(base, localConfigPath) + } + + info( + `Found config file: \`${relative(localConfigPath, base)}\` for \`${relative(sheet.file, base)}\``, + ) + configPathBySheet.set(sheet, localConfigPath) + sheetByConfigPath.get(localConfigPath).add(sheet) + } + + let problematicStylesheets = new Set() + for (let sheets of sheetByConfigPath.values()) { + if (sheets.size > 1) { + for (let sheet of sheets) { + problematicStylesheets.add(sheet) + } + } + } + + // There are multiple "root" files without `@config` directives. Manual + // intervention is needed to link to the correct Tailwind config files. + if (problematicStylesheets.size > 1) { + let msg = `You have multiple stylesheets that do not have an \`@config\`.\n` + msg += `Please add a \`@config "…";\` referencing the correct Tailwind config file to:\n` + + for (let sheet of problematicStylesheets) { + msg += `- ${relative(sheet.file!, base)}\n` } - // Link the `@config` directive to the root stylesheets - for (let sheet of withoutAtConfig) { - if (!sheet.file) continue + error(msg) + process.exit(1) + } + + for (let [sheet, configPath] of configPathBySheet) { + try { + if (!sheet || !sheet.file) return + + // Link the `@config` directive to the root stylesheets // Track the config file path on the stylesheet itself for easy access // without traversing the CSS ast and finding the corresponding @@ -409,10 +447,10 @@ export async function linkConfigs( target.after(atConfig) } } + } catch (e: any) { + error('Could not load the configuration file: ' + e.message) + process.exit(1) } - } catch (e: any) { - error('Could not load the configuration file: ' + e.message) - process.exit(1) } } diff --git a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts index 5b04e8578cf0..b5efb3d79317 100644 --- a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts +++ b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts @@ -6,7 +6,7 @@ import { loadModule } from '../../../@tailwindcss-node/src/compile' import { resolveConfig } from '../../../tailwindcss/src/compat/config/resolve-config' import type { Config } from '../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../tailwindcss/src/design-system' -import { error } from '../utils/renderer' +import { error, relative } from '../utils/renderer' import { migratePrefix } from './codemods/prefix' const __filename = fileURLToPath(import.meta.url) @@ -94,15 +94,36 @@ const DEFAULT_CONFIG_FILES = [ './tailwind.config.cts', './tailwind.config.mts', ] -export async function detectConfigPath(base: string) { - for (let file of DEFAULT_CONFIG_FILES) { - let fullPath = path.resolve(base, file) - try { - await fs.access(fullPath) - return file - } catch {} +export async function detectConfigPath(start: string, end: string = start) { + for (let base of parentPaths(start, end)) { + for (let file of DEFAULT_CONFIG_FILES) { + let fullPath = path.resolve(base, file) + try { + await fs.access(fullPath) + return fullPath + } catch {} + } } + throw new Error( - 'No configuration file found. Please provide a path to the Tailwind CSS v3 config file via the `--config` option.', + `No configuration file found for \`${relative(start)}\`. Please provide a path to the Tailwind CSS v3 config file via the \`--config\` option.`, ) } + +// Yields all parent paths from `from` to `to` (inclusive on both ends) +function* parentPaths(from: string, to: string = from) { + let fromAbsolute = path.resolve(from) + let toAbsolute = path.resolve(to) + + if (fromAbsolute === toAbsolute) { + yield fromAbsolute + return + } + + let current = fromAbsolute + do { + yield current + current = path.dirname(current) + } while (current !== toAbsolute) + yield toAbsolute +} From dc6e0e18b9c1c7eac2ccfa0618365ef1420706ba Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 14 Nov 2024 17:48:44 +0100 Subject: [PATCH 03/20] add failing tests --- integrations/upgrade/index.test.ts | 184 ++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 28 deletions(-) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index e32f299789b3..f62472bec3bf 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1,3 +1,4 @@ +import { stripVTControlCharacters } from 'node:util' import { expect } from 'vitest' import { candidate, css, html, js, json, test, ts } from '../utils' @@ -1385,9 +1386,7 @@ test( export default { content: ['./src/**/*.{html,js}'], plugins: [ - () => { - // custom stuff which is too complicated to migrate to CSS - }, + () => {}, // custom stuff which is too complicated to migrate to CSS ], } `, @@ -1396,20 +1395,28 @@ test( class="!flex sm:!block bg-gradient-to-t bg-[--my-red]" > `, - 'src/root.1.css': css` + 'src/root.1/index.css': css` /* Inject missing @config */ @tailwind base; @tailwind components; @tailwind utilities; `, - 'src/root.2.css': css` + 'src/root.1/tailwind.config.ts': js` + export default { + content: ['./src/**/*.{html,js}'], + plugins: [ + () => {}, // custom stuff which is too complicated to migrate to CSS + ], + } + `, + 'src/root.2/index.css': css` /* Already contains @config */ @tailwind base; @tailwind components; @tailwind utilities; - @config "../tailwind.config.ts"; + @config "../../tailwind.config.ts"; `, - 'src/root.3.css': css` + 'src/root.3/index.css': css` /* Inject missing @config above first @theme */ @tailwind base; @tailwind components; @@ -1425,18 +1432,35 @@ test( --color-blue-500: #00f; } `, - 'src/root.4.css': css` + 'src/root.3/tailwind.config.ts': js` + export default { + content: ['./src/**/*.{html,js}'], + plugins: [ + () => {}, // custom stuff which is too complicated to migrate to CSS + ], + } + `, + 'src/root.4/index.css': css` /* Inject missing @config due to nested imports with tailwind imports */ - @import './root.4/base.css'; - @import './root.4/utilities.css'; + @import './base.css'; + @import './utilities.css'; `, - 'src/root.4/base.css': css`@import 'tailwindcss/base';`, + 'src/root.4/tailwind.config.ts': js` + export default { + content: ['./src/**/*.{html,js}'], + plugins: [ + () => {}, // custom stuff which is too complicated to migrate to CSS + ], + } + `, + 'src/root.4/base.css': css`@import 'tailwindcss/preflight';`, 'src/root.4/utilities.css': css`@import 'tailwindcss/utilities';`, - 'src/root.5.css': css`@import './root.5/tailwind.css';`, + 'src/root.5/index.css': css`@import './tailwind.css';`, 'src/root.5/tailwind.css': css` /* Inject missing @config in this file, due to full import */ - @import 'tailwindcss/tailwind.css'; + /* Should be located in the root: ../../ */ + @import 'tailwindcss'; `, }, }, @@ -1450,11 +1474,11 @@ test( class="flex! sm:block! bg-linear-to-t bg-(--my-red)" > - --- ./src/root.1.css --- + --- ./src/root.1/index.css --- /* Inject missing @config */ @import 'tailwindcss'; - @config '../tailwind.config.ts'; + @config './tailwind.config.ts'; /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -1474,11 +1498,11 @@ test( } } - --- ./src/root.2.css --- + --- ./src/root.2/index.css --- /* Already contains @config */ @import 'tailwindcss'; - @config "../tailwind.config.ts"; + @config "../../tailwind.config.ts"; /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -1498,11 +1522,11 @@ test( } } - --- ./src/root.3.css --- + --- ./src/root.3/index.css --- /* Inject missing @config above first @theme */ @import 'tailwindcss'; - @config '../tailwind.config.ts'; + @config './tailwind.config.ts'; @variant hocus (&:hover, &:focus); @@ -1532,19 +1556,15 @@ test( } } - --- ./src/root.4.css --- + --- ./src/root.4/index.css --- /* Inject missing @config due to nested imports with tailwind imports */ - @import './root.4/base.css'; - @import './root.4/utilities.css'; - - @config '../tailwind.config.ts'; + @import './base.css'; + @import './utilities.css'; - --- ./src/root.5.css --- - @import './root.5/tailwind.css'; + @config './tailwind.config.ts'; --- ./src/root.4/base.css --- - @import 'tailwindcss/theme' layer(theme); - @import 'tailwindcss/preflight' layer(base); + @import 'tailwindcss/preflight'; /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -1567,8 +1587,12 @@ test( --- ./src/root.4/utilities.css --- @import 'tailwindcss/utilities' layer(utilities); + --- ./src/root.5/index.css --- + @import './tailwind.css'; + --- ./src/root.5/tailwind.css --- /* Inject missing @config in this file, due to full import */ + /* Should be located in the root: ../../ */ @import 'tailwindcss'; @config '../../tailwind.config.ts'; @@ -1595,6 +1619,110 @@ test( }, ) +test( + 'multiple CSS roots that resolve to the same Tailwind config file requires manual intervention', + { + fs: { + 'package.json': json` + { + "dependencies": { + "tailwindcss": "^3", + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': js` + export default { + content: ['./src/**/*.{html,js}'], + plugins: [ + () => {}, // custom stuff which is too complicated to migrate to CSS + ], + } + `, + 'src/index.html': html` +
+ `, + 'src/root.1.css': css` + /* Inject missing @config */ + @tailwind base; + @tailwind components; + @tailwind utilities; + `, + 'src/root.2.css': css` + /* Already contains @config */ + @tailwind base; + @tailwind components; + @tailwind utilities; + @config "../tailwind.config.ts"; + `, + 'src/root.3.css': css` + /* Inject missing @config above first @theme */ + @tailwind base; + @tailwind components; + @tailwind utilities; + + @variant hocus (&:hover, &:focus); + + @theme { + --color-red-500: #f00; + } + + @theme { + --color-blue-500: #00f; + } + `, + 'src/root.4.css': css` + /* Inject missing @config due to nested imports with tailwind imports */ + @import './root.4/base.css'; + @import './root.4/utilities.css'; + `, + 'src/root.4/base.css': css`@import 'tailwindcss/preflight';`, + 'src/root.4/utilities.css': css`@import 'tailwindcss/utilities';`, + + 'src/root.5.css': css`@import './root.5/tailwind.css';`, + 'src/root.5/tailwind.css': css` + /* Inject missing @config in this file, due to full import */ + @import 'tailwindcss/tailwind.css'; + `, + }, + }, + async ({ exec }) => { + let output = await exec('npx @tailwindcss/upgrade --force', {}, { ignoreStdErr: true }).catch( + (e) => e.toString(), + ) + + output = stripVTControlCharacters(output) + .replace(/tailwindcss v(.*)/g, 'tailwindcss') // Remove the version number from the error message + .replace(/\\/g, '/') // Make Windows paths look like Unix paths + + expect(output).toMatchInlineSnapshot(` + "Error: Command failed: npx @tailwindcss/upgrade --force + ≈ tailwindcss + + │ Searching for CSS files in the current directory and its subdirectories… + + │ Found config file: \`./tailwind.config.ts\` for \`./src/root.1.css\` + + │ Found config file: \`./tailwind.config.ts\` for \`./src/root.3.css\` + + │ Found config file: \`./tailwind.config.ts\` for \`./src/root.4.css\` + + │ Found config file: \`./tailwind.config.ts\` for \`./src/root.5/tailwind.css\` + + │ You have multiple stylesheets that do not have an \`@config\`. + │ Please add a \`@config "…";\` referencing the correct Tailwind config file to: + │ - ./src/root.1.css + │ - ./src/root.3.css + │ - ./src/root.4.css + │ - ./src/root.5/tailwind.css + + " + `) + }, +) + test( 'injecting `@config` in the shared root, when a tailwind.config.{js,ts,…} is detected', { From 51c6a12b373f302f850950c28f0519d0d54733f3 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 14 Nov 2024 17:49:27 +0100 Subject: [PATCH 04/20] improve output messages --- integrations/upgrade/index.test.ts | 8 ++++---- packages/@tailwindcss-upgrade/src/index.ts | 16 +++++++++------- .../src/migrate-js-config.ts | 4 ++-- .../@tailwindcss-upgrade/src/migrate-postcss.ts | 2 +- packages/@tailwindcss-upgrade/src/migrate.ts | 4 +--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index f62472bec3bf..11779c3aff35 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1703,13 +1703,13 @@ test( │ Searching for CSS files in the current directory and its subdirectories… - │ Found config file: \`./tailwind.config.ts\` for \`./src/root.1.css\` + │ Linked \`./tailwind.config.ts\` to \`./src/root.1.css\` - │ Found config file: \`./tailwind.config.ts\` for \`./src/root.3.css\` + │ Linked \`./tailwind.config.ts\` to \`./src/root.3.css\` - │ Found config file: \`./tailwind.config.ts\` for \`./src/root.4.css\` + │ Linked \`./tailwind.config.ts\` to \`./src/root.4.css\` - │ Found config file: \`./tailwind.config.ts\` for \`./src/root.5/tailwind.css\` + │ Linked \`./tailwind.config.ts\` to \`./src/root.5/tailwind.css\` │ You have multiple stylesheets that do not have an \`@config\`. │ Please add a \`@config "…";\` referencing the correct Tailwind config file to: diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 1e789a348575..3b5fe7506226 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -23,7 +23,7 @@ import { args, type Arg } from './utils/args' import { isRepoDirty } from './utils/git' import { hoistStaticGlobParts } from './utils/hoist-static-glob-parts' import { pkg } from './utils/packages' -import { eprintln, error, header, highlight, info, success } from './utils/renderer' +import { eprintln, error, header, highlight, info, relative, success } from './utils/renderer' const options = { '--config': { type: 'string', description: 'Path to the configuration file', alias: '-c' }, @@ -110,7 +110,6 @@ async function run() { } // Migrate js config files, linked to stylesheets - info('Migrating JavaScript configuration files using the provided configuration file.') let configBySheet = new Map>>() let jsConfigMigrationBySheet = new Map< Stylesheet, @@ -122,6 +121,7 @@ async function run() { let config = await prepareConfig(sheet.linkedConfigPath, { base }) configBySheet.set(sheet, config) + info(`Migrating JavaScript configuration file: \`${relative(config.configFilePath, base)}\``) let jsConfigMigration = await migrateJsConfig( config.designSystem, config.configFilePath, @@ -138,9 +138,10 @@ async function run() { // Migrate source files, linked to config files { // Template migrations - - info('Migrating templates using the provided configuration file.') for (let config of configBySheet.values()) { + info( + `Migrating templates using the provided configuration file: \`${relative(config.configFilePath, base)}\`.`, + ) let set = new Set() for (let globEntry of config.globs.flatMap((entry) => hoistStaticGlobParts(entry))) { let files = await globby([globEntry.pattern], { @@ -161,12 +162,13 @@ async function run() { await Promise.allSettled( files.map((file) => migrateTemplate(config.designSystem, config.userConfig, file)), ) - } - success('Template migration complete.') + success('↳ Template migration complete.') + } } // Migrate each CSS file + info('Migrating stylesheets') let migrateResults = await Promise.allSettled( stylesheets.map((sheet) => { let config = configBySheet.get(sheet)! @@ -233,7 +235,7 @@ async function run() { await fs.writeFile(sheet.file, sheet.root.toString()) } - success('Stylesheet migration complete.') + success('↳ Stylesheet migration complete.') } { diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index 4ac4fe8d367a..99f607b78256 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -19,7 +19,7 @@ import type { DesignSystem } from '../../tailwindcss/src/design-system' import { escape } from '../../tailwindcss/src/utils/escape' import { isValidSpacingMultiplier } from '../../tailwindcss/src/utils/infer-data-type' import { findStaticPlugins, type StaticPluginOptions } from './utils/extract-static-plugins' -import { info } from './utils/renderer' +import { info, relative } from './utils/renderer' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -44,7 +44,7 @@ export async function migrateJsConfig( if (!canMigrateConfig(unresolvedConfig, source)) { info( - 'Your configuration file could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.', + `Your configuration file at \`${relative(fullConfigPath, base)}\` could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, ) return null } diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 1f4d6c46868b..7fed5eceb061 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -105,7 +105,7 @@ export async function migratePostCSSConfig(base: string) { } catch {} } - success(`PostCSS config has been upgraded.`) + success(`↳ PostCSS config has been upgraded.`) } async function migratePostCSSJSConfig( diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index 8969213ca3ee..f3e4252d1658 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -377,9 +377,7 @@ export async function linkConfigs( localConfigPath = path.resolve(base, localConfigPath) } - info( - `Found config file: \`${relative(localConfigPath, base)}\` for \`${relative(sheet.file, base)}\``, - ) + info(`Linked \`${relative(localConfigPath, base)}\` to \`${relative(sheet.file, base)}\``) configPathBySheet.set(sheet, localConfigPath) sheetByConfigPath.get(localConfigPath).add(sheet) } From 242c17f36afb708e8a681c6dcafac07c4cb1bcdb Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 11:33:54 +0100 Subject: [PATCH 05/20] always work with absolute paths This ensures that once we figure out the absolute path, that we don't accidentally resolve it against the wrong `base`. --- .../src/migrate-postcss.ts | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 7fed5eceb061..86b3fad262c7 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -24,7 +24,7 @@ export async function migratePostCSSConfig(base: string) { // Priority 1: Handle JS config files let jsConfigPath = await detectJSConfigPath(base) if (jsConfigPath) { - let result = await migratePostCSSJSConfig(base, jsConfigPath) + let result = await migratePostCSSJSConfig(jsConfigPath) if (result) { didMigrate = true @@ -41,7 +41,7 @@ export async function migratePostCSSConfig(base: string) { packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8')) } catch {} if (!didMigrate && packageJson && 'postcss' in packageJson) { - let result = await migratePostCSSJsonConfig(base, packageJson.postcss) + let result = await migratePostCSSJsonConfig(packageJson.postcss) if (result) { await fs.writeFile( @@ -64,7 +64,7 @@ export async function migratePostCSSConfig(base: string) { jsonConfig = JSON.parse(await fs.readFile(jsonConfigPath, 'utf-8')) } catch {} if (jsonConfig) { - let result = await migratePostCSSJsonConfig(base, jsonConfig) + let result = await migratePostCSSJsonConfig(jsonConfig) if (result) { await fs.writeFile(jsonConfigPath, JSON.stringify(result.json, null, 2)) @@ -108,10 +108,7 @@ export async function migratePostCSSConfig(base: string) { success(`↳ PostCSS config has been upgraded.`) } -async function migratePostCSSJSConfig( - base: string, - configPath: string, -): Promise<{ +async function migratePostCSSJSConfig(configPath: string): Promise<{ didAddPostcssClient: boolean didRemoveAutoprefixer: boolean didRemovePostCSSImport: boolean @@ -131,7 +128,7 @@ async function migratePostCSSJSConfig( info(`Attempt to upgrade the PostCSS config in file: ${configPath}`) - let isSimpleConfig = await isSimplePostCSSConfig(base, configPath) + let isSimpleConfig = await isSimplePostCSSConfig(configPath) if (!isSimpleConfig) { warn(`The PostCSS config contains dynamic JavaScript and can not be automatically migrated.`) return null @@ -141,8 +138,7 @@ async function migratePostCSSJSConfig( let didRemoveAutoprefixer = false let didRemovePostCSSImport = false - let fullPath = path.resolve(base, configPath) - let content = await fs.readFile(fullPath, 'utf-8') + let content = await fs.readFile(configPath, 'utf-8') let lines = content.split('\n') let newLines: string[] = [] for (let i = 0; i < lines.length; i++) { @@ -186,15 +182,12 @@ async function migratePostCSSJSConfig( newLines.push(line) } } - await fs.writeFile(fullPath, newLines.join('\n')) + await fs.writeFile(configPath, newLines.join('\n')) return { didAddPostcssClient, didRemoveAutoprefixer, didRemovePostCSSImport } } -async function migratePostCSSJsonConfig( - base: string, - json: any, -): Promise<{ +async function migratePostCSSJsonConfig(json: any): Promise<{ json: any didAddPostcssClient: boolean didRemoveAutoprefixer: boolean @@ -291,7 +284,7 @@ async function detectJSConfigPath(base: string): Promise { let fullPath = path.resolve(base, file) try { await fs.access(fullPath) - return file + return fullPath } catch {} } return null @@ -308,15 +301,14 @@ async function detectJSONConfigPath(base: string): Promise { let fullPath = path.resolve(base, file) try { await fs.access(fullPath) - return file + return fullPath } catch {} } return null } -async function isSimplePostCSSConfig(base: string, configPath: string): Promise { - let fullPath = path.resolve(base, configPath) - let content = await fs.readFile(fullPath, 'utf-8') +async function isSimplePostCSSConfig(configPath: string): Promise { + let content = await fs.readFile(configPath, 'utf-8') return ( content.includes('tailwindcss:') && !( From 4782cea0939738fa4c5e277d9f40ddf0479d70d4 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 11:34:34 +0100 Subject: [PATCH 06/20] print PostCSS config path in similar fashion Other logs print files with backticks relative to the process. This makes it consistent. --- packages/@tailwindcss-upgrade/src/migrate-postcss.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 86b3fad262c7..d5b1c47a0fb6 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises' import path from 'node:path' import { pkg } from './utils/packages' -import { info, success, warn } from './utils/renderer' +import { info, relative, success, warn } from './utils/renderer' // Migrates simple PostCSS setups. This is to cover non-dynamic config files // similar to the ones we have all over our docs: @@ -126,7 +126,7 @@ async function migratePostCSSJSConfig(configPath: string): Promise<{ return /['"]tailwindcss\/nesting['"]\: ?(\{\}|['"]postcss-nesting['"])/.test(line) } - info(`Attempt to upgrade the PostCSS config in file: ${configPath}`) + info(`Attempt to upgrade the PostCSS config in file: \`${relative(configPath)}\``) let isSimpleConfig = await isSimplePostCSSConfig(configPath) if (!isSimpleConfig) { From ad0045cab2287aa99755aa2b71a0af94a97ab90f Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 11:49:32 +0100 Subject: [PATCH 07/20] use existing highlight function Otherwise all file paths are white just like all the other text. --- packages/@tailwindcss-upgrade/src/index.ts | 6 ++++-- packages/@tailwindcss-upgrade/src/migrate-js-config.ts | 4 ++-- packages/@tailwindcss-upgrade/src/migrate-postcss.ts | 6 +++--- packages/@tailwindcss-upgrade/src/migrate.ts | 6 ++++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 3b5fe7506226..57cf6790c87a 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -121,7 +121,9 @@ async function run() { let config = await prepareConfig(sheet.linkedConfigPath, { base }) configBySheet.set(sheet, config) - info(`Migrating JavaScript configuration file: \`${relative(config.configFilePath, base)}\``) + info( + `Migrating JavaScript configuration file: ${highlight(relative(config.configFilePath, base))}`, + ) let jsConfigMigration = await migrateJsConfig( config.designSystem, config.configFilePath, @@ -140,7 +142,7 @@ async function run() { // Template migrations for (let config of configBySheet.values()) { info( - `Migrating templates using the provided configuration file: \`${relative(config.configFilePath, base)}\`.`, + `Migrating templates using the provided configuration file: ${highlight(relative(config.configFilePath, base))}.`, ) let set = new Set() for (let globEntry of config.globs.flatMap((entry) => hoistStaticGlobParts(entry))) { diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index 99f607b78256..2b602783aa5c 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -19,7 +19,7 @@ import type { DesignSystem } from '../../tailwindcss/src/design-system' import { escape } from '../../tailwindcss/src/utils/escape' import { isValidSpacingMultiplier } from '../../tailwindcss/src/utils/infer-data-type' import { findStaticPlugins, type StaticPluginOptions } from './utils/extract-static-plugins' -import { info, relative } from './utils/renderer' +import { highlight, info, relative } from './utils/renderer' const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -44,7 +44,7 @@ export async function migrateJsConfig( if (!canMigrateConfig(unresolvedConfig, source)) { info( - `Your configuration file at \`${relative(fullConfigPath, base)}\` could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, + `Your configuration file at ${highlight(relative(fullConfigPath, base))} could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, ) return null } diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index d5b1c47a0fb6..17a5eb2da21d 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises' import path from 'node:path' import { pkg } from './utils/packages' -import { info, relative, success, warn } from './utils/renderer' +import { highlight, info, relative, success, warn } from './utils/renderer' // Migrates simple PostCSS setups. This is to cover non-dynamic config files // similar to the ones we have all over our docs: @@ -78,7 +78,7 @@ export async function migratePostCSSConfig(base: string) { } if (!didMigrate) { - info(`No PostCSS config found, skipping migration.`) + info('No PostCSS config found, skipping migration.') return } @@ -126,7 +126,7 @@ async function migratePostCSSJSConfig(configPath: string): Promise<{ return /['"]tailwindcss\/nesting['"]\: ?(\{\}|['"]postcss-nesting['"])/.test(line) } - info(`Attempt to upgrade the PostCSS config in file: \`${relative(configPath)}\``) + info(`Attempt to upgrade the PostCSS config in file: ${highlight(relative(configPath))}`) let isSimpleConfig = await isSimplePostCSSConfig(configPath) if (!isSimpleConfig) { diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index f3e4252d1658..a4972249ace1 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -19,7 +19,7 @@ import { migrateVariantsDirective } from './codemods/migrate-variants-directive' import type { JSConfigMigration } from './migrate-js-config' import { Stylesheet, type StylesheetConnection, type StylesheetId } from './stylesheet' import { detectConfigPath } from './template/prepare-config' -import { error, info, relative } from './utils/renderer' +import { error, highlight, info, relative } from './utils/renderer' import { resolveCssId } from './utils/resolve' import { walk, WalkAction } from './utils/walk' @@ -377,7 +377,9 @@ export async function linkConfigs( localConfigPath = path.resolve(base, localConfigPath) } - info(`Linked \`${relative(localConfigPath, base)}\` to \`${relative(sheet.file, base)}\``) + info( + `Linked ${highlight(relative(localConfigPath, base))} to ${highlight(relative(sheet.file, base))}`, + ) configPathBySheet.set(sheet, localConfigPath) sheetByConfigPath.get(localConfigPath).add(sheet) } From 1e12d53c5545b12f34b01edd28a02b155a36ebf0 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 12:11:40 +0100 Subject: [PATCH 08/20] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b7d8ca4aa29..4ba2c0ca7af5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `flex` is suggested ([#15014](https://github.com/tailwindlabs/tailwindcss/pull/15014)) - _Upgrade (experimental)_: Resolve imports when specifying a CSS entry point on the command-line ([#15010](https://github.com/tailwindlabs/tailwindcss/pull/15010)) +- _Upgrade (experimental)_: Resolve nearest Tailwind config file, when CSS file does not contain `@config` ([#15001](https://github.com/tailwindlabs/tailwindcss/pull/15001)) ### Changed From 745ca9aed6e5c9125ab179a7b9f511aa8a19c702 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 12:33:14 +0100 Subject: [PATCH 09/20] highlight for consistency --- packages/@tailwindcss-upgrade/src/template/prepare-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts index b5efb3d79317..7f0875fba93f 100644 --- a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts +++ b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts @@ -6,7 +6,7 @@ import { loadModule } from '../../../@tailwindcss-node/src/compile' import { resolveConfig } from '../../../tailwindcss/src/compat/config/resolve-config' import type { Config } from '../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../tailwindcss/src/design-system' -import { error, relative } from '../utils/renderer' +import { error, highlight, relative } from '../utils/renderer' import { migratePrefix } from './codemods/prefix' const __filename = fileURLToPath(import.meta.url) @@ -106,7 +106,7 @@ export async function detectConfigPath(start: string, end: string = start) { } throw new Error( - `No configuration file found for \`${relative(start)}\`. Please provide a path to the Tailwind CSS v3 config file via the \`--config\` option.`, + `No configuration file found for ${highlight(relative(start))}. Please provide a path to the Tailwind CSS v3 config file via the ${highlight('--config')} option.`, ) } From d9364bead4625fd23a6f04c20c88d0e40b46582c Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 16:22:42 +0100 Subject: [PATCH 10/20] use `base` instead of `preflight` Because it needs to be Tailwind CSS v3 --- integrations/upgrade/index.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index 11779c3aff35..eca3e13b05c8 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1453,7 +1453,7 @@ test( ], } `, - 'src/root.4/base.css': css`@import 'tailwindcss/preflight';`, + 'src/root.4/base.css': css`@import 'tailwindcss/base';`, 'src/root.4/utilities.css': css`@import 'tailwindcss/utilities';`, 'src/root.5/index.css': css`@import './tailwind.css';`, @@ -1564,7 +1564,8 @@ test( @config './tailwind.config.ts'; --- ./src/root.4/base.css --- - @import 'tailwindcss/preflight'; + @import 'tailwindcss/theme' layer(theme); + @import 'tailwindcss/preflight' layer(base); /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -1678,7 +1679,7 @@ test( @import './root.4/base.css'; @import './root.4/utilities.css'; `, - 'src/root.4/base.css': css`@import 'tailwindcss/preflight';`, + 'src/root.4/base.css': css`@import 'tailwindcss/base';`, 'src/root.4/utilities.css': css`@import 'tailwindcss/utilities';`, 'src/root.5.css': css`@import './root.5/tailwind.css';`, From 8b858f928bc50dc1d3121656a2106e345a6dc6bc Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 16:50:41 +0100 Subject: [PATCH 11/20] ensure from is a parent of to --- packages/@tailwindcss-upgrade/src/template/prepare-config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts index 7f0875fba93f..a151b6ab46c5 100644 --- a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts +++ b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts @@ -115,6 +115,10 @@ function* parentPaths(from: string, to: string = from) { let fromAbsolute = path.resolve(from) let toAbsolute = path.resolve(to) + if (!fromAbsolute.startsWith(toAbsolute)) { + throw new Error(`The path ${from} is not a parent of ${to}`) + } + if (fromAbsolute === toAbsolute) { yield fromAbsolute return From 370c497edb5ee85df412c3814ddd0a2f7e419060 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 17:21:34 +0100 Subject: [PATCH 12/20] explicitly use tailwindcss ^3 --- integrations/upgrade/index.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index eca3e13b05c8..ef56ed0ec6e5 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1731,6 +1731,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1864,6 +1865,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } From 9292fab80b9efff9a23eb0587ec6db22c0be02c7 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 14 Nov 2024 18:34:04 +0100 Subject: [PATCH 13/20] tmp: run Windows tests We are dealing with some paths... --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d28a1e1e0660..bd64f77c5026 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: on-next-branch: - ${{ github.ref == 'refs/heads/next' }} exclude: - - on-next-branch: false + - on-next-branch: true runner: windows-latest - on-next-branch: false runner: macos-14 From 162f6f6e09ba23e2e352b764ec6b88d7d6f9300e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 15 Nov 2024 19:51:14 +0100 Subject: [PATCH 14/20] Revert "tmp: run Windows tests" This reverts commit 8fb759c7ecae829a9ea488b6638d942275bd3684. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd64f77c5026..d28a1e1e0660 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: on-next-branch: - ${{ github.ref == 'refs/heads/next' }} exclude: - - on-next-branch: true + - on-next-branch: false runner: windows-latest - on-next-branch: false runner: macos-14 From 864981e4fbd97a4a924a3a1eef7b07c41e024155 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 15:30:56 +0100 Subject: [PATCH 15/20] Update CHANGELOG.md Co-authored-by: Jordan Pittman --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ba2c0ca7af5..204dccc5d7d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `flex` is suggested ([#15014](https://github.com/tailwindlabs/tailwindcss/pull/15014)) - _Upgrade (experimental)_: Resolve imports when specifying a CSS entry point on the command-line ([#15010](https://github.com/tailwindlabs/tailwindcss/pull/15010)) -- _Upgrade (experimental)_: Resolve nearest Tailwind config file, when CSS file does not contain `@config` ([#15001](https://github.com/tailwindlabs/tailwindcss/pull/15001)) +- _Upgrade (experimental)_: Resolve nearest Tailwind config file when CSS file does not contain `@config` ([#15001](https://github.com/tailwindlabs/tailwindcss/pull/15001)) ### Changed From b59d0e868b1847b533a0012042b83e81c31d1318 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 16:31:26 +0100 Subject: [PATCH 16/20] Update packages/@tailwindcss-upgrade/src/index.ts --- packages/@tailwindcss-upgrade/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 57cf6790c87a..25a62cc5e6bf 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -142,7 +142,7 @@ async function run() { // Template migrations for (let config of configBySheet.values()) { info( - `Migrating templates using the provided configuration file: ${highlight(relative(config.configFilePath, base))}.`, + `Migrating templates found using configuration file: ${highlight(relative(config.configFilePath, base))}.`, ) let set = new Set() for (let globEntry of config.globs.flatMap((entry) => hoistStaticGlobParts(entry))) { From b3e2c3a6b5342dbd8f4cbcd9175be337b67e8965 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 16:31:36 +0100 Subject: [PATCH 17/20] Update packages/@tailwindcss-upgrade/src/migrate-js-config.ts --- packages/@tailwindcss-upgrade/src/migrate-js-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index 2b602783aa5c..5856af21edde 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -44,7 +44,7 @@ export async function migrateJsConfig( if (!canMigrateConfig(unresolvedConfig, source)) { info( - `Your configuration file at ${highlight(relative(fullConfigPath, base))} could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, + `The configuration file at ${highlight(relative(fullConfigPath, base))} could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, ) return null } From e8c24c21dae166a972b2e7f0d7c3e8c47d5c5375 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 16:31:44 +0100 Subject: [PATCH 18/20] Update packages/@tailwindcss-upgrade/src/migrate-postcss.ts --- packages/@tailwindcss-upgrade/src/migrate-postcss.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 17a5eb2da21d..6ebf20f3d8f8 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -126,7 +126,7 @@ async function migratePostCSSJSConfig(configPath: string): Promise<{ return /['"]tailwindcss\/nesting['"]\: ?(\{\}|['"]postcss-nesting['"])/.test(line) } - info(`Attempt to upgrade the PostCSS config in file: ${highlight(relative(configPath))}`) + info(`Upgrading the PostCSS config in file: ${highlight(relative(configPath))}`) let isSimpleConfig = await isSimplePostCSSConfig(configPath) if (!isSimpleConfig) { From 75cbd5167b033a06d60a1577e983a1a36288f7a9 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 16:47:58 +0100 Subject: [PATCH 19/20] rework upgrade output messages --- packages/@tailwindcss-upgrade/src/index.ts | 34 ++++++++++++------- .../src/migrate-js-config.ts | 2 +- .../src/migrate-postcss.ts | 12 +++++-- .../src/migrate-prettier.ts | 4 +-- packages/@tailwindcss-upgrade/src/migrate.ts | 17 +++++----- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 25a62cc5e6bf..3f57ef1987b1 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -110,6 +110,7 @@ async function run() { } // Migrate js config files, linked to stylesheets + info('Migrating JavaScript configuration files…') let configBySheet = new Map>>() let jsConfigMigrationBySheet = new Map< Stylesheet, @@ -121,9 +122,6 @@ async function run() { let config = await prepareConfig(sheet.linkedConfigPath, { base }) configBySheet.set(sheet, config) - info( - `Migrating JavaScript configuration file: ${highlight(relative(config.configFilePath, base))}`, - ) let jsConfigMigration = await migrateJsConfig( config.designSystem, config.configFilePath, @@ -135,15 +133,19 @@ async function run() { // Remove the JS config if it was fully migrated cleanup.push(() => fs.rm(config.configFilePath)) } + + if (jsConfigMigration !== null) { + success( + `↳ Migrated configuration file: ${highlight(relative(config.configFilePath, base))}`, + ) + } } // Migrate source files, linked to config files + info('Migrating templates…') { // Template migrations for (let config of configBySheet.values()) { - info( - `Migrating templates found using configuration file: ${highlight(relative(config.configFilePath, base))}.`, - ) let set = new Set() for (let globEntry of config.globs.flatMap((entry) => hoistStaticGlobParts(entry))) { let files = await globby([globEntry.pattern], { @@ -165,12 +167,14 @@ async function run() { files.map((file) => migrateTemplate(config.designSystem, config.userConfig, file)), ) - success('↳ Template migration complete.') + success( + `↳ Migrated templates for configuration file: ${highlight(relative(config.configFilePath, base))}`, + ) } } // Migrate each CSS file - info('Migrating stylesheets') + info('Migrating stylesheets…') let migrateResults = await Promise.allSettled( stylesheets.map((sheet) => { let config = configBySheet.get(sheet)! @@ -235,9 +239,11 @@ async function run() { if (!sheet.file) continue await fs.writeFile(sheet.file, sheet.root.toString()) - } - success('↳ Stylesheet migration complete.') + if (sheet.isTailwindRoot) { + success(`↳ Migrated stylesheet: ${highlight(relative(sheet.file, base))}`) + } + } } { @@ -245,19 +251,21 @@ async function run() { await migratePostCSSConfig(base) } + info('Updating dependencies…') { // Migrate the prettier plugin to the latest version await migratePrettierPlugin(base) } - // Run all cleanup functions because we completed the migration - await Promise.allSettled(cleanup.map((fn) => fn())) - try { // Upgrade Tailwind CSS await pkg(base).add(['tailwindcss@next']) + success(`↳ Updated package: ${highlight('tailwindcss')}`) } catch {} + // Run all cleanup functions because we completed the migration + await Promise.allSettled(cleanup.map((fn) => fn())) + // Figure out if we made any changes if (isRepoDirty()) { success('Verify the changes and commit them to your repository.') diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index 5856af21edde..b69379df1f7d 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -44,7 +44,7 @@ export async function migrateJsConfig( if (!canMigrateConfig(unresolvedConfig, source)) { info( - `The configuration file at ${highlight(relative(fullConfigPath, base))} could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, + `↳ The configuration file at ${highlight(relative(fullConfigPath, base))} could not be automatically migrated to the new CSS configuration format, so your CSS has been updated to load your existing configuration file.`, ) return null } diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 6ebf20f3d8f8..1bfb2caa80f1 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -92,6 +92,7 @@ export async function migratePostCSSConfig(base: string) { if (location !== null) { try { await pkg(base).add(['@tailwindcss/postcss@next'], location) + success(`↳ Installed package: ${highlight('@tailwindcss/postcss')}`) } catch {} } } @@ -102,10 +103,15 @@ export async function migratePostCSSConfig(base: string) { didRemovePostCSSImport ? 'postcss-import' : null, ].filter(Boolean) as string[] await pkg(base).remove(packagesToRemove) + for (let pkg of packagesToRemove) { + success(`↳ Removed package: ${highlight(pkg)}`) + } } catch {} } - success(`↳ PostCSS config has been upgraded.`) + if (didMigrate && jsConfigPath) { + success(`↳ Migrated PostCSS configuration: ${highlight(relative(jsConfigPath, base))}`) + } } async function migratePostCSSJSConfig(configPath: string): Promise<{ @@ -126,11 +132,11 @@ async function migratePostCSSJSConfig(configPath: string): Promise<{ return /['"]tailwindcss\/nesting['"]\: ?(\{\}|['"]postcss-nesting['"])/.test(line) } - info(`Upgrading the PostCSS config in file: ${highlight(relative(configPath))}`) + info('Migrating PostCSS configuration…') let isSimpleConfig = await isSimplePostCSSConfig(configPath) if (!isSimpleConfig) { - warn(`The PostCSS config contains dynamic JavaScript and can not be automatically migrated.`) + warn('The PostCSS config contains dynamic JavaScript and can not be automatically migrated.') return null } diff --git a/packages/@tailwindcss-upgrade/src/migrate-prettier.ts b/packages/@tailwindcss-upgrade/src/migrate-prettier.ts index 359b4888180d..7edf34f47a36 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-prettier.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-prettier.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises' import path from 'node:path' import { pkg } from './utils/packages' -import { success } from './utils/renderer' +import { highlight, success } from './utils/renderer' export async function migratePrettierPlugin(base: string) { let packageJsonPath = path.resolve(base, 'package.json') @@ -9,7 +9,7 @@ export async function migratePrettierPlugin(base: string) { let packageJson = await fs.readFile(packageJsonPath, 'utf-8') if (packageJson.includes('prettier-plugin-tailwindcss')) { await pkg(base).add(['prettier-plugin-tailwindcss@latest']) - success(`Prettier plugin migrated to latest version.`) + success(`↳ Updated package: ${highlight('prettier-plugin-tailwindcss')}`) } } catch {} } diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index a4972249ace1..a3f2e344adda 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -19,7 +19,7 @@ import { migrateVariantsDirective } from './codemods/migrate-variants-directive' import type { JSConfigMigration } from './migrate-js-config' import { Stylesheet, type StylesheetConnection, type StylesheetId } from './stylesheet' import { detectConfigPath } from './template/prepare-config' -import { error, highlight, info, relative } from './utils/renderer' +import { error, highlight, relative, success } from './utils/renderer' import { resolveCssId } from './utils/resolve' import { walk, WalkAction } from './utils/walk' @@ -377,9 +377,6 @@ export async function linkConfigs( localConfigPath = path.resolve(base, localConfigPath) } - info( - `Linked ${highlight(relative(localConfigPath, base))} to ${highlight(relative(sheet.file, base))}`, - ) configPathBySheet.set(sheet, localConfigPath) sheetByConfigPath.get(localConfigPath).add(sheet) } @@ -396,20 +393,22 @@ export async function linkConfigs( // There are multiple "root" files without `@config` directives. Manual // intervention is needed to link to the correct Tailwind config files. if (problematicStylesheets.size > 1) { - let msg = `You have multiple stylesheets that do not have an \`@config\`.\n` - msg += `Please add a \`@config "…";\` referencing the correct Tailwind config file to:\n` - for (let sheet of problematicStylesheets) { - msg += `- ${relative(sheet.file!, base)}\n` + error( + `Could not determine configuration file for: ${highlight(relative(sheet.file!, base))}\nUpdate your stylesheet to use ${highlight('@config')} to specify the correct configuration file explicitly and then run the upgrade tool again.`, + ) } - error(msg) process.exit(1) } + let relativePath = relative for (let [sheet, configPath] of configPathBySheet) { try { if (!sheet || !sheet.file) return + success( + `↳ Linked ${highlight(relativePath(configPath, base))} to ${highlight(relativePath(sheet.file, base))}`, + ) // Link the `@config` directive to the root stylesheets From a00e9b457967392674970fa1df1418e99793e6b9 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 18 Nov 2024 17:36:12 +0100 Subject: [PATCH 20/20] update integration tests --- integrations/upgrade/index.test.ts | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index ef56ed0ec6e5..32fcd1b83293 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1,4 +1,3 @@ -import { stripVTControlCharacters } from 'node:util' import { expect } from 'vitest' import { candidate, css, html, js, json, test, ts } from '../utils' @@ -1694,33 +1693,7 @@ test( (e) => e.toString(), ) - output = stripVTControlCharacters(output) - .replace(/tailwindcss v(.*)/g, 'tailwindcss') // Remove the version number from the error message - .replace(/\\/g, '/') // Make Windows paths look like Unix paths - - expect(output).toMatchInlineSnapshot(` - "Error: Command failed: npx @tailwindcss/upgrade --force - ≈ tailwindcss - - │ Searching for CSS files in the current directory and its subdirectories… - - │ Linked \`./tailwind.config.ts\` to \`./src/root.1.css\` - - │ Linked \`./tailwind.config.ts\` to \`./src/root.3.css\` - - │ Linked \`./tailwind.config.ts\` to \`./src/root.4.css\` - - │ Linked \`./tailwind.config.ts\` to \`./src/root.5/tailwind.css\` - - │ You have multiple stylesheets that do not have an \`@config\`. - │ Please add a \`@config "…";\` referencing the correct Tailwind config file to: - │ - ./src/root.1.css - │ - ./src/root.3.css - │ - ./src/root.4.css - │ - ./src/root.5/tailwind.css - - " - `) + expect(output).toMatch('Could not determine configuration file for:') }, )