@@ -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 ,
@@ -54,8 +55,55 @@ export async function migrateJsConfig(
5455 `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.` ,
5556 { prefix : '↳ ' } ,
5657 )
57- for ( let msg of canMigrateConfigResult . errors ) {
58- warn ( msg , { prefix : ' ↳ ' } )
58+ for ( let [ category , messages ] of canMigrateConfigResult . errors . entries ( ) ) {
59+ switch ( category ) {
60+ case 'general' : {
61+ for ( let msg of messages ) warn ( msg , { prefix : ' ↳ ' } )
62+ break
63+ }
64+ case 'top-level' : {
65+ warn (
66+ `Cannot migrate unknown top-level keys:\n${ Array . from ( messages )
67+ . map ( ( key ) => ` - \`${ key } \`` )
68+ . join (
69+ '\n' ,
70+ ) } \n\nThese are non-standard Tailwind CSS options, so we don't know how to migrate them to CSS.`,
71+ { prefix : ' ↳ ' } ,
72+ )
73+ break
74+ }
75+ case 'unknown-theme-keys' : {
76+ warn (
77+ `Cannot migrate unknown theme keys:\n${ Array . from ( messages )
78+ . map ( ( key ) => ` - \`${ key } \`` )
79+ . join (
80+ '\n' ,
81+ ) } \n\nThese are non-standard Tailwind CSS theme keys, so we don't know how to migrate them to CSS.`,
82+ { prefix : ' ↳ ' } ,
83+ )
84+ break
85+ }
86+ case 'variant-theme-keys' : {
87+ warn (
88+ `Cannot migrate variant theme keys:\n${ Array . from ( messages )
89+ . map ( ( key ) => ` - \`${ key } \`` )
90+ . join (
91+ '\n' ,
92+ ) } \n\nThese theme keys are for variants (like \`data\`, \`aria\`, or \`supports\`), but will probably work out of the box.`,
93+ { prefix : ' ↳ ' } ,
94+ )
95+ break
96+ }
97+ case 'complex-screens' : {
98+ warn (
99+ `Cannot migrate complex screen configuration (min/max/raw):\n${ Array . from ( messages )
100+ . map ( ( key ) => ` - \`${ key } \`` )
101+ . join ( '\n' ) } `,
102+ { prefix : ' ↳ ' } ,
103+ )
104+ break
105+ }
106+ }
59107 }
60108 return null
61109 }
@@ -320,17 +368,19 @@ function stringifyPath(path: (string | number)[]): string {
320368 return result
321369}
322370
371+ // Keep track of issues given a category and a set of messages
372+ const MIGRATION_ISSUES = new DefaultMap ( ( ) => new Set < string > ( ) )
373+
323374// Applies heuristics to determine if we can attempt to migrate the config
324375function canMigrateConfig (
325376 unresolvedConfig : Config ,
326377 source : string ,
327- ) : { valid : true } | { valid : false ; errors : string [ ] } {
378+ ) : { valid : true } | { valid : false ; errors : typeof MIGRATION_ISSUES } {
328379 let theme = unresolvedConfig . theme
329- let errors : string [ ] = [ ]
330380
331381 // Migrating presets are not supported
332382 if ( unresolvedConfig . presets && unresolvedConfig . presets . length > 0 ) {
333- errors . push ( 'Cannot migrate config files that use presets' )
383+ MIGRATION_ISSUES . get ( 'general' ) . add ( 'Cannot migrate config files that use presets' )
334384 }
335385
336386 // The file may only contain known-migratable top-level properties
@@ -346,58 +396,49 @@ function canMigrateConfig(
346396
347397 for ( let key of Object . keys ( unresolvedConfig ) ) {
348398 if ( ! knownProperties . includes ( key ) ) {
349- errors . push ( `Cannot migrate unknown top-level key: \` ${ key } \`` )
399+ MIGRATION_ISSUES . get ( ' top-level' ) . add ( key )
350400 }
351401 }
352402
353403 // Only migrate the config file if all top-level theme keys are allowed to be
354404 // migrated
355405 if ( theme && typeof theme === 'object' ) {
356406 let { extend, ...themeCopy } = theme
357- errors . push ( ...onlyAllowedThemeValues ( themeCopy , [ 'theme' ] ) )
358-
359- if ( extend ) {
360- errors . push ( ...onlyAllowedThemeValues ( extend , [ 'theme' , 'extend' ] ) )
361- }
407+ onlyAllowedThemeValues ( themeCopy , [ 'theme' ] )
408+ if ( extend ) onlyAllowedThemeValues ( extend , [ 'theme' , 'extend' ] )
362409 }
363410
364411 // TODO: findStaticPlugins already logs errors for unsupported plugins, maybe
365412 // it should return them instead?
366413 findStaticPlugins ( source )
367414
368- return errors . length <= 0 ? { valid : true } : { valid : false , errors }
415+ return MIGRATION_ISSUES . size <= 0 ? { valid : true } : { valid : false , errors : MIGRATION_ISSUES }
369416}
370417
371418const ALLOWED_THEME_KEYS = [
372419 ...Object . keys ( defaultTheme ) ,
373420 // Used by @tailwindcss /container-queries
374421 'containers' ,
375422]
376- const BLOCKED_THEME_KEYS = [ 'supports' , 'data' , 'aria' ]
377- function onlyAllowedThemeValues ( theme : ThemeConfig , path : ( string | number ) [ ] ) : string [ ] {
378- let errors : string [ ] = [ ]
379-
423+ const VARIANT_THEME_KEYS = [ 'supports' , 'data' , 'aria' ]
424+ function onlyAllowedThemeValues ( theme : ThemeConfig , path : ( string | number ) [ ] ) {
380425 for ( let key of Object . keys ( theme ) ) {
381426 if ( ! ALLOWED_THEME_KEYS . includes ( key ) ) {
382- errors . push ( `Cannot migrate theme key: \` ${ stringifyPath ( [ ...path , key ] ) } \`` )
427+ MIGRATION_ISSUES . get ( 'unknown- theme-keys' ) . add ( stringifyPath ( [ ...path , key ] ) )
383428 }
384429
385- if ( BLOCKED_THEME_KEYS . includes ( key ) ) {
386- errors . push ( `Cannot migrate theme key: \` ${ stringifyPath ( [ ...path , key ] ) } \`` )
430+ if ( VARIANT_THEME_KEYS . includes ( key ) ) {
431+ MIGRATION_ISSUES . get ( 'variant- theme-keys' ) . add ( stringifyPath ( [ ...path , key ] ) )
387432 }
388433 }
389434
390435 if ( 'screens' in theme && typeof theme . screens === 'object' && theme . screens !== null ) {
391436 for ( let [ name , screen ] of Object . entries ( theme . screens ) ) {
392437 if ( typeof screen === 'object' && screen !== null && ( 'max' in screen || 'raw' in screen ) ) {
393- errors . push (
394- `Cannot migrate complex screen definition: \`${ stringifyPath ( [ ...path , 'screens' , name ] ) } \`` ,
395- )
438+ MIGRATION_ISSUES . get ( 'complex-screens' ) . add ( stringifyPath ( [ ...path , 'screens' , name ] ) )
396439 }
397440 }
398441 }
399-
400- return errors
401442}
402443
403444function keyframesToCss ( keyframes : Record < string , unknown > ) : string {
0 commit comments