@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.
@@ -180,12 +180,12 @@ function applyDefaults(userConfig, cwd) {
180
180
  // src/generate-manifest.ts
181
181
  var import_node_crypto = require("crypto");
182
182
  var import_promises15 = require("fs/promises");
183
- var import_node_path17 = require("path");
183
+ var import_node_path18 = require("path");
184
184
  var import_fast_glob3 = __toESM(require("fast-glob"), 1);
185
185
 
186
186
  // src/generate.ts
187
187
  var import_promises11 = require("fs/promises");
188
- var import_node_path12 = require("path");
188
+ var import_node_path13 = require("path");
189
189
 
190
190
  // src/discovery/pages.ts
191
191
  var import_promises2 = require("fs/promises");
@@ -514,9 +514,10 @@ function inferExpressionType(node) {
514
514
 
515
515
  // src/emit/emit-api.ts
516
516
  var import_promises3 = require("fs/promises");
517
- var import_node_path4 = require("path");
517
+ var import_node_path5 = require("path");
518
518
 
519
519
  // src/extension/registry.ts
520
+ var import_node_path4 = require("path");
520
521
  var import_ts_morph2 = require("ts-morph");
521
522
  function resolveApiSlots(extensions) {
522
523
  let layer;
@@ -549,7 +550,7 @@ function mergeExclusive(target, incoming, {
549
550
  target.set(key, { value, owner });
550
551
  }
551
552
  }
552
- function createExtensionContext(config, getRoutes) {
553
+ function createExtensionContext(config, getRoutes, trackedInputs) {
553
554
  let project;
554
555
  return {
555
556
  cwd: config.codegen.cwd,
@@ -558,6 +559,13 @@ function createExtensionContext(config, getRoutes) {
558
559
  get routes() {
559
560
  return getRoutes();
560
561
  },
562
+ trackInput(...paths) {
563
+ if (!trackedInputs) return;
564
+ for (const path of paths) {
565
+ if (!path) continue;
566
+ trackedInputs.add((0, import_node_path4.relative)(config.codegen.cwd, (0, import_node_path4.resolve)(config.codegen.cwd, path)));
567
+ }
568
+ },
561
569
  project() {
562
570
  if (!project) {
563
571
  project = new import_ts_morph2.Project({
@@ -617,7 +625,7 @@ function requestShape(route) {
617
625
  async function emitApi(routes, outDir, opts = {}) {
618
626
  await (0, import_promises3.mkdir)(outDir, { recursive: true });
619
627
  const content = buildApiFile(routes, outDir, opts);
620
- await (0, import_promises3.writeFile)((0, import_node_path4.join)(outDir, "api.ts"), content, "utf8");
628
+ await (0, import_promises3.writeFile)((0, import_node_path5.join)(outDir, "api.ts"), content, "utf8");
621
629
  }
622
630
  function splitName(name) {
623
631
  return name.split(".");
@@ -725,7 +733,7 @@ function rawResponseType(c, outDir) {
725
733
  return c.contractSource.response;
726
734
  }
727
735
  if (c.controllerRef) {
728
- let relPath = (0, import_node_path4.relative)(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
736
+ let relPath = (0, import_node_path5.relative)(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
729
737
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
730
738
  return `Awaited<ReturnType<import('${relPath}').${c.controllerRef.className}['${c.controllerRef.methodName}']>>`;
731
739
  }
@@ -1051,6 +1059,11 @@ function buildApiFile(routes, outDir, opts = {}) {
1051
1059
  config: {},
1052
1060
  project: () => {
1053
1061
  throw new Error("ExtensionContext.project() is unavailable in standalone emitApi.");
1062
+ },
1063
+ // No manifest is written on the standalone path, so there is nothing for
1064
+ // tracked dependencies to be recorded into — accept and discard them
1065
+ // rather than making every caller supply a sink.
1066
+ trackInput: () => {
1054
1067
  }
1055
1068
  };
1056
1069
  const importsByFile = /* @__PURE__ */ new Map();
@@ -1106,8 +1119,8 @@ function buildApiFile(routes, outDir, opts = {}) {
1106
1119
  const emittedNames = /* @__PURE__ */ new Set();
1107
1120
  for (const [filePath, names] of importsByFile) {
1108
1121
  let relPath;
1109
- if ((0, import_node_path4.isAbsolute)(filePath)) {
1110
- relPath = (0, import_node_path4.relative)(outDir, filePath).replace(/\.ts$/, "");
1122
+ if ((0, import_node_path5.isAbsolute)(filePath)) {
1123
+ relPath = (0, import_node_path5.relative)(outDir, filePath).replace(/\.ts$/, "");
1111
1124
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
1112
1125
  } else {
1113
1126
  relPath = filePath;
@@ -1201,7 +1214,7 @@ function buildApiFile(routes, outDir, opts = {}) {
1201
1214
 
1202
1215
  // src/emit/emit-cache.ts
1203
1216
  var import_promises4 = require("fs/promises");
1204
- var import_node_path5 = require("path");
1217
+ var import_node_path6 = require("path");
1205
1218
  async function emitCache(pages, outDir) {
1206
1219
  await (0, import_promises4.mkdir)(outDir, { recursive: true });
1207
1220
  const entries = await Promise.all(
@@ -1215,19 +1228,19 @@ async function emitCache(pages, outDir) {
1215
1228
  })
1216
1229
  );
1217
1230
  const cache = { pages: entries };
1218
- await (0, import_promises4.writeFile)((0, import_node_path5.join)(outDir, "components.json"), `${JSON.stringify(cache, null, 2)}
1231
+ await (0, import_promises4.writeFile)((0, import_node_path6.join)(outDir, "components.json"), `${JSON.stringify(cache, null, 2)}
1219
1232
  `, "utf8");
1220
1233
  }
1221
1234
 
1222
1235
  // src/emit/emit-forms.ts
1223
1236
  var import_promises5 = require("fs/promises");
1224
- var import_node_path6 = require("path");
1237
+ var import_node_path7 = require("path");
1225
1238
  async function emitForms(routes, outDir, config, adapter) {
1226
1239
  if (config && config.enabled === false) return false;
1227
1240
  const content = buildFormsFileWithAdapter(routes, outDir, adapter, config);
1228
1241
  if (content === null) return false;
1229
1242
  await (0, import_promises5.mkdir)(outDir, { recursive: true });
1230
- await (0, import_promises5.writeFile)((0, import_node_path6.join)(outDir, "forms.ts"), content, "utf8");
1243
+ await (0, import_promises5.writeFile)((0, import_node_path7.join)(outDir, "forms.ts"), content, "utf8");
1231
1244
  return true;
1232
1245
  }
1233
1246
  function pascal(segment) {
@@ -1240,7 +1253,7 @@ function deriveBaseName(routeName) {
1240
1253
  return { method, full };
1241
1254
  }
1242
1255
  function relImport(outDir, filePath) {
1243
- let relPath = (0, import_node_path6.relative)(outDir, filePath).replace(/\.ts$/, "");
1256
+ let relPath = (0, import_node_path7.relative)(outDir, filePath).replace(/\.ts$/, "");
1244
1257
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
1245
1258
  return relPath;
1246
1259
  }
@@ -1514,7 +1527,7 @@ function buildFormsFileWithAdapter(routes, outDir, adapter, config) {
1514
1527
 
1515
1528
  // src/emit/emit-index.ts
1516
1529
  var import_promises6 = require("fs/promises");
1517
- var import_node_path7 = require("path");
1530
+ var import_node_path8 = require("path");
1518
1531
  async function emitIndex(outDir, hasContracts = false, hasForms = false) {
1519
1532
  await (0, import_promises6.mkdir)(outDir, { recursive: true });
1520
1533
  const exports2 = ["export * from './pages.js';", "export * from './routes.js';"];
@@ -1527,12 +1540,12 @@ async function emitIndex(outDir, hasContracts = false, hasForms = false) {
1527
1540
  const content = ["// Generated by @dudousxd/nestjs-codegen. Do not edit.", ...exports2, ""].join(
1528
1541
  "\n"
1529
1542
  );
1530
- await (0, import_promises6.writeFile)((0, import_node_path7.join)(outDir, "index.d.ts"), content, "utf8");
1543
+ await (0, import_promises6.writeFile)((0, import_node_path8.join)(outDir, "index.d.ts"), content, "utf8");
1531
1544
  }
1532
1545
 
1533
1546
  // src/emit/emit-mocks.ts
1534
1547
  var import_promises7 = require("fs/promises");
1535
- var import_node_path8 = require("path");
1548
+ var import_node_path9 = require("path");
1536
1549
 
1537
1550
  // src/ir/schema-node-to-json-schema.ts
1538
1551
  var DEFAULT_CTX = { refPrefix: "#/components/schemas/" };
@@ -1856,12 +1869,12 @@ async function emitMocks(routes, outDir, opts = {}) {
1856
1869
  await (0, import_promises7.mkdir)(outDir, { recursive: true });
1857
1870
  const content = buildMocksFile(routes, opts);
1858
1871
  const fileName = opts.fileName ?? "mocks.ts";
1859
- await (0, import_promises7.writeFile)((0, import_node_path8.join)(outDir, fileName), content, "utf8");
1872
+ await (0, import_promises7.writeFile)((0, import_node_path9.join)(outDir, fileName), content, "utf8");
1860
1873
  }
1861
1874
 
1862
1875
  // src/emit/emit-openapi.ts
1863
1876
  var import_promises8 = require("fs/promises");
1864
- var import_node_path9 = require("path");
1877
+ var import_node_path10 = require("path");
1865
1878
  var REF_PREFIX2 = "#/components/schemas/";
1866
1879
  function toOpenApiPath(path) {
1867
1880
  return path.replace(/:([^/]+)/g, "{$1}");
@@ -1982,13 +1995,13 @@ async function emitOpenApi(routes, outDir, opts = {}) {
1982
1995
  await (0, import_promises8.mkdir)(outDir, { recursive: true });
1983
1996
  const doc = buildOpenApiSpec(routes, opts);
1984
1997
  const fileName = opts.fileName ?? "openapi.json";
1985
- await (0, import_promises8.writeFile)((0, import_node_path9.join)(outDir, fileName), `${JSON.stringify(doc, null, 2)}
1998
+ await (0, import_promises8.writeFile)((0, import_node_path10.join)(outDir, fileName), `${JSON.stringify(doc, null, 2)}
1986
1999
  `, "utf8");
1987
2000
  }
1988
2001
 
1989
2002
  // src/emit/emit-pages.ts
1990
2003
  var import_promises9 = require("fs/promises");
1991
- var import_node_path10 = require("path");
2004
+ var import_node_path11 = require("path");
1992
2005
  async function emitPages(pages, outDir, _options = {}) {
1993
2006
  await (0, import_promises9.mkdir)(outDir, { recursive: true });
1994
2007
  const pageNameUnion = pages.length > 0 ? pages.map((p) => JSON.stringify(p.name)).join(" | ") : "never";
@@ -2009,7 +2022,7 @@ ${augBody}
2009
2022
  }
2010
2023
  ${sharedPropsBlock}}
2011
2024
  `;
2012
- await (0, import_promises9.writeFile)((0, import_node_path10.join)(outDir, "pages.d.ts"), content, "utf8");
2025
+ await (0, import_promises9.writeFile)((0, import_node_path11.join)(outDir, "pages.d.ts"), content, "utf8");
2013
2026
  }
2014
2027
  function buildSharedPropsBlock(sharedProps) {
2015
2028
  if (!sharedProps) return "";
@@ -2028,7 +2041,7 @@ ${propsBody}
2028
2041
  `;
2029
2042
  }
2030
2043
  function buildAugmentationType(page, outDir) {
2031
- let importPath = (0, import_node_path10.relative)(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
2044
+ let importPath = (0, import_node_path11.relative)(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
2032
2045
  if (!importPath.startsWith(".")) {
2033
2046
  importPath = `./${importPath}`;
2034
2047
  }
@@ -2040,11 +2053,11 @@ function needsQuotes(name) {
2040
2053
 
2041
2054
  // src/emit/emit-routes.ts
2042
2055
  var import_promises10 = require("fs/promises");
2043
- var import_node_path11 = require("path");
2056
+ var import_node_path12 = require("path");
2044
2057
  async function emitRoutes(routes, outDir) {
2045
2058
  await (0, import_promises10.mkdir)(outDir, { recursive: true });
2046
2059
  const content = buildRoutesFile(routes);
2047
- await (0, import_promises10.writeFile)((0, import_node_path11.join)(outDir, "routes.ts"), content, "utf8");
2060
+ await (0, import_promises10.writeFile)((0, import_node_path12.join)(outDir, "routes.ts"), content, "utf8");
2048
2061
  }
2049
2062
  function buildRoutesFile(routes) {
2050
2063
  if (routes.length === 0) {
@@ -2172,8 +2185,8 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
2172
2185
  }
2173
2186
  async function generate(config, inputRoutes = [], entryPoint = "cli") {
2174
2187
  setCodegenDebug(config.debug);
2175
- const inputsHash = await computeInputsHash(config);
2176
2188
  const manifest = await readManifest(config.codegen.outDir);
2189
+ const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? []);
2177
2190
  if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
2178
2191
  console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
2179
2192
  return;
@@ -2194,7 +2207,8 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
2194
2207
  }
2195
2208
  const extensions = config.extensions ?? [];
2196
2209
  let routes = inputRoutes;
2197
- const ctx = createExtensionContext(config, () => routes);
2210
+ const trackedInputs = /* @__PURE__ */ new Set();
2211
+ const ctx = createExtensionContext(config, () => routes, trackedInputs);
2198
2212
  if (extensions.length > 0) {
2199
2213
  routes = await applyTransformRoutes(routes, extensions, ctx);
2200
2214
  }
@@ -2248,29 +2262,32 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
2248
2262
  if (extensions.length > 0) {
2249
2263
  const extraFiles = await collectEmittedFiles(extensions, ctx);
2250
2264
  for (const file of extraFiles) {
2251
- const dest = (0, import_node_path12.join)(config.codegen.outDir, file.path);
2252
- await (0, import_promises11.mkdir)((0, import_node_path12.dirname)(dest), { recursive: true });
2265
+ const dest = (0, import_node_path13.join)(config.codegen.outDir, file.path);
2266
+ await (0, import_promises11.mkdir)((0, import_node_path13.dirname)(dest), { recursive: true });
2253
2267
  await (0, import_promises11.writeFile)(dest, file.contents, "utf8");
2254
2268
  }
2255
2269
  }
2256
2270
  const outputFiles = await listOutputFiles(config.codegen.outDir);
2271
+ const extraInputs = [...trackedInputs].sort();
2272
+ const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
2257
2273
  await writeManifest(config.codegen.outDir, {
2258
2274
  version: VERSION,
2259
- hash: inputsHash,
2275
+ hash: recordedHash,
2260
2276
  entryPoint,
2261
2277
  configHash,
2262
2278
  configKeyHashes,
2263
- files: outputFiles
2279
+ files: outputFiles,
2280
+ ...extraInputs.length > 0 ? { extraInputs } : {}
2264
2281
  });
2265
2282
  }
2266
2283
 
2267
2284
  // src/watch/watcher.ts
2268
2285
  var import_promises14 = require("fs/promises");
2269
- var import_node_path16 = require("path");
2286
+ var import_node_path17 = require("path");
2270
2287
  var import_chokidar = __toESM(require("chokidar"), 1);
2271
2288
 
2272
2289
  // src/discovery/contracts-fast.ts
2273
- var import_node_path14 = require("path");
2290
+ var import_node_path15 = require("path");
2274
2291
  var import_fast_glob2 = __toESM(require("fast-glob"), 1);
2275
2292
  var import_ts_morph10 = require("ts-morph");
2276
2293
 
@@ -2282,7 +2299,7 @@ var import_ts_morph4 = require("ts-morph");
2282
2299
 
2283
2300
  // src/discovery/type-ref-resolution.ts
2284
2301
  var import_node_fs = require("fs");
2285
- var import_node_path13 = require("path");
2302
+ var import_node_path14 = require("path");
2286
2303
  var import_ts_morph3 = require("ts-morph");
2287
2304
  var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
2288
2305
  var _ctxByProject = /* @__PURE__ */ new WeakMap();
@@ -2334,12 +2351,12 @@ function findTypeInFile(name, file) {
2334
2351
  }
2335
2352
  function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2336
2353
  if (moduleSpecifier.startsWith(".")) {
2337
- const dir = (0, import_node_path13.dirname)(sourceFile.getFilePath());
2354
+ const dir = (0, import_node_path14.dirname)(sourceFile.getFilePath());
2338
2355
  const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
2339
2356
  return [
2340
- (0, import_node_path13.resolve)(dir, `${noExt}.ts`),
2341
- (0, import_node_path13.resolve)(dir, `${moduleSpecifier}.ts`),
2342
- (0, import_node_path13.resolve)(dir, moduleSpecifier, "index.ts")
2357
+ (0, import_node_path14.resolve)(dir, `${noExt}.ts`),
2358
+ (0, import_node_path14.resolve)(dir, `${moduleSpecifier}.ts`),
2359
+ (0, import_node_path14.resolve)(dir, moduleSpecifier, "index.ts")
2343
2360
  ];
2344
2361
  }
2345
2362
  const ctx = _ctxFor(project);
@@ -2360,8 +2377,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2360
2377
  const rest = moduleSpecifier.slice(prefix.length);
2361
2378
  const candidates = [];
2362
2379
  for (const mapping of mappings) {
2363
- const resolved = (0, import_node_path13.resolve)(baseUrl, mapping.replace("*", rest));
2364
- candidates.push(`${resolved}.ts`, (0, import_node_path13.resolve)(resolved, "index.ts"));
2380
+ const resolved = (0, import_node_path14.resolve)(baseUrl, mapping.replace("*", rest));
2381
+ candidates.push(`${resolved}.ts`, (0, import_node_path14.resolve)(resolved, "index.ts"));
2365
2382
  }
2366
2383
  dbg(" resolved candidates:", candidates);
2367
2384
  return candidates;
@@ -4003,6 +4020,19 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
4003
4020
 
4004
4021
  // src/discovery/heritage.ts
4005
4022
  var import_ts_morph8 = require("ts-morph");
4023
+ function resolveHeritageCall(node) {
4024
+ if (!node) return void 0;
4025
+ const expr = unwrapExpression(node);
4026
+ if (import_ts_morph8.Node.isCallExpression(expr)) return expr;
4027
+ if (!import_ts_morph8.Node.isIdentifier(expr)) return void 0;
4028
+ const decl = expr.getDefinitions().map((d) => d.getDeclarationNode()).find(
4029
+ (n) => n !== void 0 && import_ts_morph8.Node.isVariableDeclaration(n)
4030
+ );
4031
+ const init = decl?.getInitializer();
4032
+ if (!init) return void 0;
4033
+ const unwrapped = unwrapExpression(init);
4034
+ return import_ts_morph8.Node.isCallExpression(unwrapped) ? unwrapped : void 0;
4035
+ }
4006
4036
  function unwrapExpression(node) {
4007
4037
  let current = node;
4008
4038
  while (import_ts_morph8.Node.isAsExpression(current) || import_ts_morph8.Node.isSatisfiesExpression(current) || import_ts_morph8.Node.isParenthesizedExpression(current) || import_ts_morph8.Node.isTypeAssertion(current)) {
@@ -4030,8 +4060,8 @@ function resolveReturnedClass(factoryDecl) {
4030
4060
  return void 0;
4031
4061
  }
4032
4062
  function resolveInheritedMethods(cls) {
4033
- const expr = cls.getExtends()?.getExpression();
4034
- if (!expr || !import_ts_morph8.Node.isCallExpression(expr)) return void 0;
4063
+ const expr = resolveHeritageCall(cls.getExtends()?.getExpression());
4064
+ if (!expr) return void 0;
4035
4065
  const callee = expr.getExpression();
4036
4066
  if (!import_ts_morph8.Node.isIdentifier(callee)) return void 0;
4037
4067
  const factoryDecl = callee.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => import_ts_morph8.Node.isFunctionDeclaration(n));
@@ -4208,7 +4238,7 @@ function parseDefineContractCall(callExpr) {
4208
4238
 
4209
4239
  // src/discovery/contracts-fast.ts
4210
4240
  function resolveTsconfigPath(cwd, tsconfig) {
4211
- return tsconfig ? (0, import_node_path14.resolve)(tsconfig) : (0, import_node_path14.join)(cwd, "tsconfig.json");
4241
+ return tsconfig ? (0, import_node_path15.resolve)(tsconfig) : (0, import_node_path15.join)(cwd, "tsconfig.json");
4212
4242
  }
4213
4243
  function createDiscoveryProject(tsconfigPath) {
4214
4244
  try {
@@ -4287,7 +4317,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4287
4317
  async rediscover(changedPaths) {
4288
4318
  if (changedPaths) {
4289
4319
  for (const p of changedPaths) {
4290
- const abs = (0, import_node_path14.resolve)(p);
4320
+ const abs = (0, import_node_path15.resolve)(p);
4291
4321
  const sf = this.project.getSourceFile(abs);
4292
4322
  if (sf) {
4293
4323
  await sf.refreshFromFileSystem();
@@ -4567,9 +4597,11 @@ function extractFromSourceFile(sourceFile, project) {
4567
4597
  factoryFilePath: inherited.factoryFilePath,
4568
4598
  classArgs: inherited.classArgs
4569
4599
  } : void 0;
4600
+ const ownMethods = cls.getMethods();
4601
+ const ownNames = new Set(ownMethods.map((m) => m.getName()));
4570
4602
  const methods = [
4571
- ...cls.getMethods().map((method) => ({ method })),
4572
- ...(inherited?.methods ?? []).map((method) => ({ method, mixin: mixinBinding }))
4603
+ ...ownMethods.map((method) => ({ method, mixin: mixinBinding })),
4604
+ ...(inherited?.methods ?? []).filter((method) => !ownNames.has(method.getName())).map((method) => ({ method, mixin: mixinBinding }))
4573
4605
  ];
4574
4606
  for (const { method, mixin } of methods) {
4575
4607
  const verb = resolveVerb(method);
@@ -4605,7 +4637,7 @@ function extractFromSourceFile(sourceFile, project) {
4605
4637
  // src/watch/lock-file.ts
4606
4638
  var import_promises12 = require("fs/promises");
4607
4639
  var import_promises13 = require("fs/promises");
4608
- var import_node_path15 = require("path");
4640
+ var import_node_path16 = require("path");
4609
4641
  var LOCK_FILE = ".watcher.lock";
4610
4642
  function isProcessAlive(pid) {
4611
4643
  try {
@@ -4617,7 +4649,7 @@ function isProcessAlive(pid) {
4617
4649
  }
4618
4650
  async function acquireLock(outDir) {
4619
4651
  await (0, import_promises13.mkdir)(outDir, { recursive: true });
4620
- const lockPath = (0, import_node_path15.join)(outDir, LOCK_FILE);
4652
+ const lockPath = (0, import_node_path16.join)(outDir, LOCK_FILE);
4621
4653
  const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
4622
4654
  try {
4623
4655
  const fd = await (0, import_promises12.open)(lockPath, "wx");
@@ -4658,7 +4690,7 @@ async function watch(config, onChange, options = {}) {
4658
4690
  if (lock === null) {
4659
4691
  let holderPid = "unknown";
4660
4692
  try {
4661
- const raw = await (0, import_promises14.readFile)((0, import_node_path16.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4693
+ const raw = await (0, import_promises14.readFile)((0, import_node_path17.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4662
4694
  const data = JSON.parse(raw);
4663
4695
  if (data.pid !== void 0) holderPid = String(data.pid);
4664
4696
  } catch {
@@ -4711,7 +4743,7 @@ async function watch(config, onChange, options = {}) {
4711
4743
  }
4712
4744
  let pagesDebounceTimer;
4713
4745
  const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
4714
- const pagesWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, pagesGlob), {
4746
+ const pagesWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, pagesGlob), {
4715
4747
  ignoreInitial: true,
4716
4748
  persistent: true,
4717
4749
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4738,7 +4770,7 @@ async function watch(config, onChange, options = {}) {
4738
4770
  pagesWatcher.on("unlink", schedulePagesRegenerate);
4739
4771
  let contractsDebounceTimer;
4740
4772
  const pendingChangedPaths = /* @__PURE__ */ new Set();
4741
- const contractsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.contracts.glob), {
4773
+ const contractsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.contracts.glob), {
4742
4774
  ignoreInitial: true,
4743
4775
  persistent: true,
4744
4776
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4768,7 +4800,7 @@ async function watch(config, onChange, options = {}) {
4768
4800
  contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
4769
4801
  contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
4770
4802
  contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
4771
- const formsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.forms.watch), {
4803
+ const formsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.forms.watch), {
4772
4804
  ignoreInitial: true,
4773
4805
  persistent: true,
4774
4806
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4795,7 +4827,7 @@ async function watch(config, onChange, options = {}) {
4795
4827
  }
4796
4828
 
4797
4829
  // src/index.ts
4798
- var VERSION = "0.16.0";
4830
+ var VERSION = "0.17.1";
4799
4831
 
4800
4832
  // src/generate-manifest.ts
4801
4833
  var MANIFEST_FILE = ".codegen-manifest.json";
@@ -4819,6 +4851,9 @@ function isManifestShape(value) {
4819
4851
  if (candidate.configKeyHashes !== void 0 && !isStringRecord(candidate.configKeyHashes)) {
4820
4852
  return false;
4821
4853
  }
4854
+ if (candidate.extraInputs !== void 0 && (!Array.isArray(candidate.extraInputs) || !candidate.extraInputs.every((entry) => typeof entry === "string"))) {
4855
+ return false;
4856
+ }
4822
4857
  if (!Array.isArray(candidate.files)) return false;
4823
4858
  return candidate.files.every((entry) => typeof entry === "string");
4824
4859
  }
@@ -4858,26 +4893,35 @@ async function discoverInputFiles(config) {
4858
4893
  const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
4859
4894
  return [...new Set(matched)].sort();
4860
4895
  }
4861
- async function computeInputsHash(config) {
4896
+ async function computeInputsHash(config, extraInputs = []) {
4862
4897
  const hash = (0, import_node_crypto.createHash)("sha256");
4863
4898
  hash.update(`version:${VERSION}
4864
4899
  `);
4865
4900
  hash.update(`config:${serializeConfig(config)}
4866
4901
  `);
4867
- const inputFiles = await discoverInputFiles(config);
4868
4902
  const cwd = config.codegen.cwd;
4869
- for (const file of inputFiles) {
4903
+ const globbed = await discoverInputFiles(config);
4904
+ const globbedRelative = new Set(globbed.map((file) => (0, import_node_path18.relative)(cwd, file)));
4905
+ const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
4906
+ for (const file of globbed) {
4870
4907
  const contents = await (0, import_promises15.readFile)(file, "utf8");
4871
- hash.update(`file:${(0, import_node_path17.relative)(cwd, file)}
4908
+ hash.update(`file:${(0, import_node_path18.relative)(cwd, file)}
4872
4909
  `);
4873
4910
  hash.update(contents);
4874
4911
  hash.update("\n");
4875
4912
  }
4913
+ for (const file of extra) {
4914
+ const contents = await (0, import_promises15.readFile)((0, import_node_path18.join)(cwd, file), "utf8").catch(() => null);
4915
+ hash.update(`extra:${file}
4916
+ `);
4917
+ hash.update(contents ?? "\0missing");
4918
+ hash.update("\n");
4919
+ }
4876
4920
  return hash.digest("hex");
4877
4921
  }
4878
4922
  async function readManifest(outDir) {
4879
4923
  try {
4880
- const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(outDir, MANIFEST_FILE), "utf8");
4924
+ const raw = await (0, import_promises15.readFile)((0, import_node_path18.join)(outDir, MANIFEST_FILE), "utf8");
4881
4925
  const parsed = JSON.parse(raw);
4882
4926
  if (!isManifestShape(parsed)) return null;
4883
4927
  return {
@@ -4886,6 +4930,7 @@ async function readManifest(outDir) {
4886
4930
  ...parsed.entryPoint ? { entryPoint: parsed.entryPoint } : {},
4887
4931
  ...parsed.configHash ? { configHash: parsed.configHash } : {},
4888
4932
  ...parsed.configKeyHashes ? { configKeyHashes: parsed.configKeyHashes } : {},
4933
+ ...parsed.extraInputs ? { extraInputs: parsed.extraInputs } : {},
4889
4934
  files: parsed.files
4890
4935
  };
4891
4936
  } catch {
@@ -4896,7 +4941,7 @@ function computeConfigHash(config) {
4896
4941
  return (0, import_node_crypto.createHash)("sha256").update(serializeConfig(config)).digest("hex");
4897
4942
  }
4898
4943
  async function writeManifest(outDir, manifest) {
4899
- await (0, import_promises15.writeFile)((0, import_node_path17.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
4944
+ await (0, import_promises15.writeFile)((0, import_node_path18.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
4900
4945
  `, "utf8");
4901
4946
  }
4902
4947
  async function listOutputFiles(outDir) {
@@ -4904,11 +4949,11 @@ async function listOutputFiles(outDir) {
4904
4949
  async function walk(dir) {
4905
4950
  const entries = await (0, import_promises15.readdir)(dir, { withFileTypes: true }).catch(() => []);
4906
4951
  for (const entry of entries) {
4907
- const abs = (0, import_node_path17.join)(dir, entry.name);
4952
+ const abs = (0, import_node_path18.join)(dir, entry.name);
4908
4953
  if (entry.isDirectory()) {
4909
4954
  await walk(abs);
4910
4955
  } else if (entry.isFile()) {
4911
- const rel = (0, import_node_path17.relative)(outDir, abs);
4956
+ const rel = (0, import_node_path18.relative)(outDir, abs);
4912
4957
  if (rel === MANIFEST_FILE || rel === LOCK_FILE2) continue;
4913
4958
  found.push(rel);
4914
4959
  }