/** * lib/navroute-parser.ts — Extract [NavRoute] attributes from C# files. * Ported from SmartStack.cli/src/mcp/lib/navroute-parser.ts. * * NavRoute is a SmartStack-specific attribute placed on controllers to declare * the navigation path the controller serves (e.g. [NavRoute("hr.employees")]). * Frontend routing and permission seeding are derived from these attributes. */ export interface ParsedNavRoute { /** Base path (e.g. "administration.users") */ navRoute: string; /** Optional sub-path (e.g. "dashboard") */ suffix?: string; /** Full path including suffix (e.g. "administration.users.dashboard") */ fullNavRoute: string; /** True if inferred from [Route("api/...")] because no [NavRoute] was found */ inferred?: boolean; } /** * Extract every [NavRoute(...)] attribute from a C# file's content. * Uses matchAll() to capture multiple attributes per file. * * Fallback: if no [NavRoute] is found, infer from [Route("api/...")] attributes * by converting the URL path to a dot-path. */ export function extractNavRoutes(content: string): ParsedNavRoute[] { const results: ParsedNavRoute[] = []; const regex = /\[NavRoute\s*\(\s*"([^"]+)"(?:\s*,\s*Suffix\s*=\s*"([^"]+)")?\s*\)\]/g; for (const match of content.matchAll(regex)) { const navRoute = match[1]; const suffix = match[2]; const fullNavRoute = suffix ? `${navRoute}.${suffix}` : navRoute; results.push({ navRoute, suffix, fullNavRoute }); } if (results.length === 0) { const routeRegex = /\[Route\s*\(\s*"api\/([^"]+)"\s*\)\]/g; for (const match of content.matchAll(routeRegex)) { const routePath = match[1]; // Skip template routes like api/[controller] if (routePath.includes('[')) continue; const navRoute = routePath.replace(/\//g, '.'); results.push({ navRoute, fullNavRoute: navRoute, inferred: true }); } } return results; }