@nooh-ts/compiler 0.1.0 โ†’ 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -35,7 +35,6 @@ interface ConfigLoadResult {
35
35
  readonly diagnostics: readonly Diagnostic[];
36
36
  }
37
37
  interface DiscoveredEndpoint {
38
- readonly endpointsRoot: string;
39
38
  readonly groupPath: string;
40
39
  readonly localPath: string;
41
40
  readonly source: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/compile.ts","../src/compiler.ts","../src/diff.ts","../src/generate/index.ts","../src/pipeline/analyze.ts","../src/pipeline/config.ts","../src/pipeline/discover.ts","../src/pipeline/parse.ts","../src/pipeline/plan.ts","../src/recompile.ts"],"mappings":";cAAa;KAWD,sBAAsB;UAEjB;WACN;WACA;;UAGM;WACN,gBAAgB;;UAGV;EACf,cAAc,uBAAuB;;UAGtB;WACN;;UAGM;WACN;WACA,QAAQ;WACR,UAAU;WACV;WACA,SAAS;;UAGH;WACN;;UAGM;WACN;WACA;WACA;WACA,OAAO;;UAGD;WACN,SAAS;WACT,sBAAsB;;UAGhB;WACN;WACA;WACA;WACA;;UAGM;WACN;WACA;;UAGM;WACN,QAAQ;WACR,oBAAoB;WACpB,iBAAiB;;KAGhB;WAEG;WACA;;WAGA;WACA;;WAGA;WACA;;UAGE;WACN;WACA,QAAQ;WACR;WACA,mBAAmB;WACnB;;UAGM;WACN;WACA;;UAGM;WACN,sBAAsB;WACtB,iBAAiB;WACjB,iBAAiB;;UAGX;WACN;WAEA;WACA;WAEA;WAEA,QAAQ;WAER;WACA,wBAAwB;WACxB;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA;;UAGM;WACN,QAAQ;WACR,iBAAiB;WACjB,iBAAiB;;KAGhB;UAEK;WACN;WACA;WACA;WACA,UAAU;;KAGT;UAEK;WACN;WACA;WACA,MAAM;WACN;;UAGM;WACN,kBAAkB;WAClB;;UAGM;WACN;WACA;WACA,MAAM;;UAGA;WACN,kBAAkB;;UAGZ;WACN,sBAAsB;WACtB,OAAO;WACP,QAAQ;WACR,MAAM;;UAGA;EACf,UACE,QAAQ,eACR,QAAQ;IAER,OAAO;IACP,sBAAsB;;EAExB,UAAU,OAAO,iBAAiB,QAAQ;EAC1C,WACE,SAAS,yBACT,QAAQ,iBACL;EACL,WAAW,MAAM,iBAAiB,OAAO,iBAAiB;EAC1D,aAAa,OAAO,iBAAiB,QAAQ;EAC7C,QAAQ,SAAS,sBAAsB;EACvC,OAAO,OAAO,cAAc,wBAAwB;;UAGrC;WACN,gBAAgB;WAChB,kBAAkB;WAClB;WACA,oBAAoB;;UAGd;WACN;WACA,QAAQ;WACR,UAAU;WACV,UAAU;WACV,UAAU;;;;qBC3MR,UAAW,OAAO,iBAAe,QAAQ;;;qBCOzC,sBAAqB;;;qBCRrB,OACX,UAAU,iBACV,MAAM,oBACL;;;qBCQU,WACX,MAAM,iBACN,OAAO,iBACN;;;qBC4MU,UACX,QAAQ,eACR,QAAQ;EAER,OAAO;EACP,sBAAsB;;;;qBCvNX,aACX,OAAO,iBACN,QAAQ;;;qBC8GE,WACX,UAAU,gBACV,QAAQ,iBACP;;;qBCpHU,QAAS,SAAS,sBAAoB;;;qBCDtC,OACX,OAAO,cACP,wBACC;;;qBCRU,YAAa,OAAO,mBAAiB,QAAQ"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/compile.ts","../src/compiler.ts","../src/diff.ts","../src/generate/index.ts","../src/pipeline/analyze.ts","../src/pipeline/config.ts","../src/pipeline/discover.ts","../src/pipeline/parse.ts","../src/pipeline/plan.ts","../src/recompile.ts"],"mappings":";cAAa;KAWD,sBAAsB;UAEjB;WACN;WACA;;UAGM;WACN,gBAAgB;;UAGV;EACf,cAAc,uBAAuB;;UAGtB;WACN;;UAGM;WACN;WACA,QAAQ;WACR,UAAU;WACV;WACA,SAAS;;UAGH;WACN;;UAGM;WACN;WACA;WACA;WACA,OAAO;;UAGD;WACN,SAAS;WACT,sBAAsB;;UAGhB;WACN;WACA;WACA;;UAGM;WACN;WACA;;UAGM;WACN,QAAQ;WACR,oBAAoB;WACpB,iBAAiB;;KAGhB;WAEG;WACA;;WAGA;WACA;;WAGA;WACA;;UAGE;WACN;WACA,QAAQ;WACR;WACA,mBAAmB;WACnB;;UAGM;WACN;WACA;;UAGM;WACN,sBAAsB;WACtB,iBAAiB;WACjB,iBAAiB;;UAGX;WACN;WAEA;WACA;WAEA;WAEA,QAAQ;WAER;WACA,wBAAwB;WACxB;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA;;UAGM;WACN,QAAQ;WACR,iBAAiB;WACjB,iBAAiB;;KAGhB;UAEK;WACN;WACA;WACA;WACA,UAAU;;KAGT;UAEK;WACN;WACA;WACA,MAAM;WACN;;UAGM;WACN,kBAAkB;WAClB;;UAGM;WACN;WACA;WACA,MAAM;;UAGA;WACN,kBAAkB;;UAGZ;WACN,sBAAsB;WACtB,OAAO;WACP,QAAQ;WACR,MAAM;;UAGA;EACf,UACE,QAAQ,eACR,QAAQ;IAER,OAAO;IACP,sBAAsB;;EAExB,UAAU,OAAO,iBAAiB,QAAQ;EAC1C,WACE,SAAS,yBACT,QAAQ,iBACL;EACL,WAAW,MAAM,iBAAiB,OAAO,iBAAiB;EAC1D,aAAa,OAAO,iBAAiB,QAAQ;EAC7C,QAAQ,SAAS,sBAAsB;EACvC,OAAO,OAAO,cAAc,wBAAwB;;UAGrC;WACN,gBAAgB;WAChB,kBAAkB;WAClB;WACA,oBAAoB;;UAGd;WACN;WACA,QAAQ;WACR,UAAU;WACV,UAAU;WACV,UAAU;;;;qBC1MR,UAAW,OAAO,iBAAe,QAAQ;;;qBCOzC,sBAAqB;;;qBCRrB,OACX,UAAU,iBACV,MAAM,oBACL;;;qBCQU,WACX,MAAM,iBACN,OAAO,iBACN;;;qBC4MU,UACX,QAAQ,eACR,QAAQ;EAER,OAAO;EACP,sBAAsB;;;;qBCvNX,aACX,OAAO,iBACN,QAAQ;;;qBCkEE,WACX,UAAU,gBACV,QAAQ,iBACP;;;qBCxEU,QAAS,SAAS,sBAAoB;;;qBCDtC,OACX,OAAO,cACP,wBACC;;;qBCRU,YAAa,OAAO,mBAAiB,QAAQ"}
package/dist/index.mjs CHANGED
@@ -46,6 +46,12 @@ const dirname = (value) => {
46
46
  if (index === 0) return "/";
47
47
  return normalized.slice(0, index);
48
48
  };
