Repository navigation
Description
Summary
Extract HTTP route definitions from TypeScript/JavaScript web framework files using tree-sitter. Supports Express and Next.js App Router.
New file
src/specleft/discovery/miners/typescript/routes.py
import uuid
from specleft.discovery.models import SupportedLanguage, MinerResult, DiscoveredItem, ItemKind, ApiRouteMeta
from specleft.discovery.context import MinerContext
class TypeScriptRouteMiner:
miner_id = uuid.UUID("b06e8c32-c793-41dc-91de-12635d6c4f69")
name = "typescript_api_routes"
languages = frozenset({SupportedLanguage.TYPESCRIPT, SupportedLanguage.JAVASCRIPT})
def mine(self, ctx: MinerContext) -> MinerResult: ...Framework detection
Read from ctx.frameworks.get(SupportedLanguage.TYPESCRIPT, []) / ctx.frameworks.get(SupportedLanguage.JAVASCRIPT, []). Do NOT re-parse package.json.
Detection strategies per framework
Express:
Tree-sitter query on ctx.file_index.files_by_language(SupportedLanguage.TYPESCRIPT) + JAVASCRIPT: call expressions where callee is member expression on app/router, method is get|post|put|patch|delete|use. First string argument is path.
Next.js App Router (file-based):
Use ctx.file_index.files_matching("**/app/**/route.ts", "**/app/**/route.js"). Named exports export async function GET(request) — HTTP method from export name. Path inferred from file path relative to app/: app/users/[id]/route.ts → /users/{id}.
Typed metadata
Each item's metadata dict must conform to ApiRouteMeta:
ApiRouteMeta(
http_method = "DELETE",
path = "/api/users/{id}",
framework = "nextjs",
handler_name = "DELETE",
is_file_based_route = True,
)name: "{METHOD} {path}"
language: SupportedLanguage.TYPESCRIPT or SupportedLanguage.JAVASCRIPT based on file extension
Acceptance criteria
-
router.get("/health", handler)→ item withmethod=GET,path=/health,framework=express -
.tsfiles getSupportedLanguage.TYPESCRIPT;.jsfiles getSupportedLanguage.JAVASCRIPT - Each item's
metadatavalidates againstApiRouteMeta -
app/api/users/[id]/route.tsexportingfunction DELETE→method=DELETE,path=/api/users/{id},is_file_based_route=True - Next.js file with multiple exports (
GET,POST) produces 2 separate items - Uses
ctx.file_indexandctx.frameworks— no direct filesystem or manifest parsing - Tests in
tests/discovery/miners/test_typescript_routes.py - Update scenarios and tests in
features/feature-spec-discovery.mdto cover the functionality introduced by this issue
Activity
Dimwiddle commentedon Mar 6, 2026
Implementation Notes
Branch:
codex/130-typescript-api-routesApproach: Implement a TypeScript/JavaScript route miner that uses shared discovery context (
ctx.file_index,ctx.frameworks,ctx.registry) to extract Express and Next.js App Router routes and emit validatedApiRouteMetametadata.Decisions
ctx.frameworksto avoid scanning unsupported patterns.[id]->{id}) for consistency.export function METHOD) while file discovery still usesctx.file_indexand parser validation still flows throughctx.registry.Tasks
TypeScriptRouteMinerinsrc/specleft/discovery/miners/typescript/routes.pytests/discovery/miners/test_typescript_routes.pyfeatures/feature-spec-discovery.mdAdd TypeScript and JavaScript API route miner (#130)
Dimwiddle commentedon Mar 6, 2026
Follow-up (deferred): Broader Next.js route coverage
Current miner behavior intentionally focuses on App Router file-based routes (
app/**/route.ts|route.js, includingsrc/app/**/...).If broader Next.js support is needed later, we can extend coverage with:
pages/api/**andsrc/pages/api/**handlers.next_route_roots) so projects with custom structure can opt in.export function GET/POSTpatterns.This is optional and can be implemented in a follow-up issue if/when required.
Merge pull request #146 from SpecLeft/codex/130-typescript-api-routes