@@ -218,7 +218,7 @@ async function resolveRouterReference(
218218 if ( localRouter ) {
219219 // Filter routes that belong to this router (decorated with @router.method)
220220 const routerRoutes = analysis . routes . filter ( ( r ) => r . owner === moduleName )
221- return {
221+ const routerNode : RouterNode = {
222222 filePath : currentFileUri ,
223223 variableName : localRouter . variableName ,
224224 type : localRouter . type ,
@@ -235,6 +235,39 @@ async function resolveRouterReference(
235235 } ) ) ,
236236 children : [ ] ,
237237 }
238+
239+ // Process include_router calls owned by this router (nested routers)
240+ const routerIncludes = analysis . includeRouters . filter (
241+ ( inc ) => inc . owner === moduleName ,
242+ )
243+ for ( const include of routerIncludes ) {
244+ log (
245+ `Resolving nested include_router: ${ include . router } (owner: ${ moduleName } , prefix: ${ include . prefix || "none" } )` ,
246+ )
247+ const childRouter = await resolveRouterReference (
248+ include . router ,
249+ analysis ,
250+ currentFileUri ,
251+ projectRootUri ,
252+ parser ,
253+ fs ,
254+ visited ,
255+ )
256+ if ( childRouter ) {
257+ if ( include . tags . length > 0 ) {
258+ childRouter . tags = [
259+ ...new Set ( [ ...childRouter . tags , ...include . tags ] ) ,
260+ ]
261+ }
262+ routerNode . children . push ( {
263+ router : childRouter ,
264+ prefix : include . prefix ,
265+ tags : include . tags ,
266+ } )
267+ }
268+ }
269+
270+ return routerNode
238271 }
239272
240273 // Otherwise, look for an imported router
@@ -250,11 +283,19 @@ async function resolveRouterReference(
250283 // Helper to analyze a file with the filesystem
251284 const analyzeFileFn = ( uri : string ) => analyzeFile ( uri , parser , fs )
252285
286+ // Find the original import name (in case moduleName is an alias)
287+ // e.g., "from .api_tokens import router as api_tokens_router"
288+ // moduleName = "api_tokens_router", originalName = "router"
289+ const namedImport = matchingImport . namedImports . find (
290+ ( ni ) => ( ni . alias ?? ni . name ) === moduleName ,
291+ )
292+ const originalName = namedImport ?. name ?? moduleName
293+
253294 // Resolve the imported module to a file URI
254295 const importedFileUri = await resolveNamedImport (
255296 {
256297 modulePath : matchingImport . modulePath ,
257- names : [ moduleName ] ,
298+ names : [ originalName ] ,
258299 isRelative : matchingImport . isRelative ,
259300 relativeDots : matchingImport . relativeDots ,
260301 } ,
@@ -293,7 +334,7 @@ async function resolveRouterReference(
293334 const routerRoutes = importedAnalysis . routes . filter (
294335 ( r ) => r . owner === attributeName ,
295336 )
296- return {
337+ const routerNode : RouterNode = {
297338 filePath : importedFileUri ,
298339 variableName : targetRouter . variableName ,
299340 type : targetRouter . type ,
@@ -310,6 +351,39 @@ async function resolveRouterReference(
310351 } ) ) ,
311352 children : [ ] ,
312353 }
354+
355+ // Process include_router calls owned by this router (nested routers)
356+ const routerIncludes = importedAnalysis . includeRouters . filter (
357+ ( inc ) => inc . owner === attributeName ,
358+ )
359+ for ( const include of routerIncludes ) {
360+ log (
361+ `Resolving nested include_router: ${ include . router } (owner: ${ attributeName } , prefix: ${ include . prefix || "none" } )` ,
362+ )
363+ const childRouter = await resolveRouterReference (
364+ include . router ,
365+ importedAnalysis ,
366+ importedFileUri ,
367+ projectRootUri ,
368+ parser ,
369+ fs ,
370+ visited ,
371+ )
372+ if ( childRouter ) {
373+ if ( include . tags . length > 0 ) {
374+ childRouter . tags = [
375+ ...new Set ( [ ...childRouter . tags , ...include . tags ] ) ,
376+ ]
377+ }
378+ routerNode . children . push ( {
379+ router : childRouter ,
380+ prefix : include . prefix ,
381+ tags : include . tags ,
382+ } )
383+ }
384+ }
385+
386+ return routerNode
313387 }
314388 // If not found as a router, fall through to try building from file
315389 }
0 commit comments