49
+ const basename = (value) => {
50
+ const normalized = normalizePath(value);
51
+ const index = normalized.lastIndexOf("/");
52
+ if (index === -1) return normalized;
53
+ return normalized.slice(index + 1);
54
+ };
49
55
  const relativePath = (from, to) => {
50
56
  const fromParts = normalizePath(from).split("/").filter(Boolean);
51
57
  const toParts = normalizePath(to).split("/").filter(Boolean);
@@ -536,41 +542,32 @@ const loadConfig = async (input) => {
536
542
  };
537
543
  //#endregion
538
544
  //#region src/pipeline/discover.ts
545
+ const ROUTE_FILE_PATTERN = /\.(get|post|put|patch|delete|options|head|all)\.(?:ts|tsx)$/;
539
546
  const isTypeScriptFile = (file) => file.path.endsWith(".ts") || file.path.endsWith(".tsx");
547
+ const isRouteFile = (filePath) => ROUTE_FILE_PATTERN.test(filePath);
540
548
  const isGroupFile = (filePath) => {
541
- const filename = filePath.split("/").at(-1);
549
+ const filename = basename(filePath);
542
550
  return filename === "$.ts" || filename === "$.tsx";
543
551
  };
544
552
  const discoverGroup = (config, file) => {
545
553
  const source = toProjectPath(file.path, config.root);
546
554
  if (!isPathInside(source, config.routesRoot)) return null;
547
- const parts = relativePath(config.routesRoot, source).split("/").filter(Boolean);
548
555
  if (!isGroupFile(source)) return null;
549
- const directoryParts = parts.slice(0, -1);
550
- if (directoryParts.includes("endpoints")) return null;
556
+ const relative = relativePath(config.routesRoot, source);
557
+ const directory = dirname(relative);
551
558
  return {
552
- groupPath: normalizePath(directoryParts.join("/")),
559
+ groupPath: normalizePath(directory),
553
560
  source
554
561
  };
555
562
  };
556
563
  const discoverEndpoint = (config, file) => {
557
564
  const source = toProjectPath(file.path, config.root);
558
565
  if (!isPathInside(source, config.routesRoot)) return null;
559
- const parts = relativePath(config.routesRoot, source).split("/").filter(Boolean);
560
- const endpointIndex = parts.lastIndexOf("endpoints");
561
- if (endpointIndex === -1) return null;
562
- const endpointsRoot = normalizePath([
563
- config.routesRoot,
564
- ...parts.slice(0, endpointIndex),
565
- "endpoints"
566
- ].join("/"));
567
- const groupParts = parts.slice(0, endpointIndex);
568
- const localParts = parts.slice(endpointIndex + 1);
569
- if (localParts.length === 0) return null;
566
+ if (!isRouteFile(source)) return null;
567
+ const relative = relativePath(config.routesRoot, source);
570
568
  return {
571
- endpointsRoot,
572
- groupPath: normalizePath(groupParts.join("/")),
573
- localPath: normalizePath(localParts.join("/")),
569
+ groupPath: normalizePath(dirname(relative)),
570
+ localPath: normalizePath(basename(relative)),
574
571
  source
575
572
  };
576
573
  };
@@ -579,8 +576,6 @@ const discover = (snapshot, config) => {
579
576
  const groups = [];
580
577
  for (const file of snapshot.files) {
581
578
  if (!isTypeScriptFile(file)) continue;
582
- const source = toProjectPath(file.path, config.root);
583
- if (!isPathInside(source, config.routesRoot)) continue;
584
579
  const group = discoverGroup(config, file);
585
580
  if (group) {
586
581
  groups.push(group);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/generate/utils.ts","../src/utils/path.ts","../src/generate/app.ts","../src/generate/group.ts","../src/generate/middleware.ts","../src/generate/router.ts","../src/generate/types.ts","../src/generate/index.ts","../src/pipeline/analyze.ts","../src/pipeline/config.ts","../src/pipeline/discover.ts","../src/types.ts","../src/pipeline/route-parser.ts","../src/pipeline/parse.ts","../src/pipeline/plan.ts","../src/compiler.ts","../src/compile.ts","../src/diff.ts","../src/recompile.ts"],"sourcesContent":["import type { CompilationPlan } from \"@/types\";\n\n/**\n * Returns the output file path for a route group module.\n * The root group uses the reserved name \"root\".\n */\nexport const groupModuleId = (\n plan: CompilationPlan,\n groupId: string\n): string => {\n if (groupId === \"root\") {\n return `${plan.outputRoot}/groups/root.ts`;\n }\n\n return `${plan.outputRoot}/groups/${groupId}.ts`;\n};\n","const WINDOWS_DRIVE_REGEX = /^[A-Za-z]:\\//;\nconst LEADING_SLASH_REGEX = /^\\/+/;\nconst DRIVE_REGEX = /^([A-Za-z]):\\//;\n\nexport const isAbsolutePath = (value: string): boolean => {\n const normalized = value.replaceAll(\"\\\\\", \"/\");\n\n return normalized.startsWith(\"/\") || WINDOWS_DRIVE_REGEX.test(normalized);\n};\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ...\nexport const normalizePath = (value: string): string => {\n const normalized = value.replaceAll(\"\\\\\", \"/\");\n\n const isPosixAbsolute = normalized.startsWith(\"/\");\n const driveMatch = normalized.match(DRIVE_REGEX);\n\n const body = driveMatch\n ? normalized.slice(3)\n : // biome-ignore lint/style/noNestedTernary: ...\n isPosixAbsolute\n ? normalized.slice(1)\n : normalized;\n\n const parts = body.split(\"/\");\n const result: string[] = [];\n\n for (const part of parts) {\n if (!part || part === \".\") {\n continue;\n }\n\n if (part === \"..\") {\n if (result.length > 0 && result.at(-1) !== \"..\") {\n result.pop();\n } else if (!(isPosixAbsolute || driveMatch)) {\n result.push(\"..\");\n }\n\n continue;\n }\n\n result.push(part);\n }\n\n const joined = result.join(\"/\");\n\n if (driveMatch) {\n return joined ? `${driveMatch[1]}:/${joined}` : `${driveMatch[1]}:/`;\n }\n\n if (isPosixAbsolute) {\n return joined ? `/${joined}` : \"/\";\n }\n\n return joined;\n};\n\nexport const stripLeadingSlash = (value: string): string =>\n value.replace(LEADING_SLASH_REGEX, \"\");\n\nexport const ensureLeadingSlash = (value: string): string => {\n if (!value) {\n return \"/\";\n }\n\n return value.startsWith(\"/\") ? value : `/${value}`;\n};\n\nexport const joinPath = (...parts: string[]): string =>\n normalizePath(parts.filter(Boolean).join(\"/\"));\n\nexport const dirname = (value: string): string => {\n const normalized = normalizePath(value);\n const index = normalized.lastIndexOf(\"/\");\n\n if (index === -1) {\n return \"\";\n }\n\n if (index === 0) {\n return \"/\";\n }\n\n return normalized.slice(0, index);\n};\n\nexport const basename = (value: string): string => {\n const normalized = normalizePath(value);\n const index = normalized.lastIndexOf(\"/\");\n\n if (index === -1) {\n return normalized;\n }\n\n return normalized.slice(index + 1);\n};\n\nexport const relativePath = (from: string, to: string): string => {\n const fromParts = normalizePath(from).split(\"/\").filter(Boolean);\n const toParts = normalizePath(to).split(\"/\").filter(Boolean);\n\n let common = 0;\n\n while (\n common < fromParts.length &&\n common < toParts.length &&\n fromParts[common] === toParts[common]\n ) {\n common += 1;\n }\n\n const result = [\n ...fromParts.slice(common).map(() => \"..\"),\n ...toParts.slice(common),\n ];\n\n return result.join(\"/\");\n};\n\nexport const toProjectPath = (value: string, root: string): string => {\n const normalizedValue = normalizePath(value);\n const normalizedRoot = normalizePath(root);\n\n if (!(normalizedRoot && isAbsolutePath(normalizedRoot))) {\n return normalizedValue;\n }\n\n if (!isAbsolutePath(normalizedValue)) {\n return normalizedValue;\n }\n\n if (!isPathInside(normalizedValue, normalizedRoot)) {\n return normalizedValue;\n }\n\n return relativePath(normalizedRoot, normalizedValue);\n};\n\nexport const relativeModuleSpecifier = (\n fromModule: string,\n toSource: string\n): string => {\n const fromDirectory = dirname(fromModule);\n\n let target = normalizePath(toSource);\n\n if (target.endsWith(\".ts\")) {\n target = `${target.slice(0, -3)}.js`;\n } else if (target.endsWith(\".tsx\")) {\n target = `${target.slice(0, -4)}.js`;\n }\n\n const relative = relativePath(fromDirectory, target);\n\n return relative.startsWith(\".\") ? relative : `./${relative}`;\n};\n\nexport const isPathInside = (file: string, root: string): boolean => {\n const normalizedFile = normalizePath(file);\n const normalizedRoot = normalizePath(root);\n\n if (normalizedFile === normalizedRoot) {\n return true;\n }\n\n return normalizedFile.startsWith(`${normalizedRoot}/`);\n};\n\nconst EXTENSION_REGEX = /\\.[^.]+$/;\nexport const removeExtension = (value: string): string =>\n value.replace(EXTENSION_REGEX, \"\");\n","import { groupModuleId } from \"@/generate/utils\";\n\nimport type { CompilationPlan, GeneratedModule, ProjectModel } from \"@/types\";\nimport { relativeModuleSpecifier } from \"@/utils/path\";\n\nexport const generateAppModule = (\n plan: CompilationPlan,\n model: ProjectModel\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/app.ts`;\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n\n const root = model.groups.find((group) => group.id === \"root\");\n\n if (!root) {\n throw new Error(\"Nooh compilation requires a root route group.\");\n }\n\n const imports = [\n `import { Hono } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n `import root from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, groupModuleId(plan, root.id))\n )};`,\n ];\n\n const code = [\n ...imports,\n \"\",\n \"const app = new Hono<App>();\",\n \"\",\n 'app.route(\"/\", root);',\n \"\",\n \"export type AppType = typeof app;\",\n \"\",\n \"export default app;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"app\",\n };\n};\n","import { groupModuleId } from \"@/generate/utils\";\n\nimport type {\n CompilationPlan,\n GeneratedModule,\n ProjectModel,\n RouteGroup,\n RouteModel,\n} from \"@/types\";\nimport { ensureLeadingSlash, relativeModuleSpecifier } from \"@/utils/path\";\n\nconst getGroupRoutes = (\n model: ProjectModel,\n group: RouteGroup\n): readonly RouteModel[] => {\n const ids = new Set(group.routes);\n\n return model.routes\n .filter((route) => ids.has(route.id))\n .sort((a, b) => {\n const pathDifference = a.localPath.localeCompare(b.localPath);\n\n if (pathDifference !== 0) {\n return pathDifference;\n }\n\n const methodDifference = a.method.localeCompare(b.method);\n\n if (methodDifference !== 0) {\n return methodDifference;\n }\n\n return a.source.localeCompare(b.source);\n });\n};\n\nconst capitalize = (value: string): string =>\n value.charAt(0).toUpperCase() + value.slice(1);\n\nconst getGroup = (model: ProjectModel, id: string): RouteGroup | undefined =>\n model.groups.find((group) => group.id === id);\n\nconst getChildPath = (parent: RouteGroup, child: RouteGroup): string => {\n if (parent.path === \"/\") {\n return child.path;\n }\n\n const prefix = `${parent.path}/`;\n\n if (!child.path.startsWith(prefix)) {\n throw new Error(\n `Invalid group tree: \"${child.path}\" is not a child of \"${parent.path}\".`\n );\n }\n\n return child.path.slice(prefix.length);\n};\n\nexport const generateGroupModule = (\n plan: CompilationPlan,\n model: ProjectModel,\n group: RouteGroup\n): GeneratedModule => {\n const moduleId = groupModuleId(plan, group.id);\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n const routes = getGroupRoutes(model, group);\n\n const children = group.children\n .map((childId) => getGroup(model, childId))\n .filter((child): child is RouteGroup => child !== undefined)\n .sort((a, b) => a.path.localeCompare(b.path));\n\n const imports = [\n `import { Hono } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n ];\n\n if (group.configSource) {\n imports.push(\n `import groupConfig from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, group.configSource)\n )};`\n );\n }\n\n children.forEach((child, index) => {\n imports.push(\n `import child${index} from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, groupModuleId(plan, child.id))\n )};`\n );\n });\n\n routes.forEach((route, index) => {\n imports.push(\n `import endpoint${index} from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, route.source)\n )};`\n );\n });\n\n const methods = [...new Set(routes.map((route) => route.method))].sort();\n\n const registerTypes = [\n \"type RouteRegister = (\",\n \" path: string,\",\n \" ...handlers: any[]\",\n \") => typeof route;\",\n ];\n\n const registerDeclarations = methods.map((method) => {\n const name = `register${capitalize(method)}`;\n\n return `const ${name} = route.${method} as unknown as RouteRegister;`;\n });\n\n const useDeclaration = group.configSource\n ? [\n \"type RouteUse = (\",\n \" path: string,\",\n \" ...handlers: any[]\",\n \") => typeof route;\",\n \"\",\n \"const use = route.use as unknown as RouteUse;\",\n \"\",\n 'use(\"*\", ...(groupConfig.middleware ?? []));',\n ]\n : [];\n\n const registrations = routes.map((route, index) => {\n const register = `register${capitalize(route.method)}`;\n\n return ` ${register}(${JSON.stringify(\n ensureLeadingSlash(route.localPath)\n )}, ...endpoint${index});`;\n });\n\n const childRegistrations = children.map(\n (child, index) =>\n ` route.route(${JSON.stringify(\n getChildPath(group, child)\n )}, child${index});`\n );\n\n const code = [\n ...imports,\n \"\",\n \"const route = new Hono<App>();\",\n \"\",\n ...registerTypes,\n \"\",\n ...registerDeclarations,\n ...(useDeclaration.length > 0 ? [\"\", ...useDeclaration] : []),\n ...(registrations.length > 0 ? [\"\", ...registrations] : []),\n ...(childRegistrations.length > 0 ? [\"\", ...childRegistrations] : []),\n \"\",\n \"export default route;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"group\",\n };\n};\n","import type { CompilationPlan, GeneratedModule } from \"@/types\";\n\nexport const generateMiddlewareModule = (\n plan: CompilationPlan\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/router/middleware.ts`;\n\n return {\n code: [\n `import { createMiddleware } from \"hono/factory\";`,\n `import type { App } from \"../types.js\";`,\n \"\",\n \"export const middleware = createMiddleware<App>;\",\n \"\",\n ].join(\"\\n\"),\n id: moduleId,\n kind: \"middleware\",\n };\n};\n","import type {\n CompilationPlan,\n GeneratedModule,\n ProjectModel,\n RouteModel,\n} from \"@/types\";\nimport { ensureLeadingSlash, relativeModuleSpecifier } from \"@/utils/path\";\n\nconst VALIDATION_TARGETS = [\n \"json\",\n \"form\",\n \"query\",\n \"param\",\n \"header\",\n \"cookie\",\n] as const;\n\nconst METHOD_FUNCTION_NAMES: Record<RouteModel[\"method\"], string> = {\n all: \"all\",\n delete: \"del\",\n get: \"get\",\n head: \"head\",\n options: \"options\",\n patch: \"patch\",\n post: \"post\",\n put: \"put\",\n};\n\nconst getRoutesForRouter = (\n model: ProjectModel,\n routerPath: string\n): readonly RouteModel[] =>\n model.routes\n .filter((route) => route.routerPath === routerPath)\n .sort((a, b) => a.method.localeCompare(b.method));\n\nconst renderMethod = (route: RouteModel): string => {\n const { method } = route;\n const functionName = METHOD_FUNCTION_NAMES[method];\n\n const path = JSON.stringify(ensureLeadingSlash(route.localPath));\n\n return [\n `type Path = ${path};`,\n \"\",\n \"type RouteMiddleware = MiddlewareHandler<App, Path>;\",\n \"\",\n \"type ValidationTarget = Parameters<typeof sValidator>[0];\",\n \"type StandardSchema = Parameters<typeof sValidator>[1];\",\n \"\",\n \"type ValidationOptions = Partial<\",\n \" Record<ValidationTarget, StandardSchema>\",\n \">;\",\n \"\",\n \"type HandlerInput<T> = T extends Handler<\",\n \" any,\",\n \" any,\",\n \" infer I,\",\n \" any\",\n \"> ? I : never;\",\n \"\",\n \"type ValidationHandler<\",\n \" Target extends ValidationTarget,\",\n \" Schema extends StandardSchema,\",\n \"> = ReturnType<\",\n \" typeof sValidator<Schema, Target, App, Path>\",\n \">;\",\n \"\",\n \"type ValidationInput<V extends ValidationOptions> =\",\n ...VALIDATION_TARGETS.map(\n (target) =>\n ` & (${JSON.stringify(target)} extends keyof V ? HandlerInput<ValidationHandler<${JSON.stringify(target)}, NonNullable<V[${JSON.stringify(target)}]>>> : {})`\n ),\n \";\",\n \"\",\n \"type RouteHandler = Handler<App, Path, any, any>;\",\n \"\",\n \"type EndpointOptions<\",\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \"> = {\",\n \" readonly middleware?: M;\",\n \" readonly validation?: V;\",\n \" readonly handler: H;\",\n \"};\",\n \"\",\n `export function ${functionName}<H extends Handler<App, Path>>(`,\n \" handler: H,\",\n \"): readonly RouteHandler[];\",\n \"\",\n `export function ${functionName}<`,\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \">(\",\n \" options: EndpointOptions<M, V, H>,\",\n \"): readonly RouteHandler[];\",\n \"\",\n `export function ${functionName}<`,\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \">(\",\n \" input:\",\n \" | H\",\n \" | EndpointOptions<M, V, H>,\",\n \"): readonly RouteHandler[] {\",\n ' if (typeof input === \"function\") {',\n \" return [input as RouteHandler];\",\n \" }\",\n \"\",\n \" return [\",\n \" ...(input.middleware ?? []) as readonly RouteHandler[],\",\n ...VALIDATION_TARGETS.map(\n (target) =>\n ` ...(input.validation?.${target} !== undefined ? [sValidator(${JSON.stringify(target)}, input.validation.${target}) as RouteHandler] : []),`\n ),\n \" input.handler as RouteHandler,\",\n \" ];\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n};\n\nexport const generateRouterModule = (\n plan: CompilationPlan,\n model: ProjectModel,\n routerPath: string\n): GeneratedModule => {\n const routes = getRoutesForRouter(model, routerPath);\n\n const moduleId = `${plan.outputRoot}/${routerPath}.ts`;\n\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n\n return {\n code: [\n `import { sValidator } from \"@hono/standard-validator\";`,\n `import type { Handler, MiddlewareHandler } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n \"\",\n ...routes.map(renderMethod),\n ].join(\"\\n\"),\n id: moduleId,\n kind: \"router\",\n };\n};\n","import type { CompilationPlan, GeneratedModule, LoadedConfig } from \"@/types\";\nimport { relativeModuleSpecifier } from \"@/utils/path\";\n\nexport const generateTypesModule = (\n plan: CompilationPlan,\n config: LoadedConfig\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/types.ts`;\n\n const configImport = relativeModuleSpecifier(moduleId, config.source);\n\n const code = [\n `import type config from \"${configImport}\";`,\n \"\",\n \"type ExtractEnvironment<T> = T extends {\",\n \" readonly __nooh_env: infer Environment;\",\n \"}\",\n \" ? Environment\",\n \" : never;\",\n \"\",\n \"export type App = ExtractEnvironment<typeof config>;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"types\",\n };\n};\n","import { generateAppModule } from \"@/generate/app\";\nimport { generateGroupModule } from \"@/generate/group\";\nimport { generateMiddlewareModule } from \"@/generate/middleware\";\nimport { generateRouterModule } from \"@/generate/router\";\nimport { generateTypesModule } from \"@/generate/types\";\n\nimport type {\n CompilationPlan,\n GeneratedModule,\n GeneratedOutput,\n ProjectModel,\n} from \"@/types\";\n\nexport const generate = (\n plan: CompilationPlan,\n model: ProjectModel\n): GeneratedOutput => {\n const modules: GeneratedModule[] = [];\n\n modules.push(generateTypesModule(plan, model.config));\n\n modules.push(generateMiddlewareModule(plan));\n\n const routerPaths = [\n ...new Set(model.routes.map((route) => route.routerPath)),\n ].sort();\n\n for (const routerPath of routerPaths) {\n modules.push(generateRouterModule(plan, model, routerPath));\n }\n\n for (const group of model.groups) {\n modules.push(generateGroupModule(plan, model, group));\n }\n\n modules.push(generateAppModule(plan, model));\n\n modules.sort((a, b) => a.id.localeCompare(b.id));\n\n return {\n modules,\n };\n};\n","import type {\n Diagnostic,\n LoadedConfig,\n ParsedProject,\n ParsedRoute,\n ProjectModel,\n RouteGroup,\n RouteModel,\n RouteSegment,\n} from \"@/types\";\nimport { ensureLeadingSlash, normalizePath } from \"@/utils/path\";\n\nconst segmentToHono = (segment: RouteSegment): string => {\n // biome-ignore lint/style/useDefaultSwitchClause: ...\n switch (segment.kind) {\n case \"static\":\n return segment.value;\n\n case \"param\":\n return `:${segment.name}`;\n\n case \"splat\":\n return \"*\";\n }\n};\n\nconst segmentsToPath = (segments: readonly RouteSegment[]): string => {\n if (segments.length === 0) {\n return \"\";\n }\n\n return segments.map(segmentToHono).join(\"/\");\n};\n\nconst combinePaths = (groupPath: string, localPath: string): string => {\n const group = normalizePath(groupPath).replace(/^\\/+|\\/+$/g, \"\");\n const local = normalizePath(localPath).replace(/^\\/+|\\/+$/g, \"\");\n\n if (!(group || local)) {\n return \"/\";\n }\n\n if (!group) {\n return `/${local}`;\n }\n\n if (!local) {\n return `/${group}`;\n }\n\n return `/${group}/${local}`;\n};\n\nconst routeSegmentsToRouterPath = (\n groupPath: string,\n rawSegments: readonly string[]\n): string => {\n const parts = [\n ...groupPath.split(\"/\").filter(Boolean),\n ...rawSegments.filter(Boolean),\n ];\n\n return parts.length === 0 ? \"router/index\" : `router/${parts.join(\"/\")}`;\n};\n\nconst routeId = (route: ParsedRoute): string =>\n `${route.method.toUpperCase()} ${combinePaths(\n route.groupPath,\n segmentsToPath(route.segments)\n )}`;\n\nconst sortRoutes = (a: RouteModel, b: RouteModel): number => {\n const pathDifference = a.fullPath.localeCompare(b.fullPath);\n\n if (pathDifference !== 0) {\n return pathDifference;\n }\n\n const methodDifference = a.method.localeCompare(b.method);\n\n if (methodDifference !== 0) {\n return methodDifference;\n }\n\n return a.source.localeCompare(b.source);\n};\n\nconst parentGroupPath = (groupPath: string): string | null => {\n const normalized = normalizePath(groupPath);\n\n if (!normalized) {\n return null;\n }\n\n const parts = normalized.split(\"/\").filter(Boolean);\n\n if (parts.length <= 1) {\n return \"\";\n }\n\n return parts.slice(0, -1).join(\"/\");\n};\n\nconst getAncestorGroupPaths = (groupPath: string): readonly string[] => {\n const parts = normalizePath(groupPath).split(\"/\").filter(Boolean);\n\n return Array.from({ length: parts.length + 1 }, (_, index) =>\n parts.slice(0, index).join(\"/\")\n );\n};\n\nconst groupId = (path: string): string => path || \"root\";\n\nconst buildGroups = (\n parsed: ParsedProject,\n routeModels: readonly RouteModel[],\n diagnostics: Diagnostic[]\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ...\n): readonly RouteGroup[] => {\n const configSources = new Map<string, string>();\n\n for (const group of parsed.groups) {\n const path = normalizePath(group.groupPath);\n const previous = configSources.get(path);\n\n if (previous) {\n diagnostics.push({\n code: \"NOOH006\",\n file: group.source,\n message: [\n `Duplicate group definition for \"${path || \"/\"}\".`,\n \"\",\n `First declaration: ${previous}`,\n `Second declaration: ${group.source}`,\n ].join(\"\\n\"),\n severity: \"error\",\n });\n\n continue;\n }\n\n configSources.set(path, group.source);\n }\n\n const groupPaths = new Set<string>([\"\"]);\n\n for (const group of parsed.groups) {\n for (const ancestor of getAncestorGroupPaths(group.groupPath)) {\n groupPaths.add(ancestor);\n }\n }\n\n for (const route of routeModels) {\n for (const ancestor of getAncestorGroupPaths(route.groupPath)) {\n groupPaths.add(ancestor);\n }\n }\n\n const routesByGroup = new Map<string, string[]>();\n\n for (const route of routeModels) {\n const routes = routesByGroup.get(route.groupPath);\n\n if (routes) {\n routes.push(route.id);\n } else {\n routesByGroup.set(route.groupPath, [route.id]);\n }\n }\n\n const childrenByGroup = new Map<string, string[]>();\n\n for (const path of groupPaths) {\n if (!path) {\n continue;\n }\n\n const parent = parentGroupPath(path) ?? \"\";\n\n const children = childrenByGroup.get(parent);\n\n if (children) {\n children.push(path);\n } else {\n childrenByGroup.set(parent, [path]);\n }\n }\n\n return [...groupPaths]\n .sort((a, b) => {\n if (!a && b) {\n return -1;\n }\n\n if (a && !b) {\n return 1;\n }\n\n return a.localeCompare(b);\n })\n .map((path) => {\n const children = [...(childrenByGroup.get(path) ?? [])].sort();\n const configSource = configSources.get(path);\n const parent = parentGroupPath(path);\n\n return {\n children: children.map(groupId),\n id: groupId(path),\n ...(parent !== null && {\n parentId: groupId(parent),\n }),\n path: path ? ensureLeadingSlash(path) : \"/\",\n routes: [...(routesByGroup.get(path) ?? [])].sort(),\n ...(configSource !== undefined && {\n configSource,\n }),\n };\n });\n};\n\nexport const analyze = (\n parsed: ParsedProject,\n config: LoadedConfig\n): {\n model: ProjectModel;\n diagnostics: readonly Diagnostic[];\n} => {\n const diagnostics: Diagnostic[] = [...parsed.diagnostics];\n\n const routeModels: RouteModel[] = [];\n const seen = new Map<string, string>();\n\n for (const route of parsed.routes) {\n const localPath = segmentsToPath(route.segments);\n const fullPath = combinePaths(route.groupPath, localPath);\n const id = routeId(route);\n\n const previousSource = seen.get(id);\n\n if (previousSource) {\n diagnostics.push({\n code: \"NOOH005\",\n file: route.source,\n message: [\n `Duplicate route \"${id}\".`,\n \"\",\n `First declaration: ${previousSource}`,\n `Second declaration: ${route.source}`,\n ].join(\"\\n\"),\n severity: \"error\",\n });\n\n continue;\n }\n\n seen.set(id, route.source);\n\n routeModels.push({\n fullPath,\n groupPath: normalizePath(route.groupPath),\n id,\n localPath,\n method: route.method,\n routerPath: routeSegmentsToRouterPath(route.groupPath, route.rawSegments),\n routeSegments: route.segments,\n source: route.source,\n });\n }\n\n routeModels.sort(sortRoutes);\n\n const groups = buildGroups(parsed, routeModels, diagnostics);\n\n return {\n diagnostics,\n model: {\n config,\n groups,\n routes: routeModels,\n },\n };\n};\n","import type { CompileInput, ConfigLoadResult, RuntimeConfig } from \"@/types\";\nimport { normalizePath, toProjectPath } from \"@/utils/path\";\n\nconst DEFAULT_ROUTES_ROOT = \"src/routes\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst isString = (value: unknown): value is string => typeof value === \"string\";\n\nexport const loadConfig = async (\n input: CompileInput\n): Promise<ConfigLoadResult> => {\n let defaultExport: unknown;\n\n try {\n defaultExport = await input.loader.loadDefault(input.config);\n } catch (error) {\n return {\n diagnostics: [\n {\n code: \"NOOH010\",\n file: input.config,\n message:\n error instanceof Error\n ? `Failed to load config: ${error.message}`\n : \"Failed to load config.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n if (!isRecord(defaultExport)) {\n return {\n diagnostics: [\n {\n code: \"NOOH011\",\n file: input.config,\n message: \"The Nooh config default export must be an object.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n const routesValue = defaultExport.routes;\n\n if (routesValue !== undefined && !isString(routesValue)) {\n return {\n diagnostics: [\n {\n code: \"NOOH012\",\n file: input.config,\n message: 'The Nooh config \"routes\" option must be a string.',\n severity: \"error\",\n },\n ],\n };\n }\n\n const root = normalizePath(input.root ?? \"\");\n const source = toProjectPath(input.config, root);\n const routes = routesValue ?? DEFAULT_ROUTES_ROOT;\n const routesRoot = toProjectPath(routes, root);\n\n const value: RuntimeConfig = {\n routes: routesValue,\n };\n\n return {\n config: {\n root,\n routesRoot,\n source,\n value,\n },\n diagnostics: [],\n };\n};\n","import type {\n DiscoveredEndpoint,\n DiscoveredGroup,\n DiscoveredProject,\n LoadedConfig,\n SourceFile,\n SourceSnapshot,\n} from \"@/types\";\nimport {\n isPathInside,\n normalizePath,\n relativePath,\n toProjectPath,\n} from \"@/utils/path\";\n\nconst isTypeScriptFile = (file: SourceFile): boolean =>\n file.path.endsWith(\".ts\") || file.path.endsWith(\".tsx\");\n\nconst isGroupFile = (filePath: string): boolean => {\n const filename = filePath.split(\"/\").at(-1);\n\n return filename === \"$.ts\" || filename === \"$.tsx\";\n};\n\nconst discoverGroup = (\n config: LoadedConfig,\n file: SourceFile\n): DiscoveredGroup | null => {\n const source = toProjectPath(file.path, config.root);\n\n if (!isPathInside(source, config.routesRoot)) {\n return null;\n }\n\n const relative = relativePath(config.routesRoot, source);\n const parts = relative.split(\"/\").filter(Boolean);\n\n if (!isGroupFile(source)) {\n return null;\n }\n\n const directoryParts = parts.slice(0, -1);\n\n if (directoryParts.includes(\"endpoints\")) {\n return null;\n }\n\n return {\n groupPath: normalizePath(directoryParts.join(\"/\")),\n source,\n };\n};\n\nexport const findEndpointsDirectory = (\n routesRoot: string,\n filePath: string,\n root = \"\"\n): string | null => {\n const normalizedRoutesRoot = toProjectPath(routesRoot, root);\n\n const normalizedFilePath = toProjectPath(filePath, root);\n\n if (!isPathInside(normalizedFilePath, normalizedRoutesRoot)) {\n return null;\n }\n\n const relative = relativePath(normalizedRoutesRoot, normalizedFilePath);\n\n const parts = relative.split(\"/\").filter(Boolean);\n\n const endpointIndex = parts.lastIndexOf(\"endpoints\");\n\n if (endpointIndex === -1) {\n return null;\n }\n\n const groupParts = parts.slice(0, endpointIndex);\n\n return normalizePath(\n [normalizedRoutesRoot, ...groupParts, \"endpoints\"].filter(Boolean).join(\"/\")\n );\n};\n\nconst discoverEndpoint = (\n config: LoadedConfig,\n file: SourceFile\n): DiscoveredEndpoint | null => {\n const source = toProjectPath(file.path, config.root);\n\n if (!isPathInside(source, config.routesRoot)) {\n return null;\n }\n\n const relative = relativePath(config.routesRoot, source);\n\n const parts = relative.split(\"/\").filter(Boolean);\n\n const endpointIndex = parts.lastIndexOf(\"endpoints\");\n\n if (endpointIndex === -1) {\n return null;\n }\n\n const endpointsRoot = normalizePath(\n [config.routesRoot, ...parts.slice(0, endpointIndex), \"endpoints\"].join(\"/\")\n );\n\n const groupParts = parts.slice(0, endpointIndex);\n const localParts = parts.slice(endpointIndex + 1);\n\n if (localParts.length === 0) {\n return null;\n }\n\n return {\n endpointsRoot,\n groupPath: normalizePath(groupParts.join(\"/\")),\n localPath: normalizePath(localParts.join(\"/\")),\n source,\n };\n};\n\nexport const discover = (\n snapshot: SourceSnapshot,\n config: LoadedConfig\n): DiscoveredProject => {\n const endpoints: DiscoveredEndpoint[] = [];\n const groups: DiscoveredGroup[] = [];\n\n for (const file of snapshot.files) {\n if (!isTypeScriptFile(file)) {\n continue;\n }\n\n const source = toProjectPath(file.path, config.root);\n\n if (!isPathInside(source, config.routesRoot)) {\n continue;\n }\n\n const group = discoverGroup(config, file);\n\n if (group) {\n groups.push(group);\n continue;\n }\n\n const endpoint = discoverEndpoint(config, file);\n\n if (endpoint) {\n endpoints.push(endpoint);\n }\n }\n\n endpoints.sort((a, b) => a.source.localeCompare(b.source));\n groups.sort((a, b) => a.source.localeCompare(b.source));\n\n return {\n config,\n endpoints,\n groups,\n };\n};\n","export const ROUTE_METHODS = [\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"options\",\n \"head\",\n \"all\",\n] as const;\n\nexport type RouteMethod = (typeof ROUTE_METHODS)[number];\n\nexport interface SourceFile {\n readonly content: string;\n readonly path: string;\n}\n\nexport interface SourceSnapshot {\n readonly files: readonly SourceFile[];\n}\n\nexport interface ModuleLoader {\n loadDefault: (modulePath: string) => Promise<unknown>;\n}\n\nexport interface CompileOptions {\n readonly outputRoot?: string;\n}\n\nexport interface CompileInput {\n readonly config: string;\n readonly loader: ModuleLoader;\n readonly options?: CompileOptions;\n readonly root?: string;\n readonly sources: SourceSnapshot;\n}\n\nexport interface RuntimeConfig {\n readonly routes?: string | undefined;\n}\n\nexport interface LoadedConfig {\n readonly root: string;\n readonly routesRoot: string;\n readonly source: string;\n readonly value: RuntimeConfig;\n}\n\nexport interface ConfigLoadResult {\n readonly config?: LoadedConfig;\n readonly diagnostics: readonly Diagnostic[];\n}\n\nexport interface DiscoveredEndpoint {\n readonly endpointsRoot: string;\n readonly groupPath: string;\n readonly localPath: string;\n readonly source: string;\n}\n\nexport interface DiscoveredGroup {\n readonly groupPath: string;\n readonly source: string;\n}\n\nexport interface DiscoveredProject {\n readonly config: LoadedConfig;\n readonly endpoints: readonly DiscoveredEndpoint[];\n readonly groups: readonly DiscoveredGroup[];\n}\n\nexport type RouteSegment =\n | {\n readonly kind: \"static\";\n readonly value: string;\n }\n | {\n readonly kind: \"param\";\n readonly name: string;\n }\n | {\n readonly kind: \"splat\";\n readonly name?: string;\n };\n\nexport interface ParsedRoute {\n readonly groupPath: string;\n readonly method: RouteMethod;\n readonly rawSegments: readonly string[];\n readonly segments: readonly RouteSegment[];\n readonly source: string;\n}\n\nexport interface ParsedGroup {\n readonly groupPath: string;\n readonly source: string;\n}\n\nexport interface ParsedProject {\n readonly diagnostics: readonly Diagnostic[];\n readonly groups: readonly ParsedGroup[];\n readonly routes: readonly ParsedRoute[];\n}\n\nexport interface RouteModel {\n readonly fullPath: string;\n\n readonly groupPath: string;\n readonly id: string;\n\n readonly localPath: string;\n\n readonly method: RouteMethod;\n\n readonly routerPath: string;\n readonly routeSegments: readonly RouteSegment[];\n readonly source: string;\n}\n\nexport interface RouteGroup {\n readonly children: readonly string[];\n readonly configSource?: string;\n readonly id: string;\n readonly parentId?: string;\n readonly path: string;\n readonly routes: readonly string[];\n}\n\nexport interface ProjectModel {\n readonly config: LoadedConfig;\n readonly groups: readonly RouteGroup[];\n readonly routes: readonly RouteModel[];\n}\n\nexport type DiagnosticSeverity = \"error\" | \"warning\" | \"info\";\n\nexport interface Diagnostic {\n readonly code: string;\n readonly file?: string;\n readonly message: string;\n readonly severity: DiagnosticSeverity;\n}\n\nexport type ModuleKind = \"types\" | \"router\" | \"middleware\" | \"group\" | \"app\";\n\nexport interface ModulePlan {\n readonly groupId?: string;\n readonly id: string;\n readonly kind: ModuleKind;\n readonly routeId?: string;\n}\n\nexport interface CompilationPlan {\n readonly modules: readonly ModulePlan[];\n readonly outputRoot: string;\n}\n\nexport interface GeneratedModule {\n readonly code: string;\n readonly id: string;\n readonly kind: ModuleKind;\n}\n\nexport interface GeneratedOutput {\n readonly modules: readonly GeneratedModule[];\n}\n\nexport interface Compilation {\n readonly diagnostics: readonly Diagnostic[];\n readonly model: ProjectModel;\n readonly output: GeneratedOutput | null;\n readonly plan: CompilationPlan | null;\n}\n\nexport interface NoohCompiler {\n analyze: (\n parsed: ParsedProject,\n config: LoadedConfig\n ) => {\n model: ProjectModel;\n diagnostics: readonly Diagnostic[];\n };\n compile: (input: CompileInput) => Promise<Compilation>;\n discover: (\n sources: CompileInput[\"sources\"],\n config: LoadedConfig\n ) => DiscoveredProject;\n generate: (plan: CompilationPlan, model: ProjectModel) => GeneratedOutput;\n loadConfig: (input: CompileInput) => Promise<ConfigLoadResult>;\n parse: (project: DiscoveredProject) => ParsedProject;\n plan: (model: ProjectModel, outputRoot?: string) => CompilationPlan;\n}\n\nexport interface OutputDiff {\n readonly added: readonly GeneratedModule[];\n readonly changed: readonly GeneratedModule[];\n readonly removed: readonly string[];\n readonly unchanged: readonly GeneratedModule[];\n}\n\nexport interface RecompileInput {\n readonly config?: string;\n readonly loader: CompileInput[\"loader\"];\n readonly options?: CompileInput[\"options\"];\n readonly previous: Compilation;\n readonly snapshot: SourceSnapshot;\n}\n","import type {\n Diagnostic,\n DiscoveredEndpoint,\n ParsedRoute,\n RouteSegment,\n} from \"@/types\";\nimport { ROUTE_METHODS } from \"@/types\";\nimport { normalizePath } from \"@/utils/path\";\n\nconst METHOD_PATTERN =\n /^(.*)\\.(get|post|put|patch|delete|options|head|all)\\.(?:ts|tsx)$/;\n\nconst PARAM_PATTERN = /^\\[([A-Za-z0-9_]+)\\]$/;\nconst SPLAT_PATTERN = /^\\[\\.\\.\\.([A-Za-z0-9_]+)\\]$/;\n\nconst methodSet = new Set<string>(ROUTE_METHODS);\n\nconst parseSegment = (\n segment: string\n):\n | { segment: RouteSegment; error?: undefined }\n | {\n segment?: undefined;\n error: Diagnostic;\n } => {\n const parameter = segment.match(PARAM_PATTERN);\n\n if (parameter?.[1]) {\n return {\n segment: {\n kind: \"param\",\n name: parameter[1],\n },\n };\n }\n\n const splat = segment.match(SPLAT_PATTERN);\n\n if (splat?.[1]) {\n return {\n segment: {\n kind: \"splat\",\n name: splat[1],\n },\n };\n }\n\n if (segment.includes(\"[\") || segment.includes(\"]\")) {\n return {\n error: {\n code: \"NOOH003\",\n message: `Invalid route segment \"${segment}\".`,\n severity: \"error\",\n },\n };\n }\n\n if (!segment) {\n return {\n error: {\n code: \"NOOH004\",\n message: \"Route segments cannot be empty.\",\n severity: \"error\",\n },\n };\n }\n\n return {\n segment: {\n kind: \"static\",\n value: segment,\n },\n };\n};\n\nexport const parseEndpoint = (\n endpoint: DiscoveredEndpoint\n): {\n route?: ParsedRoute;\n diagnostics: readonly Diagnostic[];\n} => {\n const localParts = endpoint.localPath.split(\"/\").filter(Boolean);\n const filename = localParts.pop();\n\n if (!filename) {\n return {\n diagnostics: [\n {\n code: \"NOOH001\",\n file: endpoint.source,\n message: \"Invalid empty endpoint filename.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n const match = filename.match(METHOD_PATTERN);\n\n if (!match) {\n return {\n diagnostics: [\n {\n code: \"NOOH001\",\n file: endpoint.source,\n message: 'Invalid endpoint filename. Expected \"<name>.<method>.ts\".',\n severity: \"error\",\n },\n ],\n };\n }\n\n const [_match, routeFile, method] = match;\n\n if (!(method && methodSet.has(method))) {\n return {\n diagnostics: [\n {\n code: \"NOOH002\",\n file: endpoint.source,\n message: `Unsupported HTTP method \"${method}\".`,\n severity: \"error\",\n },\n ],\n };\n }\n\n const validMethod = method as ParsedRoute[\"method\"];\n\n const routeFileSegments = routeFile?.split(\"/\").filter(Boolean) || [];\n const rawSegments = [...localParts, ...routeFileSegments];\n\n const last = rawSegments.at(-1);\n const effectiveSegments =\n last === \"index\" ? rawSegments.slice(0, -1) : rawSegments;\n\n const diagnostics: Diagnostic[] = [];\n const segments: RouteSegment[] = [];\n\n for (const rawSegment of effectiveSegments) {\n const result = parseSegment(rawSegment);\n\n if (result.error) {\n diagnostics.push({\n ...result.error,\n file: endpoint.source,\n });\n\n continue;\n }\n\n segments.push(result.segment);\n }\n\n if (diagnostics.length > 0) {\n return {\n diagnostics,\n };\n }\n\n return {\n diagnostics: [],\n route: {\n groupPath: normalizePath(endpoint.groupPath),\n method: validMethod,\n rawSegments: effectiveSegments,\n segments,\n source: endpoint.source,\n },\n };\n};\n","import { parseEndpoint } from \"@/pipeline/route-parser\";\nimport type {\n Diagnostic,\n DiscoveredProject,\n ParsedGroup,\n ParsedProject,\n ParsedRoute,\n} from \"@/types\";\n\nexport const parse = (project: DiscoveredProject): ParsedProject => {\n const routes: ParsedRoute[] = [];\n const diagnostics: Diagnostic[] = [];\n\n for (const endpoint of project.endpoints) {\n const result = parseEndpoint(endpoint);\n\n diagnostics.push(...result.diagnostics);\n\n if (result.route) {\n routes.push(result.route);\n }\n }\n\n const groups: ParsedGroup[] = project.groups.map((group) => ({\n groupPath: group.groupPath,\n source: group.source,\n }));\n\n routes.sort((a, b) => a.source.localeCompare(b.source));\n groups.sort((a, b) => a.source.localeCompare(b.source));\n\n return {\n diagnostics,\n groups,\n routes,\n };\n};\n","import type { CompilationPlan, ModulePlan, ProjectModel } from \"@/types\";\nimport { normalizePath } from \"@/utils/path\";\n\nconst DEFAULT_OUTPUT_ROOT = \".nooh\";\n\nconst modulePath = (outputRoot: string, value: string): string =>\n normalizePath(`${outputRoot}/${value}.ts`);\n\nexport const plan = (\n model: ProjectModel,\n outputRoot: string = DEFAULT_OUTPUT_ROOT\n): CompilationPlan => {\n const normalizedOutputRoot = normalizePath(outputRoot);\n\n const modules: ModulePlan[] = [\n {\n id: modulePath(normalizedOutputRoot, \"types\"),\n kind: \"types\",\n },\n {\n id: modulePath(normalizedOutputRoot, \"router/middleware\"),\n kind: \"middleware\",\n },\n ];\n\n const routerPaths = [\n ...new Set(model.routes.map((route) => route.routerPath)),\n ].sort();\n\n for (const routerPath of routerPaths) {\n const route = model.routes.find(\n (candidate) => candidate.routerPath === routerPath\n );\n\n if (!route) {\n continue;\n }\n\n modules.push({\n id: modulePath(normalizedOutputRoot, routerPath),\n kind: \"router\",\n routeId: route.routerPath,\n });\n }\n\n for (const group of model.groups) {\n const groupPath =\n group.id === \"root\" ? \"groups/root\" : `groups/${group.id}`;\n\n modules.push({\n groupId: group.id,\n id: modulePath(normalizedOutputRoot, groupPath),\n kind: \"group\",\n });\n }\n\n modules.push({\n id: modulePath(normalizedOutputRoot, \"app\"),\n kind: \"app\",\n });\n\n modules.sort((a, b) => a.id.localeCompare(b.id));\n\n return {\n modules,\n outputRoot: normalizedOutputRoot,\n };\n};\n","import { generate } from \"@/generate\";\n\nimport { analyze } from \"@/pipeline/analyze\";\nimport { loadConfig } from \"@/pipeline/config\";\nimport { discover } from \"@/pipeline/discover\";\nimport { parse } from \"@/pipeline/parse\";\nimport { plan } from \"@/pipeline/plan\";\n\nimport type { NoohCompiler } from \"@/types\";\n\nexport const createCompiler = (): NoohCompiler => ({\n analyze,\n\n compile: async (input) => {\n const configResult = await loadConfig(input);\n\n if (!configResult.config) {\n return {\n diagnostics: configResult.diagnostics,\n model: {\n config: {\n root: input.root ? input.root.replaceAll(\"\\\\\", \"/\") : \"\",\n routesRoot: \"\",\n source: input.config,\n value: {},\n },\n groups: [],\n routes: [],\n },\n output: null,\n plan: null,\n };\n }\n\n const discovered = discover(input.sources, configResult.config);\n const parsed = parse(discovered);\n const analyzed = analyze(parsed, configResult.config);\n const diagnostics = [...configResult.diagnostics, ...analyzed.diagnostics];\n\n const hasErrors = diagnostics.some(\n (diagnostic) => diagnostic.severity === \"error\"\n );\n\n if (hasErrors) {\n return {\n diagnostics,\n model: analyzed.model,\n output: null,\n plan: null,\n };\n }\n\n const compilationPlan = plan(analyzed.model, input.options?.outputRoot);\n\n const output = generate(compilationPlan, analyzed.model);\n\n return {\n diagnostics,\n model: analyzed.model,\n output,\n plan: compilationPlan,\n };\n },\n\n discover,\n generate,\n loadConfig,\n parse,\n plan,\n});\n","import { createCompiler } from \"@/compiler\";\nimport type { Compilation, CompileInput } from \"@/types\";\n\nexport const compile = (input: CompileInput): Promise<Compilation> =>\n createCompiler().compile(input);\n","import type { GeneratedModule, GeneratedOutput, OutputDiff } from \"@/types\";\n\nexport const diff = (\n previous: GeneratedOutput,\n next: GeneratedOutput\n): OutputDiff => {\n const previousMap = new Map(\n previous.modules.map((module) => [module.id, module])\n );\n\n const nextMap = new Map(next.modules.map((module) => [module.id, module]));\n\n const added: GeneratedModule[] = [];\n const changed: GeneratedModule[] = [];\n const unchanged: GeneratedModule[] = [];\n const removed: string[] = [];\n\n for (const module of next.modules) {\n const previousModule = previousMap.get(module.id);\n\n if (!previousModule) {\n added.push(module);\n continue;\n }\n\n if (previousModule.code !== module.code) {\n changed.push(module);\n continue;\n }\n\n unchanged.push(module);\n }\n\n for (const module of previous.modules) {\n if (!nextMap.has(module.id)) {\n removed.push(module.id);\n }\n }\n\n return {\n added,\n changed,\n removed,\n unchanged,\n };\n};\n","import { createCompiler } from \"@/compiler\";\nimport type { Compilation, RecompileInput } from \"@/types\";\n\nexport const recompile = (input: RecompileInput): Promise<Compilation> => {\n const compiler = createCompiler();\n\n const config = input.config ?? input.previous.model.config.source;\n\n return compiler.compile({\n config,\n loader: input.loader,\n root: input.previous.model.config.root,\n\n ...(input.options !== undefined && {\n options: input.options,\n }),\n\n sources: input.snapshot,\n });\n};\n"],"mappings":"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IAAI,CAAC;GACnE;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAGF;EACH,IAAI;EACJ,MAAM;CACR;AACF;;;ACrKA,MAAa,4BACX,SACoB;CACpB,MAAM,WAAW,GAAG,KAAK,WAAW;CAEpC,OAAO;EACL,MAAM;GACJ;GACA;GACA;GACA;GACA;EACF,CAAC,CAAC,KAAK,IAAI;EACX,IAAI;EACJ,MAAM;CACR;AACF;;;ACVA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,wBAA8D;CAClE,KAAK;CACL,QAAQ;CACR,KAAK;CACL,MAAM;CACN,SAAS;CACT,OAAO;CACP,MAAM;CACN,KAAK;AACP;AAEA,MAAM,sBACJ,OACA,eAEA,MAAM,OACH,QAAQ,UAAU,MAAM,eAAe,UAAU,CAAC,CAClD,MAAM,GAAG,MAAM,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;AAEpD,MAAM,gBAAgB,UAA8B;CAClD,MAAM,EAAE,WAAW;CACnB,MAAM,eAAe,sBAAsB;CAI3C,OAAO;EACL,eAHW,KAAK,UAAU,mBAAmB,MAAM,SAAS,CAG1C,EAAE;EACpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAG,mBAAmB,KACnB,WACC,QAAQ,KAAK,UAAU,MAAM,EAAE,oDAAoD,KAAK,UAAU,MAAM,EAAE,kBAAkB,KAAK,UAAU,MAAM,EAAE,WACvJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,mBAAmB,aAAa;EAChC;EACA;EACA;EACA,mBAAmB,aAAa;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA,mBAAmB,aAAa;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,GAAG,mBAAmB,KACnB,WACC,6BAA6B,OAAO,+BAA+B,KAAK,UAAU,MAAM,EAAE,qBAAqB,OAA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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/generate/utils.ts","../src/utils/path.ts","../src/generate/app.ts","../src/generate/group.ts","../src/generate/middleware.ts","../src/generate/router.ts","../src/generate/types.ts","../src/generate/index.ts","../src/pipeline/analyze.ts","../src/pipeline/config.ts","../src/pipeline/discover.ts","../src/types.ts","../src/pipeline/route-parser.ts","../src/pipeline/parse.ts","../src/pipeline/plan.ts","../src/compiler.ts","../src/compile.ts","../src/diff.ts","../src/recompile.ts"],"sourcesContent":["import type { CompilationPlan } from \"@/types\";\n\n/**\n * Returns the output file path for a route group module.\n * The root group uses the reserved name \"root\".\n */\nexport const groupModuleId = (\n plan: CompilationPlan,\n groupId: string\n): string => {\n if (groupId === \"root\") {\n return `${plan.outputRoot}/groups/root.ts`;\n }\n\n return `${plan.outputRoot}/groups/${groupId}.ts`;\n};\n","const WINDOWS_DRIVE_REGEX = /^[A-Za-z]:\\//;\nconst LEADING_SLASH_REGEX = /^\\/+/;\nconst DRIVE_REGEX = /^([A-Za-z]):\\//;\n\nexport const isAbsolutePath = (value: string): boolean => {\n const normalized = value.replaceAll(\"\\\\\", \"/\");\n\n return normalized.startsWith(\"/\") || WINDOWS_DRIVE_REGEX.test(normalized);\n};\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ...\nexport const normalizePath = (value: string): string => {\n const normalized = value.replaceAll(\"\\\\\", \"/\");\n\n const isPosixAbsolute = normalized.startsWith(\"/\");\n const driveMatch = normalized.match(DRIVE_REGEX);\n\n const body = driveMatch\n ? normalized.slice(3)\n : // biome-ignore lint/style/noNestedTernary: ...\n isPosixAbsolute\n ? normalized.slice(1)\n : normalized;\n\n const parts = body.split(\"/\");\n const result: string[] = [];\n\n for (const part of parts) {\n if (!part || part === \".\") {\n continue;\n }\n\n if (part === \"..\") {\n if (result.length > 0 && result.at(-1) !== \"..\") {\n result.pop();\n } else if (!(isPosixAbsolute || driveMatch)) {\n result.push(\"..\");\n }\n\n continue;\n }\n\n result.push(part);\n }\n\n const joined = result.join(\"/\");\n\n if (driveMatch) {\n return joined ? `${driveMatch[1]}:/${joined}` : `${driveMatch[1]}:/`;\n }\n\n if (isPosixAbsolute) {\n return joined ? `/${joined}` : \"/\";\n }\n\n return joined;\n};\n\nexport const stripLeadingSlash = (value: string): string =>\n value.replace(LEADING_SLASH_REGEX, \"\");\n\nexport const ensureLeadingSlash = (value: string): string => {\n if (!value) {\n return \"/\";\n }\n\n return value.startsWith(\"/\") ? value : `/${value}`;\n};\n\nexport const joinPath = (...parts: string[]): string =>\n normalizePath(parts.filter(Boolean).join(\"/\"));\n\nexport const dirname = (value: string): string => {\n const normalized = normalizePath(value);\n const index = normalized.lastIndexOf(\"/\");\n\n if (index === -1) {\n return \"\";\n }\n\n if (index === 0) {\n return \"/\";\n }\n\n return normalized.slice(0, index);\n};\n\nexport const basename = (value: string): string => {\n const normalized = normalizePath(value);\n const index = normalized.lastIndexOf(\"/\");\n\n if (index === -1) {\n return normalized;\n }\n\n return normalized.slice(index + 1);\n};\n\nexport const relativePath = (from: string, to: string): string => {\n const fromParts = normalizePath(from).split(\"/\").filter(Boolean);\n const toParts = normalizePath(to).split(\"/\").filter(Boolean);\n\n let common = 0;\n\n while (\n common < fromParts.length &&\n common < toParts.length &&\n fromParts[common] === toParts[common]\n ) {\n common += 1;\n }\n\n const result = [\n ...fromParts.slice(common).map(() => \"..\"),\n ...toParts.slice(common),\n ];\n\n return result.join(\"/\");\n};\n\nexport const toProjectPath = (value: string, root: string): string => {\n const normalizedValue = normalizePath(value);\n const normalizedRoot = normalizePath(root);\n\n if (!(normalizedRoot && isAbsolutePath(normalizedRoot))) {\n return normalizedValue;\n }\n\n if (!isAbsolutePath(normalizedValue)) {\n return normalizedValue;\n }\n\n if (!isPathInside(normalizedValue, normalizedRoot)) {\n return normalizedValue;\n }\n\n return relativePath(normalizedRoot, normalizedValue);\n};\n\nexport const relativeModuleSpecifier = (\n fromModule: string,\n toSource: string\n): string => {\n const fromDirectory = dirname(fromModule);\n\n let target = normalizePath(toSource);\n\n if (target.endsWith(\".ts\")) {\n target = `${target.slice(0, -3)}.js`;\n } else if (target.endsWith(\".tsx\")) {\n target = `${target.slice(0, -4)}.js`;\n }\n\n const relative = relativePath(fromDirectory, target);\n\n return relative.startsWith(\".\") ? relative : `./${relative}`;\n};\n\nexport const isPathInside = (file: string, root: string): boolean => {\n const normalizedFile = normalizePath(file);\n const normalizedRoot = normalizePath(root);\n\n if (normalizedFile === normalizedRoot) {\n return true;\n }\n\n return normalizedFile.startsWith(`${normalizedRoot}/`);\n};\n\nconst EXTENSION_REGEX = /\\.[^.]+$/;\nexport const removeExtension = (value: string): string =>\n value.replace(EXTENSION_REGEX, \"\");\n","import { groupModuleId } from \"@/generate/utils\";\n\nimport type { CompilationPlan, GeneratedModule, ProjectModel } from \"@/types\";\nimport { relativeModuleSpecifier } from \"@/utils/path\";\n\nexport const generateAppModule = (\n plan: CompilationPlan,\n model: ProjectModel\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/app.ts`;\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n\n const root = model.groups.find((group) => group.id === \"root\");\n\n if (!root) {\n throw new Error(\"Nooh compilation requires a root route group.\");\n }\n\n const imports = [\n `import { Hono } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n `import root from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, groupModuleId(plan, root.id))\n )};`,\n ];\n\n const code = [\n ...imports,\n \"\",\n \"const app = new Hono<App>();\",\n \"\",\n 'app.route(\"/\", root);',\n \"\",\n \"export type AppType = typeof app;\",\n \"\",\n \"export default app;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"app\",\n };\n};\n","import { groupModuleId } from \"@/generate/utils\";\n\nimport type {\n CompilationPlan,\n GeneratedModule,\n ProjectModel,\n RouteGroup,\n RouteModel,\n} from \"@/types\";\nimport { ensureLeadingSlash, relativeModuleSpecifier } from \"@/utils/path\";\n\nconst getGroupRoutes = (\n model: ProjectModel,\n group: RouteGroup\n): readonly RouteModel[] => {\n const ids = new Set(group.routes);\n\n return model.routes\n .filter((route) => ids.has(route.id))\n .sort((a, b) => {\n const pathDifference = a.localPath.localeCompare(b.localPath);\n\n if (pathDifference !== 0) {\n return pathDifference;\n }\n\n const methodDifference = a.method.localeCompare(b.method);\n\n if (methodDifference !== 0) {\n return methodDifference;\n }\n\n return a.source.localeCompare(b.source);\n });\n};\n\nconst capitalize = (value: string): string =>\n value.charAt(0).toUpperCase() + value.slice(1);\n\nconst getGroup = (model: ProjectModel, id: string): RouteGroup | undefined =>\n model.groups.find((group) => group.id === id);\n\nconst getChildPath = (parent: RouteGroup, child: RouteGroup): string => {\n if (parent.path === \"/\") {\n return child.path;\n }\n\n const prefix = `${parent.path}/`;\n\n if (!child.path.startsWith(prefix)) {\n throw new Error(\n `Invalid group tree: \"${child.path}\" is not a child of \"${parent.path}\".`\n );\n }\n\n return child.path.slice(prefix.length);\n};\n\nexport const generateGroupModule = (\n plan: CompilationPlan,\n model: ProjectModel,\n group: RouteGroup\n): GeneratedModule => {\n const moduleId = groupModuleId(plan, group.id);\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n const routes = getGroupRoutes(model, group);\n\n const children = group.children\n .map((childId) => getGroup(model, childId))\n .filter((child): child is RouteGroup => child !== undefined)\n .sort((a, b) => a.path.localeCompare(b.path));\n\n const imports = [\n `import { Hono } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n ];\n\n if (group.configSource) {\n imports.push(\n `import groupConfig from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, group.configSource)\n )};`\n );\n }\n\n children.forEach((child, index) => {\n imports.push(\n `import child${index} from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, groupModuleId(plan, child.id))\n )};`\n );\n });\n\n routes.forEach((route, index) => {\n imports.push(\n `import endpoint${index} from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, route.source)\n )};`\n );\n });\n\n const methods = [...new Set(routes.map((route) => route.method))].sort();\n\n const registerTypes = [\n \"type RouteRegister = (\",\n \" path: string,\",\n \" ...handlers: any[]\",\n \") => typeof route;\",\n ];\n\n const registerDeclarations = methods.map((method) => {\n const name = `register${capitalize(method)}`;\n\n return `const ${name} = route.${method} as unknown as RouteRegister;`;\n });\n\n const useDeclaration = group.configSource\n ? [\n \"type RouteUse = (\",\n \" path: string,\",\n \" ...handlers: any[]\",\n \") => typeof route;\",\n \"\",\n \"const use = route.use as unknown as RouteUse;\",\n \"\",\n 'use(\"*\", ...(groupConfig.middleware ?? []));',\n ]\n : [];\n\n const registrations = routes.map((route, index) => {\n const register = `register${capitalize(route.method)}`;\n\n return ` ${register}(${JSON.stringify(\n ensureLeadingSlash(route.localPath)\n )}, ...endpoint${index});`;\n });\n\n const childRegistrations = children.map(\n (child, index) =>\n ` route.route(${JSON.stringify(\n getChildPath(group, child)\n )}, child${index});`\n );\n\n const code = [\n ...imports,\n \"\",\n \"const route = new Hono<App>();\",\n \"\",\n ...registerTypes,\n \"\",\n ...registerDeclarations,\n ...(useDeclaration.length > 0 ? [\"\", ...useDeclaration] : []),\n ...(registrations.length > 0 ? [\"\", ...registrations] : []),\n ...(childRegistrations.length > 0 ? [\"\", ...childRegistrations] : []),\n \"\",\n \"export default route;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"group\",\n };\n};\n","import type { CompilationPlan, GeneratedModule } from \"@/types\";\n\nexport const generateMiddlewareModule = (\n plan: CompilationPlan\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/router/middleware.ts`;\n\n return {\n code: [\n `import { createMiddleware } from \"hono/factory\";`,\n `import type { App } from \"../types.js\";`,\n \"\",\n \"export const middleware = createMiddleware<App>;\",\n \"\",\n ].join(\"\\n\"),\n id: moduleId,\n kind: \"middleware\",\n };\n};\n","import type {\n CompilationPlan,\n GeneratedModule,\n ProjectModel,\n RouteModel,\n} from \"@/types\";\nimport { ensureLeadingSlash, relativeModuleSpecifier } from \"@/utils/path\";\n\nconst VALIDATION_TARGETS = [\n \"json\",\n \"form\",\n \"query\",\n \"param\",\n \"header\",\n \"cookie\",\n] as const;\n\nconst METHOD_FUNCTION_NAMES: Record<RouteModel[\"method\"], string> = {\n all: \"all\",\n delete: \"del\",\n get: \"get\",\n head: \"head\",\n options: \"options\",\n patch: \"patch\",\n post: \"post\",\n put: \"put\",\n};\n\nconst getRoutesForRouter = (\n model: ProjectModel,\n routerPath: string\n): readonly RouteModel[] =>\n model.routes\n .filter((route) => route.routerPath === routerPath)\n .sort((a, b) => a.method.localeCompare(b.method));\n\nconst renderMethod = (route: RouteModel): string => {\n const { method } = route;\n const functionName = METHOD_FUNCTION_NAMES[method];\n\n const path = JSON.stringify(ensureLeadingSlash(route.localPath));\n\n return [\n `type Path = ${path};`,\n \"\",\n \"type RouteMiddleware = MiddlewareHandler<App, Path>;\",\n \"\",\n \"type ValidationTarget = Parameters<typeof sValidator>[0];\",\n \"type StandardSchema = Parameters<typeof sValidator>[1];\",\n \"\",\n \"type ValidationOptions = Partial<\",\n \" Record<ValidationTarget, StandardSchema>\",\n \">;\",\n \"\",\n \"type HandlerInput<T> = T extends Handler<\",\n \" any,\",\n \" any,\",\n \" infer I,\",\n \" any\",\n \"> ? I : never;\",\n \"\",\n \"type ValidationHandler<\",\n \" Target extends ValidationTarget,\",\n \" Schema extends StandardSchema,\",\n \"> = ReturnType<\",\n \" typeof sValidator<Schema, Target, App, Path>\",\n \">;\",\n \"\",\n \"type ValidationInput<V extends ValidationOptions> =\",\n ...VALIDATION_TARGETS.map(\n (target) =>\n ` & (${JSON.stringify(target)} extends keyof V ? HandlerInput<ValidationHandler<${JSON.stringify(target)}, NonNullable<V[${JSON.stringify(target)}]>>> : {})`\n ),\n \";\",\n \"\",\n \"type RouteHandler = Handler<App, Path, any, any>;\",\n \"\",\n \"type EndpointOptions<\",\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \"> = {\",\n \" readonly middleware?: M;\",\n \" readonly validation?: V;\",\n \" readonly handler: H;\",\n \"};\",\n \"\",\n `export function ${functionName}<H extends Handler<App, Path>>(`,\n \" handler: H,\",\n \"): readonly RouteHandler[];\",\n \"\",\n `export function ${functionName}<`,\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \">(\",\n \" options: EndpointOptions<M, V, H>,\",\n \"): readonly RouteHandler[];\",\n \"\",\n `export function ${functionName}<`,\n \" M extends readonly RouteMiddleware[],\",\n \" V extends ValidationOptions,\",\n \" H extends Handler<App, Path, ValidationInput<V>>,\",\n \">(\",\n \" input:\",\n \" | H\",\n \" | EndpointOptions<M, V, H>,\",\n \"): readonly RouteHandler[] {\",\n ' if (typeof input === \"function\") {',\n \" return [input as RouteHandler];\",\n \" }\",\n \"\",\n \" return [\",\n \" ...(input.middleware ?? []) as readonly RouteHandler[],\",\n ...VALIDATION_TARGETS.map(\n (target) =>\n ` ...(input.validation?.${target} !== undefined ? [sValidator(${JSON.stringify(target)}, input.validation.${target}) as RouteHandler] : []),`\n ),\n \" input.handler as RouteHandler,\",\n \" ];\",\n \"}\",\n \"\",\n ].join(\"\\n\");\n};\n\nexport const generateRouterModule = (\n plan: CompilationPlan,\n model: ProjectModel,\n routerPath: string\n): GeneratedModule => {\n const routes = getRoutesForRouter(model, routerPath);\n\n const moduleId = `${plan.outputRoot}/${routerPath}.ts`;\n\n const typesModuleId = `${plan.outputRoot}/types.ts`;\n\n return {\n code: [\n `import { sValidator } from \"@hono/standard-validator\";`,\n `import type { Handler, MiddlewareHandler } from \"hono\";`,\n `import type { App } from ${JSON.stringify(\n relativeModuleSpecifier(moduleId, typesModuleId)\n )};`,\n \"\",\n ...routes.map(renderMethod),\n ].join(\"\\n\"),\n id: moduleId,\n kind: \"router\",\n };\n};\n","import type { CompilationPlan, GeneratedModule, LoadedConfig } from \"@/types\";\nimport { relativeModuleSpecifier } from \"@/utils/path\";\n\nexport const generateTypesModule = (\n plan: CompilationPlan,\n config: LoadedConfig\n): GeneratedModule => {\n const moduleId = `${plan.outputRoot}/types.ts`;\n\n const configImport = relativeModuleSpecifier(moduleId, config.source);\n\n const code = [\n `import type config from \"${configImport}\";`,\n \"\",\n \"type ExtractEnvironment<T> = T extends {\",\n \" readonly __nooh_env: infer Environment;\",\n \"}\",\n \" ? Environment\",\n \" : never;\",\n \"\",\n \"export type App = ExtractEnvironment<typeof config>;\",\n \"\",\n ].join(\"\\n\");\n\n return {\n code,\n id: moduleId,\n kind: \"types\",\n };\n};\n","import { generateAppModule } from \"@/generate/app\";\nimport { generateGroupModule } from \"@/generate/group\";\nimport { generateMiddlewareModule } from \"@/generate/middleware\";\nimport { generateRouterModule } from \"@/generate/router\";\nimport { generateTypesModule } from \"@/generate/types\";\n\nimport type {\n CompilationPlan,\n GeneratedModule,\n GeneratedOutput,\n ProjectModel,\n} from \"@/types\";\n\nexport const generate = (\n plan: CompilationPlan,\n model: ProjectModel\n): GeneratedOutput => {\n const modules: GeneratedModule[] = [];\n\n modules.push(generateTypesModule(plan, model.config));\n\n modules.push(generateMiddlewareModule(plan));\n\n const routerPaths = [\n ...new Set(model.routes.map((route) => route.routerPath)),\n ].sort();\n\n for (const routerPath of routerPaths) {\n modules.push(generateRouterModule(plan, model, routerPath));\n }\n\n for (const group of model.groups) {\n modules.push(generateGroupModule(plan, model, group));\n }\n\n modules.push(generateAppModule(plan, model));\n\n modules.sort((a, b) => a.id.localeCompare(b.id));\n\n return {\n modules,\n };\n};\n","import type {\n Diagnostic,\n LoadedConfig,\n ParsedProject,\n ParsedRoute,\n ProjectModel,\n RouteGroup,\n RouteModel,\n RouteSegment,\n} from \"@/types\";\nimport { ensureLeadingSlash, normalizePath } from \"@/utils/path\";\n\nconst segmentToHono = (segment: RouteSegment): string => {\n // biome-ignore lint/style/useDefaultSwitchClause: ...\n switch (segment.kind) {\n case \"static\":\n return segment.value;\n\n case \"param\":\n return `:${segment.name}`;\n\n case \"splat\":\n return \"*\";\n }\n};\n\nconst segmentsToPath = (segments: readonly RouteSegment[]): string => {\n if (segments.length === 0) {\n return \"\";\n }\n\n return segments.map(segmentToHono).join(\"/\");\n};\n\nconst combinePaths = (groupPath: string, localPath: string): string => {\n const group = normalizePath(groupPath).replace(/^\\/+|\\/+$/g, \"\");\n const local = normalizePath(localPath).replace(/^\\/+|\\/+$/g, \"\");\n\n if (!(group || local)) {\n return \"/\";\n }\n\n if (!group) {\n return `/${local}`;\n }\n\n if (!local) {\n return `/${group}`;\n }\n\n return `/${group}/${local}`;\n};\n\nconst routeSegmentsToRouterPath = (\n groupPath: string,\n rawSegments: readonly string[]\n): string => {\n const parts = [\n ...groupPath.split(\"/\").filter(Boolean),\n ...rawSegments.filter(Boolean),\n ];\n\n return parts.length === 0 ? \"router/index\" : `router/${parts.join(\"/\")}`;\n};\n\nconst routeId = (route: ParsedRoute): string =>\n `${route.method.toUpperCase()} ${combinePaths(\n route.groupPath,\n segmentsToPath(route.segments)\n )}`;\n\nconst sortRoutes = (a: RouteModel, b: RouteModel): number => {\n const pathDifference = a.fullPath.localeCompare(b.fullPath);\n\n if (pathDifference !== 0) {\n return pathDifference;\n }\n\n const methodDifference = a.method.localeCompare(b.method);\n\n if (methodDifference !== 0) {\n return methodDifference;\n }\n\n return a.source.localeCompare(b.source);\n};\n\nconst parentGroupPath = (groupPath: string): string | null => {\n const normalized = normalizePath(groupPath);\n\n if (!normalized) {\n return null;\n }\n\n const parts = normalized.split(\"/\").filter(Boolean);\n\n if (parts.length <= 1) {\n return \"\";\n }\n\n return parts.slice(0, -1).join(\"/\");\n};\n\nconst getAncestorGroupPaths = (groupPath: string): readonly string[] => {\n const parts = normalizePath(groupPath).split(\"/\").filter(Boolean);\n\n return Array.from({ length: parts.length + 1 }, (_, index) =>\n parts.slice(0, index).join(\"/\")\n );\n};\n\nconst groupId = (path: string): string => path || \"root\";\n\nconst buildGroups = (\n parsed: ParsedProject,\n routeModels: readonly RouteModel[],\n diagnostics: Diagnostic[]\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: ...\n): readonly RouteGroup[] => {\n const configSources = new Map<string, string>();\n\n for (const group of parsed.groups) {\n const path = normalizePath(group.groupPath);\n const previous = configSources.get(path);\n\n if (previous) {\n diagnostics.push({\n code: \"NOOH006\",\n file: group.source,\n message: [\n `Duplicate group definition for \"${path || \"/\"}\".`,\n \"\",\n `First declaration: ${previous}`,\n `Second declaration: ${group.source}`,\n ].join(\"\\n\"),\n severity: \"error\",\n });\n\n continue;\n }\n\n configSources.set(path, group.source);\n }\n\n const groupPaths = new Set<string>([\"\"]);\n\n for (const group of parsed.groups) {\n for (const ancestor of getAncestorGroupPaths(group.groupPath)) {\n groupPaths.add(ancestor);\n }\n }\n\n for (const route of routeModels) {\n for (const ancestor of getAncestorGroupPaths(route.groupPath)) {\n groupPaths.add(ancestor);\n }\n }\n\n const routesByGroup = new Map<string, string[]>();\n\n for (const route of routeModels) {\n const routes = routesByGroup.get(route.groupPath);\n\n if (routes) {\n routes.push(route.id);\n } else {\n routesByGroup.set(route.groupPath, [route.id]);\n }\n }\n\n const childrenByGroup = new Map<string, string[]>();\n\n for (const path of groupPaths) {\n if (!path) {\n continue;\n }\n\n const parent = parentGroupPath(path) ?? \"\";\n\n const children = childrenByGroup.get(parent);\n\n if (children) {\n children.push(path);\n } else {\n childrenByGroup.set(parent, [path]);\n }\n }\n\n return [...groupPaths]\n .sort((a, b) => {\n if (!a && b) {\n return -1;\n }\n\n if (a && !b) {\n return 1;\n }\n\n return a.localeCompare(b);\n })\n .map((path) => {\n const children = [...(childrenByGroup.get(path) ?? [])].sort();\n const configSource = configSources.get(path);\n const parent = parentGroupPath(path);\n\n return {\n children: children.map(groupId),\n id: groupId(path),\n ...(parent !== null && {\n parentId: groupId(parent),\n }),\n path: path ? ensureLeadingSlash(path) : \"/\",\n routes: [...(routesByGroup.get(path) ?? [])].sort(),\n ...(configSource !== undefined && {\n configSource,\n }),\n };\n });\n};\n\nexport const analyze = (\n parsed: ParsedProject,\n config: LoadedConfig\n): {\n model: ProjectModel;\n diagnostics: readonly Diagnostic[];\n} => {\n const diagnostics: Diagnostic[] = [...parsed.diagnostics];\n\n const routeModels: RouteModel[] = [];\n const seen = new Map<string, string>();\n\n for (const route of parsed.routes) {\n const localPath = segmentsToPath(route.segments);\n const fullPath = combinePaths(route.groupPath, localPath);\n const id = routeId(route);\n\n const previousSource = seen.get(id);\n\n if (previousSource) {\n diagnostics.push({\n code: \"NOOH005\",\n file: route.source,\n message: [\n `Duplicate route \"${id}\".`,\n \"\",\n `First declaration: ${previousSource}`,\n `Second declaration: ${route.source}`,\n ].join(\"\\n\"),\n severity: \"error\",\n });\n\n continue;\n }\n\n seen.set(id, route.source);\n\n routeModels.push({\n fullPath,\n groupPath: normalizePath(route.groupPath),\n id,\n localPath,\n method: route.method,\n routerPath: routeSegmentsToRouterPath(route.groupPath, route.rawSegments),\n routeSegments: route.segments,\n source: route.source,\n });\n }\n\n routeModels.sort(sortRoutes);\n\n const groups = buildGroups(parsed, routeModels, diagnostics);\n\n return {\n diagnostics,\n model: {\n config,\n groups,\n routes: routeModels,\n },\n };\n};\n","import type { CompileInput, ConfigLoadResult, RuntimeConfig } from \"@/types\";\nimport { normalizePath, toProjectPath } from \"@/utils/path\";\n\nconst DEFAULT_ROUTES_ROOT = \"src/routes\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null;\n\nconst isString = (value: unknown): value is string => typeof value === \"string\";\n\nexport const loadConfig = async (\n input: CompileInput\n): Promise<ConfigLoadResult> => {\n let defaultExport: unknown;\n\n try {\n defaultExport = await input.loader.loadDefault(input.config);\n } catch (error) {\n return {\n diagnostics: [\n {\n code: \"NOOH010\",\n file: input.config,\n message:\n error instanceof Error\n ? `Failed to load config: ${error.message}`\n : \"Failed to load config.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n if (!isRecord(defaultExport)) {\n return {\n diagnostics: [\n {\n code: \"NOOH011\",\n file: input.config,\n message: \"The Nooh config default export must be an object.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n const routesValue = defaultExport.routes;\n\n if (routesValue !== undefined && !isString(routesValue)) {\n return {\n diagnostics: [\n {\n code: \"NOOH012\",\n file: input.config,\n message: 'The Nooh config \"routes\" option must be a string.',\n severity: \"error\",\n },\n ],\n };\n }\n\n const root = normalizePath(input.root ?? \"\");\n const source = toProjectPath(input.config, root);\n const routes = routesValue ?? DEFAULT_ROUTES_ROOT;\n const routesRoot = toProjectPath(routes, root);\n\n const value: RuntimeConfig = {\n routes: routesValue,\n };\n\n return {\n config: {\n root,\n routesRoot,\n source,\n value,\n },\n diagnostics: [],\n };\n};\n","import type {\n DiscoveredEndpoint,\n DiscoveredGroup,\n DiscoveredProject,\n LoadedConfig,\n SourceFile,\n SourceSnapshot,\n} from \"@/types\";\nimport {\n basename,\n dirname,\n isPathInside,\n normalizePath,\n relativePath,\n toProjectPath,\n} from \"@/utils/path\";\n\nconst ROUTE_FILE_PATTERN =\n /\\.(get|post|put|patch|delete|options|head|all)\\.(?:ts|tsx)$/;\n\nconst isTypeScriptFile = (file: SourceFile): boolean =>\n file.path.endsWith(\".ts\") || file.path.endsWith(\".tsx\");\n\nconst isRouteFile = (filePath: string): boolean =>\n ROUTE_FILE_PATTERN.test(filePath);\n\nconst isGroupFile = (filePath: string): boolean => {\n const filename = basename(filePath);\n\n return filename === \"$.ts\" || filename === \"$.tsx\";\n};\n\nconst discoverGroup = (\n config: LoadedConfig,\n file: SourceFile\n): DiscoveredGroup | null => {\n const source = toProjectPath(file.path, config.root);\n\n if (!isPathInside(source, config.routesRoot)) {\n return null;\n }\n\n if (!isGroupFile(source)) {\n return null;\n }\n\n const relative = relativePath(config.routesRoot, source);\n const directory = dirname(relative);\n\n return {\n groupPath: normalizePath(directory),\n source,\n };\n};\n\nconst discoverEndpoint = (\n config: LoadedConfig,\n file: SourceFile\n): DiscoveredEndpoint | null => {\n const source = toProjectPath(file.path, config.root);\n\n if (!isPathInside(source, config.routesRoot)) {\n return null;\n }\n\n if (!isRouteFile(source)) {\n return null;\n }\n\n const relative = relativePath(config.routesRoot, source);\n\n return {\n groupPath: normalizePath(dirname(relative)),\n localPath: normalizePath(basename(relative)),\n source,\n };\n};\n\nexport const discover = (\n snapshot: SourceSnapshot,\n config: LoadedConfig\n): DiscoveredProject => {\n const endpoints: DiscoveredEndpoint[] = [];\n const groups: DiscoveredGroup[] = [];\n\n for (const file of snapshot.files) {\n if (!isTypeScriptFile(file)) {\n continue;\n }\n\n const group = discoverGroup(config, file);\n\n if (group) {\n groups.push(group);\n continue;\n }\n\n const endpoint = discoverEndpoint(config, file);\n\n if (endpoint) {\n endpoints.push(endpoint);\n }\n }\n\n endpoints.sort((a, b) => a.source.localeCompare(b.source));\n groups.sort((a, b) => a.source.localeCompare(b.source));\n\n return {\n config,\n endpoints,\n groups,\n };\n};\n","export const ROUTE_METHODS = [\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"options\",\n \"head\",\n \"all\",\n] as const;\n\nexport type RouteMethod = (typeof ROUTE_METHODS)[number];\n\nexport interface SourceFile {\n readonly content: string;\n readonly path: string;\n}\n\nexport interface SourceSnapshot {\n readonly files: readonly SourceFile[];\n}\n\nexport interface ModuleLoader {\n loadDefault: (modulePath: string) => Promise<unknown>;\n}\n\nexport interface CompileOptions {\n readonly outputRoot?: string;\n}\n\nexport interface CompileInput {\n readonly config: string;\n readonly loader: ModuleLoader;\n readonly options?: CompileOptions;\n readonly root?: string;\n readonly sources: SourceSnapshot;\n}\n\nexport interface RuntimeConfig {\n readonly routes?: string | undefined;\n}\n\nexport interface LoadedConfig {\n readonly root: string;\n readonly routesRoot: string;\n readonly source: string;\n readonly value: RuntimeConfig;\n}\n\nexport interface ConfigLoadResult {\n readonly config?: LoadedConfig;\n readonly diagnostics: readonly Diagnostic[];\n}\n\nexport interface DiscoveredEndpoint {\n readonly groupPath: string;\n readonly localPath: string;\n readonly source: string;\n}\n\nexport interface DiscoveredGroup {\n readonly groupPath: string;\n readonly source: string;\n}\n\nexport interface DiscoveredProject {\n readonly config: LoadedConfig;\n readonly endpoints: readonly DiscoveredEndpoint[];\n readonly groups: readonly DiscoveredGroup[];\n}\n\nexport type RouteSegment =\n | {\n readonly kind: \"static\";\n readonly value: string;\n }\n | {\n readonly kind: \"param\";\n readonly name: string;\n }\n | {\n readonly kind: \"splat\";\n readonly name?: string;\n };\n\nexport interface ParsedRoute {\n readonly groupPath: string;\n readonly method: RouteMethod;\n readonly rawSegments: readonly string[];\n readonly segments: readonly RouteSegment[];\n readonly source: string;\n}\n\nexport interface ParsedGroup {\n readonly groupPath: string;\n readonly source: string;\n}\n\nexport interface ParsedProject {\n readonly diagnostics: readonly Diagnostic[];\n readonly groups: readonly ParsedGroup[];\n readonly routes: readonly ParsedRoute[];\n}\n\nexport interface RouteModel {\n readonly fullPath: string;\n\n readonly groupPath: string;\n readonly id: string;\n\n readonly localPath: string;\n\n readonly method: RouteMethod;\n\n readonly routerPath: string;\n readonly routeSegments: readonly RouteSegment[];\n readonly source: string;\n}\n\nexport interface RouteGroup {\n readonly children: readonly string[];\n readonly configSource?: string;\n readonly id: string;\n readonly parentId?: string;\n readonly path: string;\n readonly routes: readonly string[];\n}\n\nexport interface ProjectModel {\n readonly config: LoadedConfig;\n readonly groups: readonly RouteGroup[];\n readonly routes: readonly RouteModel[];\n}\n\nexport type DiagnosticSeverity = \"error\" | \"warning\" | \"info\";\n\nexport interface Diagnostic {\n readonly code: string;\n readonly file?: string;\n readonly message: string;\n readonly severity: DiagnosticSeverity;\n}\n\nexport type ModuleKind = \"types\" | \"router\" | \"middleware\" | \"group\" | \"app\";\n\nexport interface ModulePlan {\n readonly groupId?: string;\n readonly id: string;\n readonly kind: ModuleKind;\n readonly routeId?: string;\n}\n\nexport interface CompilationPlan {\n readonly modules: readonly ModulePlan[];\n readonly outputRoot: string;\n}\n\nexport interface GeneratedModule {\n readonly code: string;\n readonly id: string;\n readonly kind: ModuleKind;\n}\n\nexport interface GeneratedOutput {\n readonly modules: readonly GeneratedModule[];\n}\n\nexport interface Compilation {\n readonly diagnostics: readonly Diagnostic[];\n readonly model: ProjectModel;\n readonly output: GeneratedOutput | null;\n readonly plan: CompilationPlan | null;\n}\n\nexport interface NoohCompiler {\n analyze: (\n parsed: ParsedProject,\n config: LoadedConfig\n ) => {\n model: ProjectModel;\n diagnostics: readonly Diagnostic[];\n };\n compile: (input: CompileInput) => Promise<Compilation>;\n discover: (\n sources: CompileInput[\"sources\"],\n config: LoadedConfig\n ) => DiscoveredProject;\n generate: (plan: CompilationPlan, model: ProjectModel) => GeneratedOutput;\n loadConfig: (input: CompileInput) => Promise<ConfigLoadResult>;\n parse: (project: DiscoveredProject) => ParsedProject;\n plan: (model: ProjectModel, outputRoot?: string) => CompilationPlan;\n}\n\nexport interface OutputDiff {\n readonly added: readonly GeneratedModule[];\n readonly changed: readonly GeneratedModule[];\n readonly removed: readonly string[];\n readonly unchanged: readonly GeneratedModule[];\n}\n\nexport interface RecompileInput {\n readonly config?: string;\n readonly loader: CompileInput[\"loader\"];\n readonly options?: CompileInput[\"options\"];\n readonly previous: Compilation;\n readonly snapshot: SourceSnapshot;\n}\n","import type {\n Diagnostic,\n DiscoveredEndpoint,\n ParsedRoute,\n RouteSegment,\n} from \"@/types\";\nimport { ROUTE_METHODS } from \"@/types\";\nimport { normalizePath } from \"@/utils/path\";\n\nconst METHOD_PATTERN =\n /^(.*)\\.(get|post|put|patch|delete|options|head|all)\\.(?:ts|tsx)$/;\n\nconst PARAM_PATTERN = /^\\[([A-Za-z0-9_]+)\\]$/;\nconst SPLAT_PATTERN = /^\\[\\.\\.\\.([A-Za-z0-9_]+)\\]$/;\n\nconst methodSet = new Set<string>(ROUTE_METHODS);\n\nconst parseSegment = (\n segment: string\n):\n | { segment: RouteSegment; error?: undefined }\n | {\n segment?: undefined;\n error: Diagnostic;\n } => {\n const parameter = segment.match(PARAM_PATTERN);\n\n if (parameter?.[1]) {\n return {\n segment: {\n kind: \"param\",\n name: parameter[1],\n },\n };\n }\n\n const splat = segment.match(SPLAT_PATTERN);\n\n if (splat?.[1]) {\n return {\n segment: {\n kind: \"splat\",\n name: splat[1],\n },\n };\n }\n\n if (segment.includes(\"[\") || segment.includes(\"]\")) {\n return {\n error: {\n code: \"NOOH003\",\n message: `Invalid route segment \"${segment}\".`,\n severity: \"error\",\n },\n };\n }\n\n if (!segment) {\n return {\n error: {\n code: \"NOOH004\",\n message: \"Route segments cannot be empty.\",\n severity: \"error\",\n },\n };\n }\n\n return {\n segment: {\n kind: \"static\",\n value: segment,\n },\n };\n};\n\nexport const parseEndpoint = (\n endpoint: DiscoveredEndpoint\n): {\n route?: ParsedRoute;\n diagnostics: readonly Diagnostic[];\n} => {\n const localParts = endpoint.localPath.split(\"/\").filter(Boolean);\n const filename = localParts.pop();\n\n if (!filename) {\n return {\n diagnostics: [\n {\n code: \"NOOH001\",\n file: endpoint.source,\n message: \"Invalid empty endpoint filename.\",\n severity: \"error\",\n },\n ],\n };\n }\n\n const match = filename.match(METHOD_PATTERN);\n\n if (!match) {\n return {\n diagnostics: [\n {\n code: \"NOOH001\",\n file: endpoint.source,\n message: 'Invalid endpoint filename. Expected \"<name>.<method>.ts\".',\n severity: \"error\",\n },\n ],\n };\n }\n\n const [_match, routeFile, method] = match;\n\n if (!(method && methodSet.has(method))) {\n return {\n diagnostics: [\n {\n code: \"NOOH002\",\n file: endpoint.source,\n message: `Unsupported HTTP method \"${method}\".`,\n severity: \"error\",\n },\n ],\n };\n }\n\n const validMethod = method as ParsedRoute[\"method\"];\n\n const routeFileSegments = routeFile?.split(\"/\").filter(Boolean) || [];\n const rawSegments = [...localParts, ...routeFileSegments];\n\n const last = rawSegments.at(-1);\n const effectiveSegments =\n last === \"index\" ? rawSegments.slice(0, -1) : rawSegments;\n\n const diagnostics: Diagnostic[] = [];\n const segments: RouteSegment[] = [];\n\n for (const rawSegment of effectiveSegments) {\n const result = parseSegment(rawSegment);\n\n if (result.error) {\n diagnostics.push({\n ...result.error,\n file: endpoint.source,\n });\n\n continue;\n }\n\n segments.push(result.segment);\n }\n\n if (diagnostics.length > 0) {\n return {\n diagnostics,\n };\n }\n\n return {\n diagnostics: [],\n route: {\n groupPath: normalizePath(endpoint.groupPath),\n method: validMethod,\n rawSegments: effectiveSegments,\n segments,\n source: endpoint.source,\n },\n };\n};\n","import { parseEndpoint } from \"@/pipeline/route-parser\";\nimport type {\n Diagnostic,\n DiscoveredProject,\n ParsedGroup,\n ParsedProject,\n ParsedRoute,\n} from \"@/types\";\n\nexport const parse = (project: DiscoveredProject): ParsedProject => {\n const routes: ParsedRoute[] = [];\n const diagnostics: Diagnostic[] = [];\n\n for (const endpoint of project.endpoints) {\n const result = parseEndpoint(endpoint);\n\n diagnostics.push(...result.diagnostics);\n\n if (result.route) {\n routes.push(result.route);\n }\n }\n\n const groups: ParsedGroup[] = project.groups.map((group) => ({\n groupPath: group.groupPath,\n source: group.source,\n }));\n\n routes.sort((a, b) => a.source.localeCompare(b.source));\n groups.sort((a, b) => a.source.localeCompare(b.source));\n\n return {\n diagnostics,\n groups,\n routes,\n };\n};\n","import type { CompilationPlan, ModulePlan, ProjectModel } from \"@/types\";\nimport { normalizePath } from \"@/utils/path\";\n\nconst DEFAULT_OUTPUT_ROOT = \".nooh\";\n\nconst modulePath = (outputRoot: string, value: string): string =>\n normalizePath(`${outputRoot}/${value}.ts`);\n\nexport const plan = (\n model: ProjectModel,\n outputRoot: string = DEFAULT_OUTPUT_ROOT\n): CompilationPlan => {\n const normalizedOutputRoot = normalizePath(outputRoot);\n\n const modules: ModulePlan[] = [\n {\n id: modulePath(normalizedOutputRoot, \"types\"),\n kind: \"types\",\n },\n {\n id: modulePath(normalizedOutputRoot, \"router/middleware\"),\n kind: \"middleware\",\n },\n ];\n\n const routerPaths = [\n ...new Set(model.routes.map((route) => route.routerPath)),\n ].sort();\n\n for (const routerPath of routerPaths) {\n const route = model.routes.find(\n (candidate) => candidate.routerPath === routerPath\n );\n\n if (!route) {\n continue;\n }\n\n modules.push({\n id: modulePath(normalizedOutputRoot, routerPath),\n kind: \"router\",\n routeId: route.routerPath,\n });\n }\n\n for (const group of model.groups) {\n const groupPath =\n group.id === \"root\" ? \"groups/root\" : `groups/${group.id}`;\n\n modules.push({\n groupId: group.id,\n id: modulePath(normalizedOutputRoot, groupPath),\n kind: \"group\",\n });\n }\n\n modules.push({\n id: modulePath(normalizedOutputRoot, \"app\"),\n kind: \"app\",\n });\n\n modules.sort((a, b) => a.id.localeCompare(b.id));\n\n return {\n modules,\n outputRoot: normalizedOutputRoot,\n };\n};\n","import { generate } from \"@/generate\";\n\nimport { analyze } from \"@/pipeline/analyze\";\nimport { loadConfig } from \"@/pipeline/config\";\nimport { discover } from \"@/pipeline/discover\";\nimport { parse } from \"@/pipeline/parse\";\nimport { plan } from \"@/pipeline/plan\";\n\nimport type { NoohCompiler } from \"@/types\";\n\nexport const createCompiler = (): NoohCompiler => ({\n analyze,\n\n compile: async (input) => {\n const configResult = await loadConfig(input);\n\n if (!configResult.config) {\n return {\n diagnostics: configResult.diagnostics,\n model: {\n config: {\n root: input.root ? input.root.replaceAll(\"\\\\\", \"/\") : \"\",\n routesRoot: \"\",\n source: input.config,\n value: {},\n },\n groups: [],\n routes: [],\n },\n output: null,\n plan: null,\n };\n }\n\n const discovered = discover(input.sources, configResult.config);\n const parsed = parse(discovered);\n const analyzed = analyze(parsed, configResult.config);\n const diagnostics = [...configResult.diagnostics, ...analyzed.diagnostics];\n\n const hasErrors = diagnostics.some(\n (diagnostic) => diagnostic.severity === \"error\"\n );\n\n if (hasErrors) {\n return {\n diagnostics,\n model: analyzed.model,\n output: null,\n plan: null,\n };\n }\n\n const compilationPlan = plan(analyzed.model, input.options?.outputRoot);\n\n const output = generate(compilationPlan, analyzed.model);\n\n return {\n diagnostics,\n model: analyzed.model,\n output,\n plan: compilationPlan,\n };\n },\n\n discover,\n generate,\n loadConfig,\n parse,\n plan,\n});\n","import { createCompiler } from \"@/compiler\";\nimport type { Compilation, CompileInput } from \"@/types\";\n\nexport const compile = (input: CompileInput): Promise<Compilation> =>\n createCompiler().compile(input);\n","import type { GeneratedModule, GeneratedOutput, OutputDiff } from \"@/types\";\n\nexport const diff = (\n previous: GeneratedOutput,\n next: GeneratedOutput\n): OutputDiff => {\n const previousMap = new Map(\n previous.modules.map((module) => [module.id, module])\n );\n\n const nextMap = new Map(next.modules.map((module) => [module.id, module]));\n\n const added: GeneratedModule[] = [];\n const changed: GeneratedModule[] = [];\n const unchanged: GeneratedModule[] = [];\n const removed: string[] = [];\n\n for (const module of next.modules) {\n const previousModule = previousMap.get(module.id);\n\n if (!previousModule) {\n added.push(module);\n continue;\n }\n\n if (previousModule.code !== module.code) {\n changed.push(module);\n continue;\n }\n\n unchanged.push(module);\n }\n\n for (const module of previous.modules) {\n if (!nextMap.has(module.id)) {\n removed.push(module.id);\n }\n }\n\n return {\n added,\n changed,\n removed,\n unchanged,\n };\n};\n","import { createCompiler } from \"@/compiler\";\nimport type { Compilation, RecompileInput } from \"@/types\";\n\nexport const recompile = (input: RecompileInput): Promise<Compilation> => {\n const compiler = createCompiler();\n\n const config = input.config ?? input.previous.model.config.source;\n\n return compiler.compile({\n config,\n loader: input.loader,\n root: input.previous.model.config.root,\n\n ...(input.options !== undefined && {\n options: input.options,\n }),\n\n sources: input.snapshot,\n });\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nooh-ts/compiler",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The compiler core for Nooh.",
5
5
  "keywords": [
6
6
  "nooh",
package/readme.md CHANGED
@@ -0,0 +1,132 @@
1
+ <p align="center">
2
+ <img src="https://github.com/nehu3n/nooh/blob/main/.github/assets/nooh-banner.webp" alt="Nooh" width="750" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <strong>๐ŸงŠ A zero-dependency, compile-time metaframework for building type-safe file-based Hono APIs.</strong>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://nooh-ts.pages.dev">Documentation</a>
11
+ ยท
12
+ <a href="https://github.com/nehu3n/nooh">GitHub</a>
13
+ ยท
14
+ <a href="https://www.npmjs.com/package/@nooh-ts/compiler">npm</a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <img src="https://img.shields.io/npm/v/%40nooh-ts%2Fcompiler?style=flat-square" alt="npm version" />
19
+ <img src="https://img.shields.io/github/license/nehu3n/nooh?style=flat-square" alt="License" />
20
+ </p>
21
+
22
+ ## About
23
+
24
+ [`@nooh-ts/compiler`](https://www.npmjs.com/package/@nooh-ts/compiler) is the core compiler behind [**Nooh**](https://github.com/nehu3n/nooh).
25
+
26
+ It transforms a Nooh project into generated, native Hono code based on its filesystem structure, configuration, routes, groups, middleware, and dependencies.
27
+
28
+ The compiler is designed to be small, deterministic, and independent of any particular build tool or development environment.
29
+
30
+ ## How it works
31
+
32
+ A Nooh project is compiled through a simple pipeline:
33
+
34
+ ```text
35
+ Project files
36
+ โ†“
37
+ Discovery
38
+ โ†“
39
+ Parsing
40
+ โ†“
41
+ Analysis
42
+ โ†“
43
+ Planning
44
+ โ†“
45
+ Code generation
46
+ โ†“
47
+ Native Hono application
48
+ ```
49
+
50
+ For example:
51
+
52
+ ```text
53
+ src/
54
+ โ””โ”€โ”€ routes/
55
+ โ””โ”€โ”€ users/
56
+ โ””โ”€โ”€ [id].get.ts
57
+ ```
58
+
59
+ is compiled into a generated router that exposes the corresponding HTTP method:
60
+
61
+ ```ts
62
+ import { get } from "@router/users/[id]";
63
+
64
+ export default get((c) => {
65
+ const id = c.req.param("id");
66
+
67
+ return c.json({ id });
68
+ });
69
+ ```
70
+
71
+ The compiler resolves the filesystem structure and generates the Hono application that connects everything together.
72
+
73
+ ## Use the compiler directly
74
+
75
+ The compiler can be used independently of the official CLI or any particular bundler:
76
+
77
+ ```ts
78
+ import { compile } from "@nooh-ts/compiler";
79
+
80
+ const result = await compile({
81
+ root: process.cwd(),
82
+ sources: { files },
83
+ });
84
+ ```
85
+
86
+ This makes the compiler suitable for custom tooling, development environments, build systems, and integrations.
87
+
88
+ ## No runtime
89
+
90
+ The compiler does not introduce a Nooh runtime.
91
+
92
+ It generates ordinary TypeScript and Hono code:
93
+
94
+ ```text
95
+ Nooh source
96
+ โ†“
97
+ @nooh-ts/compiler
98
+ โ†“
99
+ generated TypeScript
100
+ โ†“
101
+ Hono
102
+ โ†“
103
+ your runtime
104
+ ```
105
+
106
+ Once compilation is complete, Nooh is out of the runtime path.
107
+
108
+ ## Integrations
109
+
110
+ The compiler is intentionally independent from:
111
+
112
+ * CLIs
113
+ * Vite
114
+ * Rollup
115
+ * Rolldown
116
+ * Webpack
117
+ * esbuild
118
+ * Bun
119
+ * Node.js runtimes
120
+ * deployment platforms
121
+
122
+ Build-tool integrations can use the compiler while keeping their own lifecycle, module resolution, and development model.
123
+
124
+ ## Documentation
125
+
126
+ The full documentation covers the compilation pipeline, route discovery, analysis, generation, diagnostics, and compiler API.
127
+
128
+ **[Read the documentation โ†’](https://nooh-ts.pages.dev)**
129
+
130
+ ## License
131
+
132
+ This project is licensed under the [MIT License](https://github.com/nehu3n/nooh/blob/main/license).