@dudousxd/nestjs-codegen 0.16.0 → 0.17.0

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;
@@ -4208,7 +4225,7 @@ function parseDefineContractCall(callExpr) {
4208
4225
 
4209
4226
  // src/discovery/contracts-fast.ts
4210
4227
  function resolveTsconfigPath(cwd, tsconfig) {
4211
- return tsconfig ? (0, import_node_path14.resolve)(tsconfig) : (0, import_node_path14.join)(cwd, "tsconfig.json");
4228
+ return tsconfig ? (0, import_node_path15.resolve)(tsconfig) : (0, import_node_path15.join)(cwd, "tsconfig.json");
4212
4229
  }
4213
4230
  function createDiscoveryProject(tsconfigPath) {
4214
4231
  try {
@@ -4287,7 +4304,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4287
4304
  async rediscover(changedPaths) {
4288
4305
  if (changedPaths) {
4289
4306
  for (const p of changedPaths) {
4290
- const abs = (0, import_node_path14.resolve)(p);
4307
+ const abs = (0, import_node_path15.resolve)(p);
4291
4308
  const sf = this.project.getSourceFile(abs);
4292
4309
  if (sf) {
4293
4310
  await sf.refreshFromFileSystem();
@@ -4605,7 +4622,7 @@ function extractFromSourceFile(sourceFile, project) {
4605
4622
  // src/watch/lock-file.ts
4606
4623
  var import_promises12 = require("fs/promises");
4607
4624
  var import_promises13 = require("fs/promises");
4608
- var import_node_path15 = require("path");
4625
+ var import_node_path16 = require("path");
4609
4626
  var LOCK_FILE = ".watcher.lock";
4610
4627
  function isProcessAlive(pid) {
4611
4628
  try {
@@ -4617,7 +4634,7 @@ function isProcessAlive(pid) {
4617
4634
  }
4618
4635
  async function acquireLock(outDir) {
4619
4636
  await (0, import_promises13.mkdir)(outDir, { recursive: true });
4620
- const lockPath = (0, import_node_path15.join)(outDir, LOCK_FILE);
4637
+ const lockPath = (0, import_node_path16.join)(outDir, LOCK_FILE);
4621
4638
  const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
4622
4639
  try {
4623
4640
  const fd = await (0, import_promises12.open)(lockPath, "wx");
@@ -4658,7 +4675,7 @@ async function watch(config, onChange, options = {}) {
4658
4675
  if (lock === null) {
4659
4676
  let holderPid = "unknown";
4660
4677
  try {
4661
- const raw = await (0, import_promises14.readFile)((0, import_node_path16.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4678
+ const raw = await (0, import_promises14.readFile)((0, import_node_path17.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4662
4679
  const data = JSON.parse(raw);
4663
4680
  if (data.pid !== void 0) holderPid = String(data.pid);
4664
4681
  } catch {
@@ -4711,7 +4728,7 @@ async function watch(config, onChange, options = {}) {
4711
4728
  }
4712
4729
  let pagesDebounceTimer;
4713
4730
  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), {
4731
+ const pagesWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, pagesGlob), {
4715
4732
  ignoreInitial: true,
4716
4733
  persistent: true,
4717
4734
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4738,7 +4755,7 @@ async function watch(config, onChange, options = {}) {
4738
4755
  pagesWatcher.on("unlink", schedulePagesRegenerate);
4739
4756
  let contractsDebounceTimer;
4740
4757
  const pendingChangedPaths = /* @__PURE__ */ new Set();
4741
- const contractsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.contracts.glob), {
4758
+ const contractsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.contracts.glob), {
4742
4759
  ignoreInitial: true,
4743
4760
  persistent: true,
4744
4761
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4768,7 +4785,7 @@ async function watch(config, onChange, options = {}) {
4768
4785
  contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
4769
4786
  contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
4770
4787
  contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
4771
- const formsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.forms.watch), {
4788
+ const formsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.forms.watch), {
4772
4789
  ignoreInitial: true,
4773
4790
  persistent: true,
4774
4791
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4795,7 +4812,7 @@ async function watch(config, onChange, options = {}) {
4795
4812
  }
4796
4813
 
4797
4814
  // src/index.ts
4798
- var VERSION = "0.16.0";
4815
+ var VERSION = "0.17.0";
4799
4816
 
4800
4817
  // src/generate-manifest.ts
4801
4818
  var MANIFEST_FILE = ".codegen-manifest.json";
@@ -4819,6 +4836,9 @@ function isManifestShape(value) {
4819
4836
  if (candidate.configKeyHashes !== void 0 && !isStringRecord(candidate.configKeyHashes)) {
4820
4837
  return false;
4821
4838
  }
4839
+ if (candidate.extraInputs !== void 0 && (!Array.isArray(candidate.extraInputs) || !candidate.extraInputs.every((entry) => typeof entry === "string"))) {
4840
+ return false;
4841
+ }
4822
4842
  if (!Array.isArray(candidate.files)) return false;
4823
4843
  return candidate.files.every((entry) => typeof entry === "string");
4824
4844
  }
@@ -4858,26 +4878,35 @@ async function discoverInputFiles(config) {
4858
4878
  const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
4859
4879
  return [...new Set(matched)].sort();
4860
4880
  }
4861
- async function computeInputsHash(config) {
4881
+ async function computeInputsHash(config, extraInputs = []) {
4862
4882
  const hash = (0, import_node_crypto.createHash)("sha256");
4863
4883
  hash.update(`version:${VERSION}
4864
4884
  `);
4865
4885
  hash.update(`config:${serializeConfig(config)}
4866
4886
  `);
4867
- const inputFiles = await discoverInputFiles(config);
4868
4887
  const cwd = config.codegen.cwd;
4869
- for (const file of inputFiles) {
4888
+ const globbed = await discoverInputFiles(config);
4889
+ const globbedRelative = new Set(globbed.map((file) => (0, import_node_path18.relative)(cwd, file)));
4890
+ const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
4891
+ for (const file of globbed) {
4870
4892
  const contents = await (0, import_promises15.readFile)(file, "utf8");
4871
- hash.update(`file:${(0, import_node_path17.relative)(cwd, file)}
4893
+ hash.update(`file:${(0, import_node_path18.relative)(cwd, file)}
4872
4894
  `);
4873
4895
  hash.update(contents);
4874
4896
  hash.update("\n");
4875
4897
  }
4898
+ for (const file of extra) {
4899
+ const contents = await (0, import_promises15.readFile)((0, import_node_path18.join)(cwd, file), "utf8").catch(() => null);
4900
+ hash.update(`extra:${file}
4901
+ `);
4902
+ hash.update(contents ?? "\0missing");
4903
+ hash.update("\n");
4904
+ }
4876
4905
  return hash.digest("hex");
4877
4906
  }
4878
4907
  async function readManifest(outDir) {
4879
4908
  try {
4880
- const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(outDir, MANIFEST_FILE), "utf8");
4909
+ const raw = await (0, import_promises15.readFile)((0, import_node_path18.join)(outDir, MANIFEST_FILE), "utf8");
4881
4910
  const parsed = JSON.parse(raw);
4882
4911
  if (!isManifestShape(parsed)) return null;
4883
4912
  return {
@@ -4886,6 +4915,7 @@ async function readManifest(outDir) {
4886
4915
  ...parsed.entryPoint ? { entryPoint: parsed.entryPoint } : {},
4887
4916
  ...parsed.configHash ? { configHash: parsed.configHash } : {},
4888
4917
  ...parsed.configKeyHashes ? { configKeyHashes: parsed.configKeyHashes } : {},
4918
+ ...parsed.extraInputs ? { extraInputs: parsed.extraInputs } : {},
4889
4919
  files: parsed.files
4890
4920
  };
4891
4921
  } catch {
@@ -4896,7 +4926,7 @@ function computeConfigHash(config) {
4896
4926
  return (0, import_node_crypto.createHash)("sha256").update(serializeConfig(config)).digest("hex");
4897
4927
  }
4898
4928
  async function writeManifest(outDir, manifest) {
4899
- await (0, import_promises15.writeFile)((0, import_node_path17.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
4929
+ await (0, import_promises15.writeFile)((0, import_node_path18.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
4900
4930
  `, "utf8");
4901
4931
  }
4902
4932
  async function listOutputFiles(outDir) {
@@ -4904,11 +4934,11 @@ async function listOutputFiles(outDir) {
4904
4934
  async function walk(dir) {
4905
4935
  const entries = await (0, import_promises15.readdir)(dir, { withFileTypes: true }).catch(() => []);
4906
4936
  for (const entry of entries) {
4907
- const abs = (0, import_node_path17.join)(dir, entry.name);
4937
+ const abs = (0, import_node_path18.join)(dir, entry.name);
4908
4938
  if (entry.isDirectory()) {
4909
4939
  await walk(abs);
4910
4940
  } else if (entry.isFile()) {
4911
- const rel = (0, import_node_path17.relative)(outDir, abs);
4941
+ const rel = (0, import_node_path18.relative)(outDir, abs);
4912
4942
  if (rel === MANIFEST_FILE || rel === LOCK_FILE2) continue;
4913
4943
  found.push(rel);
4914
4944
  }