everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 6.52 kB
Source Map (JSON)
{"version":3,"file":"routes.mjs","names":[],"sources":["../../../../../src/services/scaffold/upgrade-audit/checks/routes.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Finding, KNOWN_MOUNTS, MOUNT_ALIASES } from \"../domain\";\nimport { listFiles, readText } from \"../fs\";\n\nconst ROUTE_FILE_RE = /createFileRoute(?:<[^>]*>)?\\(\\s*[\"'`]([^\"'`]+)[\"'`]/;\n\nconst AUTHED_MOUNTS = new Set([\"authenticated\", \"admin\", \"organization\"]);\n\nconst SESSION_CALLEES = [\"authClient.getSession(\", \"sessionQueryOptions(\"];\n\nconst firstSegment = (routePath: string): string | null => {\n const segments = routePath.split(\"/\").filter(Boolean);\n return segments.length > 0 ? segments[0] : null;\n};\n\nconst isLayoutPath = (routePath: string): boolean =>\n routePath.split(\"/\").filter(Boolean).length === 1;\n\nconst parseRoutePath = (source: string): string | null => {\n const match = source.match(ROUTE_FILE_RE);\n return match?.[1] ?? null;\n};\n\nconst checkRoot = (relativePath: string, source: string): Finding[] => {\n const findings: Finding[] = [];\n if (!/<html[\\s>]/.test(source)) {\n findings.push(\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"warn\",\n message: \"root route has no document shell — already thin, graft-ready\",\n }),\n );\n return findings;\n }\n findings.push(\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"warn\",\n message:\n \"root route owns the document shell (<html>) — acceptable today, must become thin (<Outlet />) before the app.ts/grafting model\",\n }),\n );\n return findings;\n};\n\nconst checkRouteFile = (relativePath: string, source: string): Finding[] => {\n if (relativePath.endsWith(\"__root.tsx\")) {\n return checkRoot(relativePath, source);\n }\n\n const routePath = parseRoutePath(source);\n if (!routePath) {\n return [\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"blocker\",\n message: \"no createFileRoute() call with a path literal found\",\n }),\n ];\n }\n\n const segment = firstSegment(routePath);\n if (!segment?.startsWith(\"_\")) {\n return [\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"blocker\",\n message: `route \"/${routePath.replace(/^\\//, \"\")}\" is not mounted under a pathless layout — re-home under _<mount>`,\n }),\n ];\n }\n\n const mountId = segment.slice(1);\n const canonical = MOUNT_ALIASES[mountId] ?? mountId;\n const findings: Finding[] = [];\n\n if (!KNOWN_MOUNTS.includes(canonical as (typeof KNOWN_MOUNTS)[number])) {\n findings.push(\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"blocker\",\n message: `unknown mount \"_${mountId}\" — not in the host mount registry`,\n }),\n );\n return findings;\n }\n\n if (\n isLayoutPath(routePath) &&\n AUTHED_MOUNTS.has(canonical) &&\n !/beforeLoad\\s*[:(]/.test(source)\n ) {\n findings.push(\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"blocker\",\n message: `authed layout \"_${mountId}\" has no beforeLoad gate — session checks must live on the mount`,\n }),\n );\n }\n\n if (!isLayoutPath(routePath) && SESSION_CALLEES.some((callee) => source.includes(callee))) {\n findings.push(\n new Finding({\n check: \"routes\",\n path: relativePath,\n severity: \"warn\",\n message: \"leaf route resolves the session directly — inherit the mount gate instead\",\n }),\n );\n }\n\n return findings;\n};\n\nexport const checkRoutes = (projectDir: string): Effect.Effect<Finding[], Error> =>\n Effect.gen(function* () {\n const files = (yield* listFiles(projectDir, \"ui/src/routes/**/*.{ts,tsx}\")).filter(\n (file) => !file.endsWith(\".test.ts\"),\n );\n\n if (files.length === 0) {\n return [\n new Finding({\n check: \"routes\",\n path: \"ui/src/routes\",\n severity: \"blocker\",\n message: \"no route files found — is this a child app with UI overrides?\",\n }),\n ];\n }\n\n const findings: Finding[] = [];\n for (const file of files) {\n const source = yield* readText(projectDir, file);\n findings.push(...checkRouteFile(file, source));\n }\n return findings;\n });\n"],"mappings":";;;;;AAIA,MAAM,gBAAgB;AAEtB,MAAM,gCAAgB,IAAI,IAAI;CAAC;CAAiB;CAAS;AAAc,CAAC;AAExE,MAAM,kBAAkB,CAAC,0BAA0B,sBAAsB;AAEzE,MAAM,gBAAgB,cAAqC;CACzD,MAAM,WAAW,UAAU,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;CACpD,OAAO,SAAS,SAAS,IAAI,SAAS,KAAK;AAC7C;AAEA,MAAM,gBAAgB,cACpB,UAAU,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,WAAW;AAElD,MAAM,kBAAkB,WAAkC;CAExD,OADc,OAAO,MAAM,aAChB,CAAC,GAAG,MAAM;AACvB;AAEA,MAAM,aAAa,cAAsB,WAA8B;CACrE,MAAM,WAAsB,CAAC;CAC7B,IAAI,CAAC,aAAa,KAAK,MAAM,GAAG;EAC9B,SAAS,KACP,IAAI,QAAQ;GACV,OAAO;GACP,MAAM;GACN,UAAU;GACV,SAAS;EACX,CAAC,CACH;EACA,OAAO;CACT;CACA,SAAS,KACP,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SACE;CACJ,CAAC,CACH;CACA,OAAO;AACT;AAEA,MAAM,kBAAkB,cAAsB,WAA8B;CAC1E,IAAI,aAAa,SAAS,YAAY,GACpC,OAAO,UAAU,cAAc,MAAM;CAGvC,MAAM,YAAY,eAAe,MAAM;CACvC,IAAI,CAAC,WACH,OAAO,CACL,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS;CACX,CAAC,CACH;CAGF,MAAM,UAAU,aAAa,SAAS;CACtC,IAAI,CAAC,SAAS,WAAW,GAAG,GAC1B,OAAO,CACL,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS,WAAW,UAAU,QAAQ,OAAO,EAAE,EAAE;CACnD,CAAC,CACH;CAGF,MAAM,UAAU,QAAQ,MAAM,CAAC;CAC/B,MAAM,YAAY,cAAc,YAAY;CAC5C,MAAM,WAAsB,CAAC;CAE7B,IAAI,CAAC,aAAa,SAAS,SAA0C,GAAG;EACtE,SAAS,KACP,IAAI,QAAQ;GACV,OAAO;GACP,MAAM;GACN,UAAU;GACV,SAAS,mBAAmB,QAAQ;EACtC,CAAC,CACH;EACA,OAAO;CACT;CAEA,IACE,aAAa,SAAS,KACtB,cAAc,IAAI,SAAS,KAC3B,CAAC,oBAAoB,KAAK,MAAM,GAEhC,SAAS,KACP,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS,mBAAmB,QAAQ;CACtC,CAAC,CACH;CAGF,IAAI,CAAC,aAAa,SAAS,KAAK,gBAAgB,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC,GACtF,SAAS,KACP,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS;CACX,CAAC,CACH;CAGF,OAAO;AACT;AAEA,MAAa,eAAe,eAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO,UAAU,YAAY,6BAA6B,EAAC,CAAE,QACzE,SAAS,CAAC,KAAK,SAAS,UAAU,CACrC;CAEA,IAAI,MAAM,WAAW,GACnB,OAAO,CACL,IAAI,QAAQ;EACV,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS;CACX,CAAC,CACH;CAGF,MAAM,WAAsB,CAAC;CAC7B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,OAAO,SAAS,YAAY,IAAI;EAC/C,SAAS,KAAK,GAAG,eAAe,MAAM,MAAM,CAAC;CAC/C;CACA,OAAO;AACT,CAAC"}