@@ -53,8 +53,7 @@ function convertStaticToDynamic(code) {
5353 parser : require ( 'recast/parsers/babel-ts' ) ,
5454 } ) ;
5555
56- let navigatorInfo = null ;
57- let navigatorDeclarationIndex = - 1 ;
56+ let navigatorInfos = [ ] ;
5857 let staticNavigationIndices = [ ] ;
5958
6059 // First pass: collect information and transform imports
@@ -125,17 +124,16 @@ function convertStaticToDynamic(code) {
125124 const navigatorType = declarator . init . callee . name ; // e.g., "createStackNavigator"
126125 const config = declarator . init . arguments [ 0 ] ;
127126
128- navigatorInfo = {
127+ navigatorInfos . push ( {
129128 componentName : navigatorVariable , // Keep original name for the component
130129 type : navigatorType ,
131130 config : config ,
132131 // Store leading/trailing comments to preserve codeblock-focus
133132 leadingComments : node . comments || [ ] ,
134133 trailingComments : node . trailingComments || [ ] ,
135134 originalNode : node , // Keep reference to original node
136- } ;
137-
138- navigatorDeclarationIndex = index ;
135+ index : index ,
136+ } ) ;
139137 }
140138
141139 // Find createStaticNavigation usage
@@ -159,11 +157,14 @@ function convertStaticToDynamic(code) {
159157 t . isJSXIdentifier ( path . node . openingElement . name ) &&
160158 path . node . openingElement . name . name === 'Navigation' &&
161159 path . node . children . length === 0 &&
162- navigatorInfo
160+ navigatorInfos . length > 0
163161 ) {
164162 // Preserve any props passed to Navigation
165163 const navigationProps = path . node . openingElement . attributes || [ ] ;
166164
165+ // Use the last navigator (which is passed to createStaticNavigation)
166+ const mainNavigator = navigatorInfos [ navigatorInfos . length - 1 ] ;
167+
167168 // Replace with <NavigationContainer><MyStack /></NavigationContainer>
168169 // Pass the props from Navigation to NavigationContainer
169170 const newElement = t . jsxElement (
@@ -176,7 +177,7 @@ function convertStaticToDynamic(code) {
176177 t . jsxText ( '\n ' ) ,
177178 t . jsxElement (
178179 t . jsxOpeningElement (
179- t . jsxIdentifier ( navigatorInfo . componentName ) ,
180+ t . jsxIdentifier ( mainNavigator . componentName ) ,
180181 [ ] ,
181182 true
182183 ) ,
@@ -197,108 +198,137 @@ function convertStaticToDynamic(code) {
197198 } ) ;
198199
199200 // Second pass: manually transform the AST body
200- if ( navigatorInfo && navigatorDeclarationIndex !== - 1 ) {
201- const {
202- componentName,
203- type,
204- config,
205- leadingComments,
206- trailingComments,
207- originalNode,
208- } = navigatorInfo ;
209-
210- // Extract navigator constant name from the type
211- // Get the last word before "Navigator"
212- // e.g., "createStackNavigator" -> "Stack"
213- // e.g., "createNativeStackNavigator" -> "Stack"
214- // e.g., "createBottomTabNavigator" -> "Tab"
215- // e.g., "createMaterialTopTabNavigator" -> "Tab"
216- const withoutCreate = type . replace ( / ^ c r e a t e / , '' ) ; // "StackNavigator"
217- const withoutNavigator = withoutCreate . replace ( / N a v i g a t o r $ / , '' ) ; // "Stack"
218- // Find the last capitalized word (e.g., "NativeStack" -> "Stack", "MaterialTopTab" -> "Tab")
219- const match = withoutNavigator . match ( / ( [ A - Z ] [ a - z ] + ) $ / ) ;
220- const navigatorConstName = match ? match [ 1 ] : withoutNavigator ;
221-
222- // Parse the config object
223- const parsedConfig = parseNavigatorConfig ( config ) ;
224-
225- // Create: const Stack = createStackNavigator();
226- const navigatorConstDeclaration = t . variableDeclaration ( 'const' , [
227- t . variableDeclarator (
228- t . identifier ( navigatorConstName ) ,
229- t . callExpression ( t . identifier ( type ) , [ ] )
230- ) ,
231- ] ) ;
201+ // Process all navigators
202+ if ( navigatorInfos . length > 0 ) {
203+ const replacements = [ ] ;
204+
205+ navigatorInfos . forEach ( ( navigatorInfo ) => {
206+ const {
207+ componentName,
208+ type,
209+ config,
210+ leadingComments,
211+ trailingComments,
212+ originalNode,
213+ index,
214+ } = navigatorInfo ;
215+
216+ // Extract navigator constant name from the type
217+ // Get the last word before "Navigator"
218+ // e.g., "createStackNavigator" -> "Stack"
219+ // e.g., "createNativeStackNavigator" -> "Stack"
220+ // e.g., "createBottomTabNavigator" -> "Tab"
221+ // e.g., "createMaterialTopTabNavigator" -> "Tab"
222+ const withoutCreate = type . replace ( / ^ c r e a t e / , '' ) ; // "StackNavigator"
223+ const withoutNavigator = withoutCreate . replace ( / N a v i g a t o r $ / , '' ) ; // "Stack"
224+ // Find the last capitalized word (e.g., "NativeStack" -> "Stack", "MaterialTopTab" -> "Tab")
225+ const match = withoutNavigator . match ( / ( [ A - Z ] [ a - z ] + ) $ / ) ;
226+ const navigatorConstName = match ? match [ 1 ] : withoutNavigator ;
227+
228+ // Parse the config object
229+ const parsedConfig = parseNavigatorConfig ( config ) ;
230+
231+ // Create: const Stack = createStackNavigator();
232+ const navigatorConstDeclaration = t . variableDeclaration ( 'const' , [
233+ t . variableDeclarator (
234+ t . identifier ( navigatorConstName ) ,
235+ t . callExpression ( t . identifier ( type ) , [ ] )
236+ ) ,
237+ ] ) ;
232238
233- // Create the navigator component function (e.g., function MyStack() {...})
234- const navigatorComponent = createNavigatorComponent (
235- componentName , // function name: MyStack
236- navigatorConstName , // Stack.Navigator, Stack.Screen
237- parsedConfig
238- ) ;
239+ // Create the navigator component function (e.g., function MyStack() {...})
240+ const navigatorComponent = createNavigatorComponent (
241+ componentName , // function name: MyStack
242+ navigatorConstName , // Stack.Navigator, Stack.Screen
243+ parsedConfig
244+ ) ;
239245
240- // Preserve all comments from the original node
241- if ( originalNode . comments && originalNode . comments . length > 0 ) {
242- // Separate leading and trailing comments
243- const leadingComments = [ ] ;
244- const trailingCommentsFromNode = [ ] ;
245-
246- originalNode . comments . forEach ( ( comment ) => {
247- // Recast marks comments with leading/trailing properties
248- if ( comment . trailing ) {
249- trailingCommentsFromNode . push ( comment ) ;
250- } else {
251- leadingComments . push ( comment ) ;
246+ // Preserve all comments from the original node
247+ if ( originalNode . comments && originalNode . comments . length > 0 ) {
248+ // Separate leading and trailing comments
249+ const leadingComments = [ ] ;
250+ const trailingCommentsFromNode = [ ] ;
251+
252+ originalNode . comments . forEach ( ( comment ) => {
253+ // Recast marks comments with leading/trailing properties
254+ if ( comment . trailing ) {
255+ trailingCommentsFromNode . push ( comment ) ;
256+ } else {
257+ leadingComments . push ( comment ) ;
258+ }
259+ } ) ;
260+
261+ // Attach leading comments to the const declaration
262+ if ( leadingComments . length > 0 ) {
263+ // Mark as leading comments for proper placement
264+ leadingComments . forEach ( ( c ) => {
265+ c . leading = true ;
266+ c . trailing = false ;
267+ } ) ;
268+ navigatorConstDeclaration . comments = leadingComments ;
252269 }
253- } ) ;
254270
255- // Attach leading comments to the const declaration
256- if ( leadingComments . length > 0 ) {
257- // Mark as leading comments for proper placement
258- leadingComments . forEach ( ( c ) => {
259- c . leading = true ;
260- c . trailing = false ;
261- } ) ;
262- navigatorConstDeclaration . comments = leadingComments ;
271+ // Attach trailing comments to the function component (after the function body)
272+ if ( trailingCommentsFromNode . length > 0 ) {
273+ // Mark as trailing comments for proper placement
274+ trailingCommentsFromNode . forEach ( ( c ) => {
275+ c . leading = false ;
276+ c . trailing = true ;
277+ } ) ;
278+ navigatorComponent . comments = trailingCommentsFromNode ;
279+ }
263280 }
264281
265- // Attach trailing comments to the function component (after the function body)
266- if ( trailingCommentsFromNode . length > 0 ) {
267- // Mark as trailing comments for proper placement
268- trailingCommentsFromNode . forEach ( ( c ) => {
282+ // Also check for trailingComments property
283+ if ( trailingComments && trailingComments . length > 0 ) {
284+ trailingComments . forEach ( ( c ) => {
269285 c . leading = false ;
270286 c . trailing = true ;
271287 } ) ;
272- navigatorComponent . comments = trailingCommentsFromNode ;
288+ navigatorComponent . comments = [
289+ ...( navigatorComponent . comments || [ ] ) ,
290+ ...trailingComments ,
291+ ] ;
273292 }
274- }
275293
276- // Also check for trailingComments property
277- if ( trailingComments && trailingComments . length > 0 ) {
278- trailingComments . forEach ( ( c ) => {
279- c . leading = false ;
280- c . trailing = true ;
294+ // Store the replacement info
295+ replacements . push ( {
296+ index : index ,
297+ navigatorConstDeclaration ,
298+ navigatorComponent ,
281299 } ) ;
282- navigatorComponent . comments = [
283- ...( navigatorComponent . comments || [ ] ) ,
284- ...trailingComments ,
285- ] ;
286- }
300+ } ) ;
301+
302+ // Replace declarations in reverse order to maintain correct indices
303+ replacements . sort ( ( a , b ) => b . index - a . index ) ;
287304
288- // Replace the declaration by manipulating the body array directly
289305 const programBody = ast . program . body ;
290- programBody . splice (
291- navigatorDeclarationIndex ,
292- 1 ,
293- navigatorConstDeclaration ,
294- navigatorComponent
306+ let indexShift = 0 ;
307+
308+ replacements . forEach (
309+ ( { index, navigatorConstDeclaration, navigatorComponent } ) => {
310+ // Replace 1 node with 2 nodes
311+ programBody . splice (
312+ index ,
313+ 1 ,
314+ navigatorConstDeclaration ,
315+ navigatorComponent
316+ ) ;
317+
318+ // Track the shift for adjusting staticNavigation indices
319+ indexShift ++ ;
320+ }
295321 ) ;
296322
297323 // Adjust indices for createStaticNavigation declarations
298- // Since we replaced 1 node with 2 nodes, indices after this point shift by +1
299- staticNavigationIndices = staticNavigationIndices . map ( ( idx ) =>
300- idx > navigatorDeclarationIndex ? idx + 1 : idx
301- ) ;
324+ // Account for the fact that we replaced each navigator (1 node) with 2 nodes
325+ staticNavigationIndices = staticNavigationIndices . map ( ( idx ) => {
326+ let shift = 0 ;
327+ replacements . forEach ( ( { index } ) => {
328+ if ( idx > index ) shift ++ ;
329+ } ) ;
330+ return idx + shift ;
331+ } ) ;
302332 }
303333
304334 // Remove createStaticNavigation declarations (in reverse order to maintain indices)
0 commit comments