/** * `wrnexus generate ` — scaffold a page, component, API route, or * schema from a template. Keeps new files consistent and gets users moving fast. * * wrnexus generate page about * wrnexus generate component user-card * wrnexus generate api users/list * wrnexus generate schema signup */ import { existsSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; export type GenerateType = "page" | "component" | "api" | "schema"; const ALIASES: Record = { page: "page", p: "page", component: "component", c: "component", api: "api", a: "api", schema: "schema", s: "schema", }; export interface GeneratedFile { /** Path relative to the `app/` directory. */ path: string; content: string; } function toPascalCase(name: string): string { return name .split(/[^A-Za-z0-9]+/) .filter(Boolean) .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join(""); } function baseName(name: string): string { const parts = name.split("/"); return parts[parts.length - 1] ?? name; } /** Produce the file (relative path + content) for a generate request. */ export function scaffold(type: GenerateType, name: string): GeneratedFile { const clean = name.replace(/\.(wrn|ts)$/, "").replace(/^\/+|\/+$/g, ""); const pascal = toPascalCase(baseName(clean)); switch (type) { case "page": return { path: `pages/${clean}.wrn`, content: `page ${pascal} { layout = "public" seo { title = "${pascal}" } view {

${pascal}

Edit app/pages/${clean}.wrn to build this page.

} } `, }; case "component": return { path: `components/${clean}.wrn`, content: `component ${pascal} { props { label = "${pascal}" } view {
{label}
} } `, }; case "api": return { path: `api/${clean}.ts`, content: `import type { Context } from "@wrnexus/core"; export async function GET(ctx: Context): Promise { return Response.json({ ok: true, route: ctx.url.pathname }); } `, }; case "schema": return { path: `schemas/${clean}.ts`, content: `import { v } from "@wrnexus/validation"; export default v.object({ name: v.string().min(1, "Required"), }); `, }; } } /** Write a scaffolded file under `/app`, refusing to overwrite. */ export function runGenerate( appRoot: string, typeArg: string | undefined, name: string | undefined, ): void { const type = typeArg ? ALIASES[typeArg] : undefined; if (!type || !name) { console.error("Usage: wrnexus generate "); process.exit(1); } const file = scaffold(type, name); const target = join(resolve(appRoot), "app", file.path); if (existsSync(target)) { console.error(`Refusing to overwrite existing file: app/${file.path}`); process.exit(1); } mkdirSync(dirname(target), { recursive: true }); writeFileSync(target, file.content, "utf8"); console.log(`✓ Created app/${file.path}`); }