release: WRNexusJS 0.4.0
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { getRouteParams, type Route } from "./match.ts";
|
||||
|
||||
export interface NamedRoute extends Route {
|
||||
name: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface RouteManifestEntry {
|
||||
name: string;
|
||||
path: string;
|
||||
file: string;
|
||||
params: ReturnType<typeof getRouteParams>;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function routeName(raw: string): string {
|
||||
const value = raw.replace(/^\/+|\/+$/g, "");
|
||||
return value
|
||||
? value.replace(/\[\[?\.\.\.|\[\[?|\]\]?/g, "").replace(/[^A-Za-z0-9]+/g, ".")
|
||||
: "index";
|
||||
}
|
||||
|
||||
export function nameRoutes(
|
||||
routes: readonly Route[],
|
||||
metadata: Record<string, Record<string, unknown>> = {},
|
||||
): NamedRoute[] {
|
||||
const used = new Map<string, number>();
|
||||
return routes.map((route) => {
|
||||
const base = routeName(route.raw);
|
||||
const count = (used.get(base) ?? 0) + 1;
|
||||
used.set(base, count);
|
||||
const name = count === 1 ? base : `${base}.${count}`;
|
||||
return { ...route, name, metadata: metadata[name] };
|
||||
});
|
||||
}
|
||||
|
||||
export function createRouteManifest(routes: readonly NamedRoute[]): RouteManifestEntry[] {
|
||||
return routes.map((route) => ({
|
||||
name: route.name,
|
||||
path: route.raw,
|
||||
file: route.file,
|
||||
params: route.paramMeta ?? getRouteParams(route.raw),
|
||||
metadata: route.metadata,
|
||||
}));
|
||||
}
|
||||
|
||||
export function routeUrl(
|
||||
route: Pick<NamedRoute, "raw" | "paramMeta">,
|
||||
params: Record<string, string | number | Array<string | number> | null | undefined> = {},
|
||||
query?: Record<string, string | number | boolean | null | undefined>,
|
||||
): string {
|
||||
const meta = route.paramMeta ?? getRouteParams(route.raw);
|
||||
let output = route.raw;
|
||||
for (const param of meta) {
|
||||
const value = params[param.name];
|
||||
if (value === undefined || value === null || value === "") {
|
||||
if (!param.optional) throw new Error(`WRN-ROUTE-MISSING-PARAM: ${param.name}`);
|
||||
output = output.replace(new RegExp(`/\\[\\[?(?:\\.\\.\\.)?${param.name}\\??\\]\\]?`), "");
|
||||
continue;
|
||||
}
|
||||
const encoded = Array.isArray(value)
|
||||
? value.map((part) => encodeURIComponent(String(part))).join("/")
|
||||
: encodeURIComponent(String(value));
|
||||
output = output.replace(new RegExp(`\\[\\[?(?:\\.\\.\\.)?${param.name}\\??\\]\\]?`), encoded);
|
||||
}
|
||||
output = output.replace(/\/+/g, "/") || "/";
|
||||
if (query) {
|
||||
const search = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(query))
|
||||
if (value !== undefined && value !== null) search.set(key, String(value));
|
||||
const text = search.toString();
|
||||
if (text) output += `?${text}`;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
export function findNamedRoute(routes: readonly NamedRoute[], name: string): NamedRoute {
|
||||
const route = routes.find((candidate) => candidate.name === name);
|
||||
if (!route) throw new Error(`WRN-ROUTE-NAME-NOT-FOUND: ${name}`);
|
||||
return route;
|
||||
}
|
||||
Reference in New Issue
Block a user