@kosmojs/lib 0.1.8 → 0.1.9

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/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@kosmojs/lib",
4
- "version": "0.1.8",
4
+ "version": "0.1.9",
5
5
  "author": "Slee Woo",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "pkg/*"
9
9
  ],
10
- "imports": {
11
- "#templates/*": "./src/templates/*"
12
- },
13
10
  "exports": {
14
11
  ".": {
15
12
  "types": "./pkg/index.d.ts",
@@ -22,17 +19,17 @@
22
19
  "handlebars": "^4.7.9",
23
20
  "mime-types": "^3.0.2",
24
21
  "path-to-regexp": "^8.4.2",
25
- "picomatch": "^4.0.4",
26
- "tfusion": "^0.0.24",
27
- "tinyglobby": "^0.2.16",
22
+ "picomatch": "^4.0.5",
23
+ "tfusion": "^0.1.1",
24
+ "tinyglobby": "^0.2.17",
28
25
  "ts-morph": "^28.0.0",
29
- "@kosmojs/core": "^0.1.8"
26
+ "@kosmojs/core": "^0.1.9"
30
27
  },
31
28
  "devDependencies": {
32
29
  "@types/mime-types": "^3.0.1",
33
30
  "@types/picomatch": "^4.0.3",
34
- "vite": "^8.0.10",
35
- "@kosmojs/lib": "^0.1.8"
31
+ "vite": "^8.1.4",
32
+ "@kosmojs/lib": "^0.1.9"
36
33
  },
37
34
  "scripts": {
38
35
  "build": "wsbuild src/index.ts",
package/pkg/ast.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { flattener } from "tfusion";
1
+ import flattener from "tfusion";
2
2
  import { type CallExpression, Project, type ProjectOptions, type SourceFile } from "ts-morph";
3
+ import type { ResolvedTypeSignature } from "@kosmojs/core";
3
4
  import { type ApiRoute, type SourceFolder, type TypeDeclaration, type ValidationDefinition } from "@kosmojs/core";
4
5
  import { type HTTPMethod } from "@kosmojs/core/api";
5
6
  type PathResolver = (path: string) => string;
@@ -28,14 +29,14 @@ export declare const astFactory: () => {
28
29
  index: number;
29
30
  text: string;
30
31
  }[] | undefined;
31
- methods: ("HEAD" | "OPTIONS" | "GET" | "PUT" | "PATCH" | "POST" | "DELETE")[];
32
+ methods: ("DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT")[];
32
33
  validationDefinitions: ValidationDefinition[];
33
34
  referencedFiles: string[] | undefined;
34
35
  }>;
35
- typeResolverFactory: ({ root, name }: SourceFolder) => {
36
+ typeResolverFactory: (sourceFolder: SourceFolder) => {
36
37
  getSourceFile: (fileFullpath: string) => SourceFile;
37
38
  refreshSourceFile: (fileFullpath: string) => Promise<void>;
38
- literalTypesResolver: (literalTypes: string, options: Parameters<typeof flattener>[2]) => import("tfusion").ResolvedType[];
39
+ literalTypesResolver: (literalTypes: string, options: Parameters<typeof flattener>[2]) => Array<ResolvedTypeSignature>;
39
40
  };
40
41
  };
41
42
  export {};
package/pkg/index.d.ts CHANGED
@@ -4,5 +4,4 @@ export * from "./paths";
4
4
  export * from "./render";
5
5
  export * from "./routes";
6
6
  export * from "./spinner";
7
- export * from "./typebox";
8
7
  export * from "./vite";
package/pkg/index.js CHANGED
@@ -1,18 +1,155 @@
1
1
  import { builtinModules } from "node:module";
2
- import { basename, dirname, join, resolve } from "node:path";
3
2
  import { styleText } from "node:util";
4
3
  import crc from "crc/crc32";
5
- import { flattener } from "tfusion";
6
- import { Project, SyntaxKind } from "ts-morph";
4
+ import flattener from "tfusion";
5
+ import { ModuleResolutionKind, Project, SyntaxKind } from "ts-morph";
7
6
  import { RequestValidationTargets, defaults } from "@kosmojs/core";
8
7
  import { HTTPMethods } from "@kosmojs/core/api";
9
- import picomatch from "picomatch";
10
- import { access, constants, mkdir, readFile, writeFile } from "node:fs/promises";
8
+ import { access, constants, mkdir, readFile, stat, writeFile } from "node:fs/promises";
9
+ import { basename, dirname, isAbsolute, join, parse, resolve } from "node:path";
11
10
  import handlebars from "handlebars";
11
+ import picomatch from "picomatch";
12
12
  import { glob } from "tinyglobby";
13
- import { compile, parse } from "path-to-regexp";
13
+ import { compile, parse as parse$1 } from "path-to-regexp";
14
14
  import mimeTypes from "mime-types";
15
15
  import { Spinner } from "@topcli/spinner";
16
+ //#region src/paths.ts
17
+ var pathResolver = (sourceFolder) => {
18
+ const createPath = (...a) => {
19
+ return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
20
+ };
21
+ const createImport = {
22
+ src(a, { origin }) {
23
+ return origin === "src" ? join(defaults.srcPrefix, ...a) : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);
24
+ },
25
+ api(a, o) {
26
+ return this.src([defaults.apiDir, ...a], o);
27
+ },
28
+ pages(a, o) {
29
+ return this.src([defaults.pagesDir, ...a], o);
30
+ },
31
+ lib(a, { origin }) {
32
+ return origin === "src" ? join(defaults.libPrefix, ...a) : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);
33
+ },
34
+ libCore(a, o) {
35
+ return this.lib(["core", ...a], o);
36
+ },
37
+ libApi(a, o) {
38
+ return this.lib([defaults.apiDir, ...a], o);
39
+ },
40
+ libEntry(a, o) {
41
+ return this.lib([defaults.entryDir, ...a], o);
42
+ }
43
+ };
44
+ return {
45
+ createPath: {
46
+ src(...a) {
47
+ return createPath(defaults.srcDir, sourceFolder.name, ...a);
48
+ },
49
+ api(...a) {
50
+ return this.src(defaults.apiDir, ...a);
51
+ },
52
+ pages(...a) {
53
+ return this.src(defaults.pagesDir, ...a);
54
+ },
55
+ entry(...a) {
56
+ return this.src(defaults.entryDir, ...a);
57
+ },
58
+ lib(...a) {
59
+ return createPath(defaults.libDir, sourceFolder.name, ...a);
60
+ },
61
+ libCore(...a) {
62
+ return this.lib("core", ...a);
63
+ },
64
+ libApi(...a) {
65
+ return this.lib(defaults.apiDir, ...a);
66
+ },
67
+ libEntry(...a) {
68
+ return this.lib(defaults.entryDir, ...a);
69
+ },
70
+ libPages(...a) {
71
+ return this.lib(defaults.pagesDir, ...a);
72
+ },
73
+ distDir(...a) {
74
+ return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
75
+ }
76
+ },
77
+ createImport,
78
+ createImportHelpers(o) {
79
+ if (!["src", "lib"].includes(o?.origin)) throw new Error(`createImportHelpers: required exactly one argument of shape { origin: "src|lib" }`);
80
+ return { createImport(key, ...a) {
81
+ return createImport[key](a.slice(0, -1), o);
82
+ } };
83
+ }
84
+ };
85
+ };
86
+ var pathExists = async (path) => {
87
+ try {
88
+ await access(path, constants.F_OK);
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ };
94
+ //#endregion
95
+ //#region src/render.ts
96
+ var render = (template, context, options) => {
97
+ const { noEscape = true, renderer = handlebars } = { ...options };
98
+ return renderer.compile(template, { noEscape })(context);
99
+ };
100
+ var renderToFile = async (file, template, context, options) => {
101
+ const content = render(template, context, options);
102
+ /**
103
+ * Two fs calls (exists + read) are worth it to avoid touching the file
104
+ * and triggering watchers unnecessarily.
105
+ * */
106
+ if (await pathExists(file)) {
107
+ const { overwrite = true } = { ...options };
108
+ if (overwrite === false) return;
109
+ const fileContent = await readFile(file, "utf8");
110
+ if (typeof overwrite === "function" && !overwrite(fileContent)) return;
111
+ if (crc(content) === crc(fileContent)) return;
112
+ }
113
+ await mkdir(dirname(file), { recursive: true });
114
+ await writeFile(file, content, "utf8");
115
+ };
116
+ var renderFactory = (options) => {
117
+ const createRenderer = (selfOoptions) => {
118
+ const renderer = handlebars.create();
119
+ renderer.registerPartial({
120
+ ...options?.partials,
121
+ ...selfOoptions?.partials
122
+ });
123
+ renderer.registerHelper({
124
+ ...options?.helpers,
125
+ ...selfOoptions?.helpers
126
+ });
127
+ return renderer;
128
+ };
129
+ return {
130
+ render(template, context, selfOoptions) {
131
+ return render(template, context, {
132
+ ...options,
133
+ ...selfOoptions,
134
+ renderer: createRenderer(selfOoptions)
135
+ });
136
+ },
137
+ async renderToFile(file, template, context, selfOoptions) {
138
+ return renderToFile(options?.outdir ? join(options.outdir, file) : file, template, context, {
139
+ ...options,
140
+ ...selfOoptions,
141
+ renderer: createRenderer(selfOoptions)
142
+ });
143
+ }
144
+ };
145
+ };
146
+ //#endregion
147
+ //#region src/templates/resolved-types.hbs?raw
148
+ var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
149
+ //#endregion
150
+ //#region src/templates/types.hbs?raw
151
+ var types_default = "{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n \"{{name}}\"{{#unless isRequired}}?{{/unless}}: {{#if refinement}}\n {{refinement.text}},\n {{else}}\n {{#if isSplat}}Array<string>{{else}}string{{/if}},\n {{/if}}\n {{/each}}\n};\n\n{{#each validationTypes}}export type {{id}} = {{text}};\n{{/each}}\n";
152
+ //#endregion
16
153
  //#region src/ast.ts
17
154
  var astFactory = () => {
18
155
  const createProject = (opts) => new Project(opts);
@@ -160,7 +297,7 @@ var astFactory = () => {
160
297
  method,
161
298
  target,
162
299
  variants: variants.flatMap((e, i) => {
163
- const { status, contentType, body } = extractResponseVariant(e) || {};
300
+ const { status, contentType, body } = { ...extractResponseVariant(e) };
164
301
  if (!status) return [];
165
302
  if (contentType && typeof contentType !== "string") {
166
303
  console.warn(styleText(["bold", "red"], `✗ The second element of a response variant should specify the Response Content Type`));
@@ -300,11 +437,42 @@ var astFactory = () => {
300
437
  const extractGenerics = (callExpression) => {
301
438
  return callExpression.getTypeArguments();
302
439
  };
303
- const typeResolverFactory = ({ root, name }) => {
304
- const project = createProject({
305
- tsConfigFilePath: resolve(root, join(defaults.srcDir, name, "tsconfig.json")),
306
- skipAddingFilesFromTsConfig: true
307
- });
440
+ const typeResolverFactory = (sourceFolder) => {
441
+ const { createPath } = pathResolver(sourceFolder);
442
+ const project = createProject({ compilerOptions: {
443
+ moduleResolution: ModuleResolutionKind.Bundler,
444
+ types: [],
445
+ noLib: true,
446
+ skipLibCheck: true,
447
+ paths: {
448
+ [`${defaults.appPrefix}/*`]: [`${sourceFolder.root}/*`],
449
+ [`${defaults.srcPrefix}/*`]: [createPath.src("*")],
450
+ [`${defaults.libPrefix}/*`]: [createPath.lib("*")]
451
+ }
452
+ } });
453
+ const withTypeboxSchema = (resolvedTypes) => {
454
+ const materializedTypes = render(resolved_types_default, { resolvedTypes });
455
+ const sourceFile = project.createSourceFile(`${crc(materializedTypes)}-${Date.now()}.ts`, materializedTypes, { overwrite: true });
456
+ const types = resolvedTypes.map((type) => {
457
+ const typeNode = sourceFile.getTypeAlias(type.name)?.getTypeNode();
458
+ if (!typeNode) return type;
459
+ const properties = type.properties ? type.properties.map((prop) => {
460
+ const propNode = typeNode.isKind(SyntaxKind.TypeLiteral) ? typeNode.getProperty(prop.name)?.getTypeNode() : void 0;
461
+ if (!propNode) return prop;
462
+ return {
463
+ ...prop,
464
+ typeboxSchema: renderTypeboxSchema(propNode)
465
+ };
466
+ }) : void 0;
467
+ return {
468
+ ...type,
469
+ ...properties ? { properties } : {},
470
+ typeboxSchema: renderTypeboxSchema(typeNode)
471
+ };
472
+ });
473
+ project.removeSourceFile(sourceFile);
474
+ return types;
475
+ };
308
476
  const literalTypesResolver = (literalTypes, options) => {
309
477
  const sourceFile = project.createSourceFile(`${crc(literalTypes)}-${Date.now()}.ts`, literalTypes, { overwrite: true });
310
478
  const resolvedTypes = flattener(project, sourceFile, {
@@ -312,7 +480,7 @@ var astFactory = () => {
312
480
  stripComments: true
313
481
  });
314
482
  project.removeSourceFile(sourceFile);
315
- return resolvedTypes;
483
+ return withTypeboxSchema(resolvedTypes);
316
484
  };
317
485
  return {
318
486
  getSourceFile: (fileFullpath) => {
@@ -335,6 +503,56 @@ var astFactory = () => {
335
503
  typeResolverFactory
336
504
  };
337
505
  };
506
+ /**
507
+ * Render a ts-morph TypeNode to TypeBox Script text, replacing every VRefine
508
+ * occurrence (at any depth) with the infix `with` form.
509
+ *
510
+ * VRefine<string, { format: "email" }> -> (string with { format: "email" })
511
+ * VRefine<string, { format: "email" }>[] -> (string with { format: "email" })[]
512
+ * VRefine<Array<string>, { minItems: 1 }> -> (Array<string> with { minItems: 1 })
513
+ * VRefine<Record<string, string>, { maxProperties: 20 }>
514
+ * -> (Record<string, string> with { maxProperties: 20 })
515
+ *
516
+ * The parentheses matter: for an array element the `with` clause must bind to
517
+ * the element, not the array, so a VRefine that is the element of an array is
518
+ * wrapped. We wrap unconditionally - harmless when not nested, required when it
519
+ * is.
520
+ *
521
+ * @param typeNode the node to render
522
+ * @param refineTypeName the configured refine type name
523
+ * */
524
+ var renderTypeboxSchema = (typeNode, refineTypeName = defaults.refineTypeName) => {
525
+ const traverse = (typeNode) => {
526
+ if (typeNode.isKind(SyntaxKind.TypeReference) && typeNode.getTypeName().getText() === refineTypeName) {
527
+ const [inner, opts] = typeNode.getTypeArguments();
528
+ if (!inner || !opts) return typeNode.getText();
529
+ return `(${traverse(inner)} with ${opts.getText()})`;
530
+ }
531
+ if (typeNode.isKind(SyntaxKind.ArrayType)) return `${traverse(typeNode.getElementTypeNode())}[]`;
532
+ if (typeNode.isKind(SyntaxKind.TypeLiteral)) {
533
+ const members = [];
534
+ for (const member of typeNode.getMembers()) if (member.isKind(SyntaxKind.PropertySignature)) {
535
+ const name = member.getName();
536
+ const optional = member.hasQuestionToken() ? "?" : "";
537
+ const t = member.getTypeNode();
538
+ const rendered = t ? traverse(t) : "unknown";
539
+ members.push(`${name}${optional}: ${rendered}`);
540
+ } else members.push(member.getText());
541
+ return `{ ${members.join(", ")} }`;
542
+ }
543
+ if (typeNode.isKind(SyntaxKind.TupleType)) return `[${typeNode.getElements().map((el) => traverse(el)).join(", ")}]`;
544
+ if (typeNode.isKind(SyntaxKind.ParenthesizedType)) return `(${traverse(typeNode.getTypeNode())})`;
545
+ if (typeNode.isKind(SyntaxKind.UnionType)) return typeNode.getTypeNodes().map((t) => traverse(t)).join(" | ");
546
+ if (typeNode.isKind(SyntaxKind.IntersectionType)) return typeNode.getTypeNodes().map((t) => traverse(t)).join(" & ");
547
+ if (typeNode.isKind(SyntaxKind.TypeReference)) {
548
+ const args = typeNode.getTypeArguments();
549
+ if (args.length === 0) return typeNode.getText();
550
+ return `${typeNode.getTypeName().getText()}<${args.map((a) => traverse(a)).join(", ")}>`;
551
+ }
552
+ return typeNode.getText();
553
+ };
554
+ return [[/(?<!\\)`/g, "\\`"], [/(?<!\\)\$\{/g, "\\${"]].reduce((text, [a, b]) => text.replace(a, b), traverse(typeNode));
555
+ };
338
556
  //#endregion
339
557
  //#region src/generators.ts
340
558
  var defineGenerator = (f) => f;
@@ -348,137 +566,6 @@ var createTemplateResolver = (customTemplates, defaultTemplate) => {
348
566
  };
349
567
  };
350
568
  //#endregion
351
- //#region src/paths.ts
352
- var pathResolver = (sourceFolder) => {
353
- const createPath = (...a) => {
354
- return sourceFolder.root ? resolve(sourceFolder.root, join(...a)) : join(...a);
355
- };
356
- const createImport = {
357
- src(a, { origin }) {
358
- return origin === "src" ? join(defaults.srcPrefix, ...a) : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);
359
- },
360
- api(a, o) {
361
- return this.src([defaults.apiDir, ...a], o);
362
- },
363
- pages(a, o) {
364
- return this.src([defaults.pagesDir, ...a], o);
365
- },
366
- lib(a, { origin }) {
367
- return origin === "src" ? join(defaults.libPrefix, ...a) : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);
368
- },
369
- libCore(a, o) {
370
- return this.lib(["core", ...a], o);
371
- },
372
- libApi(a, o) {
373
- return this.lib([defaults.apiDir, ...a], o);
374
- },
375
- libEntry(a, o) {
376
- return this.lib([defaults.entryDir, ...a], o);
377
- }
378
- };
379
- return {
380
- createPath: {
381
- src(...a) {
382
- return createPath(defaults.srcDir, sourceFolder.name, ...a);
383
- },
384
- api(...a) {
385
- return this.src(defaults.apiDir, ...a);
386
- },
387
- pages(...a) {
388
- return this.src(defaults.pagesDir, ...a);
389
- },
390
- entry(...a) {
391
- return this.src(defaults.entryDir, ...a);
392
- },
393
- lib(...a) {
394
- return createPath(defaults.libDir, sourceFolder.name, ...a);
395
- },
396
- libCore(...a) {
397
- return this.lib("core", ...a);
398
- },
399
- libApi(...a) {
400
- return this.lib(defaults.apiDir, ...a);
401
- },
402
- libEntry(...a) {
403
- return this.lib(defaults.entryDir, ...a);
404
- },
405
- libPages(...a) {
406
- return this.lib(defaults.pagesDir, ...a);
407
- },
408
- distDir(...a) {
409
- return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
410
- }
411
- },
412
- createImport,
413
- createImportHelpers(o) {
414
- if (!["src", "lib"].includes(o?.origin)) throw new Error(`createImportHelpers: required exactly one argument of shape { origin: "src|lib" }`);
415
- return { createImport(key, ...a) {
416
- return createImport[key](a.slice(0, -1), o);
417
- } };
418
- }
419
- };
420
- };
421
- var pathExists = async (path) => {
422
- try {
423
- await access(path, constants.F_OK);
424
- return true;
425
- } catch {
426
- return false;
427
- }
428
- };
429
- //#endregion
430
- //#region src/render.ts
431
- var render = (template, context, options) => {
432
- const { noEscape = true, renderer = handlebars } = { ...options };
433
- return renderer.compile(template, { noEscape })(context);
434
- };
435
- var renderToFile = async (file, template, context, options) => {
436
- const content = render(template, context, options);
437
- /**
438
- * Two fs calls (exists + read) are worth it to avoid touching the file
439
- * and triggering watchers unnecessarily.
440
- * */
441
- if (await pathExists(file)) {
442
- const { overwrite = true } = { ...options };
443
- if (overwrite === false) return;
444
- const fileContent = await readFile(file, "utf8");
445
- if (typeof overwrite === "function" && !overwrite(fileContent)) return;
446
- if (crc(content) === crc(fileContent)) return;
447
- }
448
- await mkdir(dirname(file), { recursive: true });
449
- await writeFile(file, content, "utf8");
450
- };
451
- var renderFactory = (options) => {
452
- const createRenderer = (selfOoptions) => {
453
- const renderer = handlebars.create();
454
- renderer.registerPartial({
455
- ...options?.partials,
456
- ...selfOoptions?.partials
457
- });
458
- renderer.registerHelper({
459
- ...options?.helpers,
460
- ...selfOoptions?.helpers
461
- });
462
- return renderer;
463
- };
464
- return {
465
- render(template, context, selfOoptions) {
466
- return render(template, context, {
467
- ...options,
468
- ...selfOoptions,
469
- renderer: createRenderer(selfOoptions)
470
- });
471
- },
472
- async renderToFile(file, template, context, selfOoptions) {
473
- return renderToFile(options?.outdir ? join(options.outdir, file) : file, template, context, {
474
- ...options,
475
- ...selfOoptions,
476
- renderer: createRenderer(selfOoptions)
477
- });
478
- }
479
- };
480
- };
481
- //#endregion
482
569
  //#region src/routes/paths.ts
483
570
  /**
484
571
  * Parse a filesystem route path into structured PathToken array.
@@ -558,7 +645,7 @@ var pathTokensFactory = (path) => {
558
645
  if (bareParam === ":") throw new Error(`${path} contains colons outside braces, use : only within {}`);
559
646
  else if (bareParam) throw new Error(`${path} contains bare params, use [${bareParam}] instead of :${bareParam}`);
560
647
  const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
561
- const { tokens } = parse(pattern.replace(/\{[^}]*\}|(\+)/g, (m, p1) => p1 ? "\\+" : m));
648
+ const { tokens } = parse$1(pattern.replace(/\{[^}]*\}|(\+)/g, (m, p1) => p1 ? "\\+" : m));
562
649
  const parts = extractParts(tokens, (val) => {
563
650
  return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc(orig)].join("_") : val;
564
651
  });
@@ -604,7 +691,7 @@ var createHonoPattern = (tokens) => {
604
691
  return tokens.flatMap((token, i) => {
605
692
  if (token.kind === "static") return [token.parts[0].value];
606
693
  if (token.kind === "param") return [paramValue(token.parts[0])];
607
- const { tokens } = parse(token.pattern.replace(/\//g, ""));
694
+ const { tokens } = parse$1(token.pattern.replace(/\//g, ""));
608
695
  return [`:_${i}{${tokensToRegex(tokens)}}`];
609
696
  }).join("/");
610
697
  };
@@ -741,12 +828,6 @@ var sortRoutes = (a, b) => {
741
828
  return a.pathPattern.localeCompare(b.pathPattern);
742
829
  };
743
830
  //#endregion
744
- //#region src/templates/resolved-types.hbs?raw
745
- var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
746
- //#endregion
747
- //#region src/templates/types.hbs?raw
748
- var types_default = "{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n \"{{name}}\"{{#unless isRequired}}?{{/unless}}: {{#if refinement}}\n {{refinement.text}},\n {{else}}\n {{#if isSplat}}Array<string>{{else}}string{{/if}},\n {{/if}}\n {{/each}}\n};\n\n{{#each validationTypes}}export type {{id}} = {{text}};\n{{/each}}\n";
749
- //#endregion
750
831
  //#region src/routes/resolve.ts
751
832
  var resolverFactory = (sourceFolder, cacheFactory) => {
752
833
  const { generators = [], refineTypeName = defaults.refineTypeName } = sourceFolder.config;
@@ -831,7 +912,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
831
912
  withReferencedFiles: true,
832
913
  sourceFile: getSourceFile(fileFullpath),
833
914
  relpathResolver(path) {
834
- return join(sourceFolder.name, defaults.apiDir, dirname(file), path);
915
+ return join(defaults.srcPrefix, defaults.apiDir, dirname(file), path);
835
916
  }
836
917
  });
837
918
  const validationTypes = validationDefinitions.flatMap((def) => {
@@ -1091,17 +1172,101 @@ var spinnerFactory = (startText) => {
1091
1172
  };
1092
1173
  var withSpinner = (text, pipe, spinner) => pipe(spinner || spinnerFactory(text));
1093
1174
  //#endregion
1094
- //#region src/typebox.ts
1095
- var typeboxLiteralText = (text, sourceFolder) => {
1096
- const { refineTypeName = defaults.refineTypeName } = sourceFolder.config;
1097
- return [
1098
- [/(?<!\\)`/g, "\\`"],
1099
- [/(?<!\\)\$\{/g, "\\${"],
1100
- [new RegExp(`\\b${refineTypeName}\\s*<`, "g"), "Options<"]
1101
- ].reduce((text, [a, b]) => text.replace(a, b), text);
1102
- };
1103
- //#endregion
1104
1175
  //#region src/vite.ts
1176
+ /**
1177
+ * Resolves Kosmo's generated import prefixes to absolute file paths.
1178
+ *
1179
+ * WHY THIS EXISTS
1180
+ * ---------------
1181
+ * Every source folder is scaffolded with three tsconfig `paths` prefixes
1182
+ * that let generated and user code import across
1183
+ * the folder's layout without long relative chains:
1184
+ *
1185
+ * appPrefix "@" -> the project root (<root>/*)
1186
+ * srcPrefix "~" -> the folder's src dir (<root>/src/<name>/*)
1187
+ * libPrefix "_" -> the folder's lib dir (<root>/lib/<name>/*)
1188
+ *
1189
+ * These are the backbone of the generated code: `defineRoute` and friends are
1190
+ * emitted with `_/...` imports, pages import layouts and components via `~/...`,
1191
+ * and `@/...` reaches shared app-level modules. If a bundler cannot resolve
1192
+ * them, nothing the framework generates can be loaded.
1193
+ *
1194
+ * Historically Vite resolved these through its built-in `resolve.tsconfigPaths: true`,
1195
+ * reading the `paths` straight from the generated tsconfig. That option
1196
+ * regressed in Vite 8.1.0 (still broken as of 8.1.3): it stops resolving
1197
+ * `paths` mappings, especially those defined in an extended / referenced base
1198
+ * config - which is exactly Kosmo's structure, where a source folder's
1199
+ * tsconfig `extends` `lib/<name>/tsconfig.base.json` and the paths use the
1200
+ * TypeScript `${configDir}` variable. The failure surfaces as:
1201
+ *
1202
+ * [vite] Failed to resolve import "_/pageSamples/welcome.vue" from
1203
+ * "src/<name>/pages/index/index.vue". Does the file exist?
1204
+ *
1205
+ * (Upstream: vitejs/vite #22139, #22047, #22371, #21889, #21856.)
1206
+ *
1207
+ * Rather than pin Vite to 8.0.x indefinitely, or depend on the general-purpose
1208
+ * `vite-tsconfig-paths` plugin, this internal plugin resolves ONLY
1209
+ * known prefixes against dirs derived from the source folder. That makes it:
1210
+ *
1211
+ * - Correct on 8.1.x, where native `tsconfigPaths` is broken.
1212
+ * - Faster: no tsconfig discovery, no `extends` chain walking, no glob
1213
+ * matching - just a prefix check and a handful of `stat` probes,
1214
+ * cached by Vite per specifier.
1215
+ * - Non-blocking: probes via async `fs/promises` `stat`, so `resolveId` never
1216
+ * stalls the event loop.
1217
+ * - `.vue` / `.mdx`-aware: `resolveId` sees every specifier regardless of the
1218
+ * importer's type, so imports from non-JS files resolve without the
1219
+ * `loose` / `allowJs` escape hatches `vite-tsconfig-paths` needs.
1220
+ *
1221
+ * A project with custom `paths` beyond these three prefixes should install
1222
+ * `vite-tsconfig-paths`; this plugin is internal and intentionally narrow.
1223
+ *
1224
+ * The prefix -> dir bases come from `pathResolver`, the same source of truth the
1225
+ * tsconfig generator uses, so alias resolution here can never drift from the
1226
+ * paths that were written into the generated tsconfig.
1227
+ * */
1228
+ var tsconfigPaths = (sourceFolder) => {
1229
+ /**
1230
+ * Candidate extensions for an extensionless specifier, in resolution priority order.
1231
+ * Mirrors the renderable file types the generators emit;
1232
+ * a new page type (e.g. `.svelte`) must be added here or its aliased imports won't resolve.
1233
+ * */
1234
+ const EXTENSIONS = [
1235
+ ".ts",
1236
+ ".tsx",
1237
+ ".js",
1238
+ ".jsx",
1239
+ ".mjs",
1240
+ ".vue",
1241
+ ".md",
1242
+ ".mdx",
1243
+ ".json"
1244
+ ];
1245
+ const { createPath } = pathResolver(sourceFolder);
1246
+ const table = [
1247
+ [`${defaults.srcPrefix}/`, createPath.src()],
1248
+ [`${defaults.libPrefix}/`, createPath.lib()],
1249
+ [`${defaults.appPrefix}/`, sourceFolder.root]
1250
+ ];
1251
+ const resolveWithin = async (baseDir, rest) => {
1252
+ const target = join(baseDir, rest);
1253
+ const { ext } = parse(rest);
1254
+ if (EXTENSIONS.includes(ext)) {
1255
+ for (const candidate of [target, `${target}/index${ext}`]) if (await isFile(candidate)) return candidate;
1256
+ return target;
1257
+ }
1258
+ for (const e of EXTENSIONS) for (const candidate of [`${target}${e}`, `${target}/index${e}`]) if (await isFile(candidate)) return candidate;
1259
+ return target;
1260
+ };
1261
+ return {
1262
+ name: "kosmo:tsconfigPaths",
1263
+ enforce: "pre",
1264
+ async resolveId(source) {
1265
+ if (isAbsolute(source) || source.startsWith(".")) return;
1266
+ for (const [prefix, baseDir] of table) if (source.startsWith(prefix)) return resolveWithin(baseDir, source.replace(prefix, ""));
1267
+ }
1268
+ };
1269
+ };
1105
1270
  var nodePrefix = () => {
1106
1271
  return {
1107
1272
  name: "kosmojs:node-prefix",
@@ -1114,8 +1279,14 @@ var nodePrefix = () => {
1114
1279
  }
1115
1280
  };
1116
1281
  };
1117
- var vitePlugins = { nodePrefix };
1282
+ var vitePlugins = {
1283
+ tsconfigPaths,
1284
+ nodePrefix
1285
+ };
1286
+ var isFile = async (path) => {
1287
+ return stat(path).then((e) => e.isFile()).catch(() => false);
1288
+ };
1118
1289
  //#endregion
1119
- export { API_INDEX_BASENAME, API_INDEX_PATTERN, API_USE_BASENAME, API_USE_PATTERN, PAGE_INDEX_BASENAME, PAGE_INDEX_PATTERN, PAGE_LAYOUT_BASENAME, PAGE_LAYOUT_PATTERN, astFactory, createHonoPattern, createPathPattern, createRouteEntry, createTemplateResolver, defineGenerator, defineGeneratorFactory, isApiRoute, isApiUse, isPageLayout, isPageRoute, isRouteFile, nestedRoutesFactory, pathExists, pathResolver, pathTokensFactory, render, renderFactory, renderToFile, routesFactory, scanRoutes, sortRoutes, spinnerFactory, typeboxLiteralText, vitePlugins, withSpinner };
1290
+ export { API_INDEX_BASENAME, API_INDEX_PATTERN, API_USE_BASENAME, API_USE_PATTERN, PAGE_INDEX_BASENAME, PAGE_INDEX_PATTERN, PAGE_LAYOUT_BASENAME, PAGE_LAYOUT_PATTERN, astFactory, createHonoPattern, createPathPattern, createRouteEntry, createTemplateResolver, defineGenerator, defineGeneratorFactory, isApiRoute, isApiUse, isPageLayout, isPageRoute, isRouteFile, nestedRoutesFactory, pathExists, pathResolver, pathTokensFactory, render, renderFactory, renderToFile, routesFactory, scanRoutes, sortRoutes, spinnerFactory, tsconfigPaths, vitePlugins, withSpinner };
1120
1291
 
1121
1292
  //# sourceMappingURL=index.js.map
package/pkg/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/ast.ts","../src/generators.ts","../src/paths.ts","../src/render.ts","../src/routes/paths.ts","../src/routes/base.ts","../src/routes/resolve.ts","../src/routes/nesting.ts","../src/routes/index.ts","../src/spinner.ts","../src/typebox.ts","../src/vite.ts"],"sourcesContent":["import { join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport { flattener } from \"tfusion\";\nimport {\n type CallExpression,\n type Identifier,\n Project,\n type ProjectOptions,\n type SourceFile,\n SyntaxKind,\n type TypeNode,\n} from \"ts-morph\";\n\nimport {\n type ApiRoute,\n defaults,\n RequestValidationTargets,\n type SourceFolder,\n type TypeDeclaration,\n type ValidationDefinition,\n type ValidationTarget,\n} from \"@kosmojs/core\";\nimport { type HTTPMethod, HTTPMethods } from \"@kosmojs/core/api\";\n\ntype PathResolver = (path: string) => string;\n\nexport const astFactory = () => {\n const createProject = (opts?: ProjectOptions) => new Project(opts);\n\n const resolveRouteSignature = async (\n route: Pick<ApiRoute, \"id\" | \"name\" | \"fileFullpath\" | \"optionalParams\">,\n opts?: {\n relpathResolver?: PathResolver;\n sourceFile?: SourceFile;\n withReferencedFiles?: boolean;\n },\n ) => {\n const {\n sourceFile = createProject().addSourceFileAtPath(route.fileFullpath),\n } = { ...opts };\n\n const [typeDeclarations, referencedFiles] = extractTypeDeclarations(\n sourceFile,\n opts,\n );\n\n const defaultExport = extractDefaultExport(sourceFile);\n\n const paramsRefinements = defaultExport\n ? extractParamsRefinements(defaultExport)\n : undefined;\n\n const methods = defaultExport\n ? extractRouteMethods(route, defaultExport)\n : [];\n\n return {\n typeDeclarations,\n paramsRefinements,\n methods: methods.map((e) => e.method),\n validationDefinitions: methods.flatMap((e) => e.validationDefinitions),\n referencedFiles,\n };\n };\n\n const extractDefaultExport = (\n sourceFile: SourceFile,\n ): CallExpression | undefined => {\n const [defaultExport] = sourceFile\n .getExportAssignments()\n .flatMap((exportAssignment) => {\n if (exportAssignment.isExportEquals()) {\n return [];\n }\n const callExpression = exportAssignment.getExpression();\n return callExpression.isKind(SyntaxKind.CallExpression)\n ? [callExpression]\n : [];\n });\n return defaultExport;\n };\n\n const extractParamsRefinements = (\n callExpression: CallExpression,\n ): Array<{ index: number; text: string }> | undefined => {\n const [\n _routeName, // first generic - the route name\n paramsGeneric, // second generic - params refinements\n ] = extractGenerics(callExpression);\n\n if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n return paramsGeneric.getElements().map((node, index) => {\n return {\n index,\n text: node.getText(),\n };\n });\n };\n\n const extractRouteMethods = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n callExpression: CallExpression,\n ): Array<{\n method: HTTPMethod;\n validationDefinitions: Array<ValidationDefinition>;\n }> => {\n const funcDeclaration =\n callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) ||\n callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);\n\n if (!funcDeclaration) {\n return [];\n }\n\n const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n if (!arrayLiteralExpression) {\n return [];\n }\n\n const callExpressions: Array<[CallExpression, HTTPMethod]> = [];\n\n for (const e of arrayLiteralExpression.getChildrenOfKind(\n SyntaxKind.CallExpression,\n )) {\n const name = e.getExpression().getText() as HTTPMethod;\n if (HTTPMethods[name]) {\n callExpressions.push([e, name]);\n }\n }\n\n const methods: ReturnType<typeof extractRouteMethods> = [];\n\n for (const [callExpression, method] of callExpressions) {\n const [vDefs, vOpts] = extractGenerics(callExpression);\n methods.push({\n method,\n validationDefinitions: extractValidationDefinitions(\n route,\n method,\n vDefs,\n vOpts,\n ),\n });\n }\n\n return methods;\n };\n\n /** Parse a boolean literal type node */\n const parseRuntimeValidation = (typeNode: TypeNode) => {\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getFirstChild();\n if (literal?.isKind(SyntaxKind.TrueKeyword)) {\n return true;\n } else if (literal?.isKind(SyntaxKind.FalseKeyword)) {\n return false;\n }\n }\n return undefined;\n };\n\n const extractResponseVariant = (\n typeNode: TypeNode,\n ):\n | {\n status: number;\n contentType?: string | undefined;\n body?: string | undefined;\n }\n | undefined => {\n if (!typeNode.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n let status = 200; // default\n let contentType: string | undefined;\n let body: string | undefined;\n\n const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();\n\n // Status (index 0) - should be a LiteralType with NumericLiteral\n if (statusNode?.isKind(SyntaxKind.LiteralType)) {\n const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);\n if (literal) {\n status = Number(literal.getText());\n }\n }\n\n // ContentType (index 1) - should be a LiteralType with StringLiteral\n if (contentTypeNode) {\n contentType = extractStringLiteral(contentTypeNode);\n }\n\n // Response type text (index 2)\n if (bodyNode) {\n body = bodyNode.getText();\n if ([\"object\"].includes(body)) {\n body = \"{}\";\n }\n }\n\n return { status, contentType, body };\n };\n\n /** Parse opts TypeLiteral into a map keyed by target */\n const parseValidationOptions = (typeNode: TypeNode | undefined) => {\n const opts: Partial<\n Record<\n ValidationTarget,\n {\n contentType: string | undefined;\n runtimeValidation: boolean | undefined;\n customErrors: Record<string, string> | undefined;\n }\n >\n > = {};\n\n if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {\n return opts;\n }\n\n for (const prop of typeNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (!typeNode.isKind(SyntaxKind.TypeLiteral)) {\n continue;\n }\n\n let contentType: string | undefined;\n let runtimeValidation: boolean | undefined;\n const customErrors: Record<string, string> = {};\n\n for (const member of typeNode.getMembers()) {\n if (!member.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const nameNode = member.getNameNode();\n const valueNode = member.getTypeNodeOrThrow();\n\n const name = nameNode.isKind(SyntaxKind.StringLiteral)\n ? nameNode.getLiteralText() // No quotes\n : nameNode.getText(); // Regular identifier\n\n if (name === \"contentType\") {\n contentType = extractStringLiteral(valueNode);\n } else if (name === \"runtimeValidation\") {\n runtimeValidation = parseRuntimeValidation(valueNode);\n } else if (name.startsWith(\"error\")) {\n const literal = extractStringLiteral(valueNode);\n if (literal) {\n customErrors[name] = literal;\n }\n }\n }\n\n opts[target] = {\n contentType,\n runtimeValidation,\n customErrors,\n };\n }\n\n return opts;\n };\n\n const extractStringLiteral = (typeNode: TypeNode) => {\n const literal = typeNode.isKind(SyntaxKind.LiteralType)\n ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral)\n : undefined;\n return literal ? literal.getLiteralText() : undefined;\n };\n\n /**\n * Extract validation definitions from route handler generics.\n * Merges defs (schemas) and opts (validation options) into a flat array.\n * */\n const extractValidationDefinitions = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n method: HTTPMethod,\n defsNode: TypeNode,\n optsNode: TypeNode | undefined,\n ) => {\n const definitions: Array<ValidationDefinition> = [];\n\n if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {\n return definitions;\n }\n\n const optsMap = parseValidationOptions(optsNode);\n\n const createId = (target: string, hash?: string) => {\n return [\n target.replace(/^./, (c) => c.toUpperCase()),\n \"T\",\n method,\n crc(route.id + hash),\n ].join(\"\");\n };\n\n for (const prop of defsNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (target === \"response\") {\n const variants = typeNode.isKind(SyntaxKind.UnionType)\n ? typeNode.getChildrenOfKind(SyntaxKind.TupleType)\n : [typeNode];\n definitions.push({\n ...optsMap[target],\n method,\n target,\n variants: variants.flatMap((e, i) => {\n const { status, contentType, body } =\n extractResponseVariant(e) || {};\n\n if (!status) {\n return [];\n }\n\n if (contentType && typeof contentType !== \"string\") {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n `✗ The second element of a response variant should specify the Response Content Type`,\n ),\n );\n console.warn(\n styleText([\"blue\"], ` Example: [200, \"json\", Schema]`),\n );\n console.warn(\n ` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`,\n );\n console.warn();\n }\n\n return [\n {\n id: createId(\n target,\n JSON.stringify([status, contentType, body]),\n ),\n status,\n contentType,\n body,\n },\n ];\n }),\n });\n } else if (Object.keys(RequestValidationTargets).includes(target)) {\n definitions.push({\n ...optsMap[target],\n method,\n target,\n schema: {\n id: createId(target),\n text: typeNode.getText(),\n },\n });\n }\n }\n\n return definitions;\n };\n\n const extractTypeDeclarations = (\n sourceFile: SourceFile,\n opts?: {\n relpathResolver?: PathResolver;\n withReferencedFiles?: boolean;\n },\n ): [d: Array<TypeDeclaration>, f?: Array<string>] => {\n const declarations: Array<TypeDeclaration> = [];\n\n const referencedFiles: Array<string> | undefined = opts?.withReferencedFiles\n ? []\n : undefined;\n\n for (const declaration of sourceFile.getImportDeclarations()) {\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath;\n\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const defaultImport = typeOnlyDeclaration\n ? declaration.getDefaultImport()\n : undefined;\n\n if (defaultImport) {\n const name = defaultImport.getText();\n const text = `import type ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(defaultImport));\n }\n }\n\n const namespaceImport = typeOnlyDeclaration\n ? declaration.getNamespaceImport()\n : undefined;\n\n if (namespaceImport) {\n const name = namespaceImport.getText();\n const text = `import type * as ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(namespaceImport));\n }\n }\n\n for (const namedImport of declaration.getNamedImports()) {\n if (namedImport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedImport.getNameNode();\n const name = nameNode.getText();\n const alias = namedImport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n importDeclaration: {\n name,\n alias,\n path,\n },\n text: `import type { ${nameText} } from \"${path}\";`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n for (const declaration of sourceFile.getTypeAliases()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n typeAliasDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getInterfaces()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n interfaceDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getEnums()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n enumDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getExportDeclarations()) {\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = modulePath\n ? /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath\n : undefined;\n\n for (const namedExport of declaration.getNamedExports()) {\n if (namedExport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedExport.getNameNode();\n const name = nameNode.getText();\n const alias = namedExport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n exportDeclaration: {\n name,\n alias: alias ?? name,\n path,\n },\n text: path\n ? `export type { ${nameText} } from \"${path}\";`\n : `export type { ${nameText} };`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n return referencedFiles\n ? [declarations, [...new Set<string>(referencedFiles)]]\n : [declarations];\n };\n\n const getReferencedFiles = (importIdentifier: Identifier): Array<string> => {\n // ambient modules may have declarations in multiple files\n const declarations =\n importIdentifier //\n ?.getSymbol()\n ?.getAliasedSymbol()\n ?.getDeclarations() || [];\n\n return declarations.flatMap((e) => {\n const sourceFile = e.getSourceFile();\n return sourceFile //\n ? [sourceFile.getFilePath()]\n : [];\n });\n };\n\n const extractGenerics = (callExpression: CallExpression) => {\n return callExpression.getTypeArguments();\n };\n\n const typeResolverFactory = ({ root, name }: SourceFolder) => {\n const project = createProject({\n tsConfigFilePath: resolve(\n root,\n join(defaults.srcDir, name, \"tsconfig.json\"),\n ),\n skipAddingFilesFromTsConfig: true,\n });\n\n const literalTypesResolver = (\n literalTypes: string,\n options: Parameters<typeof flattener>[2],\n ) => {\n const sourceFile = project.createSourceFile(\n `${crc(literalTypes)}-${Date.now()}.ts`,\n literalTypes,\n { overwrite: true },\n );\n\n const resolvedTypes = flattener(project, sourceFile, {\n ...options,\n stripComments: true,\n });\n\n project.removeSourceFile(sourceFile);\n\n return resolvedTypes;\n };\n\n return {\n getSourceFile: (fileFullpath: string) => {\n return (\n project.getSourceFile(fileFullpath) ||\n project.addSourceFileAtPath(fileFullpath)\n );\n },\n refreshSourceFile: async (fileFullpath: string) => {\n const sourceFile = project.getSourceFile(fileFullpath);\n if (sourceFile) {\n await sourceFile.refreshFromFileSystem();\n }\n },\n literalTypesResolver,\n };\n };\n\n return {\n createProject,\n extractDefaultExport,\n extractParamsRefinements,\n extractRouteMethods,\n extractTypeDeclarations,\n resolveRouteSignature,\n typeResolverFactory,\n };\n};\n","import type { Matcher } from \"picomatch\";\nimport picomatch from \"picomatch\";\n\nimport type {\n DefineGenerator,\n DefineGeneratorFactory,\n GeneratorCustomTemplates,\n} from \"@kosmojs/core\";\n\nexport const defineGenerator: DefineGenerator = (f) => f as never;\n\nexport const defineGeneratorFactory: DefineGeneratorFactory = (f) => f;\n\nexport const createTemplateResolver = <T>(\n customTemplates: GeneratorCustomTemplates<T> | undefined,\n defaultTemplate: string,\n) => {\n const templates: Array<[Matcher, string | Function]> = Object.entries({\n ...customTemplates,\n }).map(([pattern, template]) => [picomatch(pattern), template]);\n return (pattern: string, entry: T) => {\n const match = templates.find(([isMatch]) => isMatch(pattern));\n if (!match) {\n return defaultTemplate;\n }\n return typeof match[1] === \"function\" //\n ? match[1](entry)\n : match[1];\n };\n};\n","import { access, constants } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { defaults, type SourceFolder } from \"@kosmojs/core\";\n\ntype Options = { origin: \"src\" | \"lib\" };\n\ntype CreateImport = Record<\n \"src\" | \"api\" | \"pages\" | \"lib\" | \"libCore\" | \"libApi\" | \"libEntry\",\n (a: Array<string>, o: Options) => string\n>;\n\nexport const pathResolver = (\n sourceFolder: Omit<SourceFolder, \"root\"> & { root?: string | undefined },\n): {\n createPath: Record<\n | \"src\"\n | \"api\"\n | \"pages\"\n | \"entry\"\n | \"lib\"\n | \"libCore\"\n | \"libApi\"\n | \"libEntry\"\n | \"libPages\"\n | \"distDir\",\n (...a: Array<string>) => string\n >;\n createImport: CreateImport;\n createImportHelpers: (o: Options) => {\n createImport: (k: keyof CreateImport, ...a: Array<string>) => string;\n };\n} => {\n const createPath = (...a: Array<string>) => {\n return sourceFolder.root\n ? resolve(sourceFolder.root, join(...a))\n : join(...a);\n };\n\n const createImport: CreateImport = {\n src(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.srcPrefix, ...a)\n : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);\n },\n api(a, o) {\n return this.src([defaults.apiDir, ...a], o);\n },\n pages(a, o) {\n return this.src([defaults.pagesDir, ...a], o);\n },\n lib(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.libPrefix, ...a)\n : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(a, o) {\n return this.lib([\"core\", ...a], o);\n },\n libApi(a, o) {\n return this.lib([defaults.apiDir, ...a], o);\n },\n libEntry(a, o) {\n return this.lib([defaults.entryDir, ...a], o);\n },\n };\n\n return {\n createPath: {\n src(...a) {\n return createPath(defaults.srcDir, sourceFolder.name, ...a);\n },\n api(...a) {\n return this.src(defaults.apiDir, ...a);\n },\n pages(...a) {\n return this.src(defaults.pagesDir, ...a);\n },\n entry(...a) {\n return this.src(defaults.entryDir, ...a);\n },\n lib(...a) {\n return createPath(defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(...a) {\n return this.lib(\"core\", ...a);\n },\n libApi(...a) {\n return this.lib(defaults.apiDir, ...a);\n },\n libEntry(...a) {\n return this.lib(defaults.entryDir, ...a);\n },\n libPages(...a) {\n return this.lib(defaults.pagesDir, ...a);\n },\n distDir(...a) {\n return createPath(sourceFolder.distDir, sourceFolder.name, ...a);\n },\n },\n createImport,\n createImportHelpers(o) {\n if (![\"src\", \"lib\"].includes(o?.origin)) {\n throw new Error(\n `createImportHelpers: required exactly one argument of shape { origin: \"src|lib\" }`,\n );\n }\n return {\n createImport(key, ...a) {\n // Handlebars appends an options object as the last argument,\n // slice it off before passing args to createImport\n return createImport[key](a.slice(0, -1), o);\n },\n };\n },\n };\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n};\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport crc from \"crc/crc32\";\nimport handlebars from \"handlebars\";\n\nimport { pathExists } from \"./paths\";\n\nexport type RenderOptions = {\n noEscape?: boolean;\n // handlebars instance\n renderer?: typeof handlebars;\n};\n\nexport type FactoryOptions = RenderOptions & {\n partials?: Record<string, string>;\n helpers?: Record<string, (...a: Array<never>) => unknown>;\n outdir?: string;\n /**\n * Controls whether to overwrite an existing file.\n * - `false`: skip writing if the file already exists\n * - `true` (default): always overwrite\n * - function: custom logic to decide whether to overwrite, based on current file content\n * */\n overwrite?: boolean | ((fileContent: string) => boolean);\n};\n\nexport const render = <Context = object>(\n template: string,\n context: Context,\n options?: RenderOptions,\n): string => {\n const { noEscape = true, renderer = handlebars } = { ...options };\n return renderer.compile(template, { noEscape })(context);\n};\n\nexport const renderToFile = async <Context = object>(\n file: string,\n template: string,\n context: Context,\n options?: RenderOptions & Pick<FactoryOptions, \"overwrite\">,\n): Promise<void> => {\n const content = render(template, context, options);\n\n /**\n * Two fs calls (exists + read) are worth it to avoid touching the file\n * and triggering watchers unnecessarily.\n * */\n if (await pathExists(file)) {\n const { overwrite = true } = { ...options };\n if (overwrite === false) {\n return;\n }\n const fileContent = await readFile(file, \"utf8\");\n if (typeof overwrite === \"function\" && !overwrite(fileContent)) {\n return;\n }\n if (crc(content) === crc(fileContent)) {\n return;\n }\n }\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, content, \"utf8\");\n};\n\nexport const renderFactory = (options?: FactoryOptions) => {\n const createRenderer = (selfOoptions?: FactoryOptions) => {\n const renderer = handlebars.create();\n\n renderer.registerPartial({\n ...options?.partials,\n ...selfOoptions?.partials,\n } as never);\n\n renderer.registerHelper({\n ...options?.helpers,\n ...selfOoptions?.helpers,\n } as never);\n\n return renderer;\n };\n\n return {\n render<Context = object>(\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return render(template, context, {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n });\n },\n async renderToFile<Context = object>(\n file: string,\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return renderToFile(\n options?.outdir ? join(options.outdir, file) : file,\n template,\n context,\n {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n },\n );\n },\n };\n};\n","import crc from \"crc/crc32\";\nimport { compile, parse, type Token } from \"path-to-regexp\";\n\nimport type {\n PathToken,\n PathTokenParamPart,\n PathTokenStaticPart,\n} from \"@kosmojs/core\";\n\n/**\n * Parse a filesystem route path into structured PathToken array.\n *\n * Uses path-to-regexp v8 AST for parsing, with directory-friendly syntax:\n * - [param] => required param - :param\n * - {param} => optional param - {:param}\n * - {...param} => splat - {*param}\n *\n * Direct :param syntax is prohibited outside {} to avoid ambiguity.\n * Inside {} it is treated as path-to-regexp power syntax and used as-is.\n *\n * Throw error if path can not be compiled into path-to-regexp pattern.\n *\n * Examples:\n * Required: [id], [name]\n * Optional: {name}, {format}\n * Splat: {...path}\n * Mixed segments: shop/[id]-{name}\n * Power syntax: {-v:version{-:pre}}, :name{@:version{.:min}}.js\n * */\nexport const pathTokensFactory = (path: string): Array<PathToken> => {\n /**\n * Recursively extract parts from path-to-regexp AST tokens.\n * A param inside a group is optional; top-level params are required.\n * Wildcard tokens are always splat.\n * Slash-only text nodes (restored for parsing) are skipped.\n * */\n const extractParts = (\n tokens: Array<Token>,\n createConst: (value: string) => string,\n insideGroup = false,\n ): Array<PathTokenStaticPart | PathTokenParamPart> => {\n const parts: Array<PathTokenStaticPart | PathTokenParamPart> = [];\n\n for (const token of tokens) {\n switch (token.type) {\n case \"text\":\n // Skip slash-only text nodes (restored it via transformers for parsing)\n if (token.value !== \"/\") {\n parts.push({\n type: \"static\",\n value: token.value,\n });\n }\n break;\n case \"param\":\n parts.push({\n type: \"param\",\n kind: insideGroup ? \"optional\" : \"required\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"wildcard\":\n parts.push({\n type: \"param\",\n kind: \"splat\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"group\":\n parts.push(...extractParts(token.tokens, createConst, true));\n break;\n }\n }\n\n return parts;\n };\n\n const patternTransforms: Array<(s: string) => string> = [\n // Transform required params: [id] => :id\n // Only pure \\w param names,\n // [some-id] used as is, not treated as param,\n // use [some_id] instead.\n (s) => s.replace(/\\[(\\w+)\\]/g, \":$1\"),\n\n // Transform optional params: {id} => {:id}\n // Only pure \\w param names,\n // anything else treated as a path-to-regexp pattern and used as is.\n // {some-id} treated as an optional static segment.\n // use {some_id} for simple param syntax\n // or {:some-id} pattern where :some is the param name and -id is a static segment.\n (s) => s.replace(/\\{(\\w+)\\}/g, \"{:$1}\"),\n\n // Transform splat params: {...param} => {*param}\n (s) => s.replace(/\\{\\.\\.\\./g, \"{*\"),\n\n // Insert leading slash inside optional/splat groups.\n // {:name} => {/:name}\n // {*name} => {/*name}\n (s) => {\n return s.startsWith(\"{\") // keep this check for intention clarity\n ? s.replace(/^\\{/, \"{/\")\n : s;\n },\n ];\n\n // detect :param used outside {}\n const detectBareParams = (s: string): \":\" | string | undefined => {\n let depth = 0;\n for (const [i, ch] of [...s].entries()) {\n if (ch === \"{\") {\n depth += 1;\n } else if (ch === \"}\") {\n depth -= 1;\n } else if (ch === \":\" && depth === 0) {\n const match = s.slice(i + 1).match(/^\\w+/);\n return match?.[0] || \":\";\n }\n }\n return;\n };\n\n const tokens = path\n .replace(/^index\\/?/, \"\")\n .split(\"/\")\n .flatMap<PathToken>((orig) => {\n if (!orig.length) {\n return [];\n }\n\n const bareParam = detectBareParams(orig);\n\n if (bareParam === \":\") {\n throw new Error(\n `${path} contains colons outside braces, use : only within {}`,\n );\n } else if (bareParam) {\n throw new Error(\n `${path} contains bare params, use [${bareParam}] instead of :${bareParam}`,\n );\n }\n\n const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);\n\n const { tokens } = parse(\n pattern.replace(/\\{[^}]*\\}|(\\+)/g, (m, p1) => (p1 ? \"\\\\+\" : m)),\n );\n\n const parts = extractParts(tokens, (val) => {\n // Sanitize param name into a valid JS identifier\n return /\\W/.test(val) || /^\\d/.test(val)\n ? [val.replace(/^\\d+|\\W/g, \"_\"), crc(orig)].join(\"_\")\n : val;\n });\n\n const isStatic = parts.length === 1 ? parts[0].type === \"static\" : false;\n const isParam = parts.length === 1 ? parts[0].type === \"param\" : false;\n\n const kind: PathToken[\"kind\"] = isStatic\n ? \"static\"\n : isParam\n ? \"param\"\n : \"mixed\";\n\n return [\n {\n kind,\n orig,\n pattern,\n parts,\n },\n ];\n });\n\n // final path should compile, throw otherwise\n compile(tokens.map((e) => e.pattern).join(\"/\"));\n\n return tokens;\n};\n\nexport const createPathPattern = (tokens: Array<PathToken>) => {\n return tokens\n .map(({ pattern }, i) => {\n const next = tokens[i + 1];\n\n if (!next || next.pattern.includes(\"/\")) {\n return pattern;\n }\n\n const slashRequired = tokens.slice(i + 1).some((e) => {\n return e.parts.some((e) => {\n return e.type === \"static\" || e.kind === \"required\";\n });\n });\n\n return slashRequired ? `${pattern}/` : pattern;\n })\n .join(\"\");\n};\n\nexport const createHonoPattern = (tokens: Array<PathToken>) => {\n const paramValue = (p: PathTokenParamPart) => {\n if (p.kind === \"splat\") {\n return `*`;\n }\n if (p.kind === \"optional\") {\n return `:${p.name}?`;\n }\n return `:${p.name}`;\n };\n\n const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToRegex = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeRegex(t.value)];\n }\n if (t.type === \"wildcard\") {\n return [\".+\"];\n }\n if (t.type === \"param\") {\n return [\"[^/]+\"];\n }\n if (t.type === \"group\") {\n return [`(?:${tokensToRegex(t.tokens)})?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token, i) => {\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n if (token.kind === \"param\") {\n return [paramValue(token.parts[0] as PathTokenParamPart)];\n }\n\n // mixed segment - parse pattern, build regex, emit disposable param\n const { tokens } = parse(token.pattern.replace(/\\//g, \"\"));\n\n const regex = tokensToRegex(tokens);\n\n return [`:_${i}{${regex}}`];\n })\n .join(\"/\");\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\n\nimport {\n defaults,\n type PathToken,\n type PathTokenParamPart,\n type ResolvedEntry,\n type RouteEntry,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport { pathResolver } from \"../paths\";\nimport {\n createHonoPattern,\n createPathPattern,\n pathTokensFactory,\n} from \"./paths\";\n\nexport type ResolverSignature = {\n name: string;\n handler: (updatedFile?: string) => Promise<ResolvedEntry>;\n};\n\nexport const API_INDEX_BASENAME = \"index\";\nexport const API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;\n\nexport const API_USE_BASENAME = \"use\";\nexport const API_USE_PATTERN = `${API_USE_BASENAME}.ts`;\n\nexport const PAGE_INDEX_BASENAME = \"index\";\nexport const PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue,mdx,md}`;\n\nexport const PAGE_LAYOUT_BASENAME = \"layout\";\nexport const PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue,mdx}`;\n\nconst ROUTE_FILE_PATTERNS = [\n // match index files in api dir\n `${defaults.apiDir}/**/${API_INDEX_PATTERN}`,\n // match use files in api dir\n `${defaults.apiDir}/**/${API_USE_PATTERN}`,\n // match index files in pages dir\n `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,\n // match layout files in pages dir\n `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`,\n];\n\nexport const scanRoutes = async (sourceFolder: SourceFolder) => {\n const { createPath } = pathResolver(sourceFolder);\n return glob(ROUTE_FILE_PATTERNS, {\n cwd: createPath.src(),\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: [\n // ignore top-level matches, routes resides in folders, even index route\n `${defaults.apiDir}/${API_INDEX_PATTERN}`,\n `${defaults.apiDir}/${API_USE_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_INDEX_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_LAYOUT_PATTERN}`,\n ],\n });\n};\n\nexport const isRouteFile = (\n file: string,\n sourceFolder: SourceFolder,\n):\n | [\n // Either `apiDir` or `pagesDir`\n folder: string,\n // Path to a file within the folder, nested at least one level deep\n file: string,\n ]\n | false => {\n const [\n // source folder name\n _sourceFolder,\n // route folder, api or pages\n _folder,\n ...rest\n ] = resolve(sourceFolder.root, file)\n .replace(`${sourceFolder.root}/${defaults.srcDir}/`, \"\")\n .split(\"/\");\n\n /**\n * Ensure the file:\n * - is under the correct source root\n * - belongs to a known route folder (`api/` or `pages/`)\n * - is nested at least one level deep (not a direct child of the folder)\n * */\n if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {\n return false;\n }\n\n return picomatch.isMatch(join(_folder, ...rest), ROUTE_FILE_PATTERNS)\n ? [_folder, rest.join(\"/\")]\n : false;\n};\n\nexport const isApiRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);\n};\n\nexport const isApiUse = (file: string) => {\n return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);\n};\n\nexport const isPageRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);\n};\n\nexport const isPageLayout = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);\n};\n\nexport const createRouteEntry = (\n fileFullpath: string,\n sourceFolder: SourceFolder,\n): RouteEntry | undefined => {\n // scanner already is doing a great job on matching only relevant files\n // but doing a double check here to make sure only needed files added to stack\n const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);\n\n if (!resolvedPaths) {\n return;\n }\n\n const [folder, file] = resolvedPaths;\n\n const id = `${file.replace(/\\W+/g, \"_\")}_${crc(file)}`;\n const name = dirname(file);\n\n try {\n const pathTokens = pathTokensFactory(dirname(file));\n return {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern: createPathPattern(pathTokens),\n honoPattern: createHonoPattern(pathTokens),\n };\n } catch (\n // biome-ignore lint: any\n error: any\n ) {\n console.error(\n `❗${styleText(\"red\", \"ERROR\")}: Failed parsing path for \"${styleText(\"cyan\", file)}\"`,\n );\n console.error(error.message);\n return;\n }\n};\n\n/**\n * Weight of a single path segment.\n *\n * Fixed values per kind prevent complex mixed segments\n * from outscoring multiple statics.\n *\n * static: 4 (exact match, most specific)\n * mixed: 3+ (static + param parts; more statics = slightly higher)\n * required: 2 (matches any single segment)\n * optional: 1 (may or may not match)\n * splat: 0 (matches anything, least specific)\n * */\nconst segmentWeight = (token: PathToken): number => {\n if (token.kind === \"static\") {\n return 4;\n }\n\n if (token.kind === \"mixed\") {\n let statics = 0;\n let optionals = 0;\n\n for (const part of token.parts) {\n if (part.type === \"static\") {\n statics += 1;\n } else if (part.kind === \"optional\" || part.kind === \"splat\") {\n optionals += 1;\n }\n }\n\n // unconditional statics contribute positively,\n // optionals penalize to avoid beating fully-static mixed routes\n return 3 + statics * 0.01 - optionals * 0.005;\n }\n\n const part = token.parts[0] as PathTokenParamPart;\n\n switch (part.kind) {\n case \"required\":\n return 2;\n case \"optional\":\n return 1;\n case \"splat\":\n return 0;\n }\n};\n\n/**\n * Compare two route entries for registration order.\n *\n * More specific routes sort first (higher priority).\n * Segments are compared left-to-right; first difference wins.\n *\n * When one route is a prefix of the other, the trailing segment\n * determines order: a trailing splat loses (shorter sibling first),\n * anything else wins (longer route is more specific).\n *\n * At equal weight and length, lexicographic tiebreak ensures\n * deterministic ordering across JS engines.\n * */\nexport const sortRoutes = (a: RouteEntry, b: RouteEntry): number => {\n const pairs = Array.from(\n { length: Math.max(a.pathTokens.length, b.pathTokens.length) },\n (_, i) => [a.pathTokens[i], b.pathTokens[i]] as const,\n );\n\n for (const [at, bt] of pairs) {\n if (!at || !bt) {\n // one route ran out of segments - check what the extra segment is\n const extra = at ?? bt;\n\n const isSplat =\n extra?.kind === \"param\"\n ? (extra.parts[0] as PathTokenParamPart).kind === \"splat\"\n : false;\n\n if (isSplat) {\n // trailing splat: shorter sibling registers first\n return at ? 1 : -1;\n }\n\n // trailing non-splat: longer route is more specific, registers first\n return at ? -1 : 1;\n }\n\n const aw = segmentWeight(at);\n const bw = segmentWeight(bt);\n\n if (aw !== bw) {\n return bw - aw;\n }\n }\n\n // same weight profile, same length: deterministic tiebreak\n return a.pathPattern.localeCompare(b.pathPattern);\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport mimeTypes from \"mime-types\";\n\nimport {\n type ApiRoute,\n defaults,\n type PageRoute,\n type PathTokenParamPart,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n type ValidationDefinition,\n} from \"@kosmojs/core\";\n\nimport { astFactory } from \"../ast\";\nimport { pathResolver } from \"../paths\";\nimport { render, renderToFile } from \"../render\";\nimport type { ResolverSignature } from \"./base\";\nimport * as templates from \"./templates\";\n\nexport const resolverFactory = (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n): Record<\n | \"pageLayoutResolver\"\n | \"pageRouteResolver\"\n | \"apiUseResolver\"\n | \"apiRouteResolver\",\n (entry: RouteEntry) => ResolverSignature\n> => {\n const {\n //\n generators = [],\n refineTypeName = defaults.refineTypeName,\n } = sourceFolder.config;\n\n const { typeResolverFactory, resolveRouteSignature } = astFactory();\n\n const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);\n\n const {\n //\n literalTypesResolver,\n getSourceFile,\n refreshSourceFile,\n } = typeResolverFactory(sourceFolder);\n\n return {\n pageLayoutResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"pageLayout\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n pageRouteResolver(entry) {\n const {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n const entry: PageRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n params: {\n schema: pathTokens.flatMap((e) => {\n return e.parts.filter((p) => p.type === \"param\");\n }),\n },\n folder,\n file,\n fileFullpath,\n };\n\n return {\n kind: \"pageRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiUseResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"apiUse\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiRouteResolver(entry) {\n const {\n id,\n name,\n file,\n folder,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async (updatedFile) => {\n const paramsSchema: Array<PathTokenParamPart> = pathTokens.flatMap(\n (e) => {\n return e.parts.flatMap((p) => {\n return p.type === \"param\" ? [p] : [];\n });\n },\n );\n\n const optionalParams = paramsSchema.length\n ? paramsSchema.filter((e) => e.kind === \"required\").length === 0\n : true;\n\n const cacheStore = cacheFactory\n ? cacheFactory({ id, file, fileFullpath }, sourceFolder, {\n resolveTypes,\n })\n : undefined;\n\n let cache = cacheStore\n ? await cacheStore.get({ validate: true })\n : undefined;\n\n if (!cache) {\n if (updatedFile === fileFullpath) {\n await refreshSourceFile(fileFullpath);\n }\n\n const {\n typeDeclarations,\n paramsRefinements,\n methods,\n validationDefinitions,\n referencedFiles = [],\n } = await resolveRouteSignature(\n { id, name, fileFullpath, optionalParams },\n {\n withReferencedFiles: true,\n sourceFile: getSourceFile(fileFullpath),\n relpathResolver(path) {\n return join(\n sourceFolder.name,\n defaults.apiDir,\n dirname(file),\n path,\n );\n },\n },\n );\n\n const validationTypes = validationDefinitions.flatMap<{\n id: string;\n text: string;\n }>((def) => {\n return def.target === \"response\"\n ? def.variants.flatMap(({ id, body }) => {\n return body ? [{ id, text: body }] : [];\n })\n : [def.schema];\n });\n\n const numericParams = paramsRefinements\n ? paramsRefinements.flatMap(({ text, index }) => {\n if (text === \"number\") {\n const param = paramsSchema.at(index);\n return param ? [param.name] : [];\n }\n return [];\n })\n : [];\n\n const typesFile = pathResolver(sourceFolder).createPath.libApi(\n dirname(file),\n \"types.ts\",\n );\n\n const params: ApiRoute[\"params\"] = {\n id: [\"ParamsT\", crc(name)].join(\"\"),\n schema: paramsSchema,\n resolvedType: undefined,\n };\n\n const typesFileContent = render(templates.typesFile, {\n params,\n paramsSchema: paramsSchema.map((param, index) => {\n return {\n ...param,\n isRequired: param.kind === \"required\",\n isSplat: param.kind === \"splat\",\n refinement: paramsRefinements?.at(index),\n };\n }),\n typeDeclarations,\n validationTypes,\n });\n\n const resolvedTypes = resolveTypes\n ? literalTypesResolver(typesFileContent, {\n stripComments: true,\n overrides: { [refineTypeName]: refineTypeName },\n withProperties: [\n params.id,\n ...validationTypes.flatMap(({ id }) => id),\n ],\n })\n : undefined;\n\n /**\n * Deploy types.ts file; required by core generators (like fetch).\n * If types resolved, write resolved types;\n * otherwise write original types extracted from API route.\n * */\n await renderToFile(\n typesFile,\n resolvedTypes ? templates.resolvedTypes : typesFileContent,\n { resolvedTypes },\n );\n\n params.resolvedType = resolvedTypes?.find(\n (e) => e.name === params.id,\n );\n\n cache = {\n // placeholder values, if cacheFactory given,\n // they will be replaced by persistCache\n hash: 0,\n referencedFiles: {},\n // real values\n params,\n methods,\n typeDeclarations,\n numericParams,\n validationDefinitions: validationDefinitions.map((def) => {\n return {\n ...def,\n ...(def.target === \"response\"\n ? {\n variants: def.variants.map((variant) => {\n return {\n ...variant,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === variant.id,\n ),\n };\n }),\n }\n : {\n schema: {\n ...def.schema,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === def.schema.id,\n ),\n },\n }),\n };\n }),\n };\n\n if (cacheStore) {\n const { referencedFiles: _void, ...rest } = cache;\n cache = await cacheStore.set({ ...rest, referencedFiles });\n }\n }\n\n const validationDefinitions = cache.validationDefinitions.flatMap(\n (def) => {\n let augmentedDef: ValidationDefinition | undefined = def;\n\n if (def.target === \"response\") {\n augmentedDef = {\n ...def,\n variants: def.variants.flatMap((variant, i) => {\n if (typeof variant.contentType !== \"string\") {\n return [variant];\n }\n\n if (variant.contentType.includes(\"/\")) {\n return [variant];\n }\n\n const contentType = mimeTypes.lookup(variant.contentType);\n\n if (contentType === false) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${variant.contentType}`,\n );\n console.warn(\n styleText(\n [\"cyan\"],\n ` Response variant #${i} excluded from route schemas`,\n ),\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n return [];\n }\n\n return [{ ...variant, contentType }];\n }),\n };\n } else if (def.contentType && !def.contentType.includes(\"/\")) {\n const contentType = mimeTypes.lookup(def.contentType);\n if (contentType === false) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${def.contentType}`,\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n } else {\n augmentedDef = { ...def, contentType };\n }\n }\n\n return augmentedDef ? [augmentedDef] : [];\n },\n );\n\n const entry: ApiRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n params: cache.params,\n numericParams: cache.numericParams,\n optionalParams,\n folder,\n file,\n fileFullpath,\n methods: cache.methods,\n typeDeclarations: cache.typeDeclarations,\n validationDefinitions,\n referencedFiles: Object.keys(cache.referencedFiles).map(\n // expand referenced files path,\n // they are stored as relative in cache\n (e) => resolve(sourceFolder.root, e),\n ),\n };\n\n return {\n kind: \"apiRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n };\n};\n","import { basename } from \"node:path\";\n\nimport type { NestedRouteEntry, RouteEntry } from \"@kosmojs/core\";\n\nimport { PAGE_INDEX_BASENAME, PAGE_LAYOUT_BASENAME, sortRoutes } from \"./base\";\n\nexport const nestedRoutesFactory = (routeEntries: Array<RouteEntry>) => {\n const entryStack = structuredClone(routeEntries).sort(sortRoutes);\n\n /**\n * Group entries by name (at the same level, both layout and index share same name).\n *\n * Handle 3 cases:\n * - both index and layout exists\n * - only index exists\n * - only layout exists\n *\n * */\n const transformEntries = (\n entries: Array<RouteEntry>,\n parent?: RouteEntry,\n ): Array<NestedRouteEntry> => {\n return [...new Set(entries.map((e) => e.name))].flatMap((name) => {\n const nameEntries = entryStack.flatMap(({ fileFullpath, ...entry }) => {\n return entry.name === name ? [entry] : [];\n });\n\n const index = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_INDEX_BASENAME),\n ) as RouteEntry;\n\n const layout = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_LAYOUT_BASENAME),\n ) as RouteEntry;\n\n if (index || layout) {\n return [\n {\n index: index\n ? {\n ...index,\n pathTokens: index.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n layout: layout\n ? {\n ...layout,\n pathTokens: layout.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n parent: parent?.name,\n children: transformEntries(\n findDescendantEntries(index || layout),\n index || layout,\n ),\n },\n ];\n }\n\n return [];\n });\n };\n\n /**\n * Recursively finds direct descendant routes.\n *\n * \"Direct\" means the next existing route in the path hierarchy,\n * skipping intermediate path segments that don't have index/layout files.\n *\n * Example: blog/post/[slug]/index.tsx is a direct child of blog/index.tsx\n * even though \"post\" segment exists (it has no index.tsx).\n * */\n const findDescendantEntries = ({\n name,\n pathTokens,\n }: RouteEntry): Array<RouteEntry> => {\n // Find all potential children - BOTH indexes AND layouts\n const potentialChildren = entryStack.filter((entry) => {\n // Must be deeper than current entry\n if (entry.pathTokens.length <= pathTokens.length) {\n return false;\n }\n // Must be a descendant path\n if (!entry.name.startsWith(`${name}/`)) {\n return false;\n }\n return true;\n });\n\n // Filter to direct children (no intermediate route between parent and child)\n return potentialChildren.filter((child) => {\n // Check if any route exists between parent and child\n const hasIntermediateRoute = potentialChildren.some((intermediate) => {\n if (intermediate === child) {\n return false;\n }\n // Intermediate must be between parent and child in depth\n if (intermediate.pathTokens.length <= pathTokens.length) {\n return false;\n }\n if (intermediate.pathTokens.length >= child.pathTokens.length) {\n return false;\n }\n // Child must be descendant of intermediate\n return child.name.startsWith(`${intermediate.name}/`);\n });\n\n return !hasIntermediateRoute;\n });\n };\n\n // Find root entries - entries that have no parent route\n const rootEntries = entryStack.filter((entry) => {\n // Check if any other entry could be its parent\n const hasParent = entryStack.some((potential) => {\n if (potential === entry) {\n return false;\n }\n if (potential.pathTokens.length >= entry.pathTokens.length) {\n return false;\n }\n return entry.name.startsWith(`${potential.name}/`);\n });\n\n return !hasParent;\n });\n\n return transformEntries(rootEntries);\n};\n","import {\n defaults,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport {\n createRouteEntry,\n isApiRoute,\n isApiUse,\n isPageLayout,\n isPageRoute,\n type ResolverSignature,\n scanRoutes,\n} from \"./base\";\nimport { resolverFactory } from \"./resolve\";\n\nexport * from \"./base\";\nexport * from \"./nesting\";\nexport * from \"./paths\";\n\nexport const routesFactory = async (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n) => {\n const {\n apiRouteResolver,\n apiUseResolver,\n pageRouteResolver,\n pageLayoutResolver,\n } = resolverFactory(sourceFolder, cacheFactory);\n\n const resolversFactory = (routeFiles: Array<string>) => {\n const resolvers = new Map<\n string, // fileFullpath\n ResolverSignature\n >();\n\n const entries: Array<RouteEntry> = routeFiles.flatMap((file) => {\n const entry = createRouteEntry(file, sourceFolder);\n return entry ? [entry] : [];\n });\n\n for (const entry of entries) {\n if (entry.folder === defaults.apiDir) {\n if (isApiRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, apiRouteResolver(entry));\n } else if (isApiUse(entry.file)) {\n resolvers.set(entry.fileFullpath, apiUseResolver(entry));\n }\n } else if (entry.folder === defaults.pagesDir) {\n if (isPageRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, pageRouteResolver(entry));\n } else if (isPageLayout(entry.file)) {\n resolvers.set(entry.fileFullpath, pageLayoutResolver(entry));\n }\n }\n }\n\n return resolvers;\n };\n\n const routeFiles = await scanRoutes(sourceFolder);\n\n return {\n resolvers: resolversFactory(routeFiles),\n resolversFactory,\n };\n};\n","import { Spinner } from \"@topcli/spinner\";\n\nexport type SpinnerFactory = {\n text: (text: string) => void;\n append: (text: string) => void;\n succeed: (text?: string) => void;\n failed: (text?: string) => void;\n};\n\nexport const spinnerFactory = (startText: string): SpinnerFactory => {\n const spinner = new Spinner().start(startText);\n let _text = startText;\n return {\n text(text) {\n _text = text;\n spinner.text = text;\n },\n append(text) {\n spinner.text = `${_text} › ${text}`;\n },\n succeed(text) {\n if (text) {\n this.append(text);\n } else {\n this.text(_text);\n }\n spinner.succeed();\n },\n failed(text) {\n if (text) {\n this.text([_text, text].join(\"\\n\"));\n }\n spinner.failed();\n },\n };\n};\n\nexport const withSpinner = (\n text: string,\n pipe: (spinner: SpinnerFactory) => void | Promise<void>,\n spinner?: SpinnerFactory,\n) => pipe(spinner || spinnerFactory(text));\n","import { defaults, type SourceFolder } from \"@kosmojs/core\";\n\nexport const typeboxLiteralText = (\n text: string,\n sourceFolder: SourceFolder,\n) => {\n const { refineTypeName = defaults.refineTypeName } = sourceFolder.config;\n return [\n // Escape backticks for safe use in template literals\n [/(?<!\\\\)`/g, \"\\\\`\"],\n // Escape $ for safe use in template literals\n [/(?<!\\\\)\\$\\{/g, \"\\\\${\"],\n /**\n * TypeBox's built-in `Options` type is not configurable.\n * To allow a custom type name, exposing `refineTypeName` option,\n * defaulted to VRefine, then renaming it to `Options`.\n * */\n [new RegExp(`\\\\b${refineTypeName}\\\\s*<`, \"g\"), \"Options<\"],\n ].reduce((text, [a, b]) => text.replace(a, b as never), text);\n};\n","import { builtinModules } from \"node:module\";\n\nimport type { Plugin } from \"vite\";\n\nconst nodePrefix = (): Plugin => {\n return {\n name: \"kosmojs:node-prefix\",\n enforce: \"pre\",\n resolveId(source) {\n return builtinModules.includes(source)\n ? { id: `node:${source}`, external: true }\n : undefined;\n },\n };\n};\n\nexport const vitePlugins = {\n nodePrefix,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/paths.ts","../src/render.ts","../src/ast.ts","../src/generators.ts","../src/routes/paths.ts","../src/routes/base.ts","../src/routes/resolve.ts","../src/routes/nesting.ts","../src/routes/index.ts","../src/spinner.ts","../src/vite.ts"],"sourcesContent":["import { access, constants } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { defaults, type SourceFolder } from \"@kosmojs/core\";\n\ntype Options = { origin: \"src\" | \"lib\" };\n\ntype CreateImport = Record<\n \"src\" | \"api\" | \"pages\" | \"lib\" | \"libCore\" | \"libApi\" | \"libEntry\",\n (a: Array<string>, o: Options) => string\n>;\n\nexport const pathResolver = (\n sourceFolder: Omit<SourceFolder, \"root\"> & { root?: string | undefined },\n): {\n createPath: Record<\n | \"src\"\n | \"api\"\n | \"pages\"\n | \"entry\"\n | \"lib\"\n | \"libCore\"\n | \"libApi\"\n | \"libEntry\"\n | \"libPages\"\n | \"distDir\",\n (...a: Array<string>) => string\n >;\n createImport: CreateImport;\n createImportHelpers: (o: Options) => {\n createImport: (k: keyof CreateImport, ...a: Array<string>) => string;\n };\n} => {\n const createPath = (...a: Array<string>) => {\n return sourceFolder.root\n ? resolve(sourceFolder.root, join(...a))\n : join(...a);\n };\n\n const createImport: CreateImport = {\n src(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.srcPrefix, ...a)\n : join(defaults.appPrefix, defaults.srcDir, sourceFolder.name, ...a);\n },\n api(a, o) {\n return this.src([defaults.apiDir, ...a], o);\n },\n pages(a, o) {\n return this.src([defaults.pagesDir, ...a], o);\n },\n lib(a, { origin }) {\n return origin === \"src\"\n ? join(defaults.libPrefix, ...a)\n : join(defaults.appPrefix, defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(a, o) {\n return this.lib([\"core\", ...a], o);\n },\n libApi(a, o) {\n return this.lib([defaults.apiDir, ...a], o);\n },\n libEntry(a, o) {\n return this.lib([defaults.entryDir, ...a], o);\n },\n };\n\n return {\n createPath: {\n src(...a) {\n return createPath(defaults.srcDir, sourceFolder.name, ...a);\n },\n api(...a) {\n return this.src(defaults.apiDir, ...a);\n },\n pages(...a) {\n return this.src(defaults.pagesDir, ...a);\n },\n entry(...a) {\n return this.src(defaults.entryDir, ...a);\n },\n lib(...a) {\n return createPath(defaults.libDir, sourceFolder.name, ...a);\n },\n libCore(...a) {\n return this.lib(\"core\", ...a);\n },\n libApi(...a) {\n return this.lib(defaults.apiDir, ...a);\n },\n libEntry(...a) {\n return this.lib(defaults.entryDir, ...a);\n },\n libPages(...a) {\n return this.lib(defaults.pagesDir, ...a);\n },\n distDir(...a) {\n return createPath(sourceFolder.distDir, sourceFolder.name, ...a);\n },\n },\n createImport,\n createImportHelpers(o) {\n if (![\"src\", \"lib\"].includes(o?.origin)) {\n throw new Error(\n `createImportHelpers: required exactly one argument of shape { origin: \"src|lib\" }`,\n );\n }\n return {\n createImport(key, ...a) {\n // Handlebars appends an options object as the last argument,\n // slice it off before passing args to createImport\n return createImport[key](a.slice(0, -1), o);\n },\n };\n },\n };\n};\n\nexport const pathExists = async (path: string): Promise<boolean> => {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n};\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport crc from \"crc/crc32\";\nimport handlebars from \"handlebars\";\n\nimport { pathExists } from \"./paths\";\n\nexport type RenderOptions = {\n noEscape?: boolean;\n // handlebars instance\n renderer?: typeof handlebars;\n};\n\nexport type FactoryOptions = RenderOptions & {\n partials?: Record<string, string>;\n helpers?: Record<string, (...a: Array<never>) => unknown>;\n outdir?: string;\n /**\n * Controls whether to overwrite an existing file.\n * - `false`: skip writing if the file already exists\n * - `true` (default): always overwrite\n * - function: custom logic to decide whether to overwrite, based on current file content\n * */\n overwrite?: boolean | ((fileContent: string) => boolean);\n};\n\nexport const render = <Context = object>(\n template: string,\n context: Context,\n options?: RenderOptions,\n): string => {\n const { noEscape = true, renderer = handlebars } = { ...options };\n return renderer.compile(template, { noEscape })(context);\n};\n\nexport const renderToFile = async <Context = object>(\n file: string,\n template: string,\n context: Context,\n options?: RenderOptions & Pick<FactoryOptions, \"overwrite\">,\n): Promise<void> => {\n const content = render(template, context, options);\n\n /**\n * Two fs calls (exists + read) are worth it to avoid touching the file\n * and triggering watchers unnecessarily.\n * */\n if (await pathExists(file)) {\n const { overwrite = true } = { ...options };\n if (overwrite === false) {\n return;\n }\n const fileContent = await readFile(file, \"utf8\");\n if (typeof overwrite === \"function\" && !overwrite(fileContent)) {\n return;\n }\n if (crc(content) === crc(fileContent)) {\n return;\n }\n }\n\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, content, \"utf8\");\n};\n\nexport const renderFactory = (options?: FactoryOptions) => {\n const createRenderer = (selfOoptions?: FactoryOptions) => {\n const renderer = handlebars.create();\n\n renderer.registerPartial({\n ...options?.partials,\n ...selfOoptions?.partials,\n } as never);\n\n renderer.registerHelper({\n ...options?.helpers,\n ...selfOoptions?.helpers,\n } as never);\n\n return renderer;\n };\n\n return {\n render<Context = object>(\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return render(template, context, {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n });\n },\n async renderToFile<Context = object>(\n file: string,\n template: string,\n context: Context,\n selfOoptions?: FactoryOptions,\n ) {\n return renderToFile(\n options?.outdir ? join(options.outdir, file) : file,\n template,\n context,\n {\n ...options,\n ...selfOoptions,\n renderer: createRenderer(selfOoptions),\n },\n );\n },\n };\n};\n","import { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport flattener, { type ResolvedType } from \"tfusion\";\nimport {\n type CallExpression,\n type Identifier,\n ModuleResolutionKind,\n Project,\n type ProjectOptions,\n type SourceFile,\n SyntaxKind,\n type TypeNode,\n} from \"ts-morph\";\n\nimport type { ResolvedTypeSignature } from \"@kosmojs/core\";\nimport {\n type ApiRoute,\n defaults,\n RequestValidationTargets,\n type SourceFolder,\n type TypeDeclaration,\n type ValidationDefinition,\n type ValidationTarget,\n} from \"@kosmojs/core\";\nimport { type HTTPMethod, HTTPMethods } from \"@kosmojs/core/api\";\n\nimport { pathResolver } from \"./paths\";\nimport { render } from \"./render\";\nimport * as templates from \"./templates\";\n\ntype PathResolver = (path: string) => string;\n\nexport const astFactory = () => {\n const createProject = (opts?: ProjectOptions) => new Project(opts);\n\n const resolveRouteSignature = async (\n route: Pick<ApiRoute, \"id\" | \"name\" | \"fileFullpath\" | \"optionalParams\">,\n opts?: {\n relpathResolver?: PathResolver;\n sourceFile?: SourceFile;\n withReferencedFiles?: boolean;\n },\n ) => {\n const {\n sourceFile = createProject().addSourceFileAtPath(route.fileFullpath),\n } = { ...opts };\n\n const [typeDeclarations, referencedFiles] = extractTypeDeclarations(\n sourceFile,\n opts,\n );\n\n const defaultExport = extractDefaultExport(sourceFile);\n\n const paramsRefinements = defaultExport\n ? extractParamsRefinements(defaultExport)\n : undefined;\n\n const methods = defaultExport\n ? extractRouteMethods(route, defaultExport)\n : [];\n\n return {\n typeDeclarations,\n paramsRefinements,\n methods: methods.map((e) => e.method),\n validationDefinitions: methods.flatMap((e) => e.validationDefinitions),\n referencedFiles,\n };\n };\n\n const extractDefaultExport = (\n sourceFile: SourceFile,\n ): CallExpression | undefined => {\n const [defaultExport] = sourceFile\n .getExportAssignments()\n .flatMap((exportAssignment) => {\n if (exportAssignment.isExportEquals()) {\n return [];\n }\n const callExpression = exportAssignment.getExpression();\n return callExpression.isKind(SyntaxKind.CallExpression)\n ? [callExpression]\n : [];\n });\n return defaultExport;\n };\n\n const extractParamsRefinements = (\n callExpression: CallExpression,\n ): Array<{ index: number; text: string }> | undefined => {\n const [\n _routeName, // first generic - the route name\n paramsGeneric, // second generic - params refinements\n ] = extractGenerics(callExpression);\n\n if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n return paramsGeneric.getElements().map((node, index) => {\n return {\n index,\n text: node.getText(),\n };\n });\n };\n\n const extractRouteMethods = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n callExpression: CallExpression,\n ): Array<{\n method: HTTPMethod;\n validationDefinitions: Array<ValidationDefinition>;\n }> => {\n const funcDeclaration =\n callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) ||\n callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);\n\n if (!funcDeclaration) {\n return [];\n }\n\n const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n if (!arrayLiteralExpression) {\n return [];\n }\n\n const callExpressions: Array<[CallExpression, HTTPMethod]> = [];\n\n for (const e of arrayLiteralExpression.getChildrenOfKind(\n SyntaxKind.CallExpression,\n )) {\n const name = e.getExpression().getText() as HTTPMethod;\n if (HTTPMethods[name]) {\n callExpressions.push([e, name]);\n }\n }\n\n const methods: ReturnType<typeof extractRouteMethods> = [];\n\n for (const [callExpression, method] of callExpressions) {\n const [vDefs, vOpts] = extractGenerics(callExpression);\n methods.push({\n method,\n validationDefinitions: extractValidationDefinitions(\n route,\n method,\n vDefs,\n vOpts,\n ),\n });\n }\n\n return methods;\n };\n\n /** Parse a boolean literal type node */\n const parseRuntimeValidation = (typeNode: TypeNode) => {\n if (typeNode.isKind(SyntaxKind.LiteralType)) {\n const literal = typeNode.getFirstChild();\n if (literal?.isKind(SyntaxKind.TrueKeyword)) {\n return true;\n } else if (literal?.isKind(SyntaxKind.FalseKeyword)) {\n return false;\n }\n }\n return undefined;\n };\n\n const extractResponseVariant = (\n typeNode: TypeNode,\n ):\n | {\n status: number;\n contentType?: string | undefined;\n body?: string | undefined;\n }\n | undefined => {\n if (!typeNode.isKind(SyntaxKind.TupleType)) {\n return;\n }\n\n let status = 200; // default\n let contentType: string | undefined;\n let body: string | undefined;\n\n const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();\n\n // Status (index 0) - should be a LiteralType with NumericLiteral\n if (statusNode?.isKind(SyntaxKind.LiteralType)) {\n const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);\n if (literal) {\n status = Number(literal.getText());\n }\n }\n\n // ContentType (index 1) - should be a LiteralType with StringLiteral\n if (contentTypeNode) {\n contentType = extractStringLiteral(contentTypeNode);\n }\n\n // Response type text (index 2)\n if (bodyNode) {\n body = bodyNode.getText();\n if ([\"object\"].includes(body)) {\n body = \"{}\";\n }\n }\n\n return { status, contentType, body };\n };\n\n /** Parse opts TypeLiteral into a map keyed by target */\n const parseValidationOptions = (typeNode: TypeNode | undefined) => {\n const opts: Partial<\n Record<\n ValidationTarget,\n {\n contentType: string | undefined;\n runtimeValidation: boolean | undefined;\n customErrors: Record<string, string> | undefined;\n }\n >\n > = {};\n\n if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {\n return opts;\n }\n\n for (const prop of typeNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (!typeNode.isKind(SyntaxKind.TypeLiteral)) {\n continue;\n }\n\n let contentType: string | undefined;\n let runtimeValidation: boolean | undefined;\n const customErrors: Record<string, string> = {};\n\n for (const member of typeNode.getMembers()) {\n if (!member.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const nameNode = member.getNameNode();\n const valueNode = member.getTypeNodeOrThrow();\n\n const name = nameNode.isKind(SyntaxKind.StringLiteral)\n ? nameNode.getLiteralText() // No quotes\n : nameNode.getText(); // Regular identifier\n\n if (name === \"contentType\") {\n contentType = extractStringLiteral(valueNode);\n } else if (name === \"runtimeValidation\") {\n runtimeValidation = parseRuntimeValidation(valueNode);\n } else if (name.startsWith(\"error\")) {\n const literal = extractStringLiteral(valueNode);\n if (literal) {\n customErrors[name] = literal;\n }\n }\n }\n\n opts[target] = {\n contentType,\n runtimeValidation,\n customErrors,\n };\n }\n\n return opts;\n };\n\n const extractStringLiteral = (typeNode: TypeNode) => {\n const literal = typeNode.isKind(SyntaxKind.LiteralType)\n ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral)\n : undefined;\n return literal ? literal.getLiteralText() : undefined;\n };\n\n /**\n * Extract validation definitions from route handler generics.\n * Merges defs (schemas) and opts (validation options) into a flat array.\n * */\n const extractValidationDefinitions = (\n route: Pick<ApiRoute, \"id\" | \"name\">,\n method: HTTPMethod,\n defsNode: TypeNode,\n optsNode: TypeNode | undefined,\n ) => {\n const definitions: Array<ValidationDefinition> = [];\n\n if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {\n return definitions;\n }\n\n const optsMap = parseValidationOptions(optsNode);\n\n const createId = (target: string, hash?: string) => {\n return [\n target.replace(/^./, (c) => c.toUpperCase()),\n \"T\",\n method,\n crc(route.id + hash),\n ].join(\"\");\n };\n\n for (const prop of defsNode.getMembers()) {\n if (!prop.isKind(SyntaxKind.PropertySignature)) {\n continue;\n }\n\n const target = prop.getName() as ValidationTarget;\n const typeNode = prop.getTypeNodeOrThrow();\n\n if (target === \"response\") {\n const variants = typeNode.isKind(SyntaxKind.UnionType)\n ? typeNode.getChildrenOfKind(SyntaxKind.TupleType)\n : [typeNode];\n\n definitions.push({\n ...optsMap[target],\n method,\n target,\n variants: variants.flatMap((e, i) => {\n const { status, contentType, body } = {\n ...extractResponseVariant(e),\n };\n\n if (!status) {\n return [];\n }\n\n if (contentType && typeof contentType !== \"string\") {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n `✗ The second element of a response variant should specify the Response Content Type`,\n ),\n );\n console.warn(\n styleText([\"blue\"], ` Example: [200, \"json\", Schema]`),\n );\n console.warn(\n ` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`,\n );\n console.warn();\n }\n\n return [\n {\n id: createId(\n target,\n JSON.stringify([status, contentType, body]),\n ),\n status,\n contentType,\n body,\n },\n ];\n }),\n });\n } else if (Object.keys(RequestValidationTargets).includes(target)) {\n definitions.push({\n ...optsMap[target],\n method,\n target,\n schema: {\n id: createId(target),\n text: typeNode.getText(),\n },\n });\n }\n }\n\n return definitions;\n };\n\n const extractTypeDeclarations = (\n sourceFile: SourceFile,\n opts?: {\n relpathResolver?: PathResolver;\n withReferencedFiles?: boolean;\n },\n ): [d: Array<TypeDeclaration>, f?: Array<string>] => {\n const declarations: Array<TypeDeclaration> = [];\n\n const referencedFiles: Array<string> | undefined = opts?.withReferencedFiles\n ? []\n : undefined;\n\n for (const declaration of sourceFile.getImportDeclarations()) {\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath;\n\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const defaultImport = typeOnlyDeclaration\n ? declaration.getDefaultImport()\n : undefined;\n\n if (defaultImport) {\n const name = defaultImport.getText();\n const text = `import type ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(defaultImport));\n }\n }\n\n const namespaceImport = typeOnlyDeclaration\n ? declaration.getNamespaceImport()\n : undefined;\n\n if (namespaceImport) {\n const name = namespaceImport.getText();\n const text = `import type * as ${name} from \"${path}\";`;\n declarations.push({\n importDeclaration: {\n name,\n path,\n },\n text,\n });\n if (referencedFiles) {\n referencedFiles.push(...getReferencedFiles(namespaceImport));\n }\n }\n\n for (const namedImport of declaration.getNamedImports()) {\n if (namedImport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedImport.getNameNode();\n const name = nameNode.getText();\n const alias = namedImport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n importDeclaration: {\n name,\n alias,\n path,\n },\n text: `import type { ${nameText} } from \"${path}\";`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n for (const declaration of sourceFile.getTypeAliases()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n typeAliasDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getInterfaces()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n interfaceDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getEnums()) {\n const name = declaration.getName();\n const text = declaration.getFullText().trim();\n declarations.push({\n enumDeclaration: { name },\n text,\n });\n }\n\n for (const declaration of sourceFile.getExportDeclarations()) {\n const typeOnlyDeclaration = declaration.isTypeOnly();\n\n const modulePath = declaration.getModuleSpecifierValue();\n\n const path = modulePath\n ? /^\\.\\.?\\/?/.test(modulePath)\n ? opts?.relpathResolver\n ? opts.relpathResolver(modulePath)\n : modulePath\n : modulePath\n : undefined;\n\n for (const namedExport of declaration.getNamedExports()) {\n if (namedExport.isTypeOnly() || typeOnlyDeclaration) {\n const nameNode = namedExport.getNameNode();\n const name = nameNode.getText();\n const alias = namedExport.getAliasNode()?.getText();\n const nameText = alias ? `${name} as ${alias}` : name;\n\n declarations.push({\n exportDeclaration: {\n name,\n alias: alias ?? name,\n path,\n },\n text: path\n ? `export type { ${nameText} } from \"${path}\";`\n : `export type { ${nameText} };`,\n });\n\n if (referencedFiles) {\n if (nameNode.isKind(SyntaxKind.Identifier)) {\n referencedFiles.push(...getReferencedFiles(nameNode));\n }\n }\n }\n }\n }\n\n return referencedFiles\n ? [declarations, [...new Set<string>(referencedFiles)]]\n : [declarations];\n };\n\n const getReferencedFiles = (importIdentifier: Identifier): Array<string> => {\n // ambient modules may have declarations in multiple files\n const declarations =\n importIdentifier //\n ?.getSymbol()\n ?.getAliasedSymbol()\n ?.getDeclarations() || [];\n\n return declarations.flatMap((e) => {\n const sourceFile = e.getSourceFile();\n return sourceFile //\n ? [sourceFile.getFilePath()]\n : [];\n });\n };\n\n const extractGenerics = (callExpression: CallExpression) => {\n return callExpression.getTypeArguments();\n };\n\n const typeResolverFactory = (sourceFolder: SourceFolder) => {\n const { createPath } = pathResolver(sourceFolder);\n\n const project = createProject({\n compilerOptions: {\n moduleResolution: ModuleResolutionKind.Bundler,\n types: [],\n noLib: true,\n skipLibCheck: true,\n paths: {\n [`${defaults.appPrefix}/*`]: [`${sourceFolder.root}/*`],\n [`${defaults.srcPrefix}/*`]: [createPath.src(\"*\")],\n [`${defaults.libPrefix}/*`]: [createPath.lib(\"*\")],\n },\n },\n });\n\n const withTypeboxSchema = (resolvedTypes: Array<ResolvedType>) => {\n const materializedTypes = render(templates.resolvedTypes, {\n resolvedTypes,\n });\n\n const sourceFile = project.createSourceFile(\n `${crc(materializedTypes)}-${Date.now()}.ts`,\n materializedTypes,\n { overwrite: true },\n );\n\n const types = resolvedTypes.map<ResolvedTypeSignature>((type) => {\n const typeNode = sourceFile.getTypeAlias(type.name)?.getTypeNode();\n\n if (!typeNode) {\n return type;\n }\n\n const properties = type.properties\n ? type.properties.map((prop) => {\n const propNode = typeNode.isKind(SyntaxKind.TypeLiteral)\n ? typeNode.getProperty(prop.name)?.getTypeNode()\n : undefined;\n\n if (!propNode) {\n return prop;\n }\n\n return {\n ...prop,\n typeboxSchema: renderTypeboxSchema(propNode),\n };\n })\n : undefined;\n\n return {\n ...type,\n ...(properties ? { properties } : {}),\n typeboxSchema: renderTypeboxSchema(typeNode),\n };\n });\n\n project.removeSourceFile(sourceFile);\n\n return types;\n };\n\n const literalTypesResolver = (\n literalTypes: string,\n options: Parameters<typeof flattener>[2],\n ): Array<ResolvedTypeSignature> => {\n const sourceFile = project.createSourceFile(\n `${crc(literalTypes)}-${Date.now()}.ts`,\n literalTypes,\n { overwrite: true },\n );\n\n const resolvedTypes = flattener(project, sourceFile, {\n ...options,\n stripComments: true,\n });\n\n project.removeSourceFile(sourceFile);\n\n return withTypeboxSchema(resolvedTypes);\n };\n\n return {\n getSourceFile: (fileFullpath: string) => {\n return (\n project.getSourceFile(fileFullpath) ||\n project.addSourceFileAtPath(fileFullpath)\n );\n },\n refreshSourceFile: async (fileFullpath: string) => {\n const sourceFile = project.getSourceFile(fileFullpath);\n if (sourceFile) {\n await sourceFile.refreshFromFileSystem();\n }\n },\n literalTypesResolver,\n };\n };\n\n return {\n createProject,\n extractDefaultExport,\n extractParamsRefinements,\n extractRouteMethods,\n extractTypeDeclarations,\n resolveRouteSignature,\n typeResolverFactory,\n };\n};\n\n/**\n * Render a ts-morph TypeNode to TypeBox Script text, replacing every VRefine\n * occurrence (at any depth) with the infix `with` form.\n *\n * VRefine<string, { format: \"email\" }> -> (string with { format: \"email\" })\n * VRefine<string, { format: \"email\" }>[] -> (string with { format: \"email\" })[]\n * VRefine<Array<string>, { minItems: 1 }> -> (Array<string> with { minItems: 1 })\n * VRefine<Record<string, string>, { maxProperties: 20 }>\n * -> (Record<string, string> with { maxProperties: 20 })\n *\n * The parentheses matter: for an array element the `with` clause must bind to\n * the element, not the array, so a VRefine that is the element of an array is\n * wrapped. We wrap unconditionally - harmless when not nested, required when it\n * is.\n *\n * @param typeNode the node to render\n * @param refineTypeName the configured refine type name\n * */\nconst renderTypeboxSchema = (\n typeNode: TypeNode,\n refineTypeName = defaults.refineTypeName,\n) => {\n const traverse = (typeNode: TypeNode): string => {\n // 1) VRefine<T, Opts> -> `(<render T> with <opts text>)`\n if (\n typeNode.isKind(SyntaxKind.TypeReference) &&\n typeNode.getTypeName().getText() === refineTypeName\n ) {\n const [inner, opts] = typeNode.getTypeArguments();\n if (!inner || !opts) {\n // Malformed VRefine, emit its raw text unchanged\n return typeNode.getText();\n }\n const innerText = traverse(inner);\n // Options is a single TypeLiteral; its raw text is exactly what `with`\n // expects. getText() preserves nested braces and quoted `}>` verbatim.\n return `(${innerText} with ${opts.getText()})`;\n }\n\n // 2) T[] -> `<render T>[]` (element may itself be a VRefine)\n if (typeNode.isKind(SyntaxKind.ArrayType)) {\n const element = traverse(typeNode.getElementTypeNode());\n return `${element}[]`;\n }\n\n // 3) Object type literal -> recurse into each property's type node\n if (typeNode.isKind(SyntaxKind.TypeLiteral)) {\n const members: string[] = [];\n for (const member of typeNode.getMembers()) {\n if (member.isKind(SyntaxKind.PropertySignature)) {\n const name = member.getName();\n const optional = member.hasQuestionToken() ? \"?\" : \"\";\n const t = member.getTypeNode();\n const rendered = t ? traverse(t) : \"unknown\";\n members.push(`${name}${optional}: ${rendered}`);\n } else {\n // index signatures, call signatures, etc: pass through raw\n members.push(member.getText());\n }\n }\n return `{ ${members.join(\", \")} }`;\n }\n\n // 4) Tuple -> recurse into each element\n if (typeNode.isKind(SyntaxKind.TupleType)) {\n const elements = typeNode.getElements().map((el) => traverse(el));\n return `[${elements.join(\", \")}]`;\n }\n\n // 5) Parenthesized -> recurse, keep the parens\n if (typeNode.isKind(SyntaxKind.ParenthesizedType)) {\n return `(${traverse(typeNode.getTypeNode())})`;\n }\n\n // 6) Union / Intersection -> recurse into each constituent\n if (typeNode.isKind(SyntaxKind.UnionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" | \");\n }\n if (typeNode.isKind(SyntaxKind.IntersectionType)) {\n return typeNode\n .getTypeNodes()\n .map((t) => traverse(t))\n .join(\" & \");\n }\n\n // 7) A non-VRefine type reference that carries type arguments - this covers\n // the refined bases Array<T> and Record<K, V> (which stay as-is and get a\n // trailing `with` clause from case 1), as well as any generic wrapper\n // around a VRefine. Recurse into the arguments so a nested VRefine is\n // still rewritten, and keep the head name unchanged.\n if (typeNode.isKind(SyntaxKind.TypeReference)) {\n const args = typeNode.getTypeArguments();\n if (args.length === 0) {\n return typeNode.getText();\n }\n const name = typeNode.getTypeName().getText();\n const rendered = args.map((a) => traverse(a));\n return `${name}<${rendered.join(\", \")}>`;\n }\n\n // 8) Anything else (primitive keyword, literal, etc): raw text is correct.\n return typeNode.getText();\n };\n\n return [\n // Escape backticks for safe use in template literals\n [/(?<!\\\\)`/g, \"\\\\`\"],\n // Escape $ for safe use in template literals\n [/(?<!\\\\)\\$\\{/g, \"\\\\${\"],\n ].reduce((text, [a, b]) => text.replace(a, b as never), traverse(typeNode));\n};\n","import type { Matcher } from \"picomatch\";\nimport picomatch from \"picomatch\";\n\nimport type {\n DefineGenerator,\n DefineGeneratorFactory,\n GeneratorCustomTemplates,\n} from \"@kosmojs/core\";\n\nexport const defineGenerator: DefineGenerator = (f) => f as never;\n\nexport const defineGeneratorFactory: DefineGeneratorFactory = (f) => f;\n\nexport const createTemplateResolver = <T>(\n customTemplates: GeneratorCustomTemplates<T> | undefined,\n defaultTemplate: string,\n) => {\n const templates: Array<[Matcher, string | Function]> = Object.entries({\n ...customTemplates,\n }).map(([pattern, template]) => [picomatch(pattern), template]);\n return (pattern: string, entry: T) => {\n const match = templates.find(([isMatch]) => isMatch(pattern));\n if (!match) {\n return defaultTemplate;\n }\n return typeof match[1] === \"function\" //\n ? match[1](entry)\n : match[1];\n };\n};\n","import crc from \"crc/crc32\";\nimport { compile, parse, type Token } from \"path-to-regexp\";\n\nimport type {\n PathToken,\n PathTokenParamPart,\n PathTokenStaticPart,\n} from \"@kosmojs/core\";\n\n/**\n * Parse a filesystem route path into structured PathToken array.\n *\n * Uses path-to-regexp v8 AST for parsing, with directory-friendly syntax:\n * - [param] => required param - :param\n * - {param} => optional param - {:param}\n * - {...param} => splat - {*param}\n *\n * Direct :param syntax is prohibited outside {} to avoid ambiguity.\n * Inside {} it is treated as path-to-regexp power syntax and used as-is.\n *\n * Throw error if path can not be compiled into path-to-regexp pattern.\n *\n * Examples:\n * Required: [id], [name]\n * Optional: {name}, {format}\n * Splat: {...path}\n * Mixed segments: shop/[id]-{name}\n * Power syntax: {-v:version{-:pre}}, :name{@:version{.:min}}.js\n * */\nexport const pathTokensFactory = (path: string): Array<PathToken> => {\n /**\n * Recursively extract parts from path-to-regexp AST tokens.\n * A param inside a group is optional; top-level params are required.\n * Wildcard tokens are always splat.\n * Slash-only text nodes (restored for parsing) are skipped.\n * */\n const extractParts = (\n tokens: Array<Token>,\n createConst: (value: string) => string,\n insideGroup = false,\n ): Array<PathTokenStaticPart | PathTokenParamPart> => {\n const parts: Array<PathTokenStaticPart | PathTokenParamPart> = [];\n\n for (const token of tokens) {\n switch (token.type) {\n case \"text\":\n // Skip slash-only text nodes (restored it via transformers for parsing)\n if (token.value !== \"/\") {\n parts.push({\n type: \"static\",\n value: token.value,\n });\n }\n break;\n case \"param\":\n parts.push({\n type: \"param\",\n kind: insideGroup ? \"optional\" : \"required\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"wildcard\":\n parts.push({\n type: \"param\",\n kind: \"splat\",\n name: token.name,\n const: createConst(token.name),\n });\n break;\n case \"group\":\n parts.push(...extractParts(token.tokens, createConst, true));\n break;\n }\n }\n\n return parts;\n };\n\n const patternTransforms: Array<(s: string) => string> = [\n // Transform required params: [id] => :id\n // Only pure \\w param names,\n // [some-id] used as is, not treated as param,\n // use [some_id] instead.\n (s) => s.replace(/\\[(\\w+)\\]/g, \":$1\"),\n\n // Transform optional params: {id} => {:id}\n // Only pure \\w param names,\n // anything else treated as a path-to-regexp pattern and used as is.\n // {some-id} treated as an optional static segment.\n // use {some_id} for simple param syntax\n // or {:some-id} pattern where :some is the param name and -id is a static segment.\n (s) => s.replace(/\\{(\\w+)\\}/g, \"{:$1}\"),\n\n // Transform splat params: {...param} => {*param}\n (s) => s.replace(/\\{\\.\\.\\./g, \"{*\"),\n\n // Insert leading slash inside optional/splat groups.\n // {:name} => {/:name}\n // {*name} => {/*name}\n (s) => {\n return s.startsWith(\"{\") // keep this check for intention clarity\n ? s.replace(/^\\{/, \"{/\")\n : s;\n },\n ];\n\n // detect :param used outside {}\n const detectBareParams = (s: string): \":\" | string | undefined => {\n let depth = 0;\n for (const [i, ch] of [...s].entries()) {\n if (ch === \"{\") {\n depth += 1;\n } else if (ch === \"}\") {\n depth -= 1;\n } else if (ch === \":\" && depth === 0) {\n const match = s.slice(i + 1).match(/^\\w+/);\n return match?.[0] || \":\";\n }\n }\n return;\n };\n\n const tokens = path\n .replace(/^index\\/?/, \"\")\n .split(\"/\")\n .flatMap<PathToken>((orig) => {\n if (!orig.length) {\n return [];\n }\n\n const bareParam = detectBareParams(orig);\n\n if (bareParam === \":\") {\n throw new Error(\n `${path} contains colons outside braces, use : only within {}`,\n );\n } else if (bareParam) {\n throw new Error(\n `${path} contains bare params, use [${bareParam}] instead of :${bareParam}`,\n );\n }\n\n const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);\n\n const { tokens } = parse(\n pattern.replace(/\\{[^}]*\\}|(\\+)/g, (m, p1) => (p1 ? \"\\\\+\" : m)),\n );\n\n const parts = extractParts(tokens, (val) => {\n // Sanitize param name into a valid JS identifier\n return /\\W/.test(val) || /^\\d/.test(val)\n ? [val.replace(/^\\d+|\\W/g, \"_\"), crc(orig)].join(\"_\")\n : val;\n });\n\n const isStatic = parts.length === 1 ? parts[0].type === \"static\" : false;\n const isParam = parts.length === 1 ? parts[0].type === \"param\" : false;\n\n const kind: PathToken[\"kind\"] = isStatic\n ? \"static\"\n : isParam\n ? \"param\"\n : \"mixed\";\n\n return [\n {\n kind,\n orig,\n pattern,\n parts,\n },\n ];\n });\n\n // final path should compile, throw otherwise\n compile(tokens.map((e) => e.pattern).join(\"/\"));\n\n return tokens;\n};\n\nexport const createPathPattern = (tokens: Array<PathToken>) => {\n return tokens\n .map(({ pattern }, i) => {\n const next = tokens[i + 1];\n\n if (!next || next.pattern.includes(\"/\")) {\n return pattern;\n }\n\n const slashRequired = tokens.slice(i + 1).some((e) => {\n return e.parts.some((e) => {\n return e.type === \"static\" || e.kind === \"required\";\n });\n });\n\n return slashRequired ? `${pattern}/` : pattern;\n })\n .join(\"\");\n};\n\nexport const createHonoPattern = (tokens: Array<PathToken>) => {\n const paramValue = (p: PathTokenParamPart) => {\n if (p.kind === \"splat\") {\n return `*`;\n }\n if (p.kind === \"optional\") {\n return `:${p.name}?`;\n }\n return `:${p.name}`;\n };\n\n const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n const tokensToRegex = (tokens: Array<Token>): string => {\n return tokens\n .flatMap((t) => {\n if (t.type === \"text\") {\n return t.value === \"/\" ? [] : [escapeRegex(t.value)];\n }\n if (t.type === \"wildcard\") {\n return [\".+\"];\n }\n if (t.type === \"param\") {\n return [\"[^/]+\"];\n }\n if (t.type === \"group\") {\n return [`(?:${tokensToRegex(t.tokens)})?`];\n }\n return [];\n })\n .join(\"\");\n };\n\n return tokens\n .flatMap((token, i) => {\n if (token.kind === \"static\") {\n return [(token.parts[0] as PathTokenStaticPart).value];\n }\n\n if (token.kind === \"param\") {\n return [paramValue(token.parts[0] as PathTokenParamPart)];\n }\n\n // mixed segment - parse pattern, build regex, emit disposable param\n const { tokens } = parse(token.pattern.replace(/\\//g, \"\"));\n\n const regex = tokensToRegex(tokens);\n\n return [`:_${i}{${regex}}`];\n })\n .join(\"/\");\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport picomatch from \"picomatch\";\nimport { glob } from \"tinyglobby\";\n\nimport {\n defaults,\n type PathToken,\n type PathTokenParamPart,\n type ResolvedEntry,\n type RouteEntry,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport { pathResolver } from \"../paths\";\nimport {\n createHonoPattern,\n createPathPattern,\n pathTokensFactory,\n} from \"./paths\";\n\nexport type ResolverSignature = {\n name: string;\n handler: (updatedFile?: string) => Promise<ResolvedEntry>;\n};\n\nexport const API_INDEX_BASENAME = \"index\";\nexport const API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;\n\nexport const API_USE_BASENAME = \"use\";\nexport const API_USE_PATTERN = `${API_USE_BASENAME}.ts`;\n\nexport const PAGE_INDEX_BASENAME = \"index\";\nexport const PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue,mdx,md}`;\n\nexport const PAGE_LAYOUT_BASENAME = \"layout\";\nexport const PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue,mdx}`;\n\nconst ROUTE_FILE_PATTERNS = [\n // match index files in api dir\n `${defaults.apiDir}/**/${API_INDEX_PATTERN}`,\n // match use files in api dir\n `${defaults.apiDir}/**/${API_USE_PATTERN}`,\n // match index files in pages dir\n `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,\n // match layout files in pages dir\n `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`,\n];\n\nexport const scanRoutes = async (sourceFolder: SourceFolder) => {\n const { createPath } = pathResolver(sourceFolder);\n return glob(ROUTE_FILE_PATTERNS, {\n cwd: createPath.src(),\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n ignore: [\n // ignore top-level matches, routes resides in folders, even index route\n `${defaults.apiDir}/${API_INDEX_PATTERN}`,\n `${defaults.apiDir}/${API_USE_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_INDEX_PATTERN}`,\n `${defaults.pagesDir}/${PAGE_LAYOUT_PATTERN}`,\n ],\n });\n};\n\nexport const isRouteFile = (\n file: string,\n sourceFolder: SourceFolder,\n):\n | [\n // Either `apiDir` or `pagesDir`\n folder: string,\n // Path to a file within the folder, nested at least one level deep\n file: string,\n ]\n | false => {\n const [\n // source folder name\n _sourceFolder,\n // route folder, api or pages\n _folder,\n ...rest\n ] = resolve(sourceFolder.root, file)\n .replace(`${sourceFolder.root}/${defaults.srcDir}/`, \"\")\n .split(\"/\");\n\n /**\n * Ensure the file:\n * - is under the correct source root\n * - belongs to a known route folder (`api/` or `pages/`)\n * - is nested at least one level deep (not a direct child of the folder)\n * */\n if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {\n return false;\n }\n\n return picomatch.isMatch(join(_folder, ...rest), ROUTE_FILE_PATTERNS)\n ? [_folder, rest.join(\"/\")]\n : false;\n};\n\nexport const isApiRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);\n};\n\nexport const isApiUse = (file: string) => {\n return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);\n};\n\nexport const isPageRoute = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);\n};\n\nexport const isPageLayout = (file: string) => {\n return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);\n};\n\nexport const createRouteEntry = (\n fileFullpath: string,\n sourceFolder: SourceFolder,\n): RouteEntry | undefined => {\n // scanner already is doing a great job on matching only relevant files\n // but doing a double check here to make sure only needed files added to stack\n const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);\n\n if (!resolvedPaths) {\n return;\n }\n\n const [folder, file] = resolvedPaths;\n\n const id = `${file.replace(/\\W+/g, \"_\")}_${crc(file)}`;\n const name = dirname(file);\n\n try {\n const pathTokens = pathTokensFactory(dirname(file));\n return {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern: createPathPattern(pathTokens),\n honoPattern: createHonoPattern(pathTokens),\n };\n } catch (\n // biome-ignore lint: any\n error: any\n ) {\n console.error(\n `❗${styleText(\"red\", \"ERROR\")}: Failed parsing path for \"${styleText(\"cyan\", file)}\"`,\n );\n console.error(error.message);\n return;\n }\n};\n\n/**\n * Weight of a single path segment.\n *\n * Fixed values per kind prevent complex mixed segments\n * from outscoring multiple statics.\n *\n * static: 4 (exact match, most specific)\n * mixed: 3+ (static + param parts; more statics = slightly higher)\n * required: 2 (matches any single segment)\n * optional: 1 (may or may not match)\n * splat: 0 (matches anything, least specific)\n * */\nconst segmentWeight = (token: PathToken): number => {\n if (token.kind === \"static\") {\n return 4;\n }\n\n if (token.kind === \"mixed\") {\n let statics = 0;\n let optionals = 0;\n\n for (const part of token.parts) {\n if (part.type === \"static\") {\n statics += 1;\n } else if (part.kind === \"optional\" || part.kind === \"splat\") {\n optionals += 1;\n }\n }\n\n // unconditional statics contribute positively,\n // optionals penalize to avoid beating fully-static mixed routes\n return 3 + statics * 0.01 - optionals * 0.005;\n }\n\n const part = token.parts[0] as PathTokenParamPart;\n\n switch (part.kind) {\n case \"required\":\n return 2;\n case \"optional\":\n return 1;\n case \"splat\":\n return 0;\n }\n};\n\n/**\n * Compare two route entries for registration order.\n *\n * More specific routes sort first (higher priority).\n * Segments are compared left-to-right; first difference wins.\n *\n * When one route is a prefix of the other, the trailing segment\n * determines order: a trailing splat loses (shorter sibling first),\n * anything else wins (longer route is more specific).\n *\n * At equal weight and length, lexicographic tiebreak ensures\n * deterministic ordering across JS engines.\n * */\nexport const sortRoutes = (a: RouteEntry, b: RouteEntry): number => {\n const pairs = Array.from(\n { length: Math.max(a.pathTokens.length, b.pathTokens.length) },\n (_, i) => [a.pathTokens[i], b.pathTokens[i]] as const,\n );\n\n for (const [at, bt] of pairs) {\n if (!at || !bt) {\n // one route ran out of segments - check what the extra segment is\n const extra = at ?? bt;\n\n const isSplat =\n extra?.kind === \"param\"\n ? (extra.parts[0] as PathTokenParamPart).kind === \"splat\"\n : false;\n\n if (isSplat) {\n // trailing splat: shorter sibling registers first\n return at ? 1 : -1;\n }\n\n // trailing non-splat: longer route is more specific, registers first\n return at ? -1 : 1;\n }\n\n const aw = segmentWeight(at);\n const bw = segmentWeight(bt);\n\n if (aw !== bw) {\n return bw - aw;\n }\n }\n\n // same weight profile, same length: deterministic tiebreak\n return a.pathPattern.localeCompare(b.pathPattern);\n};\n","import { dirname, join, resolve } from \"node:path\";\nimport { styleText } from \"node:util\";\n\nimport crc from \"crc/crc32\";\nimport mimeTypes from \"mime-types\";\n\nimport {\n type ApiRoute,\n defaults,\n type PageRoute,\n type PathTokenParamPart,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n type ValidationDefinition,\n} from \"@kosmojs/core\";\n\nimport { astFactory } from \"../ast\";\nimport { pathResolver } from \"../paths\";\nimport { render, renderToFile } from \"../render\";\nimport * as templates from \"../templates\";\nimport type { ResolverSignature } from \"./base\";\n\nexport const resolverFactory = (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n): Record<\n | \"pageLayoutResolver\"\n | \"pageRouteResolver\"\n | \"apiUseResolver\"\n | \"apiRouteResolver\",\n (entry: RouteEntry) => ResolverSignature\n> => {\n const {\n //\n generators = [],\n refineTypeName = defaults.refineTypeName,\n } = sourceFolder.config;\n\n const { typeResolverFactory, resolveRouteSignature } = astFactory();\n\n const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);\n\n const {\n //\n literalTypesResolver,\n getSourceFile,\n refreshSourceFile,\n } = typeResolverFactory(sourceFolder);\n\n return {\n pageLayoutResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"pageLayout\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n pageRouteResolver(entry) {\n const {\n id,\n name,\n folder,\n file,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n const entry: PageRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n params: {\n schema: pathTokens.flatMap((e) => {\n return e.parts.filter((p) => p.type === \"param\");\n }),\n },\n folder,\n file,\n fileFullpath,\n };\n\n return {\n kind: \"pageRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiUseResolver(entry) {\n const { name } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async () => {\n return {\n kind: \"apiUse\",\n entry,\n };\n };\n\n return { name, handler };\n },\n\n apiRouteResolver(entry) {\n const {\n id,\n name,\n file,\n folder,\n fileFullpath,\n pathTokens,\n pathPattern,\n honoPattern,\n } = entry;\n\n const handler: ResolverSignature[\"handler\"] = async (updatedFile) => {\n const paramsSchema: Array<PathTokenParamPart> = pathTokens.flatMap(\n (e) => {\n return e.parts.flatMap((p) => {\n return p.type === \"param\" ? [p] : [];\n });\n },\n );\n\n const optionalParams = paramsSchema.length\n ? paramsSchema.filter((e) => e.kind === \"required\").length === 0\n : true;\n\n const cacheStore = cacheFactory\n ? cacheFactory({ id, file, fileFullpath }, sourceFolder, {\n resolveTypes,\n })\n : undefined;\n\n let cache = cacheStore\n ? await cacheStore.get({ validate: true })\n : undefined;\n\n if (!cache) {\n if (updatedFile === fileFullpath) {\n await refreshSourceFile(fileFullpath);\n }\n\n const {\n typeDeclarations,\n paramsRefinements,\n methods,\n validationDefinitions,\n referencedFiles = [],\n } = await resolveRouteSignature(\n { id, name, fileFullpath, optionalParams },\n {\n withReferencedFiles: true,\n sourceFile: getSourceFile(fileFullpath),\n relpathResolver(path) {\n return join(\n defaults.srcPrefix,\n defaults.apiDir,\n dirname(file),\n path,\n );\n },\n },\n );\n\n const validationTypes = validationDefinitions.flatMap<{\n id: string;\n text: string;\n }>((def) => {\n return def.target === \"response\"\n ? def.variants.flatMap(({ id, body }) => {\n return body ? [{ id, text: body }] : [];\n })\n : [def.schema];\n });\n\n const numericParams = paramsRefinements\n ? paramsRefinements.flatMap(({ text, index }) => {\n if (text === \"number\") {\n const param = paramsSchema.at(index);\n return param ? [param.name] : [];\n }\n return [];\n })\n : [];\n\n const typesFile = pathResolver(sourceFolder).createPath.libApi(\n dirname(file),\n \"types.ts\",\n );\n\n const params: ApiRoute[\"params\"] = {\n id: [\"ParamsT\", crc(name)].join(\"\"),\n schema: paramsSchema,\n resolvedType: undefined,\n };\n\n const typesFileContent = render(templates.typesFile, {\n params,\n paramsSchema: paramsSchema.map((param, index) => {\n return {\n ...param,\n isRequired: param.kind === \"required\",\n isSplat: param.kind === \"splat\",\n refinement: paramsRefinements?.at(index),\n };\n }),\n typeDeclarations,\n validationTypes,\n });\n\n const resolvedTypes = resolveTypes\n ? literalTypesResolver(typesFileContent, {\n stripComments: true,\n overrides: { [refineTypeName]: refineTypeName },\n withProperties: [\n params.id,\n ...validationTypes.flatMap(({ id }) => id),\n ],\n })\n : undefined;\n\n /**\n * Deploy types.ts file; required by core generators (like fetch).\n * If types resolved, write resolved types;\n * otherwise write original types extracted from API route.\n * */\n await renderToFile(\n typesFile,\n resolvedTypes ? templates.resolvedTypes : typesFileContent,\n { resolvedTypes },\n );\n\n params.resolvedType = resolvedTypes?.find(\n (e) => e.name === params.id,\n );\n\n cache = {\n // placeholder values, if cacheFactory given,\n // they will be replaced by persistCache\n hash: 0,\n referencedFiles: {},\n // real values\n params,\n methods,\n typeDeclarations,\n numericParams,\n validationDefinitions: validationDefinitions.map((def) => {\n return {\n ...def,\n ...(def.target === \"response\"\n ? {\n variants: def.variants.map((variant) => {\n return {\n ...variant,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === variant.id,\n ),\n };\n }),\n }\n : {\n schema: {\n ...def.schema,\n resolvedType: resolvedTypes?.find(\n (e) => e.name === def.schema.id,\n ),\n },\n }),\n };\n }),\n };\n\n if (cacheStore) {\n const { referencedFiles: _void, ...rest } = cache;\n cache = await cacheStore.set({ ...rest, referencedFiles });\n }\n }\n\n const validationDefinitions = cache.validationDefinitions.flatMap(\n (def) => {\n let augmentedDef: ValidationDefinition | undefined = def;\n\n if (def.target === \"response\") {\n augmentedDef = {\n ...def,\n variants: def.variants.flatMap((variant, i) => {\n if (typeof variant.contentType !== \"string\") {\n return [variant];\n }\n\n if (variant.contentType.includes(\"/\")) {\n return [variant];\n }\n\n const contentType = mimeTypes.lookup(variant.contentType);\n\n if (contentType === false) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${variant.contentType}`,\n );\n console.warn(\n styleText(\n [\"cyan\"],\n ` Response variant #${i} excluded from route schemas`,\n ),\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n return [];\n }\n\n return [{ ...variant, contentType }];\n }),\n };\n } else if (def.contentType && !def.contentType.includes(\"/\")) {\n const contentType = mimeTypes.lookup(def.contentType);\n if (contentType === false) {\n console.warn(\n styleText(\n [\"bold\", \"red\"],\n \"✗ Failed resolving Response Content Type\",\n ),\n );\n console.warn(\n ` Invalid value provided for mime-types lookup - ${def.contentType}`,\n );\n console.warn(` Route: ${name}; Method: ${def.method}`);\n console.warn();\n } else {\n augmentedDef = { ...def, contentType };\n }\n }\n\n return augmentedDef ? [augmentedDef] : [];\n },\n );\n\n const entry: ApiRoute = {\n id,\n name,\n pathTokens,\n pathPattern,\n honoPattern,\n params: cache.params,\n numericParams: cache.numericParams,\n optionalParams,\n folder,\n file,\n fileFullpath,\n methods: cache.methods,\n typeDeclarations: cache.typeDeclarations,\n validationDefinitions,\n referencedFiles: Object.keys(cache.referencedFiles).map(\n // expand referenced files path,\n // they are stored as relative in cache\n (e) => resolve(sourceFolder.root, e),\n ),\n };\n\n return {\n kind: \"apiRoute\",\n entry,\n };\n };\n\n return { name, handler };\n },\n };\n};\n","import { basename } from \"node:path\";\n\nimport type { NestedRouteEntry, RouteEntry } from \"@kosmojs/core\";\n\nimport { PAGE_INDEX_BASENAME, PAGE_LAYOUT_BASENAME, sortRoutes } from \"./base\";\n\nexport const nestedRoutesFactory = (routeEntries: Array<RouteEntry>) => {\n const entryStack = structuredClone(routeEntries).sort(sortRoutes);\n\n /**\n * Group entries by name (at the same level, both layout and index share same name).\n *\n * Handle 3 cases:\n * - both index and layout exists\n * - only index exists\n * - only layout exists\n *\n * */\n const transformEntries = (\n entries: Array<RouteEntry>,\n parent?: RouteEntry,\n ): Array<NestedRouteEntry> => {\n return [...new Set(entries.map((e) => e.name))].flatMap((name) => {\n const nameEntries = entryStack.flatMap(({ fileFullpath, ...entry }) => {\n return entry.name === name ? [entry] : [];\n });\n\n const index = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_INDEX_BASENAME),\n ) as RouteEntry;\n\n const layout = nameEntries.find((e) =>\n basename(e.file).startsWith(PAGE_LAYOUT_BASENAME),\n ) as RouteEntry;\n\n if (index || layout) {\n return [\n {\n index: index\n ? {\n ...index,\n pathTokens: index.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n layout: layout\n ? {\n ...layout,\n pathTokens: layout.pathTokens.slice(\n parent?.pathTokens.length || 0,\n ),\n }\n : undefined,\n parent: parent?.name,\n children: transformEntries(\n findDescendantEntries(index || layout),\n index || layout,\n ),\n },\n ];\n }\n\n return [];\n });\n };\n\n /**\n * Recursively finds direct descendant routes.\n *\n * \"Direct\" means the next existing route in the path hierarchy,\n * skipping intermediate path segments that don't have index/layout files.\n *\n * Example: blog/post/[slug]/index.tsx is a direct child of blog/index.tsx\n * even though \"post\" segment exists (it has no index.tsx).\n * */\n const findDescendantEntries = ({\n name,\n pathTokens,\n }: RouteEntry): Array<RouteEntry> => {\n // Find all potential children - BOTH indexes AND layouts\n const potentialChildren = entryStack.filter((entry) => {\n // Must be deeper than current entry\n if (entry.pathTokens.length <= pathTokens.length) {\n return false;\n }\n // Must be a descendant path\n if (!entry.name.startsWith(`${name}/`)) {\n return false;\n }\n return true;\n });\n\n // Filter to direct children (no intermediate route between parent and child)\n return potentialChildren.filter((child) => {\n // Check if any route exists between parent and child\n const hasIntermediateRoute = potentialChildren.some((intermediate) => {\n if (intermediate === child) {\n return false;\n }\n // Intermediate must be between parent and child in depth\n if (intermediate.pathTokens.length <= pathTokens.length) {\n return false;\n }\n if (intermediate.pathTokens.length >= child.pathTokens.length) {\n return false;\n }\n // Child must be descendant of intermediate\n return child.name.startsWith(`${intermediate.name}/`);\n });\n\n return !hasIntermediateRoute;\n });\n };\n\n // Find root entries - entries that have no parent route\n const rootEntries = entryStack.filter((entry) => {\n // Check if any other entry could be its parent\n const hasParent = entryStack.some((potential) => {\n if (potential === entry) {\n return false;\n }\n if (potential.pathTokens.length >= entry.pathTokens.length) {\n return false;\n }\n return entry.name.startsWith(`${potential.name}/`);\n });\n\n return !hasParent;\n });\n\n return transformEntries(rootEntries);\n};\n","import {\n defaults,\n type RouteEntry,\n type RouteResolverCacheFactory,\n type SourceFolder,\n} from \"@kosmojs/core\";\n\nimport {\n createRouteEntry,\n isApiRoute,\n isApiUse,\n isPageLayout,\n isPageRoute,\n type ResolverSignature,\n scanRoutes,\n} from \"./base\";\nimport { resolverFactory } from \"./resolve\";\n\nexport * from \"./base\";\nexport * from \"./nesting\";\nexport * from \"./paths\";\n\nexport const routesFactory = async (\n sourceFolder: SourceFolder,\n cacheFactory?: RouteResolverCacheFactory,\n) => {\n const {\n apiRouteResolver,\n apiUseResolver,\n pageRouteResolver,\n pageLayoutResolver,\n } = resolverFactory(sourceFolder, cacheFactory);\n\n const resolversFactory = (routeFiles: Array<string>) => {\n const resolvers = new Map<\n string, // fileFullpath\n ResolverSignature\n >();\n\n const entries: Array<RouteEntry> = routeFiles.flatMap((file) => {\n const entry = createRouteEntry(file, sourceFolder);\n return entry ? [entry] : [];\n });\n\n for (const entry of entries) {\n if (entry.folder === defaults.apiDir) {\n if (isApiRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, apiRouteResolver(entry));\n } else if (isApiUse(entry.file)) {\n resolvers.set(entry.fileFullpath, apiUseResolver(entry));\n }\n } else if (entry.folder === defaults.pagesDir) {\n if (isPageRoute(entry.file)) {\n resolvers.set(entry.fileFullpath, pageRouteResolver(entry));\n } else if (isPageLayout(entry.file)) {\n resolvers.set(entry.fileFullpath, pageLayoutResolver(entry));\n }\n }\n }\n\n return resolvers;\n };\n\n const routeFiles = await scanRoutes(sourceFolder);\n\n return {\n resolvers: resolversFactory(routeFiles),\n resolversFactory,\n };\n};\n","import { Spinner } from \"@topcli/spinner\";\n\nexport type SpinnerFactory = {\n text: (text: string) => void;\n append: (text: string) => void;\n succeed: (text?: string) => void;\n failed: (text?: string) => void;\n};\n\nexport const spinnerFactory = (startText: string): SpinnerFactory => {\n const spinner = new Spinner().start(startText);\n let _text = startText;\n return {\n text(text) {\n _text = text;\n spinner.text = text;\n },\n append(text) {\n spinner.text = `${_text} › ${text}`;\n },\n succeed(text) {\n if (text) {\n this.append(text);\n } else {\n this.text(_text);\n }\n spinner.succeed();\n },\n failed(text) {\n if (text) {\n this.text([_text, text].join(\"\\n\"));\n }\n spinner.failed();\n },\n };\n};\n\nexport const withSpinner = (\n text: string,\n pipe: (spinner: SpinnerFactory) => void | Promise<void>,\n spinner?: SpinnerFactory,\n) => pipe(spinner || spinnerFactory(text));\n","import { stat } from \"node:fs/promises\";\nimport { builtinModules } from \"node:module\";\nimport { isAbsolute, join, parse } from \"node:path\";\n\nimport type { Plugin } from \"vite\";\n\nimport { defaults, type SourceFolder } from \"@kosmojs/core\";\n\nimport { pathResolver } from \"./paths\";\n\n/**\n * Resolves Kosmo's generated import prefixes to absolute file paths.\n *\n * WHY THIS EXISTS\n * ---------------\n * Every source folder is scaffolded with three tsconfig `paths` prefixes\n * that let generated and user code import across\n * the folder's layout without long relative chains:\n *\n * appPrefix \"@\" -> the project root (<root>/*)\n * srcPrefix \"~\" -> the folder's src dir (<root>/src/<name>/*)\n * libPrefix \"_\" -> the folder's lib dir (<root>/lib/<name>/*)\n *\n * These are the backbone of the generated code: `defineRoute` and friends are\n * emitted with `_/...` imports, pages import layouts and components via `~/...`,\n * and `@/...` reaches shared app-level modules. If a bundler cannot resolve\n * them, nothing the framework generates can be loaded.\n *\n * Historically Vite resolved these through its built-in `resolve.tsconfigPaths: true`,\n * reading the `paths` straight from the generated tsconfig. That option\n * regressed in Vite 8.1.0 (still broken as of 8.1.3): it stops resolving\n * `paths` mappings, especially those defined in an extended / referenced base\n * config - which is exactly Kosmo's structure, where a source folder's\n * tsconfig `extends` `lib/<name>/tsconfig.base.json` and the paths use the\n * TypeScript `${configDir}` variable. The failure surfaces as:\n *\n * [vite] Failed to resolve import \"_/pageSamples/welcome.vue\" from\n * \"src/<name>/pages/index/index.vue\". Does the file exist?\n *\n * (Upstream: vitejs/vite #22139, #22047, #22371, #21889, #21856.)\n *\n * Rather than pin Vite to 8.0.x indefinitely, or depend on the general-purpose\n * `vite-tsconfig-paths` plugin, this internal plugin resolves ONLY\n * known prefixes against dirs derived from the source folder. That makes it:\n *\n * - Correct on 8.1.x, where native `tsconfigPaths` is broken.\n * - Faster: no tsconfig discovery, no `extends` chain walking, no glob\n * matching - just a prefix check and a handful of `stat` probes,\n * cached by Vite per specifier.\n * - Non-blocking: probes via async `fs/promises` `stat`, so `resolveId` never\n * stalls the event loop.\n * - `.vue` / `.mdx`-aware: `resolveId` sees every specifier regardless of the\n * importer's type, so imports from non-JS files resolve without the\n * `loose` / `allowJs` escape hatches `vite-tsconfig-paths` needs.\n *\n * A project with custom `paths` beyond these three prefixes should install\n * `vite-tsconfig-paths`; this plugin is internal and intentionally narrow.\n *\n * The prefix -> dir bases come from `pathResolver`, the same source of truth the\n * tsconfig generator uses, so alias resolution here can never drift from the\n * paths that were written into the generated tsconfig.\n * */\nexport const tsconfigPaths = (sourceFolder: SourceFolder): Plugin => {\n /**\n * Candidate extensions for an extensionless specifier, in resolution priority order.\n * Mirrors the renderable file types the generators emit;\n * a new page type (e.g. `.svelte`) must be added here or its aliased imports won't resolve.\n * */\n const EXTENSIONS = [\n \".ts\",\n \".tsx\",\n \".js\",\n \".jsx\",\n \".mjs\",\n \".vue\",\n \".md\",\n \".mdx\",\n \".json\",\n ];\n\n const { createPath } = pathResolver(sourceFolder);\n\n const table: Array<[prefix: string, baseDir: string]> = [\n [`${defaults.srcPrefix}/`, createPath.src()],\n [`${defaults.libPrefix}/`, createPath.lib()],\n [`${defaults.appPrefix}/`, sourceFolder.root],\n ];\n\n const resolveWithin = async (\n baseDir: string,\n rest: string,\n ): Promise<string> => {\n const target = join(baseDir, rest);\n const { ext } = parse(rest);\n\n // Specifier already carries a known extension: the target IS the candidate\n // (an explicit `foo.js` must not be probed as `foo.js.js`). Only fall back\n // to its `/index.<ext>` for a directory import that happens to end in a\n // known extension (rare, but keeps behaviour total).\n if (EXTENSIONS.includes(ext)) {\n for (const candidate of [target, `${target}/index${ext}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n return target;\n }\n\n // No known extension: probe each, plus its index form.\n for (const e of EXTENSIONS) {\n for (const candidate of [`${target}${e}`, `${target}/index${e}`]) {\n if (await isFile(candidate)) {\n return candidate;\n }\n }\n }\n\n return target;\n };\n\n return {\n name: \"kosmo:tsconfigPaths\",\n enforce: \"pre\",\n async resolveId(source) {\n if (isAbsolute(source) || source.startsWith(\".\")) {\n return;\n }\n for (const [prefix, baseDir] of table) {\n if (source.startsWith(prefix)) {\n return resolveWithin(baseDir, source.replace(prefix, \"\"));\n }\n }\n return;\n },\n };\n};\n\nconst nodePrefix = (): Plugin => {\n return {\n name: \"kosmojs:node-prefix\",\n enforce: \"pre\",\n resolveId(source) {\n return builtinModules.includes(source)\n ? { id: `node:${source}`, external: true }\n : undefined;\n },\n };\n};\n\nexport const vitePlugins = {\n tsconfigPaths,\n nodePrefix,\n};\n\nconst isFile = async (path: string) => {\n return stat(path)\n .then((e) => e.isFile())\n .catch(() => false);\n};\n"],"mappings":"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"}
package/pkg/vite.d.ts CHANGED
@@ -1,4 +1,61 @@
1
1
  import type { Plugin } from "vite";
2
+ import { type SourceFolder } from "@kosmojs/core";
3
+ /**
4
+ * Resolves Kosmo's generated import prefixes to absolute file paths.
5
+ *
6
+ * WHY THIS EXISTS
7
+ * ---------------
8
+ * Every source folder is scaffolded with three tsconfig `paths` prefixes
9
+ * that let generated and user code import across
10
+ * the folder's layout without long relative chains:
11
+ *
12
+ * appPrefix "@" -> the project root (<root>/*)
13
+ * srcPrefix "~" -> the folder's src dir (<root>/src/<name>/*)
14
+ * libPrefix "_" -> the folder's lib dir (<root>/lib/<name>/*)
15
+ *
16
+ * These are the backbone of the generated code: `defineRoute` and friends are
17
+ * emitted with `_/...` imports, pages import layouts and components via `~/...`,
18
+ * and `@/...` reaches shared app-level modules. If a bundler cannot resolve
19
+ * them, nothing the framework generates can be loaded.
20
+ *
21
+ * Historically Vite resolved these through its built-in `resolve.tsconfigPaths: true`,
22
+ * reading the `paths` straight from the generated tsconfig. That option
23
+ * regressed in Vite 8.1.0 (still broken as of 8.1.3): it stops resolving
24
+ * `paths` mappings, especially those defined in an extended / referenced base
25
+ * config - which is exactly Kosmo's structure, where a source folder's
26
+ * tsconfig `extends` `lib/<name>/tsconfig.base.json` and the paths use the
27
+ * TypeScript `${configDir}` variable. The failure surfaces as:
28
+ *
29
+ * [vite] Failed to resolve import "_/pageSamples/welcome.vue" from
30
+ * "src/<name>/pages/index/index.vue". Does the file exist?
31
+ *
32
+ * (Upstream: vitejs/vite #22139, #22047, #22371, #21889, #21856.)
33
+ *
34
+ * Rather than pin Vite to 8.0.x indefinitely, or depend on the general-purpose
35
+ * `vite-tsconfig-paths` plugin, this internal plugin resolves ONLY
36
+ * known prefixes against dirs derived from the source folder. That makes it:
37
+ *
38
+ * - Correct on 8.1.x, where native `tsconfigPaths` is broken.
39
+ * - Faster: no tsconfig discovery, no `extends` chain walking, no glob
40
+ * matching - just a prefix check and a handful of `stat` probes,
41
+ * cached by Vite per specifier.
42
+ * - Non-blocking: probes via async `fs/promises` `stat`, so `resolveId` never
43
+ * stalls the event loop.
44
+ * - `.vue` / `.mdx`-aware: `resolveId` sees every specifier regardless of the
45
+ * importer's type, so imports from non-JS files resolve without the
46
+ * `loose` / `allowJs` escape hatches `vite-tsconfig-paths` needs.
47
+ *
48
+ * A project with custom `paths` beyond these three prefixes should install
49
+ * `vite-tsconfig-paths`; this plugin is internal and intentionally narrow.
50
+ *
51
+ * The prefix -> dir bases come from `pathResolver`, the same source of truth the
52
+ * tsconfig generator uses, so alias resolution here can never drift from the
53
+ * paths that were written into the generated tsconfig.
54
+ * */
55
+ export declare const tsconfigPaths: (sourceFolder: SourceFolder) => Plugin;
56
+ declare const nodePrefix: () => Plugin;
2
57
  export declare const vitePlugins: {
3
- nodePrefix: () => Plugin;
58
+ tsconfigPaths: typeof tsconfigPaths;
59
+ nodePrefix: typeof nodePrefix;
4
60
  };
61
+ export {};
package/pkg/typebox.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { type SourceFolder } from "@kosmojs/core";
2
- export declare const typeboxLiteralText: (text: string, sourceFolder: SourceFolder) => string;
File without changes