@@ -48,67 +48,6 @@ function stripDocstring(raw: string): string {
4848 const dedented = lines . map ( ( l , i ) => ( i === 0 ? l : l . slice ( minIndent ) ) )
4949 return dedented . join ( "\n" ) . trim ( )
5050}
51- /*
52- * Extracts recognized FastAPI and APIRouter names from imports and class definitions
53- * This allows the rest of the extractors to handle user-defined aliases and subclasses.
54- *
55- * For example, if the code has:
56- * from fastapi import FastAPI as MyApp
57- * from fastapi import APIRouter as MyRouter
58- * class CustomRouter(MyRouter): ...
59- *
60- * Then this function will return:
61- * fastAPINames = Set { "FastAPI", "fastapi.FastAPI", "MyApp" }
62- * apiRouterNames = Set { "APIRouter", "fastapi.APIRouter", "MyRouter", "CustomRouter" }
63- *
64- * This allows decoratorExtractor and routerExtractor to recognize routes and routers
65- * defined using these aliases and subclasses without needing complex logic in those functions.
66- */
67- export function collectRecognizedNames ( rootNode : Node ) : {
68- fastAPINames : Set < string >
69- apiRouterNames : Set < string >
70- } {
71- const fastAPINames = new Set < string > ( [ "FastAPI" , "fastapi.FastAPI" ] )
72- const apiRouterNames = new Set < string > ( [ "APIRouter" , "fastapi.APIRouter" ] )
73-
74- // Add aliases from "from fastapi import X as Y" imports
75- for ( const node of findNodesByType ( rootNode , "import_from_statement" ) ) {
76- const info = importExtractor ( node )
77- if ( ! info || info . modulePath !== "fastapi" ) continue
78- for ( const named of info . namedImports ) {
79- if ( named . alias === null ) continue
80- if ( named . name === "FastAPI" ) fastAPINames . add ( named . alias )
81- else if ( named . name === "APIRouter" ) apiRouterNames . add ( named . alias )
82- }
83- }
84-
85- // Add module aliases from "import fastapi as f" → recognizes f.FastAPI, f.APIRouter
86- for ( const node of findNodesByType ( rootNode , "import_statement" ) ) {
87- const info = importExtractor ( node )
88- if ( ! info ) continue
89- for ( const named of info . namedImports ) {
90- if ( named . alias === null ) continue
91- if ( named . name === "fastapi" ) {
92- fastAPINames . add ( `${ named . alias } .FastAPI` )
93- apiRouterNames . add ( `${ named . alias } .APIRouter` )
94- }
95- }
96- }
97-
98- // Add subclasses, checking against the already-accumulated alias sets so
99- // "class MyRouter(AR)" works when AR is an alias for APIRouter
100- for ( const cls of findNodesByType ( rootNode , "class_definition" ) ) {
101- const nameNode = cls . childForFieldName ( "name" )
102- const superclassesNode = cls . childForFieldName ( "superclasses" )
103- if ( ! nameNode || ! superclassesNode ) continue
104- for ( const parent of superclassesNode . namedChildren ) {
105- if ( apiRouterNames . has ( parent . text ) ) apiRouterNames . add ( nameNode . text )
106- else if ( fastAPINames . has ( parent . text ) ) fastAPINames . add ( nameNode . text )
107- }
108- }
109-
110- return { fastAPINames, apiRouterNames }
111- }
11251
11352function collectNodesByType ( node : Node , type : string , results : Node [ ] ) : void {
11453 if ( node . type === type ) {
@@ -316,15 +255,15 @@ export function routerExtractor(
316255 const funcName = valueNode . childForFieldName ( "function" ) ?. text
317256 let type : RouterType
318257 if (
319- funcName === "APIRouter" ||
320- funcName === "fastapi.APIRouter" ||
321- ( funcName !== undefined && apiRouterNames ?. has ( funcName ) )
258+ funcName !== undefined &&
259+ ( apiRouterNames ?. has ( funcName ) ??
260+ ( funcName === "APIRouter" || funcName === "fastapi.APIRouter" ) )
322261 ) {
323262 type = "APIRouter"
324263 } else if (
325- funcName === "FastAPI" ||
326- funcName === "fastapi.FastAPI" ||
327- ( funcName !== undefined && fastAPINames ?. has ( funcName ) )
264+ funcName !== undefined &&
265+ ( fastAPINames ?. has ( funcName ) ??
266+ ( funcName === "FastAPI" || funcName === "fastapi.FastAPI" ) )
328267 ) {
329268 type = "FastAPI"
330269 } else {
@@ -460,6 +399,65 @@ export function importExtractor(node: Node): ImportInfo | null {
460399 return { modulePath, names, namedImports, isRelative, relativeDots }
461400}
462401
402+ /**
403+ * Extracts recognized FastAPI and APIRouter names from imports and class definitions.
404+ * This allows routerExtractor to handle user-defined aliases and subclasses.
405+ *
406+ * For example, if the code has:
407+ * from fastapi import FastAPI as MyApp
408+ * from fastapi import APIRouter as MyRouter
409+ * class CustomRouter(MyRouter): ...
410+ *
411+ * Then this function will return:
412+ * fastAPINames = Set { "FastAPI", "fastapi.FastAPI", "MyApp" }
413+ * apiRouterNames = Set { "APIRouter", "fastapi.APIRouter", "MyRouter", "CustomRouter" }
414+ */
415+ export function collectRecognizedNames ( rootNode : Node ) : {
416+ fastAPINames : Set < string >
417+ apiRouterNames : Set < string >
418+ } {
419+ const fastAPINames = new Set < string > ( [ "FastAPI" , "fastapi.FastAPI" ] )
420+ const apiRouterNames = new Set < string > ( [ "APIRouter" , "fastapi.APIRouter" ] )
421+
422+ // Add aliases from "from fastapi import X as Y" imports
423+ for ( const node of findNodesByType ( rootNode , "import_from_statement" ) ) {
424+ const info = importExtractor ( node )
425+ if ( ! info || info . modulePath !== "fastapi" ) continue
426+ for ( const named of info . namedImports ) {
427+ if ( named . alias === null ) continue
428+ if ( named . name === "FastAPI" ) fastAPINames . add ( named . alias )
429+ else if ( named . name === "APIRouter" ) apiRouterNames . add ( named . alias )
430+ }
431+ }
432+
433+ // Add module aliases from "import fastapi as f" → recognizes f.FastAPI, f.APIRouter
434+ for ( const node of findNodesByType ( rootNode , "import_statement" ) ) {
435+ const info = importExtractor ( node )
436+ if ( ! info ) continue
437+ for ( const named of info . namedImports ) {
438+ if ( named . alias === null ) continue
439+ if ( named . name === "fastapi" ) {
440+ fastAPINames . add ( `${ named . alias } .FastAPI` )
441+ apiRouterNames . add ( `${ named . alias } .APIRouter` )
442+ }
443+ }
444+ }
445+
446+ // Add subclasses, checking against the already-accumulated alias sets so
447+ // "class MyRouter(AR)" works when AR is an alias for APIRouter
448+ for ( const cls of findNodesByType ( rootNode , "class_definition" ) ) {
449+ const nameNode = cls . childForFieldName ( "name" )
450+ const superclassesNode = cls . childForFieldName ( "superclasses" )
451+ if ( ! nameNode || ! superclassesNode ) continue
452+ for ( const parent of superclassesNode . namedChildren ) {
453+ if ( apiRouterNames . has ( parent . text ) ) apiRouterNames . add ( nameNode . text )
454+ else if ( fastAPINames . has ( parent . text ) ) fastAPINames . add ( nameNode . text )
455+ }
456+ }
457+
458+ return { fastAPINames, apiRouterNames }
459+ }
460+
463461/**
464462 * Resolves a function argument value node by positional index or keyword name.
465463 *
0 commit comments