@@ -19,6 +19,7 @@ import { buildCustomContainerUtilityRules } from '../../../../tailwindcss/src/co
1919import { darkModePlugin } from '../../../../tailwindcss/src/compat/dark-mode'
2020import type { Config } from '../../../../tailwindcss/src/compat/plugin-api'
2121import type { DesignSystem } from '../../../../tailwindcss/src/design-system'
22+ import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map'
2223import { escape } from '../../../../tailwindcss/src/utils/escape'
2324import {
2425 isValidOpacityValue ,
@@ -55,8 +56,44 @@ export async function migrateJsConfig(
5556 `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.` ,
5657 { prefix : '↳ ' } ,
5758 )
58- for ( let msg of canMigrateConfigResult . errors ) {
59- warn ( msg , { prefix : ' ↳ ' } )
59+ for ( let [ category , messages ] of canMigrateConfigResult . errors . entries ( ) ) {
60+ switch ( category ) {
61+ case 'general' : {
62+ for ( let msg of messages ) warn ( msg , { prefix : ' ↳ ' } )
63+ break
64+ }
65+ case 'top-level' : {
66+ warn (
67+ `Cannot migrate unknown top-level keys:\n${ Array . from ( messages )
68+ . map ( ( key ) => ` - \`${ key } \`` )
69+ . join (
70+ '\n' ,
71+ ) } \n\nThese are non-standard Tailwind CSS options, so we don't know how to migrate them to CSS.`,
72+ { prefix : ' ↳ ' } ,
73+ )
74+ break
75+ }
76+ case 'unknown-theme-keys' : {
77+ warn (
78+ `Cannot migrate unknown theme keys:\n${ Array . from ( messages )
79+ . map ( ( key ) => ` - \`${ key } \`` )
80+ . join (
81+ '\n' ,
82+ ) } \n\nThese are non-standard Tailwind CSS theme keys, so we don't know how to migrate them to CSS.`,
83+ { prefix : ' ↳ ' } ,
84+ )
85+ break
86+ }
87+ case 'complex-screens' : {
88+ warn (
89+ `Cannot migrate complex screen configuration (min/max/raw):\n${ Array . from ( messages )
90+ . map ( ( key ) => ` - \`${ key } \`` )
91+ . join ( '\n' ) } `,
92+ { prefix : ' ↳ ' } ,
93+ )
94+ break
95+ }
96+ }
6097 }
6198 return null
6299 }
@@ -405,17 +442,19 @@ function stringifyPath(path: (string | number)[]): string {
405442 return result
406443}
407444
445+ // Keep track of issues given a category and a set of messages
446+ const MIGRATION_ISSUES = new DefaultMap ( ( ) => new Set < string > ( ) )
447+
408448// Applies heuristics to determine if we can attempt to migrate the config
409449function canMigrateConfig (
410450 unresolvedConfig : Config ,
411451 source : string ,
412- ) : { valid : true } | { valid : false ; errors : string [ ] } {
452+ ) : { valid : true } | { valid : false ; errors : typeof MIGRATION_ISSUES } {
413453 let theme = unresolvedConfig . theme
414- let errors : string [ ] = [ ]
415454
416455 // Migrating presets are not supported
417456 if ( unresolvedConfig . presets && unresolvedConfig . presets . length > 0 ) {
418- errors . push ( 'Cannot migrate config files that use presets' )
457+ MIGRATION_ISSUES . get ( 'general' ) . add ( 'Cannot migrate config files that use presets' )
419458 }
420459
421460 // The file may only contain known-migratable top-level properties
@@ -431,53 +470,44 @@ function canMigrateConfig(
431470
432471 for ( let key of Object . keys ( unresolvedConfig ) ) {
433472 if ( ! knownProperties . includes ( key ) ) {
434- errors . push ( `Cannot migrate unknown top-level key: \` ${ key } \`` )
473+ MIGRATION_ISSUES . get ( ' top-level' ) . add ( key )
435474 }
436475 }
437476
438477 // Only migrate the config file if all top-level theme keys are allowed to be
439478 // migrated
440479 if ( theme && typeof theme === 'object' ) {
441480 let { extend, ...themeCopy } = theme
442- errors . push ( ...onlyAllowedThemeValues ( themeCopy , [ 'theme' ] ) )
443-
444- if ( extend ) {
445- errors . push ( ...onlyAllowedThemeValues ( extend , [ 'theme' , 'extend' ] ) )
446- }
481+ onlyAllowedThemeValues ( themeCopy , [ 'theme' ] )
482+ if ( extend ) onlyAllowedThemeValues ( extend , [ 'theme' , 'extend' ] )
447483 }
448484
449485 // TODO: findStaticPlugins already logs errors for unsupported plugins, maybe
450486 // it should return them instead?
451487 findStaticPlugins ( source )
452488
453- return errors . length <= 0 ? { valid : true } : { valid : false , errors }
489+ return MIGRATION_ISSUES . size <= 0 ? { valid : true } : { valid : false , errors : MIGRATION_ISSUES }
454490}
455491
456492const ALLOWED_THEME_KEYS = [
457493 ...Object . keys ( defaultTheme ) ,
458494 // Used by @tailwindcss /container-queries
459495 'containers' ,
460496]
461- function onlyAllowedThemeValues ( theme : ThemeConfig , path : ( string | number ) [ ] ) : string [ ] {
462- let errors : string [ ] = [ ]
463-
497+ function onlyAllowedThemeValues ( theme : ThemeConfig , path : ( string | number ) [ ] ) {
464498 for ( let key of Object . keys ( theme ) ) {
465499 if ( ! ALLOWED_THEME_KEYS . includes ( key ) ) {
466- errors . push ( `Cannot migrate theme key: \` ${ stringifyPath ( [ ...path , key ] ) } \`` )
500+ MIGRATION_ISSUES . get ( 'unknown- theme-keys' ) . add ( stringifyPath ( [ ...path , key ] ) )
467501 }
468502 }
469503
470504 if ( 'screens' in theme && typeof theme . screens === 'object' && theme . screens !== null ) {
471505 for ( let [ name , screen ] of Object . entries ( theme . screens ) ) {
472506 if ( typeof screen === 'object' && screen !== null && ( 'max' in screen || 'raw' in screen ) ) {
473- errors . push (
474- `Cannot migrate complex screen definition: \`${ stringifyPath ( [ ...path , 'screens' , name ] ) } \`` ,
475- )
507+ MIGRATION_ISSUES . get ( 'complex-screens' ) . add ( stringifyPath ( [ ...path , 'screens' , name ] ) )
476508 }
477509 }
478510 }
479-
480- return errors
481511}
482512
483513function keyframesToCss ( keyframes : Record < string , unknown > ) : string {
0 commit comments