diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 3f57ef1987b1..15d11b733d93 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -84,7 +84,7 @@ async function run() { // Load and parse all stylesheets for (let result of loadResults) { if (result.status === 'rejected') { - error(`${result.reason}`) + error(`${result.reason?.message ?? result.reason}`, { prefix: '↳ ' }) } } @@ -95,8 +95,8 @@ async function run() { // Analyze the stylesheets try { await analyzeStylesheets(stylesheets) - } catch (e: unknown) { - error(`${e}`) + } catch (e: any) { + error(`${e?.message ?? e}`, { prefix: '↳ ' }) } // Ensure stylesheets are linked to configs @@ -105,12 +105,14 @@ async function run() { configPath: flags['--config'], base, }) - } catch (e: unknown) { - error(`${e}`) + } catch (e: any) { + error(`${e?.message ?? e}`, { prefix: '↳ ' }) } // Migrate js config files, linked to stylesheets - info('Migrating JavaScript configuration files…') + if (stylesheets.some((sheet) => sheet.isTailwindRoot)) { + info('Migrating JavaScript configuration files…') + } let configBySheet = new Map>>() let jsConfigMigrationBySheet = new Map< Stylesheet, @@ -136,13 +138,16 @@ async function run() { if (jsConfigMigration !== null) { success( - `↳ Migrated configuration file: ${highlight(relative(config.configFilePath, base))}`, + `Migrated configuration file: ${highlight(relative(config.configFilePath, base))}`, + { prefix: '↳ ' }, ) } } // Migrate source files, linked to config files - info('Migrating templates…') + if (configBySheet.size > 0) { + info('Migrating templates…') + } { // Template migrations for (let config of configBySheet.values()) { @@ -168,43 +173,44 @@ async function run() { ) success( - `↳ Migrated templates for configuration file: ${highlight(relative(config.configFilePath, base))}`, + `Migrated templates for configuration file: ${highlight(relative(config.configFilePath, base))}`, + { prefix: '↳ ' }, ) } } // Migrate each CSS file - info('Migrating stylesheets…') - let migrateResults = await Promise.allSettled( - stylesheets.map((sheet) => { - let config = configBySheet.get(sheet)! - let jsConfigMigration = jsConfigMigrationBySheet.get(sheet)! - - if (!config) { - for (let parent of sheet.ancestors()) { - if (parent.isTailwindRoot) { - config ??= configBySheet.get(parent)! - jsConfigMigration ??= jsConfigMigrationBySheet.get(parent)! - break + if (stylesheets.length > 0) { + info('Migrating stylesheets…') + } + await Promise.all( + stylesheets.map(async (sheet) => { + try { + let config = configBySheet.get(sheet)! + let jsConfigMigration = jsConfigMigrationBySheet.get(sheet)! + + if (!config) { + for (let parent of sheet.ancestors()) { + if (parent.isTailwindRoot) { + config ??= configBySheet.get(parent)! + jsConfigMigration ??= jsConfigMigrationBySheet.get(parent)! + break + } } } - } - return migrateStylesheet(sheet, { ...config, jsConfigMigration }) + await migrateStylesheet(sheet, { ...config, jsConfigMigration }) + } catch (e: any) { + error(`${e?.message ?? e} in ${highlight(relative(sheet.file!, base))}`, { prefix: '↳ ' }) + } }), ) - for (let result of migrateResults) { - if (result.status === 'rejected') { - error(`${result.reason}`) - } - } - // Split up stylesheets (as needed) try { await splitStylesheets(stylesheets) - } catch (e: unknown) { - error(`${e}`) + } catch (e: any) { + error(`${e?.message ?? e}`, { prefix: '↳ ' }) } // Cleanup `@import "…" layer(utilities)` @@ -241,7 +247,7 @@ async function run() { await fs.writeFile(sheet.file, sheet.root.toString()) if (sheet.isTailwindRoot) { - success(`↳ Migrated stylesheet: ${highlight(relative(sheet.file, base))}`) + success(`Migrated stylesheet: ${highlight(relative(sheet.file, base))}`, { prefix: '↳ ' }) } } } @@ -260,7 +266,7 @@ async function run() { try { // Upgrade Tailwind CSS await pkg(base).add(['tailwindcss@next']) - success(`↳ Updated package: ${highlight('tailwindcss')}`) + success(`Updated package: ${highlight('tailwindcss')}`, { prefix: '↳ ' }) } catch {} // Run all cleanup functions because we completed the migration diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index b69379df1f7d..e17bf9601c75 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -44,7 +44,8 @@ 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.`, + { prefix: '↳ ' }, ) return null } diff --git a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts index 1bfb2caa80f1..286884522bdd 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-postcss.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-postcss.ts @@ -92,7 +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')}`) + success(`Installed package: ${highlight('@tailwindcss/postcss')}`, { prefix: '↳ ' }) } catch {} } } @@ -104,13 +104,15 @@ export async function migratePostCSSConfig(base: string) { ].filter(Boolean) as string[] await pkg(base).remove(packagesToRemove) for (let pkg of packagesToRemove) { - success(`↳ Removed package: ${highlight(pkg)}`) + success(`Removed package: ${highlight(pkg)}`, { prefix: '↳ ' }) } } catch {} } if (didMigrate && jsConfigPath) { - success(`↳ Migrated PostCSS configuration: ${highlight(relative(jsConfigPath, base))}`) + success(`Migrated PostCSS configuration: ${highlight(relative(jsConfigPath, base))}`, { + prefix: '↳ ', + }) } } diff --git a/packages/@tailwindcss-upgrade/src/migrate-prettier.ts b/packages/@tailwindcss-upgrade/src/migrate-prettier.ts index 7edf34f47a36..cd56cc6880e1 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-prettier.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-prettier.ts @@ -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(`↳ Updated package: ${highlight('prettier-plugin-tailwindcss')}`) + success(`Updated package: ${highlight('prettier-plugin-tailwindcss')}`, { prefix: '↳ ' }) } } catch {} } diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index a3f2e344adda..932a0a726b22 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -120,8 +120,10 @@ export async function analyze(stylesheets: Stylesheet[]) { resolvedPath = resolveCssId(id, basePath) } } catch (err) { - console.warn(`Failed to resolve import: ${id}. Skipping.`) - console.error(err) + error( + `Failed to resolve import: ${highlight(id)} in ${highlight(relative(node.source?.input.file!, basePath))}. Skipping.`, + { prefix: '↳ ' }, + ) return } @@ -334,10 +336,12 @@ export async function analyze(stylesheets: Stylesheet[]) { } } - let error = `You have one or more stylesheets that are imported into a utility layer and non-utility layer.\n` - error += `We cannot convert stylesheets under these conditions. Please look at the following stylesheets:\n` + { + let error = `You have one or more stylesheets that are imported into a utility layer and non-utility layer.\n` + error += `We cannot convert stylesheets under these conditions. Please look at the following stylesheets:\n` - throw new Error(error + lines.join('\n')) + throw new Error(error + lines.join('\n')) + } } export async function linkConfigs( @@ -347,7 +351,7 @@ export async function linkConfigs( let rootStylesheets = stylesheets.filter((sheet) => sheet.isTailwindRoot) if (rootStylesheets.length === 0) { throw new Error( - 'Cannot find any CSS files that reference Tailwind CSS.\nBefore your project can be upgraded you need to create a CSS file that imports Tailwind CSS or uses `@tailwind`.', + `Cannot find any CSS files that reference Tailwind CSS.\nBefore your project can be upgraded you need to create a CSS file that imports Tailwind CSS or uses ${highlight('@tailwind')}.`, ) } let withoutAtConfig = rootStylesheets.filter((sheet) => { @@ -396,6 +400,7 @@ export async function linkConfigs( for (let sheet of problematicStylesheets) { 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.`, + { prefix: '↳ ' }, ) } @@ -407,7 +412,8 @@ export async function linkConfigs( try { if (!sheet || !sheet.file) return success( - `↳ Linked ${highlight(relativePath(configPath, base))} to ${highlight(relativePath(sheet.file, base))}`, + `Linked ${highlight(relativePath(configPath, base))} to ${highlight(relativePath(sheet.file, base))}`, + { prefix: '↳ ' }, ) // Link the `@config` directive to the root stylesheets @@ -447,7 +453,7 @@ export async function linkConfigs( } } } catch (e: any) { - error('Could not load the configuration file: ' + e.message) + error('Could not load the configuration file: ' + e.message, { prefix: '↳ ' }) process.exit(1) } } diff --git a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts index a151b6ab46c5..f5a817d40ea3 100644 --- a/packages/@tailwindcss-upgrade/src/template/prepare-config.ts +++ b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts @@ -65,7 +65,7 @@ export async function prepareConfig( configFilePath, } } catch (e: any) { - error('Could not load the configuration file: ' + e.message) + error('Could not load the configuration file: ' + e.message, { prefix: '↳ ' }) process.exit(1) } } diff --git a/packages/@tailwindcss-upgrade/src/utils/extract-static-plugins.ts b/packages/@tailwindcss-upgrade/src/utils/extract-static-plugins.ts index d0f6dbf8e2f4..4318c14ef36e 100644 --- a/packages/@tailwindcss-upgrade/src/utils/extract-static-plugins.ts +++ b/packages/@tailwindcss-upgrade/src/utils/extract-static-plugins.ts @@ -272,8 +272,8 @@ export function findStaticPlugins(source: string): [string, null | StaticPluginO } } return plugins - } catch (error) { - console.error(error) + } catch (error: any) { + error(`${error?.message ?? error}`, { prefix: '↳ ' }) return null } } diff --git a/packages/@tailwindcss-upgrade/src/utils/renderer.ts b/packages/@tailwindcss-upgrade/src/utils/renderer.ts index b902fe88d15d..38bd9826a0ab 100644 --- a/packages/@tailwindcss-upgrade/src/utils/renderer.ts +++ b/packages/@tailwindcss-upgrade/src/utils/renderer.ts @@ -89,32 +89,36 @@ export function indent(value: string, offset = 0) { return `${' '.repeat(offset + UI.indent)}${value}` } -export function success(message: string, print = eprintln) { - wordWrap(message, process.stderr.columns - 3).map((line) => { - return print(`${pc.green('\u2502')} ${line}`) +function log(message: string, { art = pc.gray('\u2502'), prefix = '', print = eprintln }) { + let prefixLength = prefix.length + let padding = ' ' + let paddingLength = padding.length + let artLength = stripVTControlCharacters(art).length + let availableWidth = process.stderr.columns + let totalWidth = availableWidth - prefixLength - paddingLength * 2 - artLength + + wordWrap(message, totalWidth).map((line, idx) => { + return print( + `${art}${padding}${idx === 0 ? prefix : ' '.repeat(prefixLength)}${line}${padding}`, + ) }) print() } -export function info(message: string, print = eprintln) { - wordWrap(message, process.stderr.columns - 3).map((line) => { - return print(`${pc.blue('\u2502')} ${line}`) - }) - print() +export function success(message: string, { prefix = '', print = eprintln } = {}) { + log(message, { art: pc.green('\u2502'), prefix, print }) } -export function error(message: string, print = eprintln) { - wordWrap(message, process.stderr.columns - 3).map((line) => { - return print(`${pc.red('\u2502')} ${line}`) - }) - print() +export function info(message: string, { prefix = '', print = eprintln } = {}) { + log(message, { art: pc.blue('\u2502'), prefix, print }) } -export function warn(message: string, print = eprintln) { - wordWrap(message, process.stderr.columns - 3).map((line) => { - return print(`${pc.yellow('\u2502')} ${line}`) - }) - print() +export function error(message: string, { prefix = '', print = eprintln } = {}) { + log(message, { art: pc.red('\u2502'), prefix, print }) +} + +export function warn(message: string, { prefix = '', print = eprintln } = {}) { + log(message, { art: pc.yellow('\u2502'), prefix, print }) } // Rust inspired functions to print to the console: diff --git a/packages/tailwindcss/src/at-import.ts b/packages/tailwindcss/src/at-import.ts index e5b937c71c3b..8066abd98ff9 100644 --- a/packages/tailwindcss/src/at-import.ts +++ b/packages/tailwindcss/src/at-import.ts @@ -85,7 +85,7 @@ export function parseImportParams(params: ValueParser.ValueAstNode[]) { } if (node.kind === 'function' && node.value.toLowerCase() === 'url') { - throw new Error('url functions are not supported') + throw new Error('`url(…)` functions are not supported') } if (!uri) throw new Error('Unable to find uri') @@ -95,7 +95,7 @@ export function parseImportParams(params: ValueParser.ValueAstNode[]) { node.value.toLowerCase() === 'layer' ) { if (layer) throw new Error('Multiple layers') - if (supports) throw new Error('layers must be defined before support conditions') + if (supports) throw new Error('`layer(…)` must be defined before `supports(…)` conditions') if ('nodes' in node) { layer = ValueParser.toCss(node.nodes)