@dudousxd/nestjs-codegen 0.16.0 → 0.17.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.
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy, ExecutionContext } from '@nestjs/common';
3
- import { U as UserConfig } from '../index-LQNP7Ms3.cjs';
3
+ import { U as UserConfig } from '../index-DCF9QSPY.cjs';
4
4
  import 'ts-morph';
5
5
 
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { DynamicModule, OnApplicationBootstrap, OnModuleDestroy, ExecutionContext } from '@nestjs/common';
3
- import { U as UserConfig } from '../index-LQNP7Ms3.js';
3
+ import { U as UserConfig } from '../index-DCF9QSPY.js';
4
4
  import 'ts-morph';
5
5
 
6
6
  /**
@@ -141,7 +141,7 @@ function applyDefaults(userConfig, cwd) {
141
141
  // src/generate-manifest.ts
142
142
  import { createHash } from "crypto";
143
143
  import { readFile as readFile4, readdir, writeFile as writeFile10 } from "fs/promises";
144
- import { join as join16, relative as relative6 } from "path";
144
+ import { join as join16, relative as relative7 } from "path";
145
145
  import fg3 from "fast-glob";
146
146
 
147
147
  // src/generate.ts
@@ -475,9 +475,10 @@ function inferExpressionType(node) {
475
475
 
476
476
  // src/emit/emit-api.ts
477
477
  import { mkdir, writeFile } from "fs/promises";
478
- import { isAbsolute as isAbsolute2, join as join4, relative as relative3 } from "path";
478
+ import { isAbsolute as isAbsolute2, join as join4, relative as relative4 } from "path";
479
479
 
480
480
  // src/extension/registry.ts
481
+ import { relative as relative3, resolve as resolve2 } from "path";
481
482
  import { Project as Project2 } from "ts-morph";
482
483
  function resolveApiSlots(extensions) {
483
484
  let layer;
@@ -510,7 +511,7 @@ function mergeExclusive(target, incoming, {
510
511
  target.set(key, { value, owner });
511
512
  }
512
513
  }
513
- function createExtensionContext(config, getRoutes) {
514
+ function createExtensionContext(config, getRoutes, trackedInputs) {
514
515
  let project;
515
516
  return {
516
517
  cwd: config.codegen.cwd,
@@ -519,6 +520,13 @@ function createExtensionContext(config, getRoutes) {
519
520
  get routes() {
520
521
  return getRoutes();
521
522
  },
523
+ trackInput(...paths) {
524
+ if (!trackedInputs) return;
525
+ for (const path of paths) {
526
+ if (!path) continue;
527
+ trackedInputs.add(relative3(config.codegen.cwd, resolve2(config.codegen.cwd, path)));
528
+ }
529
+ },
522
530
  project() {
523
531
  if (!project) {
524
532
  project = new Project2({
@@ -686,7 +694,7 @@ function rawResponseType(c, outDir) {
686
694
  return c.contractSource.response;
687
695
  }
688
696
  if (c.controllerRef) {
689
- let relPath = relative3(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
697
+ let relPath = relative4(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
690
698
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
691
699
  return `Awaited<ReturnType<import('${relPath}').${c.controllerRef.className}['${c.controllerRef.methodName}']>>`;
692
700
  }
@@ -1012,6 +1020,11 @@ function buildApiFile(routes, outDir, opts = {}) {
1012
1020
  config: {},
1013
1021
  project: () => {
1014
1022
  throw new Error("ExtensionContext.project() is unavailable in standalone emitApi.");
1023
+ },
1024
+ // No manifest is written on the standalone path, so there is nothing for
1025
+ // tracked dependencies to be recorded into — accept and discard them
1026
+ // rather than making every caller supply a sink.
1027
+ trackInput: () => {
1015
1028
  }
1016
1029
  };
1017
1030
  const importsByFile = /* @__PURE__ */ new Map();
