@dudousxd/nestjs-codegen 0.5.0 → 0.5.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @dudousxd/nestjs-codegen
2
2
 
3
+ ## 0.5.2
4
+
5
+ ### Patch Changes
6
+
7
+ - f432450: Internal refactors (behavior-preserving): share `renderModule` across the zod/valibot adapters via a `createChainModuleRenderer` factory, and dedupe the nested-reference array-wrap + presence tail in `buildProperty` (`dto-to-ir`) behind a single `asField` closure.
8
+
9
+ ## 0.5.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 7dee3f6: perf: faster generation — `aliasFor` uses a maintained in-use-name set (O(n²)→O(1) over nested DTOs) and `planNestedSchemas` caches compiled rename regexes + uses a maintained Set for membership instead of rebuilding arrays. Generated output is byte-identical.
14
+
3
15
  ## 0.5.0
4
16
 
5
17
  ### Minor Changes
package/dist/cli/main.cjs CHANGED
@@ -1188,18 +1188,27 @@ function refRootIdentifier(refName) {
1188
1188
  function hasSource(src) {
1189
1189
  return !!(src.schema || src.zodText || src.zodRef);
1190
1190
  }
1191
+ function escapeRegExp(s) {
1192
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1193
+ }
1194
+ var wordBoundaryRegexCache = /* @__PURE__ */ new Map();
1195
+ function wordBoundaryRegex(token) {
1196
+ let re = wordBoundaryRegexCache.get(token);
1197
+ if (re === void 0) {
1198
+ re = new RegExp(`\\b${escapeRegExp(token)}\\b`, "g");
1199
+ wordBoundaryRegexCache.set(token, re);
1200
+ }
1201
+ return re;
1202
+ }
1191
1203
  function applyRenames(text, renames) {
1192
1204
  if (!renames || renames.size === 0) return text;
1193
1205
  let out = text;
1194
1206
  for (const [from, to] of renames) {
1195
1207
  if (from === to) continue;
1196
- out = out.replace(new RegExp(`\\b${escapeRegExp(from)}\\b`, "g"), to);
1208
+ out = out.replace(wordBoundaryRegex(from), to);
1197
1209
  }
1198
1210
  return out;
1199
1211
  }
1200
- function escapeRegExp(s) {
1201
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1202
- }
1203
1212
  function isSelfReferential(name, text) {
1204
1213
  return new RegExp(`\\b${escapeRegExp(name)}\\b`).test(text);
1205
1214
  }
@@ -1211,7 +1220,23 @@ function planNestedSchemas(entries) {
1211
1220
  const local = Object.entries(entry.nestedSchemas);
1212
1221
  if (local.length === 0) continue;
1213
1222
  const rename = /* @__PURE__ */ new Map();
1214
- for (const [name] of local) rename.set(name, name);
1223
+ const renameValues = /* @__PURE__ */ new Set();
1224
+ const setRename = (key, value) => {
1225
+ const prev = rename.get(key);
1226
+ rename.set(key, value);
1227
+ if (prev !== void 0 && prev !== value) {
1228
+ let stillUsed = false;
1229
+ for (const v of rename.values()) {
1230
+ if (v === prev) {
1231
+ stillUsed = true;
1232
+ break;
1233
+ }
1234
+ }
1235
+ if (!stillUsed) renameValues.delete(prev);
1236
+ }
1237
+ renameValues.add(value);
1238
+ };
1239
+ for (const [name] of local) setRename(name, name);
1215
1240
  const textFor = (name) => {
1216
1241
  const raw = entry.nestedSchemas?.[name] ?? "";
1217
1242
  return applyRenames(raw, rename);
@@ -1229,11 +1254,11 @@ function planNestedSchemas(entries) {
1229
1254
  if (existing === text) continue;
1230
1255
  let i = 2;
1231
1256
  let candidate = `${name}_${i}`;
1232
- while (globalSchemas.has(candidate) && globalSchemas.get(candidate) !== textFor(name) || [...rename.values()].includes(candidate)) {
1257
+ while (globalSchemas.has(candidate) && globalSchemas.get(candidate) !== textFor(name) || renameValues.has(candidate)) {
1233
1258
  i += 1;
1234
1259
  candidate = `${name}_${i}`;
1235
1260
  }
1236
- rename.set(name, candidate);
1261
+ setRename(name, candidate);
1237
1262
  changed = true;
1238
1263
  }
1239
1264
  }
@@ -2518,6 +2543,7 @@ function extractSchemaFromDto(classDecl, sourceFile, project) {
2518
2543
  warnings: [],
2519
2544
  warnedDecorators: /* @__PURE__ */ new Set(),
2520
2545
  emittedClasses: /* @__PURE__ */ new Map(),
2546
+ usedSchemaNames: /* @__PURE__ */ new Set(),
2521
2547
  visiting: /* @__PURE__ */ new Set(),
2522
2548
  recursiveSchemas: /* @__PURE__ */ new Set(),
2523
2549
  depth: 0,
@@ -2545,37 +2571,28 @@ function buildProperty(prop, classFile, ctx) {
2545
2571
  const typeNode = prop.getTypeNode();
2546
2572
  const typeText = typeNode?.getText() ?? "unknown";
2547
2573
  const isArrayType = !!typeNode && import_ts_morph4.Node.isArrayTypeNode(typeNode);
2574
+ const asField = (child) => applyPresence(
2575
+ has("IsArray") || isArrayType ? { kind: "array", element: child } : child,
2576
+ decorators
2577
+ );
2548
2578
  const discriminator = resolveDiscriminator(dec("Type"));
2549
2579
  if (discriminator) {
2550
2580
  const options = discriminator.subTypes.map(
2551
2581
  (name) => buildNestedReference(name, classFile, ctx)
2552
2582
  );
2553
- const unionNode = {
2554
- kind: "union",
2555
- options,
2556
- discriminator: discriminator.property
2557
- };
2558
- const wrapArray = has("IsArray") || isArrayType;
2559
- const node2 = wrapArray ? { kind: "array", element: unionNode } : unionNode;
2560
- return applyPresence(node2, decorators);
2583
+ return asField({ kind: "union", options, discriminator: discriminator.property });
2561
2584
  }
2562
2585
  const propTypeParam = singularClassName(typeText);
2563
2586
  if (propTypeParam && ctx.typeBindings.has(propTypeParam)) {
2564
2587
  const bound = ctx.typeBindings.get(propTypeParam);
2565
- const childNode = buildNestedReference(bound, classFile, ctx);
2566
- const wrapArray = has("IsArray") || isArrayType;
2567
- const node2 = wrapArray ? { kind: "array", element: childNode } : childNode;
2568
- return applyPresence(node2, decorators);
2588
+ return asField(buildNestedReference(bound, classFile, ctx));
2569
2589
  }
2570
2590
  const typeRefName = resolveTypeFactoryName(dec("Type"));
2571
2591
  if (has("ValidateNested") || typeRefName) {
2572
2592
  const typeArgs = genericTypeArgNames(typeNode);
2573
2593
  const childName = typeRefName ?? singularClassName(typeText);
2574
2594
  if (childName) {
2575
- const childNode = buildNestedReference(childName, classFile, ctx, typeArgs);
2576
- const wrapArray = has("IsArray") || isArrayType;
2577
- const node2 = wrapArray ? { kind: "array", element: childNode } : childNode;
2578
- return applyPresence(node2, decorators);
2595
+ return asField(buildNestedReference(childName, classFile, ctx, typeArgs));
2579
2596
  }
2580
2597
  }
2581
2598
  let base = baseFromType(typeText, isArrayType);
@@ -2703,6 +2720,7 @@ function buildNestedReference(className, fromFile, ctx, typeArgs = []) {
2703
2720
  if (ctx.visiting.has(cacheKey)) {
2704
2721
  const reserved = ctx.emittedClasses.get(cacheKey) ?? aliasFor(schemaBase, ctx);
2705
2722
  ctx.emittedClasses.set(cacheKey, reserved);
2723
+ ctx.usedSchemaNames.add(reserved);
2706
2724
  ctx.recursiveSchemas.add(reserved);
2707
2725
  if (!ctx.warnedDecorators.has(`recursive:${reserved}`)) {
2708
2726
  ctx.warnedDecorators.add(`recursive:${reserved}`);
@@ -2736,6 +2754,7 @@ function buildNestedReference(className, fromFile, ctx, typeArgs = []) {
2736
2754
  });
2737
2755
  for (const [k, v] of newBindings) ctx.typeBindings.set(k, v);
2738
2756
  ctx.emittedClasses.set(cacheKey, schemaName);
2757
+ ctx.usedSchemaNames.add(schemaName);
2739
2758
  ctx.visiting.add(cacheKey);
2740
2759
  ctx.depth += 1;
2741
2760
  const childNode = buildObject(resolved.decl, resolved.file, ctx);
@@ -2743,15 +2762,14 @@ function buildNestedReference(className, fromFile, ctx, typeArgs = []) {
2743
2762
  ctx.visiting.delete(cacheKey);
2744
2763
  for (const [k] of newBindings) ctx.typeBindings.delete(k);
2745
2764
  ctx.named.set(schemaName, childNode);
2765
+ ctx.usedSchemaNames.add(schemaName);
2746
2766
  return { kind: "ref", name: schemaName };
2747
2767
  }
2748
2768
  function aliasFor(className, ctx) {
2749
2769
  const baseName = `${className}Schema`;
2750
2770
  let candidate = baseName;
2751
2771
  let i = 1;
2752
- const used = new Set(ctx.named.keys());
2753
- for (const v of ctx.emittedClasses.values()) used.add(v);
2754
- while (used.has(candidate)) {
2772
+ while (ctx.usedSchemaNames.has(candidate)) {
2755
2773
  candidate = `${baseName}_${i}`;
2756
2774
  i += 1;
2757
2775
  }
@@ -4430,7 +4448,7 @@ async function watch(config, onChange) {
4430
4448
  }
4431
4449
 
4432
4450
  // src/index.ts
4433
- var VERSION = "0.5.0";
4451
+ var VERSION = "0.5.2";
4434
4452
 
4435
4453
  // src/cli/codegen.ts
4436
4454
  async function runCodegen(opts = {}) {