@@ -11,43 +11,43 @@ import { isSafeMigration } from '../is-safe-migration'
1111const __filename = url . fileURLToPath ( import . meta. url )
1212const __dirname = path . dirname ( __filename )
1313
14- const LEGACY_CLASS_MAP = {
15- shadow : 'shadow-sm' ,
16- 'shadow-sm' : 'shadow-xs' ,
17- 'shadow-xs' : 'shadow-2xs' ,
14+ const LEGACY_CLASS_MAP = new Map ( [
15+ [ ' shadow' , 'shadow-sm' ] ,
16+ [ 'shadow-sm' , 'shadow-xs' ] ,
17+ [ 'shadow-xs' , 'shadow-2xs' ] ,
1818
19- 'inset-shadow' : 'inset-shadow-sm' ,
20- 'inset-shadow-sm' : 'inset-shadow-xs' ,
21- 'inset-shadow-xs' : 'inset-shadow-2xs' ,
19+ [ 'inset-shadow' , 'inset-shadow-sm' ] ,
20+ [ 'inset-shadow-sm' , 'inset-shadow-xs' ] ,
21+ [ 'inset-shadow-xs' , 'inset-shadow-2xs' ] ,
2222
23- 'drop-shadow' : 'drop-shadow-sm' ,
24- 'drop-shadow-sm' : 'drop-shadow-xs' ,
23+ [ 'drop-shadow' , 'drop-shadow-sm' ] ,
24+ [ 'drop-shadow-sm' , 'drop-shadow-xs' ] ,
2525
26- rounded : 'rounded-sm' ,
27- 'rounded-sm' : 'rounded-xs' ,
26+ [ ' rounded' , 'rounded-sm' ] ,
27+ [ 'rounded-sm' , 'rounded-xs' ] ,
2828
29- blur : 'blur-sm' ,
30- 'blur-sm' : 'blur-xs' ,
31- }
29+ [ ' blur' , 'blur-sm' ] ,
30+ [ 'blur-sm' , 'blur-xs' ] ,
31+ ] )
3232
33- const THEME_KEYS = {
34- shadow : '--shadow' ,
35- 'shadow-sm' : '--shadow-sm' ,
36- 'shadow-xs' : '--shadow-xs' ,
37- 'shadow-2xs' : '--shadow-2xs' ,
33+ const THEME_KEYS = new Map ( [
34+ [ ' shadow' , '--shadow' ] ,
35+ [ 'shadow-sm' , '--shadow-sm' ] ,
36+ [ 'shadow-xs' , '--shadow-xs' ] ,
37+ [ 'shadow-2xs' , '--shadow-2xs' ] ,
3838
39- 'drop-shadow' : '--drop-shadow' ,
40- 'drop-shadow-sm' : '--drop-shadow-sm' ,
41- 'drop-shadow-xs' : '--drop-shadow-xs' ,
39+ [ 'drop-shadow' , '--drop-shadow' ] ,
40+ [ 'drop-shadow-sm' , '--drop-shadow-sm' ] ,
41+ [ 'drop-shadow-xs' , '--drop-shadow-xs' ] ,
4242
43- rounded : '--radius' ,
44- 'rounded-sm' : '--radius-sm' ,
45- 'rounded-xs' : '--radius-xs' ,
43+ [ ' rounded' , '--radius' ] ,
44+ [ 'rounded-sm' , '--radius-sm' ] ,
45+ [ 'rounded-xs' , '--radius-xs' ] ,
4646
47- blur : '--blur' ,
48- 'blur-sm' : '--blur-sm' ,
49- 'blur-xs' : '--blur-xs' ,
50- }
47+ [ ' blur' , '--blur' ] ,
48+ [ 'blur-sm' , '--blur-sm' ] ,
49+ [ 'blur-xs' , '--blur-xs' ] ,
50+ ] )
5151
5252const DESIGN_SYSTEMS = new DefaultMap ( ( base ) => {
5353 return __unstable__loadDesignSystem ( '@import "tailwindcss";' , { base } )
@@ -65,58 +65,91 @@ export async function legacyClasses(
6565) : Promise < string > {
6666 let defaultDesignSystem = await DESIGN_SYSTEMS . get ( __dirname )
6767
68- for ( let candidate of designSystem . parseCandidate ( rawCandidate ) ) {
69- if ( candidate . kind === 'functional' ) {
70- let parts = [ candidate . root ]
71- if ( candidate . value ?. kind === 'named' ) {
72- parts . push ( candidate . value . value )
68+ function * migrate ( rawCandidate : string ) {
69+ for ( let candidate of designSystem . parseCandidate ( rawCandidate ) ) {
70+ // Create a base candidate string from the candidate.
71+ // E.g.: `hover:blur!` -> `blur`
72+ let baseCandidate = structuredClone ( candidate ) as Candidate
73+ baseCandidate . variants = [ ]
74+ baseCandidate . important = false
75+ let baseCandidateString = printCandidate ( designSystem , baseCandidate )
76+
77+ // Find the new base candidate string. `blur` -> `blur-sm`
78+ let newBaseCandidateString = LEGACY_CLASS_MAP . get ( baseCandidateString )
79+ if ( ! newBaseCandidateString ) continue
80+
81+ // Parse the new base candidate string into an actual candidate AST.
82+ let [ newBaseCandidate ] = designSystem . parseCandidate ( newBaseCandidateString )
83+ if ( ! newBaseCandidate ) continue
84+
85+ // Re-apply the variants and important flag from the original candidate.
86+ // E.g.: `hover:blur!` -> `blur` -> `blur-sm` -> `hover:blur-sm!`
87+ let newCandidate = structuredClone ( newBaseCandidate ) as Candidate
88+ newCandidate . variants = candidate . variants
89+ newCandidate . important = candidate . important
90+
91+ yield [
92+ candidate ,
93+ newCandidate ,
94+ THEME_KEYS . get ( baseCandidateString ) ,
95+ THEME_KEYS . get ( newBaseCandidateString ) ,
96+ ] as const
97+ }
98+ }
99+
100+ for ( let [ fromCandidate , toCandidate , fromThemeKey , toThemeKey ] of migrate ( rawCandidate ) ) {
101+ // Every utility that has a simple representation (e.g.: `blur`, `radius`,
102+ // etc.`) without variants or special characters _could_ be a potential
103+ // problem during the migration.
104+ let isPotentialProblematicClass = ( ( ) => {
105+ if ( fromCandidate . variants . length > 0 ) {
106+ return false
73107 }
74108
75- let root = parts . join ( '-' )
76- if ( Object . hasOwn ( LEGACY_CLASS_MAP , root ) ) {
77- let newRoot = LEGACY_CLASS_MAP [ root as keyof typeof LEGACY_CLASS_MAP ]
78-
79- if ( location && ! root . includes ( '-' ) && ! isSafeMigration ( location ) ) {
80- continue
81- }
82-
83- let fromThemeKey = THEME_KEYS [ root as keyof typeof THEME_KEYS ]
84- let toThemeKey = THEME_KEYS [ newRoot as keyof typeof THEME_KEYS ]
85-
86- if ( fromThemeKey && toThemeKey ) {
87- // Migrating something that resolves to a value in the theme.
88- let customFrom = designSystem . resolveThemeValue ( fromThemeKey )
89- let defaultFrom = defaultDesignSystem . resolveThemeValue ( fromThemeKey )
90- let customTo = designSystem . resolveThemeValue ( toThemeKey )
91- let defaultTo = defaultDesignSystem . resolveThemeValue ( toThemeKey )
92-
93- // The new theme value is not defined, which means we can't safely
94- // migrate the utility.
95- if ( customTo === undefined ) {
96- continue
97- }
98-
99- // The "from" theme value changed compared to the default theme value.
100- if ( customFrom !== defaultFrom ) {
101- continue
102- }
103-
104- // The "to" theme value changed compared to the default theme value.
105- if ( customTo !== defaultTo ) {
106- continue
107- }
108- }
109-
110- for ( let newCandidate of designSystem . parseCandidate ( newRoot ) ) {
111- let clone = structuredClone ( newCandidate ) as Candidate
112-
113- clone . important = candidate . important
114- clone . variants = candidate . variants
115-
116- return printCandidate ( designSystem , clone )
117- }
109+ if ( fromCandidate . kind === 'arbitrary' ) {
110+ return false
118111 }
112+
113+ if ( fromCandidate . kind === 'static' ) {
114+ return ! fromCandidate . root . includes ( '-' )
115+ }
116+
117+ if ( fromCandidate . kind === 'functional' ) {
118+ return fromCandidate . value === null || ! fromCandidate . root . includes ( '-' )
119+ }
120+
121+ return false
122+ } ) ( )
123+
124+ if ( location && isPotentialProblematicClass && ! isSafeMigration ( location ) ) {
125+ continue
119126 }
127+
128+ if ( fromThemeKey && toThemeKey ) {
129+ // Migrating something that resolves to a value in the theme.
130+ let customFrom = designSystem . resolveThemeValue ( fromThemeKey )
131+ let defaultFrom = defaultDesignSystem . resolveThemeValue ( fromThemeKey )
132+ let customTo = designSystem . resolveThemeValue ( toThemeKey )
133+ let defaultTo = defaultDesignSystem . resolveThemeValue ( toThemeKey )
134+
135+ // The new theme value is not defined, which means we can't safely
136+ // migrate the utility.
137+ if ( customTo === undefined ) {
138+ continue
139+ }
140+
141+ // The "from" theme value changed compared to the default theme value.
142+ if ( customFrom !== defaultFrom ) {
143+ continue
144+ }
145+
146+ // The "to" theme value changed compared to the default theme value.
147+ if ( customTo !== defaultTo ) {
148+ continue
149+ }
150+ }
151+
152+ return printCandidate ( designSystem , toCandidate )
120153 }
121154
122155 return rawCandidate
0 commit comments