@@ -55,7 +55,7 @@ export function parseAndUpdatePostcssConfig(source: string, zeroUiPlugin: string
5555 if ( pluginsProperty && t . isExpression ( pluginsProperty . value ) ) {
5656 const result = addZeroUiToPlugins ( pluginsProperty . value , zeroUiPlugin ) ;
5757 handled ||= result !== "unsupported" ;
58- modified ||= result === "added" ;
58+ modified ||= result === "added" || result === "reordered" ;
5959 }
6060 }
6161 } ,
@@ -70,7 +70,7 @@ export function parseAndUpdatePostcssConfig(source: string, zeroUiPlugin: string
7070 if ( pluginsProperty && t . isExpression ( pluginsProperty . value ) ) {
7171 const result = addZeroUiToPlugins ( pluginsProperty . value , zeroUiPlugin ) ;
7272 handled ||= result !== "unsupported" ;
73- modified ||= result === "added" ;
73+ modified ||= result === "added" || result === "reordered" ;
7474 }
7575 }
7676 } ,
@@ -85,7 +85,7 @@ export function parseAndUpdatePostcssConfig(source: string, zeroUiPlugin: string
8585 if ( pluginsProperty && t . isExpression ( pluginsProperty . value ) ) {
8686 const result = addZeroUiToPlugins ( pluginsProperty . value , zeroUiPlugin ) ;
8787 handled ||= result !== "unsupported" ;
88- modified ||= result === "added" ;
88+ modified ||= result === "added" || result === "reordered" ;
8989 }
9090 }
9191 } ,
@@ -110,41 +110,80 @@ export function parseAndUpdatePostcssConfig(source: string, zeroUiPlugin: string
110110 * Helper function to add Zero-UI plugin to plugins configuration
111111 * Handles both object format {plugin: {}} and array format [plugin]
112112 */
113- function addZeroUiToPlugins ( pluginsNode : t . Expression , zeroUiPlugin : string ) : "added" | "present" | "unsupported" {
113+ function addZeroUiToPlugins ( pluginsNode : t . Expression , zeroUiPlugin : string ) : "added" | "reordered" | " present" | "unsupported" {
114114 if ( t . isObjectExpression ( pluginsNode ) ) {
115- const alreadyPresent = pluginsNode . properties . some (
116- ( prop ) => t . isObjectProperty ( prop ) && t . isStringLiteral ( prop . key ) && prop . key . value === zeroUiPlugin
115+ const zeroIndex = pluginsNode . properties . findIndex (
116+ ( prop ) => t . isObjectProperty ( prop ) && getPluginObjectKey ( prop ) === zeroUiPlugin
117+ ) ;
118+ const tailwindIndex = pluginsNode . properties . findIndex (
119+ ( prop ) => t . isObjectProperty ( prop ) && getPluginObjectKey ( prop ) === "@tailwindcss/postcss"
117120 ) ;
118- if ( alreadyPresent ) return "present" ;
121+
122+ if ( zeroIndex !== - 1 ) {
123+ if ( tailwindIndex !== - 1 && zeroIndex > tailwindIndex ) {
124+ const [ zeroProp ] = pluginsNode . properties . splice ( zeroIndex , 1 ) ;
125+ const nextTailwindIndex = pluginsNode . properties . findIndex (
126+ ( prop ) => t . isObjectProperty ( prop ) && getPluginObjectKey ( prop ) === "@tailwindcss/postcss"
127+ ) ;
128+ pluginsNode . properties . splice ( nextTailwindIndex , 0 , zeroProp ) ;
129+ return "reordered" ;
130+ }
131+ return "present" ;
132+ }
119133
120134 // Object format: { 'plugin': {} }
121- pluginsNode . properties . unshift ( t . objectProperty ( t . stringLiteral ( zeroUiPlugin ) , t . objectExpression ( [ ] ) ) ) ;
135+ const newProp = t . objectProperty ( t . stringLiteral ( zeroUiPlugin ) , t . objectExpression ( [ ] ) ) ;
136+ if ( tailwindIndex !== - 1 ) {
137+ pluginsNode . properties . splice ( tailwindIndex , 0 , newProp ) ;
138+ } else {
139+ pluginsNode . properties . unshift ( newProp ) ;
140+ }
122141 return "added" ;
123142 } else if ( t . isArrayExpression ( pluginsNode ) ) {
124- const alreadyPresent = pluginsNode . elements . some ( ( el ) => isZeroUiPostcssEntry ( el , zeroUiPlugin ) ) ;
125- if ( alreadyPresent ) return "present" ;
143+ const zeroIndex = pluginsNode . elements . findIndex ( ( el ) => isPluginArrayEntry ( el , zeroUiPlugin ) ) ;
144+ const tailwindIndex = pluginsNode . elements . findIndex ( ( el ) => isPluginArrayEntry ( el , "@tailwindcss/postcss" ) ) ;
145+
146+ if ( zeroIndex !== - 1 ) {
147+ if ( tailwindIndex !== - 1 && zeroIndex > tailwindIndex ) {
148+ const [ zeroEntry ] = pluginsNode . elements . splice ( zeroIndex , 1 ) ;
149+ const nextTailwindIndex = pluginsNode . elements . findIndex ( ( el ) => isPluginArrayEntry ( el , "@tailwindcss/postcss" ) ) ;
150+ pluginsNode . elements . splice ( nextTailwindIndex , 0 , zeroEntry ) ;
151+ return "reordered" ;
152+ }
153+ return "present" ;
154+ }
126155
127156 // Array format: ['plugin']
128- pluginsNode . elements . unshift ( t . stringLiteral ( zeroUiPlugin ) ) ;
157+ if ( tailwindIndex !== - 1 ) {
158+ pluginsNode . elements . splice ( tailwindIndex , 0 , t . stringLiteral ( zeroUiPlugin ) ) ;
159+ } else {
160+ pluginsNode . elements . unshift ( t . stringLiteral ( zeroUiPlugin ) ) ;
161+ }
129162 return "added" ;
130163 }
131164 return "unsupported" ;
132165}
133166
134- function isZeroUiPostcssEntry ( node : t . ArrayExpression [ "elements" ] [ number ] , zeroUiPlugin : string ) : boolean {
167+ function isPluginArrayEntry ( node : t . ArrayExpression [ "elements" ] [ number ] , pluginName : string ) : boolean {
135168 if ( ! node ) return false ;
136- if ( t . isStringLiteral ( node ) ) return node . value === zeroUiPlugin ;
169+ if ( t . isStringLiteral ( node ) ) return node . value === pluginName ;
137170 if (
138171 t . isCallExpression ( node ) &&
139172 t . isIdentifier ( node . callee , { name : "require" } ) &&
140173 node . arguments . length === 1 &&
141174 t . isStringLiteral ( node . arguments [ 0 ] )
142175 ) {
143- return node . arguments [ 0 ] . value === zeroUiPlugin ;
176+ return node . arguments [ 0 ] . value === pluginName ;
144177 }
145178 return false ;
146179}
147180
181+ function getPluginObjectKey ( node : t . ObjectProperty ) : string | null {
182+ if ( t . isStringLiteral ( node . key ) ) return node . key . value ;
183+ if ( t . isIdentifier ( node . key ) ) return node . key . name ;
184+ return null ;
185+ }
186+
148187/**
149188 * Parse Vite config TypeScript/JavaScript file and add Zero-UI plugin
150189 * Removes tailwindcss plugin if present, and adds zeroUI plugin if missing
0 commit comments