release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-02 23:18:51 +05:30
parent 87507edf59
commit 586a6db8ff
625 changed files with 243608 additions and 11210 deletions
+49 -10
View File
@@ -4,10 +4,12 @@
*/
import { getRouteParams, type Route } from "./match.ts";
import { nameRoutes } from "./named.ts";
export function generateRoutesFile(pages: Route[]): string {
const seen = new Set<string>();
const entries: string[] = [];
const namedEntries: string[] = [];
for (const page of [...pages].sort((a, b) => a.raw.localeCompare(b.raw))) {
if (seen.has(page.raw)) continue;
seen.add(page.raw);
@@ -23,6 +25,8 @@ export function generateRoutesFile(pages: Route[]): string {
: "Record<string, never>";
entries.push(` ${JSON.stringify(page.raw)}: ${type};`);
}
for (const page of nameRoutes([...pages].sort((a, b) => a.raw.localeCompare(b.raw))))
namedEntries.push(` ${JSON.stringify(page.name)}: ${JSON.stringify(page.raw)};`);
return `// AUTO-GENERATED by \`wrnexus dev\` - do not edit.
// Typed routes support required, optional, and catch-all parameters.
@@ -31,7 +35,19 @@ export interface Routes {
${entries.join("\n") || " [path: string]: Record<string, string>;"}
}
export interface RouteNames {
${namedEntries.join("\n") || " [name: string]: string;"}
}
export interface RouteQueries {
[path: string]: Record<string, string | number | boolean | null | undefined>;
}
export type RoutePath = keyof Routes;
export type RouteName = keyof RouteNames;
export type RouteQuery<P extends RoutePath> = P extends keyof RouteQueries
? RouteQueries[P]
: Record<string, string | number | boolean | null | undefined>;
type RouteValue = string | readonly string[] | undefined;
function encodeRouteValue(value: RouteValue, catchAll: boolean): string {
@@ -40,17 +56,9 @@ function encodeRouteValue(value: RouteValue, catchAll: boolean): string {
return values.map((part) => encodeURIComponent(part)).join("/");
}
export function href<P extends RoutePath>(
path: P,
...args: keyof Routes[P] extends never
? []
: Record<string, never> extends Routes[P]
? [params?: Routes[P]]
: [params: Routes[P]]
): string {
const params = (args[0] ?? {}) as Record<string, RouteValue>;
function buildHref(path: string, params: Record<string, RouteValue> = {}): string {
const output: string[] = [];
for (const segment of String(path).split("/").filter(Boolean)) {
for (const segment of path.split("/").filter(Boolean)) {
let name: string | undefined;
let optional = false;
let catchAll = false;
@@ -79,5 +87,36 @@ export function href<P extends RoutePath>(
}
return "/" + output.filter(Boolean).join("/");
}
export function href<P extends RoutePath>(
path: P,
...args: keyof Routes[P] extends never
? []
: Record<string, never> extends Routes[P]
? [params?: Routes[P]]
: [params: Routes[P]]
): string {
const params = (args[0] ?? {}) as Record<string, RouteValue>;
return buildHref(String(path), params);
}
export function route<N extends RouteName>(
name: N,
...args: keyof Routes[RouteNames[N]] extends never
? [params?: Routes[RouteNames[N]], query?: RouteQuery<RouteNames[N]>]
: Record<string, never> extends Routes[RouteNames[N]]
? [params?: Routes[RouteNames[N]], query?: RouteQuery<RouteNames[N]>]
: [params: Routes[RouteNames[N]], query?: RouteQuery<RouteNames[N]>]
): string {
const paths: Record<RouteName, RoutePath> = ${JSON.stringify(Object.fromEntries(nameRoutes([...pages].sort((a, b) => a.raw.localeCompare(b.raw))).map((page) => [page.name, page.raw])), null, 2)} as Record<RouteName, RoutePath>;
const output = buildHref(paths[name], (args[0] ?? {}) as Record<string, RouteValue>);
const query = args[1];
if (!query) return output;
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();
return text ? \`\${output}?\${text}\` : output;
}
`;
}