Skip to content

Commit e3955eb

Browse files
♻️ Refactor endpoint tree provider
1 parent a1d1f7b commit e3955eb

7 files changed

Lines changed: 293 additions & 253 deletions

File tree

src/appDiscovery.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,22 +172,27 @@ export async function discoverFastAPIApps(
172172

173173
if (routerNode) {
174174
const app = routerNodeToAppDefinition(routerNode, folder.uri.fsPath)
175-
const totalRoutes = collectRoutes([app]).length
176-
log(
177-
`Found FastAPI app "${app.name}" with ${totalRoutes} route(s) in ${app.routers.length} router(s)`,
178-
)
179175
folderApps.push(app)
180176
apps.push(app)
181177
break // TODO: Only use first successful app per workspace folder, for now
182178
}
183179
}
184180

181+
const folderRoutes = collectRoutes(folderApps)
182+
183+
if (folderApps.length > 0) {
184+
const app = folderApps[0]
185+
log(
186+
`Found FastAPI app "${app.name}" with ${folderRoutes.length} route(s) in ${app.routers.length} router(s)`,
187+
)
188+
}
189+
185190
// Track entrypoint detection per workspace folder
186191
trackEntrypointDetected({
187192
duration_ms: folderTimer(),
188193
method: detectionMethod,
189194
success: folderApps.length > 0,
190-
routes_count: collectRoutes(folderApps).length,
195+
routes_count: folderRoutes.length,
191196
routers_count: countRouters(folderApps),
192197
})
193198
}

src/core/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ export { Parser } from "./parser"
1111
export { findProjectRoot } from "./pathUtils"
1212
export { buildRouterGraph, type RouterNode } from "./routerResolver"
1313
export { routerNodeToAppDefinition } from "./transformer"
14-
export { collectRoutes, countRouters, findRouter } from "./treeUtils"
14+
export {
15+
collectRoutes,
16+
countRouters,
17+
countRoutesInRouter,
18+
findRouter,
19+
} from "./treeUtils"
1520
export type {
1621
AppDefinition,
1722
HTTPMethod,

src/core/treeUtils.ts

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,45 @@
1-
/**
2-
* Utility functions for traversing router trees.
3-
* Consolidates common recursive tree operations used across the codebase.
4-
*/
5-
61
import type { AppDefinition, RouteDefinition, RouterDefinition } from "./types"
72

8-
/**
9-
* Traverses all routers in a tree, calling the visitor function for each.
10-
* Returns early if visitor returns a non-undefined value.
11-
*/
12-
function traverseRouters<T>(
13-
routers: RouterDefinition[],
14-
visitor: (router: RouterDefinition) => T | undefined,
15-
): T | undefined {
16-
for (const router of routers) {
17-
const result = visitor(router)
18-
if (result !== undefined) {
19-
return result
20-
}
21-
const childResult = traverseRouters(router.children, visitor)
22-
if (childResult !== undefined) {
23-
return childResult
24-
}
25-
}
26-
return undefined
27-
}
28-
29-
/**
30-
* Finds a router matching the predicate across all apps.
31-
*/
3+
/** Finds the first router matching a condition across all apps. */
324
export function findRouter(
335
apps: AppDefinition[],
346
predicate: (router: RouterDefinition) => boolean,
357
): RouterDefinition | undefined {
8+
function findIn(routers: RouterDefinition[]): RouterDefinition | undefined {
9+
for (const r of routers) {
10+
if (predicate(r)) return r
11+
const found = findIn(r.children)
12+
if (found) return found
13+
}
14+
return undefined
15+
}
3616
for (const app of apps) {
37-
const found = traverseRouters(app.routers, (router) =>
38-
predicate(router) ? router : undefined,
39-
)
17+
const found = findIn(app.routers)
4018
if (found) return found
4119
}
4220
return undefined
4321
}
4422

45-
/**
46-
* Collects all routes from a list of routers, including nested children.
47-
*/
48-
function collectRoutesFromRouters(
49-
routers: RouterDefinition[],
50-
): RouteDefinition[] {
51-
return routers.flatMap((router) => [
52-
...router.routes,
53-
...collectRoutesFromRouters(router.children),
54-
])
23+
/** Collects all routes from all apps, including nested router routes. */
24+
export function collectRoutes(apps: AppDefinition[]): RouteDefinition[] {
25+
function fromRouters(routers: RouterDefinition[]): RouteDefinition[] {
26+
return routers.flatMap((r) => [...r.routes, ...fromRouters(r.children)])
27+
}
28+
return apps.flatMap((app) => [...app.routes, ...fromRouters(app.routers)])
5529
}
5630

57-
/**
58-
* Collects all routes from all apps, including nested router routes.
59-
*/
60-
export function collectRoutes(apps: AppDefinition[]): RouteDefinition[] {
61-
return apps.flatMap((app) => [
62-
...app.routes,
63-
...collectRoutesFromRouters(app.routers),
64-
])
31+
/** Counts all routes in a router, including nested routers. */
32+
export function countRoutesInRouter(router: RouterDefinition): number {
33+
return (
34+
router.routes.length +
35+
router.children.reduce((sum, child) => sum + countRoutesInRouter(child), 0)
36+
)
6537
}
6638

67-
/**
68-
* Counts total routers across all apps.
69-
*/
39+
/** Counts total routers across all apps. */
7040
export function countRouters(apps: AppDefinition[]): number {
71-
let count = 0
72-
for (const app of apps) {
73-
traverseRouters(app.routers, () => {
74-
count++
75-
return undefined
76-
})
41+
function count(routers: RouterDefinition[]): number {
42+
return routers.reduce((sum, r) => sum + 1 + count(r.children), 0)
7743
}
78-
return count
44+
return apps.reduce((sum, app) => sum + count(app.routers), 0)
7945
}

src/extension.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export async function activate(context: vscode.ExtensionContext) {
138138
})
139139
}
140140

141-
const endpointProvider = new EndpointTreeProvider(apps, groupApps)
141+
const endpointProvider = new EndpointTreeProvider(apps, groupApps(apps))
142142
const codeLensProvider = new TestCodeLensProvider(parserService, apps)
143143

144144
// File watcher for auto-refresh
@@ -148,7 +148,7 @@ export async function activate(context: vscode.ExtensionContext) {
148148
refreshTimeout = setTimeout(async () => {
149149
if (!parserService) return
150150
const newApps = await discoverFastAPIApps(parserService)
151-
endpointProvider.setApps(newApps, groupApps)
151+
endpointProvider.setApps(newApps, groupApps(newApps))
152152
codeLensProvider.setApps(newApps)
153153
}, 300)
154154
}
@@ -214,7 +214,7 @@ function registerCommands(
214214
if (!parserService) return
215215
clearImportCache()
216216
const newApps = await discoverFastAPIApps(parserService)
217-
endpointProvider.setApps(newApps, groupApps)
217+
endpointProvider.setApps(newApps, groupApps(newApps))
218218
codeLensProvider.setApps(newApps)
219219
},
220220
),

0 commit comments

Comments
 (0)