Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve robustness when upgrading #15038

Merged
merged 5 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 39 additions & 33 deletions packages/@tailwindcss-upgrade/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: '↳ ' })
}
}

Expand All @@ -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
Expand All @@ -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<Stylesheet, Awaited<ReturnType<typeof prepareConfig>>>()
let jsConfigMigrationBySheet = new Map<
Stylesheet,
Expand All @@ -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()) {
Expand All @@ -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)`
Expand Down Expand Up @@ -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: '↳ ' })
}
}
}
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion packages/@tailwindcss-upgrade/src/migrate-js-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
8 changes: 5 additions & 3 deletions packages/@tailwindcss-upgrade/src/migrate-postcss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
}
Expand All @@ -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: '↳ ',
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@tailwindcss-upgrade/src/migrate-prettier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
22 changes: 14 additions & 8 deletions packages/@tailwindcss-upgrade/src/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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(
Expand All @@ -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) => {
Expand Down Expand Up @@ -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: '↳ ' },
)
}

Expand All @@ -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
Expand Down Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
40 changes: 22 additions & 18 deletions packages/@tailwindcss-upgrade/src/utils/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions packages/tailwindcss/src/at-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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)
Expand Down