@dudousxd/nestjs-codegen 0.10.0 → 0.12.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.
- package/CHANGELOG.md +47 -0
- package/dist/cli/main.cjs +209 -89
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +193 -73
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +167 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +154 -34
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +212 -73
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +15 -4
- package/dist/nest/index.d.ts +15 -4
- package/dist/nest/index.js +212 -73
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/nest/index.cjs
CHANGED
|
@@ -174,8 +174,8 @@ function applyDefaults(userConfig, cwd) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
// src/watch/watcher.ts
|
|
177
|
-
var
|
|
178
|
-
var
|
|
177
|
+
var import_promises15 = require("fs/promises");
|
|
178
|
+
var import_node_path17 = require("path");
|
|
179
179
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
180
180
|
|
|
181
181
|
// src/discovery/contracts-fast.ts
|
|
@@ -2315,8 +2315,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
2315
2315
|
}
|
|
2316
2316
|
|
|
2317
2317
|
// src/generate.ts
|
|
2318
|
-
var
|
|
2319
|
-
var
|
|
2318
|
+
var import_promises14 = require("fs/promises");
|
|
2319
|
+
var import_node_path16 = require("path");
|
|
2320
2320
|
|
|
2321
2321
|
// src/discovery/pages.ts
|
|
2322
2322
|
var import_promises2 = require("fs/promises");
|
|
@@ -2930,7 +2930,11 @@ function buildRequestModel(c) {
|
|
|
2930
2930
|
urlExpr,
|
|
2931
2931
|
optsExpr,
|
|
2932
2932
|
responseType: `${TA}['response']`,
|
|
2933
|
-
|
|
2933
|
+
// When no input is supplied the key omits the trailing element entirely
|
|
2934
|
+
// (`[name]` rather than `[name, undefined]`) so the bare `.queryKey()` is a
|
|
2935
|
+
// clean prefix that partial-matches every parametrized variant — making it
|
|
2936
|
+
// directly usable for `invalidateQueries`.
|
|
2937
|
+
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)`
|
|
2934
2938
|
};
|
|
2935
2939
|
}
|
|
2936
2940
|
function renderFetcherRequest(req) {
|
|
@@ -4207,9 +4211,159 @@ function buildEmpty() {
|
|
|
4207
4211
|
].join("\n");
|
|
4208
4212
|
}
|
|
4209
4213
|
|
|
4214
|
+
// src/generate-manifest.ts
|
|
4215
|
+
var import_node_crypto = require("crypto");
|
|
4216
|
+
var import_promises13 = require("fs/promises");
|
|
4217
|
+
var import_node_path15 = require("path");
|
|
4218
|
+
var import_fast_glob3 = __toESM(require("fast-glob"), 1);
|
|
4219
|
+
|
|
4220
|
+
// src/watch/lock-file.ts
|
|
4221
|
+
var import_promises11 = require("fs/promises");
|
|
4222
|
+
var import_promises12 = require("fs/promises");
|
|
4223
|
+
var import_node_path14 = require("path");
|
|
4224
|
+
var LOCK_FILE = ".watcher.lock";
|
|
4225
|
+
function isProcessAlive(pid) {
|
|
4226
|
+
try {
|
|
4227
|
+
process.kill(pid, 0);
|
|
4228
|
+
return true;
|
|
4229
|
+
} catch {
|
|
4230
|
+
return false;
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
async function acquireLock(outDir) {
|
|
4234
|
+
await (0, import_promises12.mkdir)(outDir, { recursive: true });
|
|
4235
|
+
const lockPath = (0, import_node_path14.join)(outDir, LOCK_FILE);
|
|
4236
|
+
const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4237
|
+
try {
|
|
4238
|
+
const fd = await (0, import_promises11.open)(lockPath, "wx");
|
|
4239
|
+
await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
|
|
4240
|
+
`, "utf8");
|
|
4241
|
+
await fd.close();
|
|
4242
|
+
} catch (err) {
|
|
4243
|
+
if (err.code === "EEXIST") {
|
|
4244
|
+
try {
|
|
4245
|
+
const raw = await (0, import_promises12.readFile)(lockPath, "utf8");
|
|
4246
|
+
const existing = JSON.parse(raw);
|
|
4247
|
+
if (isProcessAlive(existing.pid)) return null;
|
|
4248
|
+
await (0, import_promises12.unlink)(lockPath);
|
|
4249
|
+
return acquireLock(outDir);
|
|
4250
|
+
} catch {
|
|
4251
|
+
return null;
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
return null;
|
|
4255
|
+
}
|
|
4256
|
+
return {
|
|
4257
|
+
release: async () => {
|
|
4258
|
+
try {
|
|
4259
|
+
await (0, import_promises12.unlink)(lockPath);
|
|
4260
|
+
} catch {
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
// src/index.ts
|
|
4267
|
+
var VERSION = "0.12.0";
|
|
4268
|
+
|
|
4269
|
+
// src/generate-manifest.ts
|
|
4270
|
+
var MANIFEST_FILE = ".codegen-manifest.json";
|
|
4271
|
+
var LOCK_FILE2 = ".watcher.lock";
|
|
4272
|
+
function isManifestShape(value) {
|
|
4273
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4274
|
+
const candidate = value;
|
|
4275
|
+
if (typeof candidate.version !== "string") return false;
|
|
4276
|
+
if (typeof candidate.hash !== "string") return false;
|
|
4277
|
+
if (!Array.isArray(candidate.files)) return false;
|
|
4278
|
+
return candidate.files.every((entry) => typeof entry === "string");
|
|
4279
|
+
}
|
|
4280
|
+
function serializeConfig(config) {
|
|
4281
|
+
try {
|
|
4282
|
+
return JSON.stringify(config, (_key, value) => {
|
|
4283
|
+
if (typeof value === "function") return `[fn:${value.name}]${value.toString()}`;
|
|
4284
|
+
return value;
|
|
4285
|
+
});
|
|
4286
|
+
} catch {
|
|
4287
|
+
return `unserializable:${config.codegen.outDir}:${config.contracts.glob}`;
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
async function discoverInputFiles(config) {
|
|
4291
|
+
const globs = [config.contracts.glob, config.forms.watch];
|
|
4292
|
+
if (config.pages) globs.push(config.pages.glob);
|
|
4293
|
+
const cwd = config.codegen.cwd;
|
|
4294
|
+
const matched = await (0, import_fast_glob3.default)(globs, { cwd, absolute: true, onlyFiles: true });
|
|
4295
|
+
return [...new Set(matched)].sort();
|
|
4296
|
+
}
|
|
4297
|
+
async function computeInputsHash(config) {
|
|
4298
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
4299
|
+
hash.update(`version:${VERSION}
|
|
4300
|
+
`);
|
|
4301
|
+
hash.update(`config:${serializeConfig(config)}
|
|
4302
|
+
`);
|
|
4303
|
+
const inputFiles = await discoverInputFiles(config);
|
|
4304
|
+
const cwd = config.codegen.cwd;
|
|
4305
|
+
for (const file of inputFiles) {
|
|
4306
|
+
const contents = await (0, import_promises13.readFile)(file, "utf8");
|
|
4307
|
+
hash.update(`file:${(0, import_node_path15.relative)(cwd, file)}
|
|
4308
|
+
`);
|
|
4309
|
+
hash.update(contents);
|
|
4310
|
+
hash.update("\n");
|
|
4311
|
+
}
|
|
4312
|
+
return hash.digest("hex");
|
|
4313
|
+
}
|
|
4314
|
+
async function readManifest(outDir) {
|
|
4315
|
+
try {
|
|
4316
|
+
const raw = await (0, import_promises13.readFile)((0, import_node_path15.join)(outDir, MANIFEST_FILE), "utf8");
|
|
4317
|
+
const parsed = JSON.parse(raw);
|
|
4318
|
+
if (!isManifestShape(parsed)) return null;
|
|
4319
|
+
return { version: parsed.version, hash: parsed.hash, files: parsed.files };
|
|
4320
|
+
} catch {
|
|
4321
|
+
return null;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
async function writeManifest(outDir, manifest) {
|
|
4325
|
+
await (0, import_promises13.writeFile)((0, import_node_path15.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
|
|
4326
|
+
`, "utf8");
|
|
4327
|
+
}
|
|
4328
|
+
async function listOutputFiles(outDir) {
|
|
4329
|
+
const found = [];
|
|
4330
|
+
async function walk(dir) {
|
|
4331
|
+
const entries = await (0, import_promises13.readdir)(dir, { withFileTypes: true }).catch(() => []);
|
|
4332
|
+
for (const entry of entries) {
|
|
4333
|
+
const abs = (0, import_node_path15.join)(dir, entry.name);
|
|
4334
|
+
if (entry.isDirectory()) {
|
|
4335
|
+
await walk(abs);
|
|
4336
|
+
} else if (entry.isFile()) {
|
|
4337
|
+
const rel = (0, import_node_path15.relative)(outDir, abs);
|
|
4338
|
+
if (rel === MANIFEST_FILE || rel === LOCK_FILE2) continue;
|
|
4339
|
+
found.push(rel);
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
await walk(outDir);
|
|
4344
|
+
return found.sort();
|
|
4345
|
+
}
|
|
4346
|
+
async function allOutputsExist(outDir, files) {
|
|
4347
|
+
const present = new Set(await listOutputFiles(outDir));
|
|
4348
|
+
return files.every((file) => present.has(file));
|
|
4349
|
+
}
|
|
4350
|
+
async function isManifestFresh(outDir, manifest, inputsHash) {
|
|
4351
|
+
if (manifest === null) return false;
|
|
4352
|
+
if (manifest.version !== VERSION) return false;
|
|
4353
|
+
if (manifest.hash !== inputsHash) return false;
|
|
4354
|
+
if (manifest.files.length === 0) return false;
|
|
4355
|
+
return allOutputsExist(outDir, manifest.files);
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4210
4358
|
// src/generate.ts
|
|
4211
4359
|
async function generate(config, inputRoutes = []) {
|
|
4212
4360
|
setCodegenDebug(config.debug);
|
|
4361
|
+
const inputsHash = await computeInputsHash(config);
|
|
4362
|
+
const manifest = await readManifest(config.codegen.outDir);
|
|
4363
|
+
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
4364
|
+
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
4365
|
+
return;
|
|
4366
|
+
}
|
|
4213
4367
|
const extensions = config.extensions ?? [];
|
|
4214
4368
|
let routes = inputRoutes;
|
|
4215
4369
|
const ctx = createExtensionContext(config, () => routes);
|
|
@@ -4266,69 +4420,29 @@ async function generate(config, inputRoutes = []) {
|
|
|
4266
4420
|
if (extensions.length > 0) {
|
|
4267
4421
|
const extraFiles = await collectEmittedFiles(extensions, ctx);
|
|
4268
4422
|
for (const file of extraFiles) {
|
|
4269
|
-
const dest = (0,
|
|
4270
|
-
await (0,
|
|
4271
|
-
await (0,
|
|
4272
|
-
}
|
|
4273
|
-
}
|
|
4274
|
-
}
|
|
4275
|
-
|
|
4276
|
-
// src/watch/lock-file.ts
|
|
4277
|
-
var import_promises12 = require("fs/promises");
|
|
4278
|
-
var import_promises13 = require("fs/promises");
|
|
4279
|
-
var import_node_path15 = require("path");
|
|
4280
|
-
var LOCK_FILE = ".watcher.lock";
|
|
4281
|
-
function isProcessAlive(pid) {
|
|
4282
|
-
try {
|
|
4283
|
-
process.kill(pid, 0);
|
|
4284
|
-
return true;
|
|
4285
|
-
} catch {
|
|
4286
|
-
return false;
|
|
4287
|
-
}
|
|
4288
|
-
}
|
|
4289
|
-
async function acquireLock(outDir) {
|
|
4290
|
-
await (0, import_promises13.mkdir)(outDir, { recursive: true });
|
|
4291
|
-
const lockPath = (0, import_node_path15.join)(outDir, LOCK_FILE);
|
|
4292
|
-
const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4293
|
-
try {
|
|
4294
|
-
const fd = await (0, import_promises12.open)(lockPath, "wx");
|
|
4295
|
-
await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
|
|
4296
|
-
`, "utf8");
|
|
4297
|
-
await fd.close();
|
|
4298
|
-
} catch (err) {
|
|
4299
|
-
if (err.code === "EEXIST") {
|
|
4300
|
-
try {
|
|
4301
|
-
const raw = await (0, import_promises13.readFile)(lockPath, "utf8");
|
|
4302
|
-
const existing = JSON.parse(raw);
|
|
4303
|
-
if (isProcessAlive(existing.pid)) return null;
|
|
4304
|
-
await (0, import_promises13.unlink)(lockPath);
|
|
4305
|
-
return acquireLock(outDir);
|
|
4306
|
-
} catch {
|
|
4307
|
-
return null;
|
|
4308
|
-
}
|
|
4423
|
+
const dest = (0, import_node_path16.join)(config.codegen.outDir, file.path);
|
|
4424
|
+
await (0, import_promises14.mkdir)((0, import_node_path16.dirname)(dest), { recursive: true });
|
|
4425
|
+
await (0, import_promises14.writeFile)(dest, file.contents, "utf8");
|
|
4309
4426
|
}
|
|
4310
|
-
return null;
|
|
4311
4427
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
}
|
|
4319
|
-
};
|
|
4428
|
+
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
4429
|
+
await writeManifest(config.codegen.outDir, {
|
|
4430
|
+
version: VERSION,
|
|
4431
|
+
hash: inputsHash,
|
|
4432
|
+
files: outputFiles
|
|
4433
|
+
});
|
|
4320
4434
|
}
|
|
4321
4435
|
|
|
4322
4436
|
// src/watch/watcher.ts
|
|
4323
4437
|
var PAGES_DEBOUNCE_MS = 150;
|
|
4324
4438
|
var NO_OP_WATCHER = { close: async () => {
|
|
4325
4439
|
} };
|
|
4326
|
-
async function watch(config, onChange) {
|
|
4440
|
+
async function watch(config, onChange, options = {}) {
|
|
4327
4441
|
const lock = await acquireLock(config.codegen.outDir);
|
|
4328
4442
|
if (lock === null) {
|
|
4329
4443
|
let holderPid = "unknown";
|
|
4330
4444
|
try {
|
|
4331
|
-
const raw = await (0,
|
|
4445
|
+
const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
|
|
4332
4446
|
const data = JSON.parse(raw);
|
|
4333
4447
|
if (data.pid !== void 0) holderPid = String(data.pid);
|
|
4334
4448
|
} catch {
|
|
@@ -4351,22 +4465,33 @@ async function watch(config, onChange) {
|
|
|
4351
4465
|
}
|
|
4352
4466
|
return discovery;
|
|
4353
4467
|
}
|
|
4354
|
-
|
|
4355
|
-
const initialRoutes = (await getDiscovery()).discover();
|
|
4356
|
-
lastRoutes = initialRoutes;
|
|
4357
|
-
await generate(config, initialRoutes);
|
|
4358
|
-
} catch (err) {
|
|
4359
|
-
console.warn(
|
|
4360
|
-
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4361
|
-
);
|
|
4468
|
+
async function runInitialPass() {
|
|
4362
4469
|
try {
|
|
4363
|
-
await
|
|
4364
|
-
|
|
4470
|
+
const initialRoutes = (await getDiscovery()).discover();
|
|
4471
|
+
lastRoutes = initialRoutes;
|
|
4472
|
+
await generate(config, initialRoutes);
|
|
4473
|
+
} catch (err) {
|
|
4474
|
+
console.warn(
|
|
4475
|
+
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4476
|
+
);
|
|
4477
|
+
try {
|
|
4478
|
+
await generate(config, lastRoutes);
|
|
4479
|
+
} catch {
|
|
4480
|
+
}
|
|
4365
4481
|
}
|
|
4366
4482
|
}
|
|
4483
|
+
if (options.deferInitialGenerate) {
|
|
4484
|
+
void runInitialPass().catch((err) => {
|
|
4485
|
+
console.warn(
|
|
4486
|
+
`[nestjs-codegen] Background initial generate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4487
|
+
);
|
|
4488
|
+
});
|
|
4489
|
+
} else {
|
|
4490
|
+
await runInitialPass();
|
|
4491
|
+
}
|
|
4367
4492
|
let pagesDebounceTimer;
|
|
4368
4493
|
const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
|
|
4369
|
-
const pagesWatcher = import_chokidar.default.watch((0,
|
|
4494
|
+
const pagesWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, pagesGlob), {
|
|
4370
4495
|
ignoreInitial: true,
|
|
4371
4496
|
persistent: true,
|
|
4372
4497
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4393,7 +4518,7 @@ async function watch(config, onChange) {
|
|
|
4393
4518
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
4394
4519
|
let contractsDebounceTimer;
|
|
4395
4520
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
4396
|
-
const contractsWatcher = import_chokidar.default.watch((0,
|
|
4521
|
+
const contractsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.contracts.glob), {
|
|
4397
4522
|
ignoreInitial: true,
|
|
4398
4523
|
persistent: true,
|
|
4399
4524
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4423,7 +4548,7 @@ async function watch(config, onChange) {
|
|
|
4423
4548
|
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
4424
4549
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
4425
4550
|
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
4426
|
-
const formsWatcher = import_chokidar.default.watch((0,
|
|
4551
|
+
const formsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.forms.watch), {
|
|
4427
4552
|
ignoreInitial: true,
|
|
4428
4553
|
persistent: true,
|
|
4429
4554
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4451,9 +4576,13 @@ async function watch(config, onChange) {
|
|
|
4451
4576
|
|
|
4452
4577
|
// src/nest/module.ts
|
|
4453
4578
|
var CODEGEN_MODULE_OPTIONS = Symbol("NESTJS_CODEGEN_MODULE_OPTIONS");
|
|
4579
|
+
function isProductionEnv(env) {
|
|
4580
|
+
return (env ?? "").trim().toLowerCase() === "production";
|
|
4581
|
+
}
|
|
4454
4582
|
function shouldRun(options, env) {
|
|
4455
4583
|
if (options.enabled !== void 0) return options.enabled;
|
|
4456
|
-
|
|
4584
|
+
if (isProductionEnv(env)) return options.runInProduction === true;
|
|
4585
|
+
return true;
|
|
4457
4586
|
}
|
|
4458
4587
|
var NestjsCodegenService = class {
|
|
4459
4588
|
constructor(options) {
|
|
@@ -4462,11 +4591,21 @@ var NestjsCodegenService = class {
|
|
|
4462
4591
|
logger = new import_common.Logger("NestjsCodegen");
|
|
4463
4592
|
watcher = null;
|
|
4464
4593
|
async onApplicationBootstrap() {
|
|
4465
|
-
if (!shouldRun(this.options, process.env.NODE_ENV))
|
|
4466
|
-
|
|
4594
|
+
if (!shouldRun(this.options, process.env.NODE_ENV)) {
|
|
4595
|
+
if (this.options.enabled === void 0 && isProductionEnv(process.env.NODE_ENV)) {
|
|
4596
|
+
this.logger.log("Skipped in production (set runInProduction: true to override).");
|
|
4597
|
+
}
|
|
4598
|
+
return;
|
|
4599
|
+
}
|
|
4600
|
+
const {
|
|
4601
|
+
enabled: _enabled,
|
|
4602
|
+
runInProduction: _runInProduction,
|
|
4603
|
+
cwd,
|
|
4604
|
+
...userConfig
|
|
4605
|
+
} = this.options;
|
|
4467
4606
|
try {
|
|
4468
4607
|
const config = resolveConfig(userConfig, cwd ?? process.cwd());
|
|
4469
|
-
this.watcher = await watch(config);
|
|
4608
|
+
this.watcher = await watch(config, void 0, { deferInitialGenerate: true });
|
|
4470
4609
|
this.logger.log(`Watching ${config.contracts.glob} \u2192 ${config.codegen.outDir}`);
|
|
4471
4610
|
} catch (err) {
|
|
4472
4611
|
this.logger.warn(
|