@kosmojs/lib 0.0.26 → 0.0.28

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/pkg/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/ast.ts
2
- import { resolve } from "node:path";
2
+ import { join, resolve } from "node:path";
3
3
  import { styleText } from "node:util";
4
4
  import crc from "crc/crc32";
5
5
  import { flattener } from "tfusion";
@@ -8,9 +8,10 @@ import {
8
8
  SyntaxKind
9
9
  } from "ts-morph";
10
10
  import {
11
- HTTPMethods,
11
+ defaults,
12
12
  RequestValidationTargets
13
- } from "@kosmojs/api";
13
+ } from "@kosmojs/core";
14
+ import { HTTPMethods } from "@kosmojs/core/api";
14
15
  var astFactory = () => {
15
16
  const createProject = (opts) => new Project(opts);
16
17
  const resolveRouteSignature = async (route, opts) => {
@@ -272,6 +273,21 @@ var astFactory = () => {
272
273
  referencedFiles.push(...getReferencedFiles(defaultImport));
273
274
  }
274
275
  }
276
+ const namespaceImport = typeOnlyDeclaration ? declaration.getNamespaceImport() : void 0;
277
+ if (namespaceImport) {
278
+ const name = namespaceImport.getText();
279
+ const text = `import type * as ${name} from "${path}";`;
280
+ declarations.push({
281
+ importDeclaration: {
282
+ name,
283
+ path
284
+ },
285
+ text
286
+ });
287
+ if (referencedFiles) {
288
+ referencedFiles.push(...getReferencedFiles(namespaceImport));
289
+ }
290
+ }
275
291
  for (const namedImport of declaration.getNamedImports()) {
276
292
  if (namedImport.isTypeOnly() || typeOnlyDeclaration) {
277
293
  const nameNode = namedImport.getNameNode();
@@ -356,9 +372,12 @@ var astFactory = () => {
356
372
  const extractGenerics = (callExpression) => {
357
373
  return callExpression.getTypeArguments();
358
374
  };
359
- const typeResolverFactory = ({ root }) => {
375
+ const typeResolverFactory = ({ root, name }) => {
360
376
  const project = createProject({
361
- tsConfigFilePath: resolve(root, "tsconfig.json"),
377
+ tsConfigFilePath: resolve(
378
+ root,
379
+ join(defaults.srcDir, name, "tsconfig.json")
380
+ ),
362
381
  skipAddingFilesFromTsConfig: true
363
382
  });
364
383
  const literalTypesResolver = (literalTypes, options) => {
@@ -398,136 +417,105 @@ var astFactory = () => {
398
417
  };
399
418
  };
400
419
 
401
- // src/defaults.ts
402
- var defaults = {
403
- appPrefix: "~",
404
- srcPrefix: "@",
405
- libPrefix: "_",
406
- coreDir: "core",
407
- srcDir: "src",
408
- libDir: "lib",
409
- configDir: "config",
410
- apiDir: "api",
411
- pagesDir: "pages",
412
- entryDir: "entry",
413
- fetchDir: "fetch",
414
- refineTypeName: "VRefine"
415
- };
416
-
417
420
  // src/generators.ts
418
- var GENERATOR_META = /* @__PURE__ */ Symbol.for("KOSMO:GENERATOR_META");
419
- var defineGenerator = (factory, meta) => {
420
- const value = meta ? deepFreeze(structuredClone(meta)) : void 0;
421
- const defineProperty = (fn) => {
422
- Object.defineProperty(fn, GENERATOR_META, {
423
- value,
424
- enumerable: false,
425
- writable: false,
426
- configurable: false
427
- });
428
- return fn;
429
- };
430
- return defineProperty((...args) => {
431
- return defineProperty(factory(...args));
432
- });
433
- };
434
- var isGenerator = (fn) => {
435
- return GENERATOR_META in fn;
436
- };
437
- var getGeneratorMeta = (fn) => {
438
- return fn[GENERATOR_META];
439
- };
421
+ import picomatch from "picomatch";
422
+ var defineGenerator = (f) => f;
440
423
  var defineGeneratorFactory = (f) => f;
441
- var deepFreeze = (obj) => {
442
- if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
443
- Object.freeze(obj);
444
- for (const prop of Object.getOwnPropertyNames(obj)) {
445
- deepFreeze(obj[prop]);
424
+ var createTemplateResolver = (customTemplates, defaultTemplate) => {
425
+ const templates = Object.entries({
426
+ ...customTemplates
427
+ }).map(([pattern, template]) => [picomatch(pattern), template]);
428
+ return (pattern, entry) => {
429
+ const match = templates.find(([isMatch]) => isMatch(pattern));
430
+ if (!match) {
431
+ return defaultTemplate;
446
432
  }
447
- }
448
- return obj;
433
+ return typeof match[1] === "function" ? match[1](entry) : match[1];
434
+ };
449
435
  };
450
436
 
451
437
  // src/paths.ts
452
438
  import { access, constants } from "node:fs/promises";
453
- import { join, resolve as resolve2 } from "node:path";
454
- var createTsconfigPaths = (prefix) => {
455
- return {
456
- [`${defaults.appPrefix}/*`]: [`${prefix}/*`],
457
- [`${defaults.srcPrefix}/*`]: [`${prefix}/${defaults.srcDir}/*`],
458
- [`${defaults.libPrefix}/*`]: [
459
- `${prefix}/${defaults.libDir}/${defaults.srcDir}/*`
460
- ]
461
- };
462
- };
439
+ import { join as join2, resolve as resolve2 } from "node:path";
440
+ import { defaults as defaults2 } from "@kosmojs/core";
463
441
  var pathResolver = (sourceFolder) => {
464
442
  const createPath = (...a) => {
465
- return sourceFolder.root ? resolve2(sourceFolder.root, join(...a)) : join(...a);
443
+ return sourceFolder.root ? resolve2(sourceFolder.root, join2(...a)) : join2(...a);
466
444
  };
467
445
  const createImport = {
468
- src(...a) {
469
- return join(defaults.srcPrefix, sourceFolder.name, ...a);
446
+ src(a, { origin }) {
447
+ return origin === "src" ? join2(defaults2.srcPrefix, ...a) : join2(defaults2.appPrefix, defaults2.srcDir, sourceFolder.name, ...a);
448
+ },
449
+ config(a, o) {
450
+ return this.src([defaults2.configDir, ...a], o);
470
451
  },
471
- config(...a) {
472
- return this.src(defaults.configDir, ...a);
452
+ api(a, o) {
453
+ return this.src([defaults2.apiDir, ...a], o);
473
454
  },
474
- api(...a) {
475
- return this.src(defaults.apiDir, ...a);
455
+ pages(a, o) {
456
+ return this.src([defaults2.pagesDir, ...a], o);
476
457
  },
477
- pages(...a) {
478
- return this.src(defaults.pagesDir, ...a);
458
+ lib(a, { origin }) {
459
+ return origin === "src" ? join2(defaults2.libPrefix, ...a) : join2(defaults2.appPrefix, defaults2.libDir, sourceFolder.name, ...a);
479
460
  },
480
- lib(...a) {
481
- return join(defaults.libPrefix, sourceFolder.name, ...a);
461
+ libCore(a, o) {
462
+ return this.lib(["core", ...a], o);
482
463
  },
483
- libApi(...a) {
484
- return this.lib(defaults.apiDir, ...a);
464
+ libApi(a, o) {
465
+ return this.lib([defaults2.apiDir, ...a], o);
485
466
  },
486
- libEntry(...a) {
487
- return this.lib(defaults.entryDir, ...a);
467
+ libEntry(a, o) {
468
+ return this.lib([defaults2.entryDir, ...a], o);
488
469
  }
489
470
  };
490
471
  return {
491
472
  createPath: {
492
473
  src(...a) {
493
- return createPath(defaults.srcDir, sourceFolder.name, ...a);
474
+ return createPath(defaults2.srcDir, sourceFolder.name, ...a);
494
475
  },
495
476
  api(...a) {
496
- return this.src(defaults.apiDir, ...a);
477
+ return this.src(defaults2.apiDir, ...a);
497
478
  },
498
479
  pages(...a) {
499
- return this.src(defaults.pagesDir, ...a);
480
+ return this.src(defaults2.pagesDir, ...a);
500
481
  },
501
482
  config(...a) {
502
- return this.src(defaults.configDir, ...a);
483
+ return this.src(defaults2.configDir, ...a);
503
484
  },
504
485
  entry(...a) {
505
- return this.src(defaults.entryDir, ...a);
486
+ return this.src(defaults2.entryDir, ...a);
506
487
  },
507
488
  lib(...a) {
508
- return createPath(
509
- defaults.libDir,
510
- defaults.srcDir,
511
- sourceFolder.name,
512
- ...a
513
- );
489
+ return createPath(defaults2.libDir, sourceFolder.name, ...a);
490
+ },
491
+ libCore(...a) {
492
+ return this.lib("core", ...a);
514
493
  },
515
494
  libApi(...a) {
516
- return this.lib(defaults.apiDir, ...a);
495
+ return this.lib(defaults2.apiDir, ...a);
517
496
  },
518
497
  libEntry(...a) {
519
- return this.lib(defaults.entryDir, ...a);
498
+ return this.lib(defaults2.entryDir, ...a);
520
499
  },
521
500
  libPages(...a) {
522
- return this.lib(defaults.pagesDir, ...a);
501
+ return this.lib(defaults2.pagesDir, ...a);
523
502
  },
524
503
  distDir(...a) {
525
504
  return createPath(sourceFolder.distDir, sourceFolder.name, ...a);
526
505
  }
527
506
  },
528
507
  createImport,
529
- createImportHelper: (key, ...a) => {
530
- return createImport[key](...a.slice(0, -1));
508
+ createImportHelpers(o) {
509
+ if (!["src", "lib"].includes(o?.origin)) {
510
+ throw new Error(
511
+ `createImportHelpers: required exactly one argument of shape { origin: "src|lib" }`
512
+ );
513
+ }
514
+ return {
515
+ createImport(key, ...a) {
516
+ return createImport[key](a.slice(0, -1), o);
517
+ }
518
+ };
531
519
  }
532
520
  };
533
521
  };
@@ -542,7 +530,7 @@ var pathExists = async (path) => {
542
530
 
543
531
  // src/render.ts
544
532
  import { mkdir, readFile, writeFile } from "node:fs/promises";
545
- import { dirname, join as join2 } from "node:path";
533
+ import { dirname, join as join3 } from "node:path";
546
534
  import crc2 from "crc/crc32";
547
535
  import handlebars from "handlebars";
548
536
  var render = (template, context, options) => {
@@ -568,114 +556,59 @@ var renderToFile = async (file, template, context, options) => {
568
556
  await writeFile(file, content, "utf8");
569
557
  };
570
558
  var renderFactory = (options) => {
571
- const renderer = handlebars.create();
572
- renderer.registerPartial({ ...options?.partials });
573
- renderer.registerHelper({ ...options?.helpers });
559
+ const createRenderer = (selfOoptions) => {
560
+ const renderer = handlebars.create();
561
+ renderer.registerPartial({
562
+ ...options?.partials,
563
+ ...selfOoptions?.partials
564
+ });
565
+ renderer.registerHelper({
566
+ ...options?.helpers,
567
+ ...selfOoptions?.helpers
568
+ });
569
+ return renderer;
570
+ };
574
571
  return {
575
572
  render(template, context, selfOoptions) {
576
573
  return render(template, context, {
577
- renderer,
578
574
  ...options,
579
- ...selfOoptions
575
+ ...selfOoptions,
576
+ renderer: createRenderer(selfOoptions)
580
577
  });
581
578
  },
582
579
  async renderToFile(file, template, context, selfOoptions) {
583
580
  return renderToFile(
584
- options?.outdir ? join2(options.outdir, file) : file,
581
+ options?.outdir ? join3(options.outdir, file) : file,
585
582
  template,
586
583
  context,
587
- { renderer, ...options, ...selfOoptions }
584
+ {
585
+ ...options,
586
+ ...selfOoptions,
587
+ renderer: createRenderer(selfOoptions)
588
+ }
588
589
  );
589
590
  }
590
591
  };
591
592
  };
592
- var renderHelpers = {
593
- createParamsLiteral: (params) => {
594
- return params.schema.map((p) => {
595
- return p.kind === "splat" ? `${p.const}?: Array<string | number>` : p.kind === "optional" ? `${p.const}?: string | number` : `${p.const}: string | number`;
596
- }).join(", ");
597
- }
598
- };
593
+
594
+ // src/routes/index.ts
595
+ import {
596
+ defaults as defaults5
597
+ } from "@kosmojs/core";
599
598
 
600
599
  // src/routes/base.ts
601
- import { dirname as dirname2, join as join3, resolve as resolve3 } from "node:path";
600
+ import { dirname as dirname2, join as join4, resolve as resolve3 } from "node:path";
602
601
  import { styleText as styleText2 } from "node:util";
602
+ import crc4 from "crc/crc32";
603
+ import picomatch2 from "picomatch";
604
+ import { glob } from "tinyglobby";
605
+ import {
606
+ defaults as defaults3
607
+ } from "@kosmojs/core";
608
+
609
+ // src/routes/paths.ts
603
610
  import crc3 from "crc/crc32";
604
611
  import { parse } from "path-to-regexp";
605
- import picomatch from "picomatch";
606
- import { glob } from "tinyglobby";
607
- var API_INDEX_BASENAME = "index";
608
- var API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;
609
- var API_USE_BASENAME = "use";
610
- var API_USE_PATTERN = `${API_USE_BASENAME}.ts`;
611
- var PAGE_INDEX_BASENAME = "index";
612
- var PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue}`;
613
- var PAGE_LAYOUT_BASENAME = "layout";
614
- var PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue}`;
615
- var ROUTE_FILE_PATTERNS = [
616
- // match index files in api dir
617
- `${defaults.apiDir}/**/${API_INDEX_PATTERN}`,
618
- // match use files in api dir
619
- `${defaults.apiDir}/**/${API_USE_PATTERN}`,
620
- // match index files in pages dir
621
- `${defaults.pagesDir}/**/${PAGE_INDEX_PATTERN}`,
622
- // match layout files in pages dir
623
- `${defaults.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`
624
- ];
625
- var scanRoutes = async (sourceFolder) => {
626
- const { createPath } = pathResolver(sourceFolder);
627
- return glob(ROUTE_FILE_PATTERNS, {
628
- cwd: createPath.src(),
629
- absolute: true,
630
- onlyFiles: true,
631
- followSymbolicLinks: false,
632
- ignore: [
633
- // ignore top-level matches, routes resides in folders, even index route
634
- `${defaults.apiDir}/${API_INDEX_PATTERN}`,
635
- `${defaults.apiDir}/${API_USE_PATTERN}`,
636
- `${defaults.pagesDir}/${PAGE_INDEX_PATTERN}`,
637
- `${defaults.pagesDir}/${PAGE_LAYOUT_PATTERN}`
638
- ]
639
- });
640
- };
641
- var isRouteFile = (file, sourceFolder) => {
642
- const [_sourceFolder, _folder, ...rest] = resolve3(sourceFolder.root, file).replace(`${sourceFolder.root}/${defaults.srcDir}/`, "").split("/");
643
- if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {
644
- return false;
645
- }
646
- return picomatch.isMatch(join3(_folder, ...rest), ROUTE_FILE_PATTERNS) ? [_folder, rest.join("/")] : false;
647
- };
648
- var isApiRoute = (file) => {
649
- return picomatch.matchBase(file, `**/${API_INDEX_PATTERN}`);
650
- };
651
- var isApiUse = (file) => {
652
- return picomatch.matchBase(file, `**/${API_USE_PATTERN}`);
653
- };
654
- var isPageRoute = (file) => {
655
- return picomatch.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);
656
- };
657
- var isPageLayout = (file) => {
658
- return picomatch.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);
659
- };
660
- var createRouteEntry = (fileFullpath, sourceFolder) => {
661
- const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);
662
- if (!resolvedPaths) {
663
- return;
664
- }
665
- const [folder, file] = resolvedPaths;
666
- const id = `${file.replace(/\W+/g, "_")}_${crc3(file)}`;
667
- const name = dirname2(file);
668
- try {
669
- const [pathTokens, pathPattern] = pathTokensFactory(dirname2(file));
670
- return { id, name, folder, file, fileFullpath, pathTokens, pathPattern };
671
- } catch (error) {
672
- console.error(
673
- `\u2757${styleText2("red", "ERROR")}: Failed parsing path for "${styleText2("cyan", file)}"`
674
- );
675
- console.error(error);
676
- return;
677
- }
678
- };
679
612
  var pathTokensFactory = (path, {
680
613
  transformStaticValue = normalizeStaticValue
681
614
  } = {}) => {
@@ -765,7 +698,9 @@ var pathTokensFactory = (path, {
765
698
  );
766
699
  }
767
700
  const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
768
- const { tokens: tokens2 } = parse(pattern);
701
+ const { tokens: tokens2 } = parse(
702
+ pattern.replace(/\{[^}]*\}|(\+)/g, (m, p1) => p1 ? "\\+" : m)
703
+ );
769
704
  const parts = extractParts(tokens2, (val) => {
770
705
  return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc3(orig)].join("_") : val;
771
706
  });
@@ -781,70 +716,219 @@ var pathTokensFactory = (path, {
781
716
  }
782
717
  ];
783
718
  });
784
- return [
785
- tokens,
786
- tokens.map(({ pattern }, i) => {
787
- const next = tokens[i + 1];
788
- if (!next || next.pattern.includes("/")) {
789
- return pattern;
790
- }
791
- const slashRequired = tokens.slice(i + 1).some((e) => {
792
- return e.parts.some((e2) => {
793
- return e2.type === "static" || e2.kind === "required";
794
- });
719
+ return tokens;
720
+ };
721
+ var createPathPattern = (tokens) => {
722
+ return tokens.map(({ pattern }, i) => {
723
+ const next = tokens[i + 1];
724
+ if (!next || next.pattern.includes("/")) {
725
+ return pattern;
726
+ }
727
+ const slashRequired = tokens.slice(i + 1).some((e) => {
728
+ return e.parts.some((e2) => {
729
+ return e2.type === "static" || e2.kind === "required";
795
730
  });
796
- return slashRequired ? `${pattern}/` : pattern;
797
- }).join("")
798
- ];
731
+ });
732
+ return slashRequired ? `${pattern}/` : pattern;
733
+ }).join("");
734
+ };
735
+ var createHonoPattern = (tokens) => {
736
+ const staticValue = ({ value }) => {
737
+ return normalizeStaticValue(value);
738
+ };
739
+ const paramValue = (p) => {
740
+ if (p.kind === "splat") {
741
+ return `*`;
742
+ }
743
+ if (p.kind === "optional") {
744
+ return `:${p.name}?`;
745
+ }
746
+ return `:${p.name}`;
747
+ };
748
+ const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
749
+ const tokensToRegex = (tokens2) => {
750
+ return tokens2.flatMap((t) => {
751
+ if (t.type === "text") {
752
+ return t.value === "/" ? [] : [escapeRegex(t.value)];
753
+ }
754
+ if (t.type === "wildcard") {
755
+ return [".+"];
756
+ }
757
+ if (t.type === "param") {
758
+ return ["[^/]+"];
759
+ }
760
+ if (t.type === "group") {
761
+ return [`(?:${tokensToRegex(t.tokens)})?`];
762
+ }
763
+ return [];
764
+ }).join("");
765
+ };
766
+ return tokens.flatMap((token, i) => {
767
+ if (token.kind === "static") {
768
+ return [staticValue(token.parts[0])];
769
+ }
770
+ if (token.kind === "param") {
771
+ return [paramValue(token.parts[0])];
772
+ }
773
+ const { tokens: tokens2 } = parse(token.pattern.replace(/\//g, ""));
774
+ const regex = tokensToRegex(tokens2);
775
+ return [`:_${i}{${regex}}`];
776
+ }).join("/");
799
777
  };
800
778
  var normalizeStaticValue = (value) => {
801
779
  return value.replace(/\+/g, "\\\\+");
802
780
  };
803
- var sortRoutes = (a, b) => {
804
- const aSpecificity = routeSpecificity(a.pathTokens);
805
- const bSpecificity = routeSpecificity(b.pathTokens);
806
- if (aSpecificity !== bSpecificity) {
807
- return bSpecificity - aSpecificity;
808
- }
809
- if (a.pathTokens.length !== b.pathTokens.length) {
810
- return a.pathTokens.length - b.pathTokens.length;
781
+
782
+ // src/routes/base.ts
783
+ var API_INDEX_BASENAME = "index";
784
+ var API_INDEX_PATTERN = `${API_INDEX_BASENAME}.ts`;
785
+ var API_USE_BASENAME = "use";
786
+ var API_USE_PATTERN = `${API_USE_BASENAME}.ts`;
787
+ var PAGE_INDEX_BASENAME = "index";
788
+ var PAGE_INDEX_PATTERN = `${PAGE_INDEX_BASENAME}.{tsx,vue,mdx,md}`;
789
+ var PAGE_LAYOUT_BASENAME = "layout";
790
+ var PAGE_LAYOUT_PATTERN = `${PAGE_LAYOUT_BASENAME}.{tsx,vue,mdx}`;
791
+ var ROUTE_FILE_PATTERNS = [
792
+ // match index files in api dir
793
+ `${defaults3.apiDir}/**/${API_INDEX_PATTERN}`,
794
+ // match use files in api dir
795
+ `${defaults3.apiDir}/**/${API_USE_PATTERN}`,
796
+ // match index files in pages dir
797
+ `${defaults3.pagesDir}/**/${PAGE_INDEX_PATTERN}`,
798
+ // match layout files in pages dir
799
+ `${defaults3.pagesDir}/**/${PAGE_LAYOUT_PATTERN}`
800
+ ];
801
+ var scanRoutes = async (sourceFolder) => {
802
+ const { createPath } = pathResolver(sourceFolder);
803
+ return glob(ROUTE_FILE_PATTERNS, {
804
+ cwd: createPath.src(),
805
+ absolute: true,
806
+ onlyFiles: true,
807
+ followSymbolicLinks: false,
808
+ ignore: [
809
+ // ignore top-level matches, routes resides in folders, even index route
810
+ `${defaults3.apiDir}/${API_INDEX_PATTERN}`,
811
+ `${defaults3.apiDir}/${API_USE_PATTERN}`,
812
+ `${defaults3.pagesDir}/${PAGE_INDEX_PATTERN}`,
813
+ `${defaults3.pagesDir}/${PAGE_LAYOUT_PATTERN}`
814
+ ]
815
+ });
816
+ };
817
+ var isRouteFile = (file, sourceFolder) => {
818
+ const [
819
+ // source folder name
820
+ _sourceFolder,
821
+ // route folder, api or pages
822
+ _folder,
823
+ ...rest
824
+ ] = resolve3(sourceFolder.root, file).replace(`${sourceFolder.root}/${defaults3.srcDir}/`, "").split("/");
825
+ if (!_folder || _sourceFolder !== sourceFolder.name || rest.length < 2) {
826
+ return false;
811
827
  }
812
- return a.name.localeCompare(b.name);
828
+ return picomatch2.isMatch(join4(_folder, ...rest), ROUTE_FILE_PATTERNS) ? [_folder, rest.join("/")] : false;
813
829
  };
814
- var paramWeight = (part) => {
815
- return {
816
- required: 2,
817
- optional: 1,
818
- splat: 0
819
- }[part.kind];
830
+ var isApiRoute = (file) => {
831
+ return picomatch2.matchBase(file, `**/${API_INDEX_PATTERN}`);
820
832
  };
821
- var mixedSegmentWeight = (parts) => {
822
- const hasSplat = parts.some((p) => {
823
- return p.type === "param" ? p.kind === "splat" : false;
824
- });
825
- return hasSplat ? 0.5 : 3;
833
+ var isApiUse = (file) => {
834
+ return picomatch2.matchBase(file, `**/${API_USE_PATTERN}`);
835
+ };
836
+ var isPageRoute = (file) => {
837
+ return picomatch2.matchBase(file, `**/${PAGE_INDEX_PATTERN}`);
838
+ };
839
+ var isPageLayout = (file) => {
840
+ return picomatch2.matchBase(file, `**/${PAGE_LAYOUT_PATTERN}`);
841
+ };
842
+ var createRouteEntry = (fileFullpath, sourceFolder) => {
843
+ const resolvedPaths = isRouteFile(fileFullpath, sourceFolder);
844
+ if (!resolvedPaths) {
845
+ return;
846
+ }
847
+ const [folder, file] = resolvedPaths;
848
+ const id = `${file.replace(/\W+/g, "_")}_${crc4(file)}`;
849
+ const name = dirname2(file);
850
+ try {
851
+ const pathTokens = pathTokensFactory(dirname2(file));
852
+ return {
853
+ id,
854
+ name,
855
+ folder,
856
+ file,
857
+ fileFullpath,
858
+ pathTokens,
859
+ pathPattern: createPathPattern(pathTokens),
860
+ honoPattern: createHonoPattern(pathTokens)
861
+ };
862
+ } catch (error) {
863
+ console.error(
864
+ `\u2757${styleText2("red", "ERROR")}: Failed parsing path for "${styleText2("cyan", file)}"`
865
+ );
866
+ console.error(error);
867
+ return;
868
+ }
826
869
  };
827
870
  var segmentWeight = (token) => {
828
- return {
829
- static: 4,
830
- mixed: mixedSegmentWeight(token.parts),
831
- param: paramWeight(token.parts[0])
832
- }[token.kind];
871
+ if (token.kind === "static") {
872
+ return 4;
873
+ }
874
+ if (token.kind === "mixed") {
875
+ let statics = 0;
876
+ let optionals = 0;
877
+ for (const part2 of token.parts) {
878
+ if (part2.type === "static") {
879
+ statics += 1;
880
+ } else if (part2.kind === "optional" || part2.kind === "splat") {
881
+ optionals += 1;
882
+ }
883
+ }
884
+ return 3 + statics * 0.01 - optionals * 5e-3;
885
+ }
886
+ const part = token.parts[0];
887
+ switch (part.kind) {
888
+ case "required":
889
+ return 2;
890
+ case "optional":
891
+ return 1;
892
+ case "splat":
893
+ return 0;
894
+ }
833
895
  };
834
- var routeSpecificity = (pathTokens) => {
835
- return pathTokens.reduce((sum, token) => sum + segmentWeight(token), 0);
896
+ var sortRoutes = (a, b) => {
897
+ const pairs = Array.from(
898
+ { length: Math.max(a.pathTokens.length, b.pathTokens.length) },
899
+ (_, i) => [a.pathTokens[i], b.pathTokens[i]]
900
+ );
901
+ for (const [at, bt] of pairs) {
902
+ if (!at || !bt) {
903
+ const extra = at ?? bt;
904
+ const isSplat = extra?.kind === "param" ? extra.parts[0].kind === "splat" : false;
905
+ if (isSplat) {
906
+ return at ? 1 : -1;
907
+ }
908
+ return at ? -1 : 1;
909
+ }
910
+ const aw = segmentWeight(at);
911
+ const bw = segmentWeight(bt);
912
+ if (aw !== bw) {
913
+ return bw - aw;
914
+ }
915
+ }
916
+ return a.pathPattern.localeCompare(b.pathPattern);
836
917
  };
837
918
 
838
919
  // src/routes/resolve.ts
839
- import { dirname as dirname3, join as join4, resolve as resolve4 } from "node:path";
920
+ import { dirname as dirname3, join as join5, resolve as resolve4 } from "node:path";
840
921
  import { styleText as styleText3 } from "node:util";
841
- import crc4 from "crc/crc32";
922
+ import crc5 from "crc/crc32";
842
923
  import mimeTypes from "mime-types";
924
+ import {
925
+ defaults as defaults4
926
+ } from "@kosmojs/core";
843
927
 
844
- // src/routes/templates/resolved-types.hbs
928
+ // src/templates/resolved-types.hbs
845
929
  var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
846
930
 
847
- // src/routes/templates/types.hbs
931
+ // src/templates/types.hbs
848
932
  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';
849
933
 
850
934
  // src/routes/resolve.ts
@@ -852,12 +936,10 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
852
936
  const {
853
937
  //
854
938
  generators = [],
855
- refineTypeName = defaults.refineTypeName
939
+ refineTypeName = defaults4.refineTypeName
856
940
  } = sourceFolder.config;
857
941
  const { typeResolverFactory, resolveRouteSignature } = astFactory();
858
- const resolveTypes = generators.some(
859
- (e) => getGeneratorMeta(e)?.resolveTypes
860
- );
942
+ const resolveTypes = generators.some(({ meta }) => meta.resolveTypes);
861
943
  const {
862
944
  //
863
945
  literalTypesResolver,
@@ -876,13 +958,23 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
876
958
  return { name, handler };
877
959
  },
878
960
  pageRouteResolver(entry) {
879
- const { id, name, folder, file, fileFullpath, pathTokens, pathPattern } = entry;
961
+ const {
962
+ id,
963
+ name,
964
+ folder,
965
+ file,
966
+ fileFullpath,
967
+ pathTokens,
968
+ pathPattern,
969
+ honoPattern
970
+ } = entry;
880
971
  const handler = async () => {
881
972
  const entry2 = {
882
973
  id,
883
974
  name,
884
975
  pathTokens,
885
976
  pathPattern,
977
+ honoPattern,
886
978
  params: {
887
979
  schema: pathTokens.flatMap((e) => {
888
980
  return e.parts.filter((p) => p.type === "param");
@@ -911,14 +1003,14 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
911
1003
  },
912
1004
  apiRouteResolver(entry) {
913
1005
  const {
914
- //
915
1006
  id,
916
1007
  name,
917
1008
  file,
918
1009
  folder,
919
1010
  fileFullpath,
920
1011
  pathTokens,
921
- pathPattern
1012
+ pathPattern,
1013
+ honoPattern
922
1014
  } = entry;
923
1015
  const handler = async (updatedFile) => {
924
1016
  const paramsSchema = pathTokens.flatMap(
@@ -949,9 +1041,9 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
949
1041
  withReferencedFiles: true,
950
1042
  sourceFile: getSourceFile(fileFullpath),
951
1043
  relpathResolver(path) {
952
- return join4(
1044
+ return join5(
953
1045
  sourceFolder.name,
954
- defaults.apiDir,
1046
+ defaults4.apiDir,
955
1047
  dirname3(file),
956
1048
  path
957
1049
  );
@@ -975,7 +1067,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
975
1067
  "types.ts"
976
1068
  );
977
1069
  const params = {
978
- id: ["ParamsT", crc4(name)].join(""),
1070
+ id: ["ParamsT", crc5(name)].join(""),
979
1071
  schema: paramsSchema,
980
1072
  resolvedType: void 0
981
1073
  };
@@ -1109,6 +1201,7 @@ var resolverFactory = (sourceFolder, cacheFactory) => {
1109
1201
  name,
1110
1202
  pathTokens,
1111
1203
  pathPattern,
1204
+ honoPattern,
1112
1205
  params: cache.params,
1113
1206
  numericParams: cache.numericParams,
1114
1207
  optionalParams,
@@ -1234,13 +1327,13 @@ var routesFactory = async (sourceFolder, cacheFactory) => {
1234
1327
  return entry ? [entry] : [];
1235
1328
  });
1236
1329
  for (const entry of entries) {
1237
- if (entry.folder === defaults.apiDir) {
1330
+ if (entry.folder === defaults5.apiDir) {
1238
1331
  if (isApiRoute(entry.file)) {
1239
1332
  resolvers.set(entry.fileFullpath, apiRouteResolver(entry));
1240
1333
  } else if (isApiUse(entry.file)) {
1241
1334
  resolvers.set(entry.fileFullpath, apiUseResolver(entry));
1242
1335
  }
1243
- } else if (entry.folder === defaults.pagesDir) {
1336
+ } else if (entry.folder === defaults5.pagesDir) {
1244
1337
  if (isPageRoute(entry.file)) {
1245
1338
  resolvers.set(entry.fileFullpath, pageRouteResolver(entry));
1246
1339
  } else if (isPageLayout(entry.file)) {
@@ -1289,8 +1382,9 @@ var spinnerFactory = (startText) => {
1289
1382
  var withSpinner = (text, pipe, spinner) => pipe(spinner || spinnerFactory(text));
1290
1383
 
1291
1384
  // src/typebox.ts
1385
+ import { defaults as defaults6 } from "@kosmojs/core";
1292
1386
  var typeboxLiteralText = (text, sourceFolder) => {
1293
- const { refineTypeName = defaults.refineTypeName } = sourceFolder.config;
1387
+ const { refineTypeName = defaults6.refineTypeName } = sourceFolder.config;
1294
1388
  return [
1295
1389
  // Escape backticks for safe use in template literals
1296
1390
  [/(?<!\\)`/g, "\\`"],
@@ -1304,26 +1398,39 @@ var typeboxLiteralText = (text, sourceFolder) => {
1304
1398
  [new RegExp(`\\b${refineTypeName}\\s*<`, "g"), "Options<"]
1305
1399
  ].reduce((text2, [a, b]) => text2.replace(a, b), text);
1306
1400
  };
1401
+
1402
+ // src/vite.ts
1403
+ import { builtinModules } from "node:module";
1404
+ var nodePrefix = () => {
1405
+ return {
1406
+ name: "kosmojs:node-prefix",
1407
+ enforce: "pre",
1408
+ resolveId(source) {
1409
+ return builtinModules.includes(source) ? { id: `node:${source}`, external: true } : void 0;
1410
+ }
1411
+ };
1412
+ };
1413
+ var vitePlugins = {
1414
+ nodePrefix
1415
+ };
1307
1416
  export {
1308
1417
  API_INDEX_BASENAME,
1309
1418
  API_INDEX_PATTERN,
1310
1419
  API_USE_BASENAME,
1311
1420
  API_USE_PATTERN,
1312
- GENERATOR_META,
1313
1421
  PAGE_INDEX_BASENAME,
1314
1422
  PAGE_INDEX_PATTERN,
1315
1423
  PAGE_LAYOUT_BASENAME,
1316
1424
  PAGE_LAYOUT_PATTERN,
1317
1425
  astFactory,
1426
+ createHonoPattern,
1427
+ createPathPattern,
1318
1428
  createRouteEntry,
1319
- createTsconfigPaths,
1320
- defaults,
1429
+ createTemplateResolver,
1321
1430
  defineGenerator,
1322
1431
  defineGeneratorFactory,
1323
- getGeneratorMeta,
1324
1432
  isApiRoute,
1325
1433
  isApiUse,
1326
- isGenerator,
1327
1434
  isPageLayout,
1328
1435
  isPageRoute,
1329
1436
  isRouteFile,
@@ -1334,13 +1441,13 @@ export {
1334
1441
  pathTokensFactory,
1335
1442
  render,
1336
1443
  renderFactory,
1337
- renderHelpers,
1338
1444
  renderToFile,
1339
1445
  routesFactory,
1340
1446
  scanRoutes,
1341
1447
  sortRoutes,
1342
1448
  spinnerFactory,
1343
1449
  typeboxLiteralText,
1450
+ vitePlugins,
1344
1451
  withSpinner
1345
1452
  };
1346
1453
  //# sourceMappingURL=index.js.map