@dudousxd/nestjs-codegen 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -336,10 +336,19 @@ function followModuleForType(name, moduleSpecifier, fromFile, project, seen) {
336
336
  }
337
337
  return null;
338
338
  }
339
+ var _findTypeCache = /* @__PURE__ */ new WeakMap();
339
340
  function findType(name, sourceFile, project) {
341
+ let byKey = _findTypeCache.get(project);
342
+ if (byKey === void 0) {
343
+ byKey = /* @__PURE__ */ new Map();
344
+ _findTypeCache.set(project, byKey);
345
+ }
346
+ const key = `${sourceFile.getFilePath()}\0${name}`;
347
+ if (byKey.has(key)) return byKey.get(key) ?? null;
340
348
  const local = findTypeInFile(name, sourceFile);
341
- if (local) return local;
342
- return resolveImportedType(name, sourceFile, project);
349
+ const result = local ?? resolveImportedType(name, sourceFile, project);
350
+ byKey.set(key, result);
351
+ return result;
343
352
  }
344
353
  var _NON_REF_NAMES = /* @__PURE__ */ new Set(["string", "number", "boolean", "void", "unknown", "any", "Date"]);
345
354
  function _localDeclForKinds(name, file, kinds) {
@@ -376,6 +385,26 @@ function resolveTypeRef(nodeOrName, sourceFile, project, opts) {
376
385
  if (_NON_REF_NAMES.has(refName)) return null;
377
386
  name = refName;
378
387
  }
388
+ return _resolveNamedRef(name, sourceFile, project, opts);
389
+ }
390
+ var _resolveNamedRefCache = /* @__PURE__ */ new WeakMap();
391
+ function _resolveNamedRef(name, sourceFile, project, opts) {
392
+ let byKey = _resolveNamedRefCache.get(project);
393
+ if (byKey === void 0) {
394
+ byKey = /* @__PURE__ */ new Map();
395
+ _resolveNamedRefCache.set(project, byKey);
396
+ }
397
+ const kindsKey = [...opts.kinds].sort().join(",");
398
+ const key = `${sourceFile.getFilePath()}\0${name}\0${kindsKey}\0${opts.allowBareSpecifier ? 1 : 0}`;
399
+ if (byKey.has(key)) {
400
+ const cached = byKey.get(key) ?? null;
401
+ return cached ? { ...cached } : null;
402
+ }
403
+ const computed = _computeNamedRef(name, sourceFile, project, opts);
404
+ byKey.set(key, computed);
405
+ return computed ? { ...computed } : null;
406
+ }
407
+ function _computeNamedRef(name, sourceFile, project, opts) {
379
408
  if (_localDeclForKinds(name, sourceFile, opts.kinds)) {
380
409
  return { name, filePath: sourceFile.getFilePath() };
381
410
  }
@@ -453,10 +482,7 @@ function extractSchemaFromDto(classDecl, sourceFile, project) {
453
482
  depth: 0
454
483
  };
455
484
  const root = buildObject(classDecl, sourceFile, ctx);
456
- for (const schemaName of ctx.recursiveSchemas) {
457
- ctx.named.set(schemaName, { kind: "unknown", note: "recursive type \u2014 not expanded" });
458
- }
459
- return { root, named: ctx.named, warnings: ctx.warnings };
485
+ return { root, named: ctx.named, warnings: ctx.warnings, recursive: ctx.recursiveSchemas };
460
486
  }