@@ -1068,7 +1081,7 @@ function buildApiFile(routes, outDir, opts = {}) {
1068
1081
  for (const [filePath, names] of importsByFile) {
1069
1082
  let relPath;
1070
1083
  if (isAbsolute2(filePath)) {
1071
- relPath = relative3(outDir, filePath).replace(/\.ts$/, "");
1084
+ relPath = relative4(outDir, filePath).replace(/\.ts$/, "");
1072
1085
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
1073
1086
  } else {
1074
1087
  relPath = filePath;
@@ -1182,7 +1195,7 @@ async function emitCache(pages, outDir) {
1182
1195
 
1183
1196
  // src/emit/emit-forms.ts
1184
1197
  import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1185
- import { join as join6, relative as relative4 } from "path";
1198
+ import { join as join6, relative as relative5 } from "path";
1186
1199
  async function emitForms(routes, outDir, config, adapter) {
1187
1200
  if (config && config.enabled === false) return false;
1188
1201
  const content = buildFormsFileWithAdapter(routes, outDir, adapter, config);
@@ -1201,7 +1214,7 @@ function deriveBaseName(routeName) {
1201
1214
  return { method, full };
1202
1215
  }
1203
1216
  function relImport(outDir, filePath) {
1204
- let relPath = relative4(outDir, filePath).replace(/\.ts$/, "");
1217
+ let relPath = relative5(outDir, filePath).replace(/\.ts$/, "");
1205
1218
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
1206
1219
  return relPath;
1207
1220
  }
@@ -1949,7 +1962,7 @@ async function emitOpenApi(routes, outDir, opts = {}) {
1949
1962
 
1950
1963
  // src/emit/emit-pages.ts
1951
1964
  import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
1952
- import { join as join10, relative as relative5 } from "path";
1965
+ import { join as join10, relative as relative6 } from "path";
1953
1966
  async function emitPages(pages, outDir, _options = {}) {
1954
1967
  await mkdir7(outDir, { recursive: true });
1955
1968
  const pageNameUnion = pages.length > 0 ? pages.map((p) => JSON.stringify(p.name)).join(" | ") : "never";
@@ -1989,7 +2002,7 @@ ${propsBody}
1989
2002
  `;
1990
2003
  }
1991
2004
  function buildAugmentationType(page, outDir) {
1992
- let importPath = relative5(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
2005
+ let importPath = relative6(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
1993
2006
  if (!importPath.startsWith(".")) {
1994
2007
  importPath = `./${importPath}`;
1995
2008
  }
@@ -2133,8 +2146,8 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
2133
2146
  }
2134
2147
  async function generate(config, inputRoutes = [], entryPoint = "cli") {
2135
2148
  setCodegenDebug(config.debug);
2136
- const inputsHash = await computeInputsHash(config);
2137
2149
  const manifest = await readManifest(config.codegen.outDir);
2150
+ const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? []);
2138
2151
  if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
2139
2152
  console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
2140
2153
  return;
@@ -2155,7 +2168,8 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
2155
2168
  }
2156
2169
  const extensions = config.extensions ?? [];
2157
2170
  let routes = inputRoutes;
2158
- const ctx = createExtensionContext(config, () => routes);
2171
+ const trackedInputs = /* @__PURE__ */ new Set();
2172
+ const ctx = createExtensionContext(config, () => routes, trackedInputs);
2159
2173
  if (extensions.length > 0) {
2160
2174
  routes = await applyTransformRoutes(routes, extensions, ctx);
2161
2175
  }
@@ -2215,13 +2229,16 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
2215
2229
  }
2216
2230
  }
2217
2231
  const outputFiles = await listOutputFiles(config.codegen.outDir);
2232
+ const extraInputs = [...trackedInputs].sort();
2233
+ const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
2218
2234
  await writeManifest(config.codegen.outDir, {
2219
2235
  version: VERSION,
2220
- hash: inputsHash,
2236
+ hash: recordedHash,
2221
2237
  entryPoint,
2222
2238
  configHash,
2223
2239
  configKeyHashes,
2224
- files: outputFiles
2240
+ files: outputFiles,
2241
+ ...extraInputs.length > 0 ? { extraInputs } : {}
2225
2242
  });
2226
2243
  }
2227
2244
 
@@ -2231,7 +2248,7 @@ import { join as join15 } from "path";
2231
2248
  import chokidar from "chokidar";
2232
2249
 
2233
2250
  // src/discovery/contracts-fast.ts
2234
- import { join as join13, resolve as resolve3 } from "path";
2251
+ import { join as join13, resolve as resolve4 } from "path";
2235
2252
  import fg2 from "fast-glob";
2236
2253
  import {
2237
2254
  Node as Node9,
@@ -2251,7 +2268,7 @@ import {
2251
2268
 
2252
2269
  // src/discovery/type-ref-resolution.ts
2253
2270
  import { readFileSync } from "fs";
2254
- import { dirname as dirname3, resolve as resolve2 } from "path";
2271
+ import { dirname as dirname3, resolve as resolve3 } from "path";
2255
2272
  import {
2256
2273
  Node as Node2
2257
2274
  } from "ts-morph";
@@ -2308,9 +2325,9 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2308
2325
  const dir = dirname3(sourceFile.getFilePath());
2309
2326
  const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
2310
2327
  return [
2311
- resolve2(dir, `${noExt}.ts`),
2312
- resolve2(dir, `${moduleSpecifier}.ts`),
2313
- resolve2(dir, moduleSpecifier, "index.ts")
2328
+ resolve3(dir, `${noExt}.ts`),
2329
+ resolve3(dir, `${moduleSpecifier}.ts`),
2330
+ resolve3(dir, moduleSpecifier, "index.ts")
2314
2331
  ];
2315
2332
  }
2316
2333
  const ctx = _ctxFor(project);
@@ -2331,8 +2348,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2331
2348
  const rest = moduleSpecifier.slice(prefix.length);
2332
2349
  const candidates = [];
2333
2350
  for (const mapping of mappings) {
2334
- const resolved = resolve2(baseUrl, mapping.replace("*", rest));
2335
- candidates.push(`${resolved}.ts`, resolve2(resolved, "index.ts"));
2351
+ const resolved = resolve3(baseUrl, mapping.replace("*", rest));
2352
+ candidates.push(`${resolved}.ts`, resolve3(resolved, "index.ts"));
2336
2353
  }
2337
2354
  dbg(" resolved candidates:", candidates);
2338
2355
  return candidates;
@@ -3979,6 +3996,19 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
3979
3996
 
3980
3997
  // src/discovery/heritage.ts
3981
3998
  import { Node as Node7, Project as Project3 } from "ts-morph";
3999
+ function resolveHeritageCall(node) {
4000
+ if (!node) return void 0;
4001
+ const expr = unwrapExpression(node);
4002
+ if (Node7.isCallExpression(expr)) return expr;
4003
+ if (!Node7.isIdentifier(expr)) return void 0;
4004
+ const decl = expr.getDefinitions().map((d) => d.getDeclarationNode()).find(
4005
+ (n) => n !== void 0 && Node7.isVariableDeclaration(n)
4006
+ );
4007
+ const init = decl?.getInitializer();
4008
+ if (!init) return void 0;
4009
+ const unwrapped = unwrapExpression(init);
4010
+ return Node7.isCallExpression(unwrapped) ? unwrapped : void 0;
4011
+ }
3982
4012
  function unwrapExpression(node) {
3983
4013
  let current = node;
3984
4014
  while (Node7.isAsExpression(current) || Node7.isSatisfiesExpression(current) || Node7.isParenthesizedExpression(current) || Node7.isTypeAssertion(current)) {
@@ -4006,8 +4036,8 @@ function resolveReturnedClass(factoryDecl) {
4006
4036
  return void 0;
4007
4037
  }
4008
4038
  function resolveInheritedMethods(cls) {
4009
- const expr = cls.getExtends()?.getExpression();
4010
- if (!expr || !Node7.isCallExpression(expr)) return void 0;
4039
+ const expr = resolveHeritageCall(cls.getExtends()?.getExpression());
4040
+ if (!expr) return void 0;
4011
4041
  const callee = expr.getExpression();
4012
4042
  if (!Node7.isIdentifier(callee)) return void 0;
4013
4043
  const factoryDecl = callee.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => Node7.isFunctionDeclaration(n));
@@ -4184,7 +4214,7 @@ function parseDefineContractCall(callExpr) {
4184
4214
 
4185
4215
  // src/discovery/contracts-fast.ts
4186
4216
  function resolveTsconfigPath(cwd, tsconfig) {
4187
- return tsconfig ? resolve3(tsconfig) : join13(cwd, "tsconfig.json");
4217
+ return tsconfig ? resolve4(tsconfig) : join13(cwd, "tsconfig.json");
4188
4218
  }
4189
4219
  function createDiscoveryProject(tsconfigPath) {
4190
4220
  try {
@@ -4263,7 +4293,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4263
4293
  async rediscover(changedPaths) {
4264
4294
  if (changedPaths) {
4265
4295
  for (const p of changedPaths) {
4266
- const abs = resolve3(p);
4296
+ const abs = resolve4(p);
4267
4297
  const sf = this.project.getSourceFile(abs);
4268
4298
  if (sf) {
4269
4299
  await sf.refreshFromFileSystem();
@@ -4543,9 +4573,11 @@ function extractFromSourceFile(sourceFile, project) {
4543
4573
  factoryFilePath: inherited.factoryFilePath,
4544
4574
  classArgs: inherited.classArgs
4545
4575
  } : void 0;
4576
+ const ownMethods = cls.getMethods();
4577
+ const ownNames = new Set(ownMethods.map((m) => m.getName()));
4546
4578
  const methods = [
4547
- ...cls.getMethods().map((method) => ({ method })),
4548
- ...(inherited?.methods ?? []).map((method) => ({ method, mixin: mixinBinding }))
4579
+ ...ownMethods.map((method) => ({ method, mixin: mixinBinding })),
4580
+ ...(inherited?.methods ?? []).filter((method) => !ownNames.has(method.getName())).map((method) => ({ method, mixin: mixinBinding }))
4549
4581
  ];
4550
4582
  for (const { method, mixin } of methods) {
4551
4583
  const verb = resolveVerb(method);
@@ -4771,7 +4803,7 @@ async function watch(config, onChange, options = {}) {
4771
4803
  }
4772
4804
 
4773
4805
  // src/index.ts
4774
- var VERSION = "0.16.0";
4806
+ var VERSION = "0.17.1";
4775
4807
 
4776
4808
  // src/generate-manifest.ts
4777
4809
  var MANIFEST_FILE = ".codegen-manifest.json";
@@ -4795,6 +4827,9 @@ function isManifestShape(value) {
4795
4827
  if (candidate.configKeyHashes !== void 0 && !isStringRecord(candidate.configKeyHashes)) {
4796
4828
  return false;
4797
4829
  }
4830
+ if (candidate.extraInputs !== void 0 && (!Array.isArray(candidate.extraInputs) || !candidate.extraInputs.every((entry) => typeof entry === "string"))) {
4831
+ return false;
4832
+ }
4798
4833
  if (!Array.isArray(candidate.files)) return false;
4799
4834
  return candidate.files.every((entry) => typeof entry === "string");
4800
4835
  }
@@ -4834,21 +4869,30 @@ async function discoverInputFiles(config) {
4834
4869
  const matched = await fg3(globs, { cwd, absolute: true, onlyFiles: true });
4835
4870
  return [...new Set(matched)].sort();
4836
4871
  }
4837
- async function computeInputsHash(config) {
4872
+ async function computeInputsHash(config, extraInputs = []) {
4838
4873
  const hash = createHash("sha256");
4839
4874
  hash.update(`version:${VERSION}
4840
4875
  `);
4841
4876
  hash.update(`config:${serializeConfig(config)}
4842
4877
  `);
4843
- const inputFiles = await discoverInputFiles(config);
4844
4878
  const cwd = config.codegen.cwd;
4845
- for (const file of inputFiles) {
4879
+ const globbed = await discoverInputFiles(config);
4880
+ const globbedRelative = new Set(globbed.map((file) => relative7(cwd, file)));
4881
+ const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
4882
+ for (const file of globbed) {
4846
4883
  const contents = await readFile4(file, "utf8");
4847
- hash.update(`file:${relative6(cwd, file)}
4884
+ hash.update(`file:${relative7(cwd, file)}
4848
4885
  `);
4849
4886
  hash.update(contents);
4850
4887
  hash.update("\n");
4851
4888
  }
4889
+ for (const file of extra) {
4890
+ const contents = await readFile4(join16(cwd, file), "utf8").catch(() => null);
4891
+ hash.update(`extra:${file}
4892
+ `);
4893
+ hash.update(contents ?? "\0missing");
4894
+ hash.update("\n");
4895
+ }
4852
4896
  return hash.digest("hex");
4853
4897
  }
4854
4898
  async function readManifest(outDir) {
@@ -4862,6 +4906,7 @@ async function readManifest(outDir) {
4862
4906
  ...parsed.entryPoint ? { entryPoint: parsed.entryPoint } : {},
4863
4907
  ...parsed.configHash ? { configHash: parsed.configHash } : {},
4864
4908
  ...parsed.configKeyHashes ? { configKeyHashes: parsed.configKeyHashes } : {},
4909
+ ...parsed.extraInputs ? { extraInputs: parsed.extraInputs } : {},
4865
4910
  files: parsed.files
4866
4911
  };
4867
4912
  } catch {
@@ -4884,7 +4929,7 @@ async function listOutputFiles(outDir) {
4884
4929
  if (entry.isDirectory()) {
4885
4930
  await walk(abs);
4886
4931
  } else if (entry.isFile()) {
4887
- const rel = relative6(outDir, abs);
4932
+ const rel = relative7(outDir, abs);
4888
4933
  if (rel === MANIFEST_FILE || rel === LOCK_FILE2) continue;
4889
4934
  found.push(rel);
4890
4935
  }