one
Version:
One is a new React Framework that makes Vite serve both native and web.
128 lines (126 loc) • 4.79 kB
JavaScript
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