@dudousxd/nestjs-codegen 0.15.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.
- package/CHANGELOG.md +56 -0
- package/dist/cli/main.cjs +299 -147
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +239 -87
- package/dist/cli/main.js.map +1 -1
- package/dist/extension/index.cjs.map +1 -1
- package/dist/extension/index.d.cts +1 -1
- package/dist/extension/index.d.ts +1 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-CjIDPMsV.d.cts → index-DCF9QSPY.d.cts} +47 -0
- package/dist/{index-CjIDPMsV.d.ts → index-DCF9QSPY.d.ts} +47 -0
- package/dist/index.cjs +262 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +233 -81
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +261 -110
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +1 -1
- package/dist/nest/index.d.ts +1 -1
- package/dist/nest/index.js +232 -81
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -514,9 +514,10 @@ function inferExpressionType(node) {
|
|
|
514
514
|
|
|
515
515
|
// src/emit/emit-api.ts
|
|
516
516
|
import { mkdir, writeFile } from "fs/promises";
|
|
517
|
-
import { isAbsolute as isAbsolute2, join as join4, relative as
|
|
517
|
+
import { isAbsolute as isAbsolute2, join as join4, relative as relative4 } from "path";
|
|
518
518
|
|
|
519
519
|
// src/extension/registry.ts
|
|
520
|
+
import { relative as relative3, resolve as resolve2 } from "path";
|
|
520
521
|
import { Project as Project2 } from "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(relative3(config.codegen.cwd, resolve2(config.codegen.cwd, path)));
|
|
567
|
+
}
|
|
568
|
+
},
|
|
561
569
|
project() {
|
|
562
570
|
if (!project) {
|
|
563
571
|
project = new Project2({
|
|
@@ -725,7 +733,7 @@ function rawResponseType(c, outDir) {
|
|
|
725
733
|
return c.contractSource.response;
|
|
726
734
|
}
|
|
727
735
|
if (c.controllerRef) {
|
|
728
|
-
let relPath =
|
|
736
|
+
let relPath = relative4(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();
|
|
@@ -1107,7 +1120,7 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1107
1120
|
for (const [filePath, names] of importsByFile) {
|
|
1108
1121
|
let relPath;
|
|
1109
1122
|
if (isAbsolute2(filePath)) {
|
|
1110
|
-
relPath =
|
|
1123
|
+
relPath = relative4(outDir, filePath).replace(/\.ts$/, "");
|
|
1111
1124
|
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
1112
1125
|
} else {
|
|
1113
1126
|
relPath = filePath;
|
|
@@ -1221,7 +1234,7 @@ async function emitCache(pages, outDir) {
|
|
|
1221
1234
|
|
|
1222
1235
|
// src/emit/emit-forms.ts
|
|
1223
1236
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
1224
|
-
import { join as join6, relative as
|
|
1237
|
+
import { join as join6, relative as relative5 } from "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);
|
|
@@ -1240,7 +1253,7 @@ function deriveBaseName(routeName) {
|
|
|
1240
1253
|
return { method, full };
|
|
1241
1254
|
}
|
|
1242
1255
|
function relImport(outDir, filePath) {
|
|
1243
|
-
let relPath =
|
|
1256
|
+
let relPath = relative5(outDir, filePath).replace(/\.ts$/, "");
|
|
1244
1257
|
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
1245
1258
|
return relPath;
|
|
1246
1259
|
}
|
|
@@ -1988,7 +2001,7 @@ async function emitOpenApi(routes, outDir, opts = {}) {
|
|
|
1988
2001
|
|
|
1989
2002
|
// src/emit/emit-pages.ts
|
|
1990
2003
|
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
1991
|
-
import { join as join10, relative as
|
|
2004
|
+
import { join as join10, relative as relative6 } from "path";
|
|
1992
2005
|
async function emitPages(pages, outDir, _options = {}) {
|
|
1993
2006
|
await mkdir7(outDir, { recursive: true });
|
|
1994
2007
|
const pageNameUnion = pages.length > 0 ? pages.map((p) => JSON.stringify(p.name)).join(" | ") : "never";
|
|
@@ -2028,7 +2041,7 @@ ${propsBody}
|
|
|
2028
2041
|
`;
|
|
2029
2042
|
}
|
|
2030
2043
|
function buildAugmentationType(page, outDir) {
|
|
2031
|
-
let importPath =
|
|
2044
|
+
let importPath = relative6(outDir, page.absolutePath).replace(/\.(tsx?|vue|svelte)$/, "");
|
|
2032
2045
|
if (!importPath.startsWith(".")) {
|
|
2033
2046
|
importPath = `./${importPath}`;
|
|
2034
2047
|
}
|
|
@@ -2159,7 +2172,7 @@ function buildEmpty() {
|
|
|
2159
2172
|
// src/generate-manifest.ts
|
|
2160
2173
|
import { createHash } from "crypto";
|
|
2161
2174
|
import { readFile as readFile2, readdir, writeFile as writeFile9 } from "fs/promises";
|
|
2162
|
-
import { join as join12, relative as
|
|
2175
|
+
import { join as join12, relative as relative7 } from "path";
|
|
2163
2176
|
import fg2 from "fast-glob";
|
|
2164
2177
|
var MANIFEST_FILE = ".codegen-manifest.json";
|
|
2165
2178
|
var LOCK_FILE = ".watcher.lock";
|
|
@@ -2182,6 +2195,9 @@ function isManifestShape(value) {
|
|
|
2182
2195
|
if (candidate.configKeyHashes !== void 0 && !isStringRecord(candidate.configKeyHashes)) {
|
|
2183
2196
|
return false;
|
|
2184
2197
|
}
|
|
2198
|
+
if (candidate.extraInputs !== void 0 && (!Array.isArray(candidate.extraInputs) || !candidate.extraInputs.every((entry) => typeof entry === "string"))) {
|
|
2199
|
+
return false;
|
|
2200
|
+
}
|
|
2185
2201
|
if (!Array.isArray(candidate.files)) return false;
|
|
2186
2202
|
return candidate.files.every((entry) => typeof entry === "string");
|
|
2187
2203
|
}
|
|
@@ -2221,21 +2237,30 @@ async function discoverInputFiles(config) {
|
|
|
2221
2237
|
const matched = await fg2(globs, { cwd, absolute: true, onlyFiles: true });
|
|
2222
2238
|
return [...new Set(matched)].sort();
|
|
2223
2239
|
}
|
|
2224
|
-
async function computeInputsHash(config) {
|
|
2240
|
+
async function computeInputsHash(config, extraInputs = []) {
|
|
2225
2241
|
const hash = createHash("sha256");
|
|
2226
2242
|
hash.update(`version:${VERSION}
|
|
2227
2243
|
`);
|
|
2228
2244
|
hash.update(`config:${serializeConfig(config)}
|
|
2229
2245
|
`);
|
|
2230
|
-
const inputFiles = await discoverInputFiles(config);
|
|
2231
2246
|
const cwd = config.codegen.cwd;
|
|
2232
|
-
|
|
2247
|
+
const globbed = await discoverInputFiles(config);
|
|
2248
|
+
const globbedRelative = new Set(globbed.map((file) => relative7(cwd, file)));
|
|
2249
|
+
const extra = [...new Set(extraInputs)].filter((file) => !globbedRelative.has(file)).sort();
|
|
2250
|
+
for (const file of globbed) {
|
|
2233
2251
|
const contents = await readFile2(file, "utf8");
|
|
2234
|
-
hash.update(`file:${
|
|
2252
|
+
hash.update(`file:${relative7(cwd, file)}
|
|
2235
2253
|
`);
|
|
2236
2254
|
hash.update(contents);
|
|
2237
2255
|
hash.update("\n");
|
|
2238
2256
|
}
|
|
2257
|
+
for (const file of extra) {
|
|
2258
|
+
const contents = await readFile2(join12(cwd, file), "utf8").catch(() => null);
|
|
2259
|
+
hash.update(`extra:${file}
|
|
2260
|
+
`);
|
|
2261
|
+
hash.update(contents ?? "\0missing");
|
|
2262
|
+
hash.update("\n");
|
|
2263
|
+
}
|
|
2239
2264
|
return hash.digest("hex");
|
|
2240
2265
|
}
|
|
2241
2266
|
async function readManifest(outDir) {
|
|
@@ -2249,6 +2274,7 @@ async function readManifest(outDir) {
|
|
|
2249
2274
|
...parsed.entryPoint ? { entryPoint: parsed.entryPoint } : {},
|
|
2250
2275
|
...parsed.configHash ? { configHash: parsed.configHash } : {},
|
|
2251
2276
|
...parsed.configKeyHashes ? { configKeyHashes: parsed.configKeyHashes } : {},
|
|
2277
|
+
...parsed.extraInputs ? { extraInputs: parsed.extraInputs } : {},
|
|
2252
2278
|
files: parsed.files
|
|
2253
2279
|
};
|
|
2254
2280
|
} catch {
|
|
@@ -2271,7 +2297,7 @@ async function listOutputFiles(outDir) {
|
|
|
2271
2297
|
if (entry.isDirectory()) {
|
|
2272
2298
|
await walk(abs);
|
|
2273
2299
|
} else if (entry.isFile()) {
|
|
2274
|
-
const rel =
|
|
2300
|
+
const rel = relative7(outDir, abs);
|
|
2275
2301
|
if (rel === MANIFEST_FILE || rel === LOCK_FILE) continue;
|
|
2276
2302
|
found.push(rel);
|
|
2277
2303
|
}
|
|
@@ -2308,8 +2334,8 @@ function driftGuardMessage(outDir, previousEntryPoint, currentEntryPoint, differ
|
|
|
2308
2334
|
}
|
|
2309
2335
|
async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
2310
2336
|
setCodegenDebug(config.debug);
|
|
2311
|
-
const inputsHash = await computeInputsHash(config);
|
|
2312
2337
|
const manifest = await readManifest(config.codegen.outDir);
|
|
2338
|
+
const inputsHash = await computeInputsHash(config, manifest?.extraInputs ?? []);
|
|
2313
2339
|
if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
|
|
2314
2340
|
console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
|
|
2315
2341
|
return;
|
|
@@ -2330,7 +2356,8 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
2330
2356
|
}
|
|
2331
2357
|
const extensions = config.extensions ?? [];
|
|
2332
2358
|
let routes = inputRoutes;
|
|
2333
|
-
const
|
|
2359
|
+
const trackedInputs = /* @__PURE__ */ new Set();
|
|
2360
|
+
const ctx = createExtensionContext(config, () => routes, trackedInputs);
|
|
2334
2361
|
if (extensions.length > 0) {
|
|
2335
2362
|
routes = await applyTransformRoutes(routes, extensions, ctx);
|
|
2336
2363
|
}
|
|
@@ -2390,13 +2417,16 @@ async function generate(config, inputRoutes = [], entryPoint = "cli") {
|
|
|
2390
2417
|
}
|
|
2391
2418
|
}
|
|
2392
2419
|
const outputFiles = await listOutputFiles(config.codegen.outDir);
|
|
2420
|
+
const extraInputs = [...trackedInputs].sort();
|
|
2421
|
+
const recordedHash = extraInputs.length > 0 ? await computeInputsHash(config, extraInputs) : inputsHash;
|
|
2393
2422
|
await writeManifest(config.codegen.outDir, {
|
|
2394
2423
|
version: VERSION,
|
|
2395
|
-
hash:
|
|
2424
|
+
hash: recordedHash,
|
|
2396
2425
|
entryPoint,
|
|
2397
2426
|
configHash,
|
|
2398
2427
|
configKeyHashes,
|
|
2399
|
-
files: outputFiles
|
|
2428
|
+
files: outputFiles,
|
|
2429
|
+
...extraInputs.length > 0 ? { extraInputs } : {}
|
|
2400
2430
|
});
|
|
2401
2431
|
}
|
|
2402
2432
|
|
|
@@ -2406,11 +2436,11 @@ import { join as join16 } from "path";
|
|
|
2406
2436
|
import chokidar from "chokidar";
|
|
2407
2437
|
|
|
2408
2438
|
// src/discovery/contracts-fast.ts
|
|
2409
|
-
import { join as join14, resolve as
|
|
2439
|
+
import { join as join14, resolve as resolve4 } from "path";
|
|
2410
2440
|
import fg3 from "fast-glob";
|
|
2411
2441
|
import {
|
|
2412
|
-
Node as
|
|
2413
|
-
Project as
|
|
2442
|
+
Node as Node9,
|
|
2443
|
+
Project as Project4
|
|
2414
2444
|
} from "ts-morph";
|
|
2415
2445
|
|
|
2416
2446
|
// src/discovery/dto-type-resolver.ts
|
|
@@ -2426,7 +2456,7 @@ import {
|
|
|
2426
2456
|
|
|
2427
2457
|
// src/discovery/type-ref-resolution.ts
|
|
2428
2458
|
import { readFileSync } from "fs";
|
|
2429
|
-
import { dirname as dirname3, resolve as
|
|
2459
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
2430
2460
|
import {
|
|
2431
2461
|
Node as Node2
|
|
2432
2462
|
} from "ts-morph";
|
|
@@ -2483,9 +2513,9 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
|
2483
2513
|
const dir = dirname3(sourceFile.getFilePath());
|
|
2484
2514
|
const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
|
|
2485
2515
|
return [
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2516
|
+
resolve3(dir, `${noExt}.ts`),
|
|
2517
|
+
resolve3(dir, `${moduleSpecifier}.ts`),
|
|
2518
|
+
resolve3(dir, moduleSpecifier, "index.ts")
|
|
2489
2519
|
];
|
|
2490
2520
|
}
|
|
2491
2521
|
const ctx = _ctxFor(project);
|
|
@@ -2506,8 +2536,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
|
|
|
2506
2536
|
const rest = moduleSpecifier.slice(prefix.length);
|
|
2507
2537
|
const candidates = [];
|
|
2508
2538
|
for (const mapping of mappings) {
|
|
2509
|
-
const resolved =
|
|
2510
|
-
candidates.push(`${resolved}.ts`,
|
|
2539
|
+
const resolved = resolve3(baseUrl, mapping.replace("*", rest));
|
|
2540
|
+
candidates.push(`${resolved}.ts`, resolve3(resolved, "index.ts"));
|
|
2511
2541
|
}
|
|
2512
2542
|
dbg(" resolved candidates:", candidates);
|
|
2513
2543
|
return candidates;
|
|
@@ -3402,6 +3432,12 @@ function toFilterFieldType(name, r) {
|
|
|
3402
3432
|
}
|
|
3403
3433
|
|
|
3404
3434
|
// src/discovery/filter-for.ts
|
|
3435
|
+
function resolveMixinEntityClass(mixin, project) {
|
|
3436
|
+
const entityArg = mixin?.classArgs[0];
|
|
3437
|
+
if (!entityArg) return void 0;
|
|
3438
|
+
const file = project.getSourceFile(entityArg.filePath) ?? project.addSourceFileAtPathIfExists(entityArg.filePath);
|
|
3439
|
+
return file?.getClass(entityArg.name);
|
|
3440
|
+
}
|
|
3405
3441
|
function classifyFilterForHint(typeInit) {
|
|
3406
3442
|
if (Node5.isStringLiteral(typeInit)) {
|
|
3407
3443
|
switch (typeInit.getLiteralValue()) {
|
|
@@ -3475,7 +3511,9 @@ function extractFilterForHints(classDecl, project) {
|
|
|
3475
3511
|
}
|
|
3476
3512
|
return hints;
|
|
3477
3513
|
}
|
|
3478
|
-
function extractApplyFilterInfo(method, sourceFile, project) {
|
|
3514
|
+
function extractApplyFilterInfo(method, sourceFile, project, mixin) {
|
|
3515
|
+
const declFile = method.getSourceFile();
|
|
3516
|
+
const mixinEntity = resolveMixinEntityClass(mixin, project);
|
|
3479
3517
|
for (const param of method.getParameters()) {
|
|
3480
3518
|
const filterDecorator = param.getDecorators().find((d) => d.getName() === "ApplyFilter");
|
|
3481
3519
|
if (!filterDecorator) continue;
|
|
@@ -3495,12 +3533,12 @@ function extractApplyFilterInfo(method, sourceFile, project) {
|
|
|
3495
3533
|
}
|
|
3496
3534
|
}
|
|
3497
3535
|
const filterClassName = filterClassArg.getText();
|
|
3498
|
-
const resolved = findType(filterClassName,
|
|
3499
|
-
|
|
3500
|
-
|
|
3536
|
+
const resolved = findType(filterClassName, declFile, project);
|
|
3537
|
+
const classDecl = resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg);
|
|
3538
|
+
if (classDecl) {
|
|
3501
3539
|
let fieldTypes = extractClassPropertyTypes(classDecl, project);
|
|
3502
3540
|
if (fieldTypes.length === 0) {
|
|
3503
|
-
fieldTypes = extractFilterableEntityFields(classDecl, project);
|
|
3541
|
+
fieldTypes = extractFilterableEntityFields(classDecl, project, mixinEntity);
|
|
3504
3542
|
}
|
|
3505
3543
|
const filterForHints = extractFilterForHints(classDecl, project);
|
|
3506
3544
|
if (filterForHints.size > 0) {
|
|
@@ -3585,22 +3623,29 @@ function extractClassPropertyTypes(classDecl, project) {
|
|
|
3585
3623
|
}
|
|
3586
3624
|
return fields;
|
|
3587
3625
|
}
|
|
3588
|
-
function
|
|
3626
|
+
function resolveLocalClassDeclaration(identifier) {
|
|
3627
|
+
if (!Node5.isIdentifier(identifier)) return void 0;
|
|
3628
|
+
return identifier.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node5.isClassDeclaration(n));
|
|
3629
|
+
}
|
|
3630
|
+
function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
3631
|
+
if (!Node5.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
3632
|
+
const entityProp = optionsArg.getProperty("entity");
|
|
3633
|
+
if (!entityProp || !Node5.isPropertyAssignment(entityProp)) return void 0;
|
|
3634
|
+
const entityInit = entityProp.getInitializer();
|
|
3635
|
+
if (!entityInit || !Node5.isIdentifier(entityInit)) return void 0;
|
|
3636
|
+
const resolved = findType(entityInit.getText(), filterClass.getSourceFile(), project);
|
|
3637
|
+
if (!resolved || resolved.kind !== "class") return void 0;
|
|
3638
|
+
return resolved.decl;
|
|
3639
|
+
}
|
|
3640
|
+
function extractFilterableEntityFields(filterClass, project, entityOverride) {
|
|
3589
3641
|
const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
|
|
3590
3642
|
if (!filterableDecorator) return [];
|
|
3591
3643
|
const args = filterableDecorator.getArguments();
|
|
3592
3644
|
if (args.length === 0) return [];
|
|
3593
3645
|
const optionsArg = args[0];
|
|
3594
3646
|
if (!Node5.isObjectLiteralExpression(optionsArg)) return [];
|
|
3595
|
-
const
|
|
3596
|
-
if (!
|
|
3597
|
-
const entityInit = entityProp.getInitializer();
|
|
3598
|
-
if (!entityInit || !Node5.isIdentifier(entityInit)) return [];
|
|
3599
|
-
const entityName = entityInit.getText();
|
|
3600
|
-
const filterSourceFile = filterClass.getSourceFile();
|
|
3601
|
-
const resolvedEntity = findType(entityName, filterSourceFile, project);
|
|
3602
|
-
if (!resolvedEntity || resolvedEntity.kind !== "class") return [];
|
|
3603
|
-
const entityDecl = resolvedEntity.decl;
|
|
3647
|
+
const entityDecl = entityOverride ?? resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
3648
|
+
if (!entityDecl) return [];
|
|
3604
3649
|
const fields = collectEntityFields(
|
|
3605
3650
|
entityDecl,
|
|
3606
3651
|
entityDecl.getSourceFile(),
|
|
@@ -4025,9 +4070,9 @@ function unwrapNamedContainer(node, names) {
|
|
|
4025
4070
|
}
|
|
4026
4071
|
return node;
|
|
4027
4072
|
}
|
|
4028
|
-
function extractDtoContract(method, sourceFile, project) {
|
|
4073
|
+
function extractDtoContract(method, sourceFile, project, mixin) {
|
|
4029
4074
|
let body = extractBodyType(method, sourceFile, project);
|
|
4030
|
-
const filterInfo = extractApplyFilterInfo(method, sourceFile, project);
|
|
4075
|
+
const filterInfo = extractApplyFilterInfo(method, sourceFile, project, mixin);
|
|
4031
4076
|
const query = extractQueryType(method, sourceFile, project);
|
|
4032
4077
|
const uploads = extractUploadedFiles(method);
|
|
4033
4078
|
const multipartBody = uploads.fields ? `{ ${uploads.fields} }` : null;
|
|
@@ -4137,12 +4182,94 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
|
|
|
4137
4182
|
return null;
|
|
4138
4183
|
}
|
|
4139
4184
|
|
|
4185
|
+
// src/discovery/heritage.ts
|
|
4186
|
+
import { Node as Node7, Project as Project3 } from "ts-morph";
|
|
4187
|
+
function unwrapExpression(node) {
|
|
4188
|
+
let current = node;
|
|
4189
|
+
while (Node7.isAsExpression(current) || Node7.isSatisfiesExpression(current) || Node7.isParenthesizedExpression(current) || Node7.isTypeAssertion(current)) {
|
|
4190
|
+
current = current.getExpression();
|
|
4191
|
+
}
|
|
4192
|
+
return current;
|
|
4193
|
+
}
|
|
4194
|
+
function resolveReturnedClass(factoryDecl) {
|
|
4195
|
+
const body = factoryDecl.getBody();
|
|
4196
|
+
if (!body) return void 0;
|
|
4197
|
+
const returns = body.getDescendants().filter((n) => Node7.isReturnStatement(n));
|
|
4198
|
+
for (const ret of returns) {
|
|
4199
|
+
const expr = ret.getExpression();
|
|
4200
|
+
if (!expr) continue;
|
|
4201
|
+
const inner = unwrapExpression(expr);
|
|
4202
|
+
if (Node7.isClassExpression(inner)) {
|
|
4203
|
+
return inner;
|
|
4204
|
+
}
|
|
4205
|
+
if (Node7.isIdentifier(inner)) {
|
|
4206
|
+
const name = inner.getText();
|
|
4207
|
+
const decl = body.getDescendants().find((n) => Node7.isClassDeclaration(n) && n.getName() === name);
|
|
4208
|
+
if (decl) return decl;
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
return void 0;
|
|
4212
|
+
}
|
|
4213
|
+
function resolveInheritedMethods(cls) {
|
|
4214
|
+
const expr = cls.getExtends()?.getExpression();
|
|
4215
|
+
if (!expr || !Node7.isCallExpression(expr)) return void 0;
|
|
4216
|
+
const callee = expr.getExpression();
|
|
4217
|
+
if (!Node7.isIdentifier(callee)) return void 0;
|
|
4218
|
+
const factoryDecl = callee.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => Node7.isFunctionDeclaration(n));
|
|
4219
|
+
if (!factoryDecl) return void 0;
|
|
4220
|
+
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
4221
|
+
if (!returnedClass) return void 0;
|
|
4222
|
+
const classArgs = [];
|
|
4223
|
+
for (const arg of expr.getArguments()) {
|
|
4224
|
+
if (!Node7.isIdentifier(arg)) continue;
|
|
4225
|
+
const decl = arg.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => Node7.isClassDeclaration(n));
|
|
4226
|
+
if (decl) {
|
|
4227
|
+
classArgs.push({
|
|
4228
|
+
name: decl.getName() ?? arg.getText(),
|
|
4229
|
+
filePath: decl.getSourceFile().getFilePath()
|
|
4230
|
+
});
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
return {
|
|
4234
|
+
methods: returnedClass.getMethods(),
|
|
4235
|
+
factoryName: callee.getText(),
|
|
4236
|
+
factoryFilePath: factoryDecl.getSourceFile().getFilePath(),
|
|
4237
|
+
classArgs
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
var mixinTypeProject;
|
|
4241
|
+
function getMixinTypeProject() {
|
|
4242
|
+
mixinTypeProject ??= new Project3({
|
|
4243
|
+
skipAddingFilesFromTsConfig: true,
|
|
4244
|
+
compilerOptions: { strict: true }
|
|
4245
|
+
});
|
|
4246
|
+
return mixinTypeProject;
|
|
4247
|
+
}
|
|
4248
|
+
function clearMixinTypeProject() {
|
|
4249
|
+
mixinTypeProject = void 0;
|
|
4250
|
+
}
|
|
4251
|
+
function resolveInstantiatedReturnType(cls, methodName) {
|
|
4252
|
+
const filePath = cls.getSourceFile().getFilePath();
|
|
4253
|
+
const className = cls.getName();
|
|
4254
|
+
if (!className) return void 0;
|
|
4255
|
+
const project = getMixinTypeProject();
|
|
4256
|
+
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPathIfExists(filePath);
|
|
4257
|
+
const typedCls = sourceFile?.getClass(className);
|
|
4258
|
+
if (!typedCls) return void 0;
|
|
4259
|
+
const prop = typedCls.getType().getProperty(methodName);
|
|
4260
|
+
if (!prop) return void 0;
|
|
4261
|
+
const returnType = prop.getTypeAtLocation(typedCls).getCallSignatures()[0]?.getReturnType();
|
|
4262
|
+
if (!returnType) return void 0;
|
|
4263
|
+
const unwrapped = returnType.getSymbol()?.getName() === "Promise" ? returnType.getTypeArguments()[0] ?? returnType : returnType;
|
|
4264
|
+
return unwrapped.getText(typedCls);
|
|
4265
|
+
}
|
|
4266
|
+
|
|
4140
4267
|
// src/discovery/zod-ast-to-ts.ts
|
|
4141
|
-
import { Node as
|
|
4268
|
+
import { Node as Node8, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
4142
4269
|
function zodAstToTs(node) {
|
|
4143
|
-
if (!
|
|
4270
|
+
if (!Node8.isCallExpression(node)) return "unknown";
|
|
4144
4271
|
const expr = node.getExpression();
|
|
4145
|
-
if (
|
|
4272
|
+
if (Node8.isPropertyAccessExpression(expr)) {
|
|
4146
4273
|
const methodName = expr.getName();
|
|
4147
4274
|
const receiver = expr.getExpression();
|
|
4148
4275
|
if (methodName === "optional") {
|
|
@@ -4166,17 +4293,17 @@ function zodAstToTs(node) {
|
|
|
4166
4293
|
case "literal": {
|
|
4167
4294
|
const lit = args[0];
|
|
4168
4295
|
if (!lit) return "unknown";
|
|
4169
|
-
if (
|
|
4170
|
-
if (
|
|
4296
|
+
if (Node8.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
|
|
4297
|
+
if (Node8.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
|
|
4171
4298
|
if (lit.getKind() === SyntaxKind4.TrueKeyword) return "true";
|
|
4172
4299
|
if (lit.getKind() === SyntaxKind4.FalseKeyword) return "false";
|
|
4173
4300
|
return "unknown";
|
|
4174
4301
|
}
|
|
4175
4302
|
case "enum": {
|
|
4176
4303
|
const arrArg = args[0];
|
|
4177
|
-
if (!arrArg || !
|
|
4304
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4178
4305
|
const members = arrArg.getElements().map(
|
|
4179
|
-
(el) =>
|
|
4306
|
+
(el) => Node8.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
|
|
4180
4307
|
);
|
|
4181
4308
|
return members.join(" | ");
|
|
4182
4309
|
}
|
|
@@ -4187,10 +4314,10 @@ function zodAstToTs(node) {
|
|
|
4187
4314
|
}
|
|
4188
4315
|
case "object": {
|
|
4189
4316
|
const objArg = args[0];
|
|
4190
|
-
if (!objArg || !
|
|
4317
|
+
if (!objArg || !Node8.isObjectLiteralExpression(objArg)) return "unknown";
|
|
4191
4318
|
const lines = [];
|
|
4192
4319
|
for (const prop of objArg.getProperties()) {
|
|
4193
|
-
if (!
|
|
4320
|
+
if (!Node8.isPropertyAssignment(prop)) continue;
|
|
4194
4321
|
const key = prop.getName();
|
|
4195
4322
|
const valNode = prop.getInitializer();
|
|
4196
4323
|
if (!valNode) continue;
|
|
@@ -4202,7 +4329,7 @@ function zodAstToTs(node) {
|
|
|
4202
4329
|
}
|
|
4203
4330
|
case "union": {
|
|
4204
4331
|
const arrArg = args[0];
|
|
4205
|
-
if (!arrArg || !
|
|
4332
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4206
4333
|
return arrArg.getElements().map(zodAstToTs).join(" | ");
|
|
4207
4334
|
}
|
|
4208
4335
|
case "record": {
|
|
@@ -4212,7 +4339,7 @@ function zodAstToTs(node) {
|
|
|
4212
4339
|
}
|
|
4213
4340
|
case "tuple": {
|
|
4214
4341
|
const arrArg = args[0];
|
|
4215
|
-
if (!arrArg || !
|
|
4342
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4216
4343
|
return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
|
|
4217
4344
|
}
|
|
4218
4345
|
default:
|
|
@@ -4222,18 +4349,18 @@ function zodAstToTs(node) {
|
|
|
4222
4349
|
return "unknown";
|
|
4223
4350
|
}
|
|
4224
4351
|
function isOptionalChain(node) {
|
|
4225
|
-
if (!
|
|
4352
|
+
if (!Node8.isCallExpression(node)) return false;
|
|
4226
4353
|
const expr = node.getExpression();
|
|
4227
|
-
return
|
|
4354
|
+
return Node8.isPropertyAccessExpression(expr) && expr.getName() === "optional";
|
|
4228
4355
|
}
|
|
4229
4356
|
function parseDefineContractCall(callExpr) {
|
|
4230
|
-
if (!
|
|
4357
|
+
if (!Node8.isCallExpression(callExpr)) return null;
|
|
4231
4358
|
const callee = callExpr.getExpression();
|
|
4232
|
-
const calleeName =
|
|
4359
|
+
const calleeName = Node8.isIdentifier(callee) ? callee.getText() : Node8.isPropertyAccessExpression(callee) ? callee.getName() : "";
|
|
4233
4360
|
if (calleeName !== "defineContract") return null;
|
|
4234
4361
|
const args = callExpr.getArguments();
|
|
4235
4362
|
const optsArg = args[0];
|
|
4236
|
-
if (!optsArg || !
|
|
4363
|
+
if (!optsArg || !Node8.isObjectLiteralExpression(optsArg)) return null;
|
|
4237
4364
|
let query = null;
|
|
4238
4365
|
let body = null;
|
|
4239
4366
|
let response = "unknown";
|
|
@@ -4241,7 +4368,7 @@ function parseDefineContractCall(callExpr) {
|
|
|
4241
4368
|
let bodyZodText = null;
|
|
4242
4369
|
let queryZodText = null;
|
|
4243
4370
|
for (const prop of optsArg.getProperties()) {
|
|
4244
|
-
if (!
|
|
4371
|
+
if (!Node8.isPropertyAssignment(prop)) continue;
|
|
4245
4372
|
const propName = prop.getName();
|
|
4246
4373
|
const val = prop.getInitializer();
|
|
4247
4374
|
if (!val) continue;
|
|
@@ -4270,21 +4397,22 @@ async function discoverContractsFast(opts) {
|
|
|
4270
4397
|
project.addSourceFileAtPath(f);
|
|
4271
4398
|
}
|
|
4272
4399
|
bindDiscoveryContext(project, cwd, tsconfigPath);
|
|
4400
|
+
clearMixinTypeProject();
|
|
4273
4401
|
return extractAllRoutes(project);
|
|
4274
4402
|
}
|
|
4275
4403
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
4276
|
-
return tsconfig ?
|
|
4404
|
+
return tsconfig ? resolve4(tsconfig) : join14(cwd, "tsconfig.json");
|
|
4277
4405
|
}
|
|
4278
4406
|
function createDiscoveryProject(tsconfigPath) {
|
|
4279
4407
|
try {
|
|
4280
|
-
return new
|
|
4408
|
+
return new Project4({
|
|
4281
4409
|
tsConfigFilePath: tsconfigPath,
|
|
4282
4410
|
skipAddingFilesFromTsConfig: true,
|
|
4283
4411
|
skipLoadingLibFiles: true,
|
|
4284
4412
|
skipFileDependencyResolution: true
|
|
4285
4413
|
});
|
|
4286
4414
|
} catch {
|
|
4287
|
-
return new
|
|
4415
|
+
return new Project4({
|
|
4288
4416
|
skipAddingFilesFromTsConfig: true,
|
|
4289
4417
|
skipLoadingLibFiles: true,
|
|
4290
4418
|
skipFileDependencyResolution: true,
|
|
@@ -4359,7 +4487,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4359
4487
|
async rediscover(changedPaths) {
|
|
4360
4488
|
if (changedPaths) {
|
|
4361
4489
|
for (const p of changedPaths) {
|
|
4362
|
-
const abs =
|
|
4490
|
+
const abs = resolve4(p);
|
|
4363
4491
|
const sf = this.project.getSourceFile(abs);
|
|
4364
4492
|
if (sf) {
|
|
4365
4493
|
await sf.refreshFromFileSystem();
|
|
@@ -4391,15 +4519,16 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4391
4519
|
runExtraction() {
|
|
4392
4520
|
clearTypeResolutionCaches(this.project);
|
|
4393
4521
|
clearEnumCache(this.project);
|
|
4522
|
+
clearMixinTypeProject();
|
|
4394
4523
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
4395
4524
|
}
|
|
4396
4525
|
};
|
|
4397
4526
|
function decoratorStringArg(decoratorExpr) {
|
|
4398
4527
|
if (!decoratorExpr) return void 0;
|
|
4399
|
-
if (
|
|
4400
|
-
if (
|
|
4528
|
+
if (Node9.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
|
|
4529
|
+
if (Node9.isArrayLiteralExpression(decoratorExpr)) {
|
|
4401
4530
|
const first = decoratorExpr.getElements()[0];
|
|
4402
|
-
if (first &&
|
|
4531
|
+
if (first && Node9.isStringLiteral(first)) return first.getLiteralValue();
|
|
4403
4532
|
}
|
|
4404
4533
|
return void 0;
|
|
4405
4534
|
}
|
|
@@ -4421,7 +4550,8 @@ function joinPaths(prefix, suffix) {
|
|
|
4421
4550
|
if (!prefix && !suffix) return "/";
|
|
4422
4551
|
if (!prefix) return suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4423
4552
|
if (!suffix) return prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4424
|
-
const
|
|
4553
|
+
const withLeadingSlash = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4554
|
+
const p = withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
4425
4555
|
const s = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4426
4556
|
const combined = p + s;
|
|
4427
4557
|
return combined === "" ? "/" : combined;
|
|
@@ -4475,7 +4605,8 @@ function buildRoute(args) {
|
|
|
4475
4605
|
methodAs,
|
|
4476
4606
|
sourceFile,
|
|
4477
4607
|
seenNames,
|
|
4478
|
-
contractSource
|
|
4608
|
+
contractSource,
|
|
4609
|
+
mixin
|
|
4479
4610
|
} = args;
|
|
4480
4611
|
const routeName = resolveRouteName(className, methodName, classAs, methodAs);
|
|
4481
4612
|
const qualifiedRef = `${className}.${methodName}`;
|
|
@@ -4491,7 +4622,12 @@ function buildRoute(args) {
|
|
|
4491
4622
|
path: combinedPath,
|
|
4492
4623
|
name: routeName,
|
|
4493
4624
|
params: extractParams(combinedPath),
|
|
4494
|
-
controllerRef: {
|
|
4625
|
+
controllerRef: {
|
|
4626
|
+
className,
|
|
4627
|
+
methodName,
|
|
4628
|
+
filePath: sourceFile.getFilePath(),
|
|
4629
|
+
...mixin ? { mixin } : {}
|
|
4630
|
+
},
|
|
4495
4631
|
contract: { contractSource }
|
|
4496
4632
|
};
|
|
4497
4633
|
}
|
|
@@ -4505,16 +4641,17 @@ function extractContractRoute(args) {
|
|
|
4505
4641
|
className,
|
|
4506
4642
|
sourceFile,
|
|
4507
4643
|
project,
|
|
4508
|
-
seenNames
|
|
4644
|
+
seenNames,
|
|
4645
|
+
mixin
|
|
4509
4646
|
} = args;
|
|
4510
4647
|
const firstDecoratorArg = applyContractDecorator.getArguments()[0];
|
|
4511
4648
|
if (!firstDecoratorArg) return null;
|
|
4512
4649
|
let contractDef = null;
|
|
4513
4650
|
let bodyZodRef = null;
|
|
4514
4651
|
let queryZodRef = null;
|
|
4515
|
-
if (
|
|
4652
|
+
if (Node9.isCallExpression(firstDecoratorArg)) {
|
|
4516
4653
|
contractDef = parseDefineContractCall(firstDecoratorArg);
|
|
4517
|
-
} else if (
|
|
4654
|
+
} else if (Node9.isIdentifier(firstDecoratorArg)) {
|
|
4518
4655
|
const identName = firstDecoratorArg.getText();
|
|
4519
4656
|
const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
|
|
4520
4657
|
if (!resolvedVar) {
|
|
@@ -4557,6 +4694,7 @@ function extractContractRoute(args) {
|
|
|
4557
4694
|
methodAs,
|
|
4558
4695
|
sourceFile,
|
|
4559
4696
|
seenNames,
|
|
4697
|
+
mixin,
|
|
4560
4698
|
contractSource: {
|
|
4561
4699
|
query: contractDef.query,
|
|
4562
4700
|
body: contractDef.body,
|
|
@@ -4573,13 +4711,14 @@ function extractContractRoute(args) {
|
|
|
4573
4711
|
});
|
|
4574
4712
|
}
|
|
4575
4713
|
function extractDtoRoute(args) {
|
|
4576
|
-
const { cls, method, verb, prefix, className, sourceFile, project, seenNames } = args;
|
|
4714
|
+
const { cls, method, verb, prefix, className, sourceFile, project, seenNames, mixin } = args;
|
|
4577
4715
|
if (!verb) return null;
|
|
4578
4716
|
const combined = joinPaths(prefix, verb.handlerPath);
|
|
4579
4717
|
const methodName = method.getName();
|
|
4580
4718
|
const classAs = readAsDecorator(cls, `class ${className}`);
|
|
4581
4719
|
const methodAs = readAsDecorator(method, `${className}.${methodName}`);
|
|
4582
|
-
const dtoContract = extractDtoContract(method, sourceFile, project);
|
|
4720
|
+
const dtoContract = extractDtoContract(method, sourceFile, project, mixin);
|
|
4721
|
+
const mixinResponse = mixin ? resolveInstantiatedReturnType(cls, methodName) : void 0;
|
|
4583
4722
|
return buildRoute({
|
|
4584
4723
|
className,
|
|
4585
4724
|
methodName,
|
|
@@ -4589,10 +4728,11 @@ function extractDtoRoute(args) {
|
|
|
4589
4728
|
methodAs,
|
|
4590
4729
|
sourceFile,
|
|
4591
4730
|
seenNames,
|
|
4731
|
+
mixin,
|
|
4592
4732
|
contractSource: {
|
|
4593
4733
|
query: dtoContract?.query ?? null,
|
|
4594
4734
|
body: dtoContract?.body ?? null,
|
|
4595
|
-
response: dtoContract?.response ?? "unknown",
|
|
4735
|
+
response: mixinResponse ?? dtoContract?.response ?? "unknown",
|
|
4596
4736
|
error: dtoContract?.error ?? null,
|
|
4597
4737
|
queryRef: dtoContract?.queryRef ?? null,
|
|
4598
4738
|
bodyRef: dtoContract?.bodyRef ?? null,
|
|
@@ -4621,7 +4761,17 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4621
4761
|
const firstArg2 = controllerDecorator.getArguments()[0];
|
|
4622
4762
|
const prefix = decoratorStringArg(firstArg2) ?? "";
|
|
4623
4763
|
const className = cls.getName() ?? "Unknown";
|
|
4624
|
-
|
|
4764
|
+
const inherited = resolveInheritedMethods(cls);
|
|
4765
|
+
const mixinBinding = inherited ? {
|
|
4766
|
+
factoryName: inherited.factoryName,
|
|
4767
|
+
factoryFilePath: inherited.factoryFilePath,
|
|
4768
|
+
classArgs: inherited.classArgs
|
|
4769
|
+
} : void 0;
|
|
4770
|
+
const methods = [
|
|
4771
|
+
...cls.getMethods().map((method) => ({ method })),
|
|
4772
|
+
...(inherited?.methods ?? []).map((method) => ({ method, mixin: mixinBinding }))
|
|
4773
|
+
];
|
|
4774
|
+
for (const { method, mixin } of methods) {
|
|
4625
4775
|
const verb = resolveVerb(method);
|
|
4626
4776
|
const applyContractDecorator = method.getDecorator("ApplyContract");
|
|
4627
4777
|
const route = applyContractDecorator ? extractContractRoute({
|
|
@@ -4633,7 +4783,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4633
4783
|
className,
|
|
4634
4784
|
sourceFile,
|
|
4635
4785
|
project,
|
|
4636
|
-
seenNames
|
|
4786
|
+
seenNames,
|
|
4787
|
+
mixin
|
|
4637
4788
|
}) : extractDtoRoute({
|
|
4638
4789
|
cls,
|
|
4639
4790
|
method,
|
|
@@ -4642,7 +4793,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4642
4793
|
className,
|
|
4643
4794
|
sourceFile,
|
|
4644
4795
|
project,
|
|
4645
|
-
seenNames
|
|
4796
|
+
seenNames,
|
|
4797
|
+
mixin
|
|
4646
4798
|
});
|
|
4647
4799
|
if (route) routes.push(route);
|
|
4648
4800
|
}
|
|
@@ -4843,7 +4995,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
4843
4995
|
}
|
|
4844
4996
|
|
|
4845
4997
|
// src/index.ts
|
|
4846
|
-
var VERSION = "0.
|
|
4998
|
+
var VERSION = "0.17.0";
|
|
4847
4999
|
|
|
4848
5000
|
// src/cli/codegen.ts
|
|
4849
5001
|
async function runCodegen(opts = {}) {
|
|
@@ -4851,9 +5003,9 @@ async function runCodegen(opts = {}) {
|
|
|
4851
5003
|
const config = await loadConfig(cwd);
|
|
4852
5004
|
if (opts.watch) {
|
|
4853
5005
|
const watcher = await watch(config, void 0, { entryPoint: "cli" });
|
|
4854
|
-
await new Promise((
|
|
5006
|
+
await new Promise((resolve5) => {
|
|
4855
5007
|
function onSignal() {
|
|
4856
|
-
watcher.close().then(
|
|
5008
|
+
watcher.close().then(resolve5).catch(resolve5);
|
|
4857
5009
|
}
|
|
4858
5010
|
process.once("SIGINT", onSignal);
|
|
4859
5011
|
process.once("SIGTERM", onSignal);
|
|
@@ -4983,16 +5135,16 @@ async function detectPackageManager(cwd) {
|
|
|
4983
5135
|
}
|
|
4984
5136
|
async function promptFramework() {
|
|
4985
5137
|
if (!process.stdin.isTTY) return "react";
|
|
4986
|
-
return new Promise((
|
|
5138
|
+
return new Promise((resolve5) => {
|
|
4987
5139
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
4988
5140
|
rl.question(
|
|
4989
5141
|
"[nestjs-codegen] Which frontend framework? (react/vue/svelte) [react]: ",
|
|
4990
5142
|
(answer) => {
|
|
4991
5143
|
rl.close();
|
|
4992
5144
|
const trimmed = answer.trim().toLowerCase();
|
|
4993
|
-
if (trimmed === "vue")
|
|
4994
|
-
else if (trimmed === "svelte")
|
|
4995
|
-
else
|
|
5145
|
+
if (trimmed === "vue") resolve5("vue");
|
|
5146
|
+
else if (trimmed === "svelte") resolve5("svelte");
|
|
5147
|
+
else resolve5("react");
|
|
4996
5148
|
}
|
|
4997
5149
|
);
|
|
4998
5150
|
});
|