461
487
  function buildObject(classDecl, classFile, ctx) {
462
488
  const props = classDecl.getProperties();
@@ -476,7 +502,7 @@ function buildProperty(prop, classFile, ctx) {
476
502
  const dec = (n) => decorators.get(n);
477
503
  const typeNode = prop.getTypeNode();
478
504
  const typeText = typeNode?.getText() ?? "unknown";
479
- const isArrayType = !!typeNode && typeNode.getText().endsWith("[]");
505
+ const isArrayType = !!typeNode && import_ts_morph2.Node.isArrayTypeNode(typeNode);
480
506
  const typeRefName = resolveTypeFactoryName(dec("Type"));
481
507
  if (has("ValidateNested") || typeRefName) {
482
508
  const childName = typeRefName ?? singularClassName(typeText);
@@ -607,18 +633,27 @@ function baseFromType(typeText, isArrayType) {
607
633
  }
608
634
  }
609
635
  function buildNestedReference(className, fromFile, ctx) {
610
- if (ctx.visiting.has(className) || ctx.depth >= 8) {
636
+ if (ctx.visiting.has(className)) {
611
637
  const reserved = ctx.emittedClasses.get(className) ?? aliasFor(className, ctx);
612
638
  ctx.emittedClasses.set(className, reserved);
613
639
  ctx.recursiveSchemas.add(reserved);
614
640
  if (!ctx.warnedDecorators.has(`recursive:${reserved}`)) {
615
641
  ctx.warnedDecorators.add(`recursive:${reserved}`);
616
- const msg = `${className} is a recursive type and was not expanded; the generated schema uses unknown for it.`;
642
+ const msg = `${className} is a recursive type; the generated schema validates it via a lazy self-reference.`;
617
643
  ctx.warnings.push(msg);
618
644
  console.warn(`[nestjs-codegen] ${msg}`);
619
645
  }
620
646
  return { kind: "lazyRef", name: reserved };
621
647
  }
648
+ if (ctx.depth >= 8) {
649
+ if (!ctx.warnedDecorators.has(`deep:${className}`)) {
650
+ ctx.warnedDecorators.add(`deep:${className}`);
651
+ const msg = `${className} nesting is too deep to expand; the generated schema uses unknown for it.`;
652
+ ctx.warnings.push(msg);
653
+ console.warn(`[nestjs-codegen] ${msg}`);
654
+ }
655
+ return { kind: "unknown", note: "nesting too deep \u2014 not expanded" };
656
+ }
622
657
  const existing = ctx.emittedClasses.get(className);
623
658
  if (existing) return { kind: "ref", name: existing };
624
659
  const schemaName = aliasFor(className, ctx);
@@ -744,17 +779,31 @@ var import_ts_morph4 = require("ts-morph");
744
779
  var import_ts_morph3 = require("ts-morph");
745
780
 
746
781
  // src/discovery/enum-resolution.ts
782
+ var _enumCache = /* @__PURE__ */ new WeakMap();
747
783
  function resolveEnumValues(name, sourceFile, project) {
784
+ let byKey = _enumCache.get(project);
785
+ if (byKey === void 0) {
786
+ byKey = /* @__PURE__ */ new Map();
787
+ _enumCache.set(project, byKey);
788
+ }
789
+ const key = `${sourceFile.getFilePath()}\0${name}`;
790
+ if (byKey.has(key)) {
791
+ const cached = byKey.get(key) ?? null;
792
+ return cached ? { values: [...cached.values], numeric: cached.numeric } : null;
793
+ }
748
794
  const resolved = findType(name, sourceFile, project);
749
- if (!resolved || resolved.kind !== "enum") return null;
750
- let numeric = true;
751
- const values = resolved.members.map((m) => {
752
- const parsed = JSON.parse(m);
753
- if (typeof parsed === "string") numeric = false;
754
- return String(parsed);
755
- });
756
- if (values.length === 0) return null;
757
- return { values, numeric };
795
+ let result = null;
796
+ if (resolved && resolved.kind === "enum") {
797
+ let numeric = true;
798
+ const values = resolved.members.map((m) => {
799
+ const parsed = JSON.parse(m);
800
+ if (typeof parsed === "string") numeric = false;
801
+ return String(parsed);
802
+ });
803
+ if (values.length > 0) result = { values, numeric };
804
+ }
805
+ byKey.set(key, result);
806
+ return result ? { values: [...result.values], numeric: result.numeric } : null;
758
807
  }
759
808
 
760
809
  // src/discovery/filter-field-types.ts
@@ -2947,6 +2996,8 @@ function buildFormsFileWithAdapter(routes, outDir, adapter, config) {
2947
2996
  }
2948
2997
  const { globalSchemas, renamesByEntry } = planNestedSchemas(entries);
2949
2998
  const irNamed = /* @__PURE__ */ new Map();
2999
+ const irTypeAliases = /* @__PURE__ */ new Map();
3000
+ const irAnnotations = /* @__PURE__ */ new Map();
2950
3001
  const decls = [];
2951
3002
  const mapEntries = [];
2952
3003
  let used = false;
@@ -2954,6 +3005,8 @@ function buildFormsFileWithAdapter(routes, outDir, adapter, config) {
2954
3005
  if (src.schema) {
2955
3006
  const r = adapter.renderModule(src.schema);
2956
3007
  for (const [n, t] of r.namedNestedSchemas) irNamed.set(n, t);
3008
+ if (r.namedTypeAliases) for (const [n, t] of r.namedTypeAliases) irTypeAliases.set(n, t);
3009
+ if (r.namedAnnotations) for (const [n, a] of r.namedAnnotations) irAnnotations.set(n, a);
2957
3010
  return { text: r.schemaText };
2958
3011
  }
2959
3012
  if (src.zodText) {
@@ -3027,7 +3080,13 @@ function buildFormsFileWithAdapter(routes, outDir, adapter, config) {
3027
3080
  for (const [n, t] of irNamed) if (!allNested.has(n)) allNested.set(n, t);
3028
3081
  if (allNested.size > 0) {
3029
3082
  lines.push("// Hoisted nested schemas (shared across endpoints).");
3030
- for (const [n, t] of allNested) lines.push(`const ${n} = ${t};`);
3083
+ for (const [n, alias] of irTypeAliases) {
3084
+ if (allNested.has(n)) lines.push(`${alias};`);
3085
+ }
3086
+ for (const [n, t] of allNested) {
3087
+ const annotation = irAnnotations.get(n);
3088
+ lines.push(`const ${n}${annotation ? `: ${annotation}` : ""} = ${t};`);
3089
+ }
3031
3090
  lines.push("");
3032
3091
  }
3033
3092
  lines.push(...decls);