@dudousxd/nestjs-codegen 0.11.0 → 0.13.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 +59 -0
- package/dist/cli/main.cjs +264 -91
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +248 -75
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/{index-CxkGbILp.d.cts → index-DvUzPXdh.d.cts} +7 -0
- package/dist/{index-CxkGbILp.d.ts → index-DvUzPXdh.d.ts} +7 -0
- package/dist/index.cjs +222 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -5
- package/dist/index.d.ts +31 -5
- package/dist/index.js +209 -36
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +267 -75
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +16 -5
- package/dist/nest/index.d.ts +16 -5
- package/dist/nest/index.js +267 -75
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-
|
|
1
|
+
export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-DvUzPXdh.cjs';
|
|
2
2
|
import 'ts-morph';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-
|
|
1
|
+
export { m as ApiClientLayer, n as ApiHeaderContribution, o as ApiModuleDeps, C as CodegenExtension, p as EmittedFile, E as ExtensionContext, L as LeafModel, q as RequestModel, s as RequestShape, t as defineExtension, u as requestShape } from '../index-DvUzPXdh.js';
|
|
2
2
|
import 'ts-morph';
|
|
@@ -489,6 +489,13 @@ interface ContractSource {
|
|
|
489
489
|
* `AsyncIterable<T>` stream rather than a single awaited value.
|
|
490
490
|
*/
|
|
491
491
|
stream?: boolean;
|
|
492
|
+
/**
|
|
493
|
+
* True when the route consumes `multipart/form-data` — its handler takes an
|
|
494
|
+
* `@UploadedFile()` / `@UploadedFiles()` (via a Multer interceptor). The
|
|
495
|
+
* uploaded-file field(s) are merged into `body` as `File | Blob`, and the
|
|
496
|
+
* generated client serializes the body to a `FormData` instead of JSON.
|
|
497
|
+
*/
|
|
498
|
+
multipart?: boolean;
|
|
492
499
|
}
|
|
493
500
|
interface ContractDescriptor {
|
|
494
501
|
contractSource: ContractSource;
|
|
@@ -489,6 +489,13 @@ interface ContractSource {
|
|
|
489
489
|
* `AsyncIterable<T>` stream rather than a single awaited value.
|
|
490
490
|
*/
|
|
491
491
|
stream?: boolean;
|
|
492
|
+
/**
|
|
493
|
+
* True when the route consumes `multipart/form-data` — its handler takes an
|
|
494
|
+
* `@UploadedFile()` / `@UploadedFiles()` (via a Multer interceptor). The
|
|
495
|
+
* uploaded-file field(s) are merged into `body` as `File | Blob`, and the
|
|
496
|
+
* generated client serializes the body to a `FormData` instead of JSON.
|
|
497
|
+
*/
|
|
498
|
+
multipart?: boolean;
|
|
492
499
|
}
|
|
493
500
|
interface ContractDescriptor {
|
|
494
501
|
contractSource: ContractSource;
|
package/dist/index.cjs
CHANGED
|
@@ -248,8 +248,8 @@ Run \`nestjs-codegen init\` to create a starter config.`
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
// src/generate.ts
|
|
251
|
-
var
|
|
252
|
-
var
|
|
251
|
+
var import_promises12 = require("fs/promises");
|
|
252
|
+
var import_node_path13 = require("path");
|
|
253
253
|
|
|
254
254
|
// src/discovery/pages.ts
|
|
255
255
|
var import_promises2 = require("fs/promises");
|
|
@@ -851,6 +851,7 @@ function buildRequestModel(c) {
|
|
|
851
851
|
const optsParts = [];
|
|
852
852
|
if (hasQuery) optsParts.push("query: input?.query as Record<string, unknown> | undefined");
|
|
853
853
|
if (hasBody) optsParts.push("body: input?.body");
|
|
854
|
+
if (hasBody && c.contractSource.multipart) optsParts.push("multipart: true");
|
|
854
855
|
const optsExpr = optsParts.length ? `{ ${optsParts.join(", ")} }` : "{}";
|
|
855
856
|
return {
|
|
856
857
|
routeName: c.name,
|
|
@@ -2147,6 +2148,99 @@ function buildEmpty() {
|
|
|
2147
2148
|
].join("\n");
|
|
2148
2149
|
}
|
|
2149
2150
|
|
|
2151
|
+
// src/generate-manifest.ts
|
|
2152
|
+
var import_node_crypto = require("crypto");
|
|
2153
|
+
var import_promises11 = require("fs/promises");
|
|
2154
|
+
var import_node_path12 = require("path");
|
|
2155
|
+
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
2156
|
+
var MANIFEST_FILE = ".codegen-manifest.json";
|
|
2157
|
+
var LOCK_FILE = ".watcher.lock";
|
|
2158
|
+
function isManifestShape(value) {
|
|
2159
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2160
|
+
const candidate = value;
|
|
2161
|
+
if (typeof candidate.version !== "string") return false;
|
|
2162
|
+
if (typeof candidate.hash !== "string") return false;
|
|
2163
|
+
if (!Array.isArray(candidate.files)) return false;
|
|
2164
|
+
return candidate.files.every((entry) => typeof entry === "string");
|
|
2165
|
+
}
|
|
2166
|
+
function serializeConfig(config) {
|
|
2167
|
+
try {
|
|
2168
|
+
return JSON.stringify(config, (_key, value) => {
|
|
2169
|
+
if (typeof value === "function") return `[fn:${value.name}]${value.toString()}`;
|
|
2170
|
+
return value;
|
|
2171
|
+
});
|
|
2172
|
+
} catch {
|
|
2173
|
+
return `unserializable:${config.codegen.outDir}:${config.contracts.glob}`;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
async function discoverInputFiles(config) {
|
|
2177
|
+
const globs = [config.contracts.glob, config.forms.watch];
|
|
2178
|
+
if (config.pages) globs.push(config.pages.glob);
|
|
2179
|
+
const cwd = config.codegen.cwd;
|
|
2180
|
+
const matched = await (0, import_fast_glob2.default)(globs, { cwd, absolute: true, onlyFiles: true });
|
|
2181
|
+
return [...new Set(matched)].sort();
|
|
2182
|
+
}
|
|
2183
|
+
async function computeInputsHash(config) {
|
|
2184
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
2185
|
+
hash.update(`version:${VERSION}
|
|
2186
|
+
`);
|
|
2187
|
+
hash.update(`config:${serializeConfig(config)}
|
|
2188
|
+
`);
|
|
2189
|
+
const inputFiles = await discoverInputFiles(config);
|
|
2190
|
+
const cwd = config.codegen.cwd;
|
|
2191
|
+
for (const file of inputFiles) {
|
|
2192
|
+
const contents = await (0, import_promises11.readFile)(file, "utf8");
|
|
2193
|
+
hash.update(`file:${(0, import_node_path12.relative)(cwd, file)}
|
|
2194
|
+
`);
|
|
2195
|
+
hash.update(contents);
|
|
2196
|
+
hash.update("\n");
|
|
2197
|
+
}
|
|
2198
|
+
return hash.digest("hex");
|
|
2199
|
+
}
|
|
2200
|
+
async function readManifest(outDir) {
|
|
2201
|
+
try {
|
|
2202
|
+
const raw = await (0, import_promises11.readFile)((0, import_node_path12.join)(outDir, MANIFEST_FILE), "utf8");
|
|
2203
|
+
const parsed = JSON.parse(raw);
|
|
2204
|
+
if (!isManifestShape(parsed)) return null;
|
|
2205
|
+
return { version: parsed.version, hash: parsed.hash, files: parsed.files };
|
|
2206
|
+
} catch {
|
|
2207
|
+
return null;
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
async function writeManifest(outDir, manifest) {
|
|
2211
|
+
await (0, import_promises11.writeFile)((0, import_node_path12.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
|
|
2212
|
+
`, "utf8");
|
|
2213
|
+
}
|
|
2214
|
+
async function listOutputFiles(outDir) {
|
|
2215
|
+
const found = [];
|
|
2216
|
+
async function walk(dir) {
|
|
2217
|
+
const entries = await (0, import_promises11.readdir)(dir, { withFileTypes: true }).catch(() => []);
|
|
2218
|
+
for (const entry of entries) {
|
|
2219
|
+
const abs = (0, import_node_path12.join)(dir, entry.name);
|
|
2220
|
+
if (entry.isDirectory()) {
|
|
2221
|
+
await walk(abs);
|
|
2222
|
+
} else if (entry.isFile()) {
|
|
2223
|
+
const rel = (0, import_node_path12.relative)(outDir, abs);
|
|
2224
|
+
if (rel === MANIFEST_FILE || rel === LOCK_FILE) continue;
|
|
2225
|
+
found.push(rel);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
await walk(outDir);
|
|
2230
|
+
return found.sort();
|
|
2231
|
+
}
|
|
2232
|
+
async function allOutputsExist(outDir, files) {
|
|
2233
|
+
const present = new Set(await listOutputFiles(outDir));
|
|
2234
|
+
return files.every((file) => present.has(file));
|
|
2235
|
+
}
|
|
2236
|
+
async function isManifestFresh(outDir, manifest, inputsHash) {
|
|
2237
|
+
if (manifest === null) return false;
|
|
2238
|
+
if (manifest.version !== VERSION) return false;
|
|
2239
|
+
if (manifest.hash !== inputsHash) return false;
|
|
2240
|
+
if (manifest.files.length === 0) return false;
|
|
2241
|
+
return allOutputsExist(outDir, manifest.files);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2150
2244
|
// src/util/debug-log.ts
|
|
2151
2245
|
var debugEnabled = false;
|
|
2152
2246
|
function setCodegenDebug(enabled) {
|
|
@@ -2159,6 +2253,12 @@ function debugWarn(message) {
|
|
|
2159
2253
|
// src/generate.ts
|
|
2160
2254
|
async function generate(config, inputRoutes = []) {
|
|
2161
2255
|
setCodegenDebug(config.debug);
|
|
2256
|
+
const inputsHash = await computeInputsHash(config);
|
|
2257
|
+
const manifest = await readManifest(config.codegen.outDir);
|
|
2258
|
+
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
2259
|
+
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
2260
|
+
return;
|
|
2261
|
+
}
|
|
2162
2262
|
const extensions = config.extensions ?? [];
|
|
2163
2263
|
let routes = inputRoutes;
|
|
2164
2264
|
const ctx = createExtensionContext(config, () => routes);
|
|
@@ -2215,21 +2315,27 @@ async function generate(config, inputRoutes = []) {
|
|
|
2215
2315
|
if (extensions.length > 0) {
|
|
2216
2316
|
const extraFiles = await collectEmittedFiles(extensions, ctx);
|
|
2217
2317
|
for (const file of extraFiles) {
|
|
2218
|
-
const dest = (0,
|
|
2219
|
-
await (0,
|
|
2220
|
-
await (0,
|
|
2318
|
+
const dest = (0, import_node_path13.join)(config.codegen.outDir, file.path);
|
|
2319
|
+
await (0, import_promises12.mkdir)((0, import_node_path13.dirname)(dest), { recursive: true });
|
|
2320
|
+
await (0, import_promises12.writeFile)(dest, file.contents, "utf8");
|
|
2221
2321
|
}
|
|
2222
2322
|
}
|
|
2323
|
+
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
2324
|
+
await writeManifest(config.codegen.outDir, {
|
|
2325
|
+
version: VERSION,
|
|
2326
|
+
hash: inputsHash,
|
|
2327
|
+
files: outputFiles
|
|
2328
|
+
});
|
|
2223
2329
|
}
|
|
2224
2330
|
|
|
2225
2331
|
// src/watch/watcher.ts
|
|
2226
|
-
var
|
|
2227
|
-
var
|
|
2332
|
+
var import_promises15 = require("fs/promises");
|
|
2333
|
+
var import_node_path17 = require("path");
|
|
2228
2334
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
2229
2335
|
|
|
2230
2336
|
// src/discovery/contracts-fast.ts
|
|
2231
|
-
var
|
|
2232
|
-
var
|
|
2337
|
+
var import_node_path15 = require("path");
|
|
2338
|
+
var import_fast_glob3 = __toESM(require("fast-glob"), 1);
|
|
2233
2339
|
var import_ts_morph9 = require("ts-morph");
|
|
2234
2340
|
|
|
2235
2341
|
// src/discovery/dto-type-resolver.ts
|
|
@@ -2240,7 +2346,7 @@ var import_ts_morph4 = require("ts-morph");
|
|
|
2240
2346
|
|
|
2241
2347
|
// src/discovery/type-ref-resolution.ts
|
|
2242
2348
|
var import_node_fs = require("fs");
|
|
2243
|
-
var
|
|
2349
|
+
var import_node_path14 = require("path");
|
|
2244
2350
|
var import_ts_morph3 = require("ts-morph");
|
|
2245
2351
|
var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
|
|
2246
2352
|
var _ctxByProject = /* @__PURE__ */ new WeakMap();
|
|
@@ -2292,12 +2398,12 @@ function findTypeInFile(name, file) {
|
|
|
2292
2398
|
}
|
|
2293
2399
|
function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
2294
2400
|
if (moduleSpecifier.startsWith(".")) {
|
|
2295
|
-
const dir = (0,
|
|
2401
|
+
const dir = (0, import_node_path14.dirname)(sourceFile.getFilePath());
|
|
2296
2402
|
const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
|
|
2297
2403
|
return [
|
|
2298
|
-
(0,
|
|
2299
|
-
(0,
|
|
2300
|
-
(0,
|
|
2404
|
+
(0, import_node_path14.resolve)(dir, `${noExt}.ts`),
|
|
2405
|
+
(0, import_node_path14.resolve)(dir, `${moduleSpecifier}.ts`),
|
|
2406
|
+
(0, import_node_path14.resolve)(dir, moduleSpecifier, "index.ts")
|
|
2301
2407
|
];
|
|
2302
2408
|
}
|
|
2303
2409
|
const ctx = _ctxFor(project);
|
|
@@ -2318,8 +2424,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
|
2318
2424
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
2319
2425
|
const candidates = [];
|
|
2320
2426
|
for (const mapping of mappings) {
|
|
2321
|
-
const resolved = (0,
|
|
2322
|
-
candidates.push(`${resolved}.ts`, (0,
|
|
2427
|
+
const resolved = (0, import_node_path14.resolve)(baseUrl, mapping.replace("*", rest));
|
|
2428
|
+
candidates.push(`${resolved}.ts`, (0, import_node_path14.resolve)(resolved, "index.ts"));
|
|
2323
2429
|
}
|
|
2324
2430
|
dbg(" resolved candidates:", candidates);
|
|
2325
2431
|
return candidates;
|
|
@@ -3629,6 +3735,55 @@ function extractParamsType(method, sourceFile, project) {
|
|
|
3629
3735
|
}
|
|
3630
3736
|
return entries.length > 0 ? `{ ${entries.join("; ")} }` : null;
|
|
3631
3737
|
}
|
|
3738
|
+
function extractUploadedFiles(method) {
|
|
3739
|
+
const FILE = "File | Blob";
|
|
3740
|
+
const entries = [];
|
|
3741
|
+
let multipart = false;
|
|
3742
|
+
const hasUploadedFileParam = method.getParameters().some(
|
|
3743
|
+
(p) => p.getDecorators().some((d) => {
|
|
3744
|
+
const name = d.getName();
|
|
3745
|
+
return name === "UploadedFile" || name === "UploadedFiles";
|
|
3746
|
+
})
|
|
3747
|
+
);
|
|
3748
|
+
for (const decorator of method.getDecorators()) {
|
|
3749
|
+
if (decorator.getName() !== "UseInterceptors") continue;
|
|
3750
|
+
for (const arg of decorator.getArguments()) {
|
|
3751
|
+
if (!import_ts_morph7.Node.isCallExpression(arg)) continue;
|
|
3752
|
+
const interceptor = arg.getExpression().getText();
|
|
3753
|
+
const callArgs = arg.getArguments();
|
|
3754
|
+
const firstArg2 = callArgs[0];
|
|
3755
|
+
if (interceptor === "FileInterceptor") {
|
|
3756
|
+
if (firstArg2 && import_ts_morph7.Node.isStringLiteral(firstArg2)) {
|
|
3757
|
+
entries.push(`${firstArg2.getLiteralValue()}: ${FILE}`);
|
|
3758
|
+
multipart = true;
|
|
3759
|
+
}
|
|
3760
|
+
} else if (interceptor === "FilesInterceptor") {
|
|
3761
|
+
if (firstArg2 && import_ts_morph7.Node.isStringLiteral(firstArg2)) {
|
|
3762
|
+
entries.push(`${firstArg2.getLiteralValue()}: Array<${FILE}>`);
|
|
3763
|
+
multipart = true;
|
|
3764
|
+
}
|
|
3765
|
+
} else if (interceptor === "FileFieldsInterceptor") {
|
|
3766
|
+
if (firstArg2 && import_ts_morph7.Node.isArrayLiteralExpression(firstArg2)) {
|
|
3767
|
+
for (const el of firstArg2.getElements()) {
|
|
3768
|
+
if (!import_ts_morph7.Node.isObjectLiteralExpression(el)) continue;
|
|
3769
|
+
const nameProp = el.getProperty("name");
|
|
3770
|
+
if (nameProp && import_ts_morph7.Node.isPropertyAssignment(nameProp)) {
|
|
3771
|
+
const init = nameProp.getInitializer();
|
|
3772
|
+
if (init && import_ts_morph7.Node.isStringLiteral(init)) {
|
|
3773
|
+
entries.push(`${init.getLiteralValue()}: Array<${FILE}>`);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
multipart = true;
|
|
3778
|
+
}
|
|
3779
|
+
} else if (interceptor === "AnyFilesInterceptor") {
|
|
3780
|
+
multipart = true;
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
if (hasUploadedFileParam) multipart = true;
|
|
3785
|
+
return { fields: entries.length > 0 ? entries.join("; ") : null, multipart };
|
|
3786
|
+
}
|
|
3632
3787
|
function extractResponseType(method, sourceFile, project) {
|
|
3633
3788
|
const apiResponseDecorator = method.getDecorators().find((d) => d.getName() === "ApiResponse" && (apiResponseStatus(d) ?? 0) < 400);
|
|
3634
3789
|
if (apiResponseDecorator) {
|
|
@@ -3763,6 +3918,11 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
3763
3918
|
let body = extractBodyType(method, sourceFile, project);
|
|
3764
3919
|
const filterInfo = extractApplyFilterInfo(method, sourceFile, project);
|
|
3765
3920
|
const query = extractQueryType(method, sourceFile, project);
|
|
3921
|
+
const uploads = extractUploadedFiles(method);
|
|
3922
|
+
if (uploads.fields) {
|
|
3923
|
+
const fileObject = `{ ${uploads.fields} }`;
|
|
3924
|
+
body = body ? `(${body}) & ${fileObject}` : fileObject;
|
|
3925
|
+
}
|
|
3766
3926
|
const streamElement = detectStreamElement(method);
|
|
3767
3927
|
const isStream = streamElement !== null;
|
|
3768
3928
|
if (filterInfo && filterInfo.source === "body") {
|
|
@@ -3772,7 +3932,7 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
3772
3932
|
const paramsType = extractParamsType(method, sourceFile, project);
|
|
3773
3933
|
const response = isStream ? resolveTypeNodeToString(streamElement, sourceFile, project, 3) : extractResponseType(method, sourceFile, project);
|
|
3774
3934
|
const errorInfo = extractErrorType(method, sourceFile, project);
|
|
3775
|
-
if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream) {
|
|
3935
|
+
if (body === null && query === null && paramsType === null && response === "unknown" && errorInfo === null && filterInfo === null && !isStream && !uploads.multipart) {
|
|
3776
3936
|
return null;
|
|
3777
3937
|
}
|
|
3778
3938
|
let bodyRef = null;
|
|
@@ -3845,7 +4005,8 @@ function extractDtoContract(method, sourceFile, project) {
|
|
|
3845
4005
|
formWarnings,
|
|
3846
4006
|
bodySchema,
|
|
3847
4007
|
querySchema,
|
|
3848
|
-
stream: isStream
|
|
4008
|
+
stream: isStream,
|
|
4009
|
+
multipart: uploads.multipart
|
|
3849
4010
|
};
|
|
3850
4011
|
}
|
|
3851
4012
|
function resolveParamClass(method, decoratorName, sourceFile, project) {
|
|
@@ -3991,7 +4152,7 @@ async function discoverContractsFast(opts) {
|
|
|
3991
4152
|
const { cwd, glob, tsconfig } = opts;
|
|
3992
4153
|
const tsconfigPath = resolveTsconfigPath(cwd, tsconfig);
|
|
3993
4154
|
const project = createDiscoveryProject(tsconfigPath);
|
|
3994
|
-
const files = await (0,
|
|
4155
|
+
const files = await (0, import_fast_glob3.default)(glob, { cwd, absolute: true, onlyFiles: true });
|
|
3995
4156
|
for (const f of files) {
|
|
3996
4157
|
project.addSourceFileAtPath(f);
|
|
3997
4158
|
}
|
|
@@ -3999,7 +4160,7 @@ async function discoverContractsFast(opts) {
|
|
|
3999
4160
|
return extractAllRoutes(project);
|
|
4000
4161
|
}
|
|
4001
4162
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
4002
|
-
return tsconfig ? (0,
|
|
4163
|
+
return tsconfig ? (0, import_node_path15.resolve)(tsconfig) : (0, import_node_path15.join)(cwd, "tsconfig.json");
|
|
4003
4164
|
}
|
|
4004
4165
|
function createDiscoveryProject(tsconfigPath) {
|
|
4005
4166
|
try {
|
|
@@ -4064,7 +4225,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4064
4225
|
const project = createDiscoveryProject(tsconfigPath);
|
|
4065
4226
|
bindDiscoveryContext(project, cwd, tsconfigPath);
|
|
4066
4227
|
const instance = new _PersistentDiscovery(project, cwd, glob);
|
|
4067
|
-
const files = await (0,
|
|
4228
|
+
const files = await (0, import_fast_glob3.default)(glob, { cwd, absolute: true, onlyFiles: true });
|
|
4068
4229
|
for (const f of files) {
|
|
4069
4230
|
project.addSourceFileAtPath(f);
|
|
4070
4231
|
instance.controllerPaths.add(f);
|
|
@@ -4085,7 +4246,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4085
4246
|
async rediscover(changedPaths) {
|
|
4086
4247
|
if (changedPaths) {
|
|
4087
4248
|
for (const p of changedPaths) {
|
|
4088
|
-
const abs = (0,
|
|
4249
|
+
const abs = (0, import_node_path15.resolve)(p);
|
|
4089
4250
|
const sf = this.project.getSourceFile(abs);
|
|
4090
4251
|
if (sf) {
|
|
4091
4252
|
await sf.refreshFromFileSystem();
|
|
@@ -4093,7 +4254,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4093
4254
|
}
|
|
4094
4255
|
}
|
|
4095
4256
|
const globbed = new Set(
|
|
4096
|
-
await (0,
|
|
4257
|
+
await (0, import_fast_glob3.default)(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
|
|
4097
4258
|
);
|
|
4098
4259
|
for (const f of globbed) {
|
|
4099
4260
|
if (!this.controllerPaths.has(f)) {
|
|
@@ -4330,7 +4491,8 @@ function extractDtoRoute(args) {
|
|
|
4330
4491
|
formWarnings: dtoContract?.formWarnings ?? [],
|
|
4331
4492
|
bodySchema: dtoContract?.bodySchema ?? null,
|
|
4332
4493
|
querySchema: dtoContract?.querySchema ?? null,
|
|
4333
|
-
stream: dtoContract?.stream ?? false
|
|
4494
|
+
stream: dtoContract?.stream ?? false,
|
|
4495
|
+
multipart: dtoContract?.multipart ?? false
|
|
4334
4496
|
}
|
|
4335
4497
|
});
|
|
4336
4498
|
}
|
|
@@ -4373,10 +4535,10 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4373
4535
|
}
|
|
4374
4536
|
|
|
4375
4537
|
// src/watch/lock-file.ts
|
|
4376
|
-
var import_promises12 = require("fs/promises");
|
|
4377
4538
|
var import_promises13 = require("fs/promises");
|
|
4378
|
-
var
|
|
4379
|
-
var
|
|
4539
|
+
var import_promises14 = require("fs/promises");
|
|
4540
|
+
var import_node_path16 = require("path");
|
|
4541
|
+
var LOCK_FILE2 = ".watcher.lock";
|
|
4380
4542
|
function isProcessAlive(pid) {
|
|
4381
4543
|
try {
|
|
4382
4544
|
process.kill(pid, 0);
|
|
@@ -4386,21 +4548,21 @@ function isProcessAlive(pid) {
|
|
|
4386
4548
|
}
|
|
4387
4549
|
}
|
|
4388
4550
|
async function acquireLock(outDir) {
|
|
4389
|
-
await (0,
|
|
4390
|
-
const lockPath = (0,
|
|
4551
|
+
await (0, import_promises14.mkdir)(outDir, { recursive: true });
|
|
4552
|
+
const lockPath = (0, import_node_path16.join)(outDir, LOCK_FILE2);
|
|
4391
4553
|
const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4392
4554
|
try {
|
|
4393
|
-
const fd = await (0,
|
|
4555
|
+
const fd = await (0, import_promises13.open)(lockPath, "wx");
|
|
4394
4556
|
await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
|
|
4395
4557
|
`, "utf8");
|
|
4396
4558
|
await fd.close();
|
|
4397
4559
|
} catch (err) {
|
|
4398
4560
|
if (err.code === "EEXIST") {
|
|
4399
4561
|
try {
|
|
4400
|
-
const raw = await (0,
|
|
4562
|
+
const raw = await (0, import_promises14.readFile)(lockPath, "utf8");
|
|
4401
4563
|
const existing = JSON.parse(raw);
|
|
4402
4564
|
if (isProcessAlive(existing.pid)) return null;
|
|
4403
|
-
await (0,
|
|
4565
|
+
await (0, import_promises14.unlink)(lockPath);
|
|
4404
4566
|
return acquireLock(outDir);
|
|
4405
4567
|
} catch {
|
|
4406
4568
|
return null;
|
|
@@ -4411,7 +4573,7 @@ async function acquireLock(outDir) {
|
|
|
4411
4573
|
return {
|
|
4412
4574
|
release: async () => {
|
|
4413
4575
|
try {
|
|
4414
|
-
await (0,
|
|
4576
|
+
await (0, import_promises14.unlink)(lockPath);
|
|
4415
4577
|
} catch {
|
|
4416
4578
|
}
|
|
4417
4579
|
}
|
|
@@ -4422,12 +4584,12 @@ async function acquireLock(outDir) {
|
|
|
4422
4584
|
var PAGES_DEBOUNCE_MS = 150;
|
|
4423
4585
|
var NO_OP_WATCHER = { close: async () => {
|
|
4424
4586
|
} };
|
|
4425
|
-
async function watch(config, onChange) {
|
|
4587
|
+
async function watch(config, onChange, options = {}) {
|
|
4426
4588
|
const lock = await acquireLock(config.codegen.outDir);
|
|
4427
4589
|
if (lock === null) {
|
|
4428
4590
|
let holderPid = "unknown";
|
|
4429
4591
|
try {
|
|
4430
|
-
const raw = await (0,
|
|
4592
|
+
const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
|
|
4431
4593
|
const data = JSON.parse(raw);
|
|
4432
4594
|
if (data.pid !== void 0) holderPid = String(data.pid);
|
|
4433
4595
|
} catch {
|
|
@@ -4450,22 +4612,33 @@ async function watch(config, onChange) {
|
|
|
4450
4612
|
}
|
|
4451
4613
|
return discovery;
|
|
4452
4614
|
}
|
|
4453
|
-
|
|
4454
|
-
const initialRoutes = (await getDiscovery()).discover();
|
|
4455
|
-
lastRoutes = initialRoutes;
|
|
4456
|
-
await generate(config, initialRoutes);
|
|
4457
|
-
} catch (err) {
|
|
4458
|
-
console.warn(
|
|
4459
|
-
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4460
|
-
);
|
|
4615
|
+
async function runInitialPass() {
|
|
4461
4616
|
try {
|
|
4462
|
-
await
|
|
4463
|
-
|
|
4617
|
+
const initialRoutes = (await getDiscovery()).discover();
|
|
4618
|
+
lastRoutes = initialRoutes;
|
|
4619
|
+
await generate(config, initialRoutes);
|
|
4620
|
+
} catch (err) {
|
|
4621
|
+
console.warn(
|
|
4622
|
+
`[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
|
|
4623
|
+
);
|
|
4624
|
+
try {
|
|
4625
|
+
await generate(config, lastRoutes);
|
|
4626
|
+
} catch {
|
|
4627
|
+
}
|
|
4464
4628
|
}
|
|
4465
4629
|
}
|
|
4630
|
+
if (options.deferInitialGenerate) {
|
|
4631
|
+
void runInitialPass().catch((err) => {
|
|
4632
|
+
console.warn(
|
|
4633
|
+
`[nestjs-codegen] Background initial generate failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4634
|
+
);
|
|
4635
|
+
});
|
|
4636
|
+
} else {
|
|
4637
|
+
await runInitialPass();
|
|
4638
|
+
}
|
|
4466
4639
|
let pagesDebounceTimer;
|
|
4467
4640
|
const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
|
|
4468
|
-
const pagesWatcher = import_chokidar.default.watch((0,
|
|
4641
|
+
const pagesWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, pagesGlob), {
|
|
4469
4642
|
ignoreInitial: true,
|
|
4470
4643
|
persistent: true,
|
|
4471
4644
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4492,7 +4665,7 @@ async function watch(config, onChange) {
|
|
|
4492
4665
|
pagesWatcher.on("unlink", schedulePagesRegenerate);
|
|
4493
4666
|
let contractsDebounceTimer;
|
|
4494
4667
|
const pendingChangedPaths = /* @__PURE__ */ new Set();
|
|
4495
|
-
const contractsWatcher = import_chokidar.default.watch((0,
|
|
4668
|
+
const contractsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.contracts.glob), {
|
|
4496
4669
|
ignoreInitial: true,
|
|
4497
4670
|
persistent: true,
|
|
4498
4671
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4522,7 +4695,7 @@ async function watch(config, onChange) {
|
|
|
4522
4695
|
contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
|
|
4523
4696
|
contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
|
|
4524
4697
|
contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
|
|
4525
|
-
const formsWatcher = import_chokidar.default.watch((0,
|
|
4698
|
+
const formsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.forms.watch), {
|
|
4526
4699
|
ignoreInitial: true,
|
|
4527
4700
|
persistent: true,
|
|
4528
4701
|
awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
|
|
@@ -4632,7 +4805,7 @@ function createChainModuleRenderer(opts) {
|
|
|
4632
4805
|
}
|
|
4633
4806
|
|
|
4634
4807
|
// src/index.ts
|
|
4635
|
-
var VERSION = "0.
|
|
4808
|
+
var VERSION = "0.13.0";
|
|
4636
4809
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4637
4810
|
0 && (module.exports = {
|
|
4638
4811
|
CodegenError,
|