UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

128 lines (126 loc) 4.79 kB
import { getRoutes } from "../router/getRoutes.mjs"; import { isTypedRoute, removeSupportedExtensions } from "../router/matchers.mjs"; const CATCH_ALL = /\[\.\.\..+?\]/g; const SLUG = /\[.+?\]/g; function getTypedRoutesDeclarationFile(ctx) { const staticRoutes = /* @__PURE__ */new Set(); const dynamicRoutes = /* @__PURE__ */new Set(); const dynamicRouteContextKeys = /* @__PURE__ */new Set(); walkRouteNode(getRoutes(ctx, { platformRoutes: false, // We don't need to generate platform specific routes ignoreEntryPoints: true, ignoreRequireErrors: true // importMode: 'async', }), "", staticRoutes, dynamicRoutes, dynamicRouteContextKeys); const hasRoutes = dynamicRouteContextKeys.size > 0; return `// deno-lint-ignore-file /* eslint-disable */ // biome-ignore: needed import import type { OneRouter } from 'one' declare module 'one' { export namespace OneRouter { export interface __routes<T extends string = string> extends Record<string, unknown> { StaticRoutes:${setToUnionType(staticRoutes)} DynamicRoutes:${setToUnionType(dynamicRoutes)} DynamicRouteTemplate:${setToUnionType(dynamicRouteContextKeys)} IsTyped: true ${hasRoutes ? `RouteTypes: ${generateRouteTypesMap(dynamicRouteContextKeys)}` : ""} } } } ${hasRoutes ? ` /** * Helper type for route information */ type RouteInfo<Params = Record<string, never>> = { Params: Params LoaderProps: { path: string; search?: string; subdomain?: string; params: Params; request?: Request } }` : ""} `.trim(); } function generateRouteTypesMap(dynamicRouteContextKeys) { if (dynamicRouteContextKeys.size === 0) { return "{}"; } const routes = [...dynamicRouteContextKeys].sort(); const entries = routes.map(routePath => { const params = extractParams(routePath); const paramsType = params.length === 0 ? "{}" : generateInlineParamsType(params); return ` '${routePath}': RouteInfo<${paramsType}>`; }).join("\n"); return `{ ${entries} }`; } function extractParams(routePath) { const params = []; const paramRegex = /\[(\.\.\.)?([\w]+)\]/g; let match; while ((match = paramRegex.exec(routePath)) !== null) { params.push({ name: match[2], isCatchAll: match[1] === "..." }); } return params; } function generateInlineParamsType(params) { const entries = params.map(p => { const type = p.isCatchAll ? "string[]" : "string"; return `${p.name}: ${type}`; }); return `{ ${entries.join("; ")} }`; } function walkRouteNode(routeNode, parentRoutePath, staticRoutes, dynamicRoutes, dynamicRouteContextKeys) { if (!routeNode) return; addRouteNode(routeNode, parentRoutePath, staticRoutes, dynamicRoutes, dynamicRouteContextKeys); parentRoutePath = `${removeSupportedExtensions(`${parentRoutePath}/${routeNode.route}`).replace(/\/?index$/, "")}`; for (const child of routeNode.children) { walkRouteNode(child, parentRoutePath, staticRoutes, dynamicRoutes, dynamicRouteContextKeys); } } function addRouteNode(routeNode, parentRoutePath, staticRoutes, dynamicRoutes, dynamicRouteContextKeys) { if (!routeNode?.route) return; if (!isTypedRoute(routeNode.route)) return; let routePath = `${parentRoutePath}/${removeSupportedExtensions(routeNode.route).replace(/\/?index$/, "")}`; if (!routePath.startsWith("/")) { routePath = `/${routePath}`; } if (routeNode.dynamic) { for (const path of generateCombinations(routePath)) { dynamicRouteContextKeys.add(path); dynamicRoutes.add( // biome-ignore lint/suspicious/noTemplateCurlyInString: intentionally generating type string `${path.replaceAll(CATCH_ALL, "${string}").replaceAll(SLUG, "${OneRouter.SingleRoutePart<T>}")}`); } } else { for (const combination of generateCombinations(routePath)) { staticRoutes.add(combination); } } } const setToUnionType = set => { if (set.size === 0) return " never"; const sorted = [...set].sort(); if (sorted.length === 1) return ` \`${sorted[0]}\``; return "\n | " + sorted.map(s => `\`${s}\``).join("\n | "); }; function generateCombinations(pathname) { const groups = pathname.split("/").filter(part => part.startsWith("(") && part.endsWith(")")); const combinations = []; function generate(currentIndex, currentPath) { if (currentIndex === groups.length) { combinations.push(currentPath.replace(/\/{2,}/g, "/")); return; } const group = groups[currentIndex]; const withoutGroup = currentPath.replace(`/${group}`, ""); generate(currentIndex + 1, withoutGroup); generate(currentIndex + 1, currentPath); } generate(0, pathname); return combinations; } export { getTypedRoutesDeclarationFile }; //# sourceMappingURL=getTypedRoutesDeclarationFile.mjs.map