@@ -16,14 +16,48 @@ export class FastapiEndpointExtractor implements IEndpointExtractor
1616 // Ensure fastapi module was imported
1717 if ( ! tokens . any ( t => t . text == 'fastapi' && t . type == TokenType . module ) )
1818 return [ ] ;
19+
20+ let prefix = '' ;
1921
2022 // Search for "@app.get" decorators
21- const results : EndpointInfo [ ] = [ ]
23+ const results : EndpointInfo [ ] = [ ] ;
2224 for ( let i = 0 ; i < tokens . length - 1 ; i ++ )
2325 {
2426 const appToken = tokens [ i ] ;
2527 const methodToken = tokens [ i + 1 ] ;
26- if ( appToken . text != 'app' || appToken . type != TokenType . variable || methodToken . type != TokenType . method )
28+
29+ //Check if this is a router variable
30+ if ( appToken . type === TokenType . variable
31+ && methodToken . type === TokenType . class && methodToken . text === 'APIRouter' ) {
32+
33+ const routerLine = document . getText ( new vscode . Range (
34+ appToken . range . start ,
35+ new vscode . Position ( methodToken . range . end . line , 1000 ) ) ) ;
36+
37+ //extract the prefix
38+ let match = new RegExp ( `^${ appToken . text } \\s*=\\s*\\APIRouter\\s*\\((.*=.*,\\s*)*prefix=\\s*["'](.*?)["'](ֿֿֿ\\s*,.*=.*)*\\)*\\)` ) . exec ( routerLine ) ;
39+ if ( match ) {
40+ prefix = match [ 2 ] ;
41+ }
42+
43+ //Future: use the references to extract the 'include' statement to the router if it contains a prefix
44+
45+ // const position =new vscode.Position(appToken.range.start.line,appToken.range.start.character );
46+
47+ // let references : vscode.Location[] = await vscode.commands.executeCommand("vscode.executeReferenceProvider", document.uri,position);
48+ // references = references.filter(x=>x.uri.fsPath!==document.uri.fsPath);
49+ // if (references.length>0){
50+ // let referencedDocument = vscode.workspace.openTextDocument(references[0].uri);
51+ // let text = (await referencedDocument).getText(references[0].range);
52+ // console.log(text);
53+
54+ // }
55+
56+
57+ }
58+
59+
60+ if ( ( appToken . text != 'app' && appToken . text != 'router' ) || appToken . type != TokenType . variable || methodToken . type != TokenType . method )
2761 continue ;
2862
2963 const method = methodToken . text ;
@@ -33,21 +67,37 @@ export class FastapiEndpointExtractor implements IEndpointExtractor
3367 const lineText = document . getText ( new vscode . Range (
3468 appToken . range . start ,
3569 new vscode . Position ( methodToken . range . end . line , 1000 ) ) ) ;
36- const match = new RegExp ( `^app\\.${ method } \\(["'](.*?)["']` ) . exec ( lineText ) ;
70+
71+ let index = 2 ;
72+ let match = new RegExp ( `^(app|router)\\.${ method } \\(["'](\/.*?)["']` ) . exec ( lineText ) ;
73+ if ( ! match ) {
74+ //Different regex for optional params (named)
75+ match = new RegExp ( `^(app|router)\\.${ method } \\((.*=.*,\\s*)*path=\\s*["'](\\/.*?)["'](ֿֿֿ\\s*,.*=.*)*\\)` ) . exec ( lineText ) ;
76+ index = 3 ;
77+ }
78+
3779 if ( ! match )
3880 continue ;
3981
4082 const relevantFunc = symbolInfo . firstOrDefault ( s => s . range . contains ( methodToken . range ) )
4183 if ( ! relevantFunc )
4284 continue ;
4385
44- const path = match [ 1 ] ;
45- results . push ( new EndpointInfo (
46- vscode . workspace . getWorkspaceFolder ( document . uri ) ! . name + '$_$' + method + ' ' + match [ 1 ] ,
47- method ,
48- path ,
49- relevantFunc . range ,
50- document . uri ) ) ;
86+ const path = match [ index ] ;
87+ let folder = vscode . workspace . getWorkspaceFolder ( document . uri ) ;
88+ let folderPrefix = folder ?. uri . path . split ( '/' ) . slice ( 0 , - 1 ) . join ( '/' ) ;
89+ let relevantPath = document . uri . path . substring ( folderPrefix ! . length ) ;
90+ let pathParts = relevantPath . split ( '/' ) . filter ( x => x ) ;
91+ for ( let j = 0 ; j < pathParts . length - 1 ; j ++ ) {
92+ let possibleRoot = pathParts [ j ] ;
93+ results . push ( new EndpointInfo (
94+ possibleRoot + '$_$' + method + ' ' + prefix + path ,
95+ method ,
96+ path ,
97+ relevantFunc . range ,
98+ document . uri ) ) ;
99+ }
100+
51101 }
52102 return results ;
53103 }
0 commit comments