@dudousxd/nestjs-codegen 0.14.2 → 0.16.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 +49 -0
- package/dist/cli/main.cjs +207 -57
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +206 -56
- 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-DT8SgPxp.d.cts → index-LQNP7Ms3.d.cts} +30 -0
- package/dist/{index-DT8SgPxp.d.ts → index-LQNP7Ms3.d.ts} +30 -0
- package/dist/index.cjs +207 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +206 -56
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +227 -59
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +56 -3
- package/dist/nest/index.d.ts +56 -3
- package/dist/nest/index.js +222 -57
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/nest/index.cjs
CHANGED
|
@@ -42,7 +42,10 @@ __export(nest_exports, {
|
|
|
42
42
|
CODEGEN_MODULE_OPTIONS: () => CODEGEN_MODULE_OPTIONS,
|
|
43
43
|
NestjsCodegenModule: () => NestjsCodegenModule,
|
|
44
44
|
NestjsCodegenService: () => NestjsCodegenService,
|
|
45
|
-
|
|
45
|
+
QueryList: () => QueryList,
|
|
46
|
+
resolveQueryList: () => resolveQueryList,
|
|
47
|
+
shouldRun: () => shouldRun,
|
|
48
|
+
toStringList: () => toStringList
|
|
46
49
|
});
|
|
47
50
|
module.exports = __toCommonJS(nest_exports);
|
|
48
51
|
|
|
@@ -738,6 +741,9 @@ function buildErrorType(c) {
|
|
|
738
741
|
}
|
|
739
742
|
return c.contractSource.error ?? "unknown";
|
|
740
743
|
}
|
|
744
|
+
function filterFieldLiterals(fields) {
|
|
745
|
+
return fields?.length ? fields.map((f) => JSON.stringify(f)) : [];
|
|
746
|
+
}
|
|
741
747
|
function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
742
748
|
const pad = " ".repeat(indent);
|
|
743
749
|
const lines = [];
|
|
@@ -764,7 +770,8 @@ function emitRouterTypeBlock(tree, indent, outDir, serialization) {
|
|
|
764
770
|
const params = buildParamsType(c.params);
|
|
765
771
|
const safeMethod = JSON.stringify(method);
|
|
766
772
|
const safeUrl = JSON.stringify(c.path);
|
|
767
|
-
const
|
|
773
|
+
const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
|
|
774
|
+
const filterFields = filterLiterals.length ? filterLiterals.join(" | ") : "never";
|
|
768
775
|
const stream = c.contractSource.stream ? "true" : "false";
|
|
769
776
|
const binary = c.contractSource.binaryResponse ? "true" : "false";
|
|
770
777
|
lines.push(
|
|
@@ -804,6 +811,7 @@ function buildRequestModel(c) {
|
|
|
804
811
|
const TA = buildRouterTypeAccess(c.name);
|
|
805
812
|
const withParams = hasPathParams(c.params);
|
|
806
813
|
const { isGet, isQuery, hasBody, hasQuery } = requestShape(c.route);
|
|
814
|
+
const filterLiterals = filterFieldLiterals(c.contractSource.filterFields);
|
|
807
815
|
const fields = [];
|
|
808
816
|
if (withParams) fields.push(`params: ${TA}['params']`);
|
|
809
817
|
if (hasQuery) fields.push(`query?: ${TA}['query']`);
|
|
@@ -833,7 +841,12 @@ function buildRequestModel(c) {
|
|
|
833
841
|
// (`[name]` rather than `[name, undefined]`) so the bare `.queryKey()` is a
|
|
834
842
|
// clean prefix that partial-matches every parametrized variant — making it
|
|
835
843
|
// directly usable for `invalidateQueries`.
|
|
836
|
-
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)
|
|
844
|
+
queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)`,
|
|
845
|
+
// Runtime counterpart to the type-level `filterFields` union: the same
|
|
846
|
+
// discovered field list, emitted as a literal `[...] as const` so apps can
|
|
847
|
+
// validate a dynamic/user-supplied field string with `isFilterField(...)`
|
|
848
|
+
// instead of casting. Omitted for routes with no filter.
|
|
849
|
+
...filterLiterals.length ? { filterFieldsExpr: `[${filterLiterals.join(", ")}] as const` } : {}
|
|
837
850
|
};
|
|
838
851
|
}
|
|
839
852
|
function renderFetcherRequest(req, binaryResponse) {
|
|
@@ -868,9 +881,24 @@ function emitReqHelper() {
|
|
|
868
881
|
""
|
|
869
882
|
];
|
|
870
883
|
}
|
|
884
|
+
function emitFilterFieldGuard() {
|
|
885
|
+
return [
|
|
886
|
+
"/** Runtime guard: narrows `value` to one of the leaf's `filterFields` (a `readonly K[] as const`), so a dynamic field string can be passed to `.where()` without a cast. */",
|
|
887
|
+
"export function isFilterField<const K extends string>(",
|
|
888
|
+
" fields: readonly K[],",
|
|
889
|
+
" value: string,",
|
|
890
|
+
"): value is K {",
|
|
891
|
+
" return (fields as readonly string[]).includes(value);",
|
|
892
|
+
"}",
|
|
893
|
+
""
|
|
894
|
+
];
|
|
895
|
+
}
|
|
871
896
|
function renderLeaf(pad, objKey, req, requestExpr, members, streamExpr) {
|
|
872
897
|
const lines = [`${pad}${objKey}: (input?: ${req.inputType}) => ({`];
|
|
873
898
|
lines.push(`${pad} ...__req<${req.responseType}>(() => ${requestExpr}),`);
|
|
899
|
+
if (req.filterFieldsExpr) {
|
|
900
|
+
lines.push(`${pad} filterFields: ${req.filterFieldsExpr},`);
|
|
901
|
+
}
|
|
874
902
|
if (streamExpr) {
|
|
875
903
|
lines.push(`${pad} stream: () => ${streamExpr},`);
|
|
876
904
|
}
|
|
@@ -1142,6 +1170,9 @@ function buildApiFile(routes, outDir, opts = {}) {
|
|
|
1142
1170
|
lines.push("};");
|
|
1143
1171
|
lines.push("");
|
|
1144
1172
|
lines.push(...emitReqHelper());
|
|
1173
|
+
if (contracted.some((r) => r.contract?.contractSource.filterFields?.length)) {
|
|
1174
|
+
lines.push(...emitFilterFieldGuard());
|
|
1175
|
+
}
|
|
1145
1176
|
lines.push("export function createApi(fetcher: Fetcher) {");
|
|
1146
1177
|
lines.push(" return {");
|
|
1147
1178
|
lines.push(
|
|
@@ -2241,7 +2272,7 @@ var import_chokidar = __toESM(require("chokidar"), 1);
|
|
|
2241
2272
|
// src/discovery/contracts-fast.ts
|
|
2242
2273
|
var import_node_path14 = require("path");
|
|
2243
2274
|
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
2244
|
-
var
|
|
2275
|
+
var import_ts_morph10 = require("ts-morph");
|
|
2245
2276
|
|
|
2246
2277
|
// src/discovery/dto-type-resolver.ts
|
|
2247
2278
|
var import_ts_morph7 = require("ts-morph");
|
|
@@ -3220,6 +3251,12 @@ function toFilterFieldType(name, r) {
|
|
|
3220
3251
|
}
|
|
3221
3252
|
|
|
3222
3253
|
// src/discovery/filter-for.ts
|
|
3254
|
+
function resolveMixinEntityClass(mixin, project) {
|
|
3255
|
+
const entityArg = mixin?.classArgs[0];
|
|
3256
|
+
if (!entityArg) return void 0;
|
|
3257
|
+
const file = project.getSourceFile(entityArg.filePath) ?? project.addSourceFileAtPathIfExists(entityArg.filePath);
|
|
3258
|
+
return file?.getClass(entityArg.name);
|
|
3259
|
+
}
|
|
3223
3260
|
function classifyFilterForHint(typeInit) {
|
|
3224
3261
|
if (import_ts_morph6.Node.isStringLiteral(typeInit)) {
|
|
3225
3262
|
switch (typeInit.getLiteralValue()) {
|
|
@@ -3293,7 +3330,9 @@ function extractFilterForHints(classDecl, project) {
|
|
|
3293
3330
|
}
|
|
3294
3331
|
return hints;
|
|
3295
3332
|
}
|
|
3296
|
-
function extractApplyFilterInfo(method, sourceFile, project) {
|
|
3333
|
+
function extractApplyFilterInfo(method, sourceFile, project, mixin) {
|
|
3334
|
+
const declFile = method.getSourceFile();
|
|
3335
|
+
const mixinEntity = resolveMixinEntityClass(mixin, project);
|
|
3297
3336
|
for (const param of method.getParameters()) {
|
|
3298
3337
|
const filterDecorator = param.getDecorators().find((d) => d.getName() === "ApplyFilter");
|
|
3299
3338
|
if (!filterDecorator) continue;
|
|
@@ -3313,12 +3352,12 @@ function extractApplyFilterInfo(method, sourceFile, project) {
|
|
|
3313
3352
|
}
|
|
3314
3353
|
}
|
|
3315
3354
|
const filterClassName = filterClassArg.getText();
|
|
3316
|
-
const resolved = findType(filterClassName,
|
|
3317
|
-
|
|
3318
|
-
|
|
3355
|
+
const resolved = findType(filterClassName, declFile, project);
|
|
3356
|
+
const classDecl = resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg);
|
|
3357
|
+
if (classDecl) {
|
|
3319
3358
|
let fieldTypes = extractClassPropertyTypes(classDecl, project);
|
|
3320
3359
|
if (fieldTypes.length === 0) {
|
|
3321
|
-
fieldTypes = extractFilterableEntityFields(classDecl, project);
|
|
3360
|
+
fieldTypes = extractFilterableEntityFields(classDecl, project, mixinEntity);
|
|
3322
3361
|
}
|
|
3323
3362
|
const filterForHints = extractFilterForHints(classDecl, project);
|
|
3324
3363
|
if (filterForHints.size > 0) {
|
|
@@ -3403,22 +3442,29 @@ function extractClassPropertyTypes(classDecl, project) {
|
|
|
3403
3442
|
}
|
|
3404
3443
|
return fields;
|
|
3405
3444
|
}
|
|
3406
|
-
function
|
|
3445
|
+
function resolveLocalClassDeclaration(identifier) {
|
|
3446
|
+
if (!import_ts_morph6.Node.isIdentifier(identifier)) return void 0;
|
|
3447
|
+
return identifier.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && import_ts_morph6.Node.isClassDeclaration(n));
|
|
3448
|
+
}
|
|
3449
|
+
function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
3450
|
+
if (!import_ts_morph6.Node.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
3451
|
+
const entityProp = optionsArg.getProperty("entity");
|
|
3452
|
+
if (!entityProp || !import_ts_morph6.Node.isPropertyAssignment(entityProp)) return void 0;
|
|
3453
|
+
const entityInit = entityProp.getInitializer();
|
|
3454
|
+
if (!entityInit || !import_ts_morph6.Node.isIdentifier(entityInit)) return void 0;
|
|
3455
|
+
const resolved = findType(entityInit.getText(), filterClass.getSourceFile(), project);
|
|
3456
|
+
if (!resolved || resolved.kind !== "class") return void 0;
|
|
3457
|
+
return resolved.decl;
|
|
3458
|
+
}
|
|
3459
|
+
function extractFilterableEntityFields(filterClass, project, entityOverride) {
|
|
3407
3460
|
const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
|
|
3408
3461
|
if (!filterableDecorator) return [];
|
|
3409
3462
|
const args = filterableDecorator.getArguments();
|
|
3410
3463
|
if (args.length === 0) return [];
|
|
3411
3464
|
const optionsArg = args[0];
|
|
3412
3465
|
if (!import_ts_morph6.Node.isObjectLiteralExpression(optionsArg)) return [];
|
|
3413
|
-
const
|
|
3414
|
-
if (!
|
|
3415
|
-
const entityInit = entityProp.getInitializer();
|
|
3416
|
-
if (!entityInit || !import_ts_morph6.Node.isIdentifier(entityInit)) return [];
|
|
3417
|
-
const entityName = entityInit.getText();
|
|
3418
|
-
const filterSourceFile = filterClass.getSourceFile();
|
|
3419
|
-
const resolvedEntity = findType(entityName, filterSourceFile, project);
|
|
3420
|
-
if (!resolvedEntity || resolvedEntity.kind !== "class") return [];
|
|
3421
|
-
const entityDecl = resolvedEntity.decl;
|
|
3466
|
+
const entityDecl = entityOverride ?? resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
3467
|
+
if (!entityDecl) return [];
|
|
3422
3468
|
const fields = collectEntityFields(
|
|
3423
3469
|
entityDecl,
|
|
3424
3470
|
entityDecl.getSourceFile(),
|
|
@@ -3843,9 +3889,9 @@ function unwrapNamedContainer(node, names) {
|
|
|
3843
3889
|
}
|
|
3844
3890
|
return node;
|
|
3845
3891
|
}
|
|
3846
|
-
function extractDtoContract(method, sourceFile, project) {
|
|
3892
|
+
function extractDtoContract(method, sourceFile, project, mixin) {
|
|
3847
3893
|
let body = extractBodyType(method, sourceFile, project);
|
|
3848
|
-
const filterInfo = extractApplyFilterInfo(method, sourceFile, project);
|
|
3894
|
+
const filterInfo = extractApplyFilterInfo(method, sourceFile, project, mixin);
|
|
3849
3895
|
const query = extractQueryType(method, sourceFile, project);
|
|
3850
3896
|
const uploads = extractUploadedFiles(method);
|
|
3851
3897
|
const multipartBody = uploads.fields ? `{ ${uploads.fields} }` : null;
|
|
@@ -3955,12 +4001,94 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
|
|
|
3955
4001
|
return null;
|
|
3956
4002
|
}
|
|
3957
4003
|
|
|
3958
|
-
// src/discovery/
|
|
4004
|
+
// src/discovery/heritage.ts
|
|
3959
4005
|
var import_ts_morph8 = require("ts-morph");
|
|
4006
|
+
function unwrapExpression(node) {
|
|
4007
|
+
let current = node;
|
|
4008
|
+
while (import_ts_morph8.Node.isAsExpression(current) || import_ts_morph8.Node.isSatisfiesExpression(current) || import_ts_morph8.Node.isParenthesizedExpression(current) || import_ts_morph8.Node.isTypeAssertion(current)) {
|
|
4009
|
+
current = current.getExpression();
|
|
4010
|
+
}
|
|
4011
|
+
return current;
|
|
4012
|
+
}
|
|
4013
|
+
function resolveReturnedClass(factoryDecl) {
|
|
4014
|
+
const body = factoryDecl.getBody();
|
|
4015
|
+
if (!body) return void 0;
|
|
4016
|
+
const returns = body.getDescendants().filter((n) => import_ts_morph8.Node.isReturnStatement(n));
|
|
4017
|
+
for (const ret of returns) {
|
|
4018
|
+
const expr = ret.getExpression();
|
|
4019
|
+
if (!expr) continue;
|
|
4020
|
+
const inner = unwrapExpression(expr);
|
|
4021
|
+
if (import_ts_morph8.Node.isClassExpression(inner)) {
|
|
4022
|
+
return inner;
|
|
4023
|
+
}
|
|
4024
|
+
if (import_ts_morph8.Node.isIdentifier(inner)) {
|
|
4025
|
+
const name = inner.getText();
|
|
4026
|
+
const decl = body.getDescendants().find((n) => import_ts_morph8.Node.isClassDeclaration(n) && n.getName() === name);
|
|
4027
|
+
if (decl) return decl;
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
return void 0;
|
|
4031
|
+
}
|
|
4032
|
+
function resolveInheritedMethods(cls) {
|
|
4033
|
+
const expr = cls.getExtends()?.getExpression();
|
|
4034
|
+
if (!expr || !import_ts_morph8.Node.isCallExpression(expr)) return void 0;
|
|
4035
|
+
const callee = expr.getExpression();
|
|
4036
|
+
if (!import_ts_morph8.Node.isIdentifier(callee)) return void 0;
|
|
4037
|
+
const factoryDecl = callee.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => import_ts_morph8.Node.isFunctionDeclaration(n));
|
|
4038
|
+
if (!factoryDecl) return void 0;
|
|
4039
|
+
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
4040
|
+
if (!returnedClass) return void 0;
|
|
4041
|
+
const classArgs = [];
|
|
4042
|
+
for (const arg of expr.getArguments()) {
|
|
4043
|
+
if (!import_ts_morph8.Node.isIdentifier(arg)) continue;
|
|
4044
|
+
const decl = arg.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => import_ts_morph8.Node.isClassDeclaration(n));
|
|
4045
|
+
if (decl) {
|
|
4046
|
+
classArgs.push({
|
|
4047
|
+
name: decl.getName() ?? arg.getText(),
|
|
4048
|
+
filePath: decl.getSourceFile().getFilePath()
|
|
4049
|
+
});
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
return {
|
|
4053
|
+
methods: returnedClass.getMethods(),
|
|
4054
|
+
factoryName: callee.getText(),
|
|
4055
|
+
factoryFilePath: factoryDecl.getSourceFile().getFilePath(),
|
|
4056
|
+
classArgs
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4059
|
+
var mixinTypeProject;
|
|
4060
|
+
function getMixinTypeProject() {
|
|
4061
|
+
mixinTypeProject ??= new import_ts_morph8.Project({
|
|
4062
|
+
skipAddingFilesFromTsConfig: true,
|
|
4063
|
+
compilerOptions: { strict: true }
|
|
4064
|
+
});
|
|
4065
|
+
return mixinTypeProject;
|
|
4066
|
+
}
|
|
4067
|
+
function clearMixinTypeProject() {
|
|
4068
|
+
mixinTypeProject = void 0;
|
|
4069
|
+
}
|
|
4070
|
+
function resolveInstantiatedReturnType(cls, methodName) {
|
|
4071
|
+
const filePath = cls.getSourceFile().getFilePath();
|
|
4072
|
+
const className = cls.getName();
|
|
4073
|
+
if (!className) return void 0;
|
|
4074
|
+
const project = getMixinTypeProject();
|
|
4075
|
+
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPathIfExists(filePath);
|
|
4076
|
+
const typedCls = sourceFile?.getClass(className);
|
|
4077
|
+
if (!typedCls) return void 0;
|
|
4078
|
+
const prop = typedCls.getType().getProperty(methodName);
|
|
4079
|
+
if (!prop) return void 0;
|
|
4080
|
+
const returnType = prop.getTypeAtLocation(typedCls).getCallSignatures()[0]?.getReturnType();
|
|
4081
|
+
if (!returnType) return void 0;
|
|
4082
|
+
const unwrapped = returnType.getSymbol()?.getName() === "Promise" ? returnType.getTypeArguments()[0] ?? returnType : returnType;
|
|
4083
|
+
return unwrapped.getText(typedCls);
|
|
4084
|
+
}
|
|
4085
|
+
|
|
4086
|
+
// src/discovery/zod-ast-to-ts.ts
|
|
4087
|
+
var import_ts_morph9 = require("ts-morph");
|
|
3960
4088
|
function zodAstToTs(node) {
|
|
3961
|
-
if (!
|
|
4089
|
+
if (!import_ts_morph9.Node.isCallExpression(node)) return "unknown";
|
|
3962
4090
|
const expr = node.getExpression();
|
|
3963
|
-
if (
|
|
4091
|
+
if (import_ts_morph9.Node.isPropertyAccessExpression(expr)) {
|
|
3964
4092
|
const methodName = expr.getName();
|
|
3965
4093
|
const receiver = expr.getExpression();
|
|
3966
4094
|
if (methodName === "optional") {
|
|
@@ -3984,17 +4112,17 @@ function zodAstToTs(node) {
|
|
|
3984
4112
|
case "literal": {
|
|
3985
4113
|
const lit = args[0];
|
|
3986
4114
|
if (!lit) return "unknown";
|
|
3987
|
-
if (
|
|
3988
|
-
if (
|
|
3989
|
-
if (lit.getKind() ===
|
|
3990
|
-
if (lit.getKind() ===
|
|
4115
|
+
if (import_ts_morph9.Node.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
|
|
4116
|
+
if (import_ts_morph9.Node.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
|
|
4117
|
+
if (lit.getKind() === import_ts_morph9.SyntaxKind.TrueKeyword) return "true";
|
|
4118
|
+
if (lit.getKind() === import_ts_morph9.SyntaxKind.FalseKeyword) return "false";
|
|
3991
4119
|
return "unknown";
|
|
3992
4120
|
}
|
|
3993
4121
|
case "enum": {
|
|
3994
4122
|
const arrArg = args[0];
|
|
3995
|
-
if (!arrArg || !
|
|
4123
|
+
if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
3996
4124
|
const members = arrArg.getElements().map(
|
|
3997
|
-
(el) =>
|
|
4125
|
+
(el) => import_ts_morph9.Node.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
|
|
3998
4126
|
);
|
|
3999
4127
|
return members.join(" | ");
|
|
4000
4128
|
}
|
|
@@ -4005,10 +4133,10 @@ function zodAstToTs(node) {
|
|
|
4005
4133
|
}
|
|
4006
4134
|
case "object": {
|
|
4007
4135
|
const objArg = args[0];
|
|
4008
|
-
if (!objArg || !
|
|
4136
|
+
if (!objArg || !import_ts_morph9.Node.isObjectLiteralExpression(objArg)) return "unknown";
|
|
4009
4137
|
const lines = [];
|
|
4010
4138
|
for (const prop of objArg.getProperties()) {
|
|
4011
|
-
if (!
|
|
4139
|
+
if (!import_ts_morph9.Node.isPropertyAssignment(prop)) continue;
|
|
4012
4140
|
const key = prop.getName();
|
|
4013
4141
|
const valNode = prop.getInitializer();
|
|
4014
4142
|
if (!valNode) continue;
|
|
@@ -4020,7 +4148,7 @@ function zodAstToTs(node) {
|
|
|
4020
4148
|
}
|
|
4021
4149
|
case "union": {
|
|
4022
4150
|
const arrArg = args[0];
|
|
4023
|
-
if (!arrArg || !
|
|
4151
|
+
if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4024
4152
|
return arrArg.getElements().map(zodAstToTs).join(" | ");
|
|
4025
4153
|
}
|
|
4026
4154
|
case "record": {
|
|
@@ -4030,7 +4158,7 @@ function zodAstToTs(node) {
|
|
|
4030
4158
|
}
|
|
4031
4159
|
case "tuple": {
|
|
4032
4160
|
const arrArg = args[0];
|
|
4033
|
-
if (!arrArg || !
|
|
4161
|
+
if (!arrArg || !import_ts_morph9.Node.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4034
4162
|
return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
|
|
4035
4163
|
}
|
|
4036
4164
|
default:
|
|
@@ -4040,18 +4168,18 @@ function zodAstToTs(node) {
|
|
|
4040
4168
|
return "unknown";
|
|
4041
4169
|
}
|
|
4042
4170
|
function isOptionalChain(node) {
|
|
4043
|
-
if (!
|
|
4171
|
+
if (!import_ts_morph9.Node.isCallExpression(node)) return false;
|
|
4044
4172
|
const expr = node.getExpression();
|
|
4045
|
-
return
|
|
4173
|
+
return import_ts_morph9.Node.isPropertyAccessExpression(expr) && expr.getName() === "optional";
|
|
4046
4174
|
}
|
|
4047
4175
|
function parseDefineContractCall(callExpr) {
|
|
4048
|
-
if (!
|
|
4176
|
+
if (!import_ts_morph9.Node.isCallExpression(callExpr)) return null;
|
|
4049
4177
|
const callee = callExpr.getExpression();
|
|
4050
|
-
const calleeName =
|
|
4178
|
+
const calleeName = import_ts_morph9.Node.isIdentifier(callee) ? callee.getText() : import_ts_morph9.Node.isPropertyAccessExpression(callee) ? callee.getName() : "";
|
|
4051
4179
|
if (calleeName !== "defineContract") return null;
|
|
4052
4180
|
const args = callExpr.getArguments();
|
|
4053
4181
|
const optsArg = args[0];
|
|
4054
|
-
if (!optsArg || !
|
|
4182
|
+
if (!optsArg || !import_ts_morph9.Node.isObjectLiteralExpression(optsArg)) return null;
|
|
4055
4183
|
let query = null;
|
|
4056
4184
|
let body = null;
|
|
4057
4185
|
let response = "unknown";
|
|
@@ -4059,7 +4187,7 @@ function parseDefineContractCall(callExpr) {
|
|
|
4059
4187
|
let bodyZodText = null;
|
|
4060
4188
|
let queryZodText = null;
|
|
4061
4189
|
for (const prop of optsArg.getProperties()) {
|
|
4062
|
-
if (!
|
|
4190
|
+
if (!import_ts_morph9.Node.isPropertyAssignment(prop)) continue;
|
|
4063
4191
|
const propName = prop.getName();
|
|
4064
4192
|
const val = prop.getInitializer();
|
|
4065
4193
|
if (!val) continue;
|
|
@@ -4084,14 +4212,14 @@ function resolveTsconfigPath(cwd, tsconfig) {
|
|
|
4084
4212
|
}
|
|
4085
4213
|
function createDiscoveryProject(tsconfigPath) {
|
|
4086
4214
|
try {
|
|
4087
|
-
return new
|
|
4215
|
+
return new import_ts_morph10.Project({
|
|
4088
4216
|
tsConfigFilePath: tsconfigPath,
|
|
4089
4217
|
skipAddingFilesFromTsConfig: true,
|
|
4090
4218
|
skipLoadingLibFiles: true,
|
|
4091
4219
|
skipFileDependencyResolution: true
|
|
4092
4220
|
});
|
|
4093
4221
|
} catch {
|
|
4094
|
-
return new
|
|
4222
|
+
return new import_ts_morph10.Project({
|
|
4095
4223
|
skipAddingFilesFromTsConfig: true,
|
|
4096
4224
|
skipLoadingLibFiles: true,
|
|
4097
4225
|
skipFileDependencyResolution: true,
|
|
@@ -4191,15 +4319,16 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4191
4319
|
runExtraction() {
|
|
4192
4320
|
clearTypeResolutionCaches(this.project);
|
|
4193
4321
|
clearEnumCache(this.project);
|
|
4322
|
+
clearMixinTypeProject();
|
|
4194
4323
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
4195
4324
|
}
|
|
4196
4325
|
};
|
|
4197
4326
|
function decoratorStringArg(decoratorExpr) {
|
|
4198
4327
|
if (!decoratorExpr) return void 0;
|
|
4199
|
-
if (
|
|
4200
|
-
if (
|
|
4328
|
+
if (import_ts_morph10.Node.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
|
|
4329
|
+
if (import_ts_morph10.Node.isArrayLiteralExpression(decoratorExpr)) {
|
|
4201
4330
|
const first = decoratorExpr.getElements()[0];
|
|
4202
|
-
if (first &&
|
|
4331
|
+
if (first && import_ts_morph10.Node.isStringLiteral(first)) return first.getLiteralValue();
|
|
4203
4332
|
}
|
|
4204
4333
|
return void 0;
|
|
4205
4334
|
}
|
|
@@ -4221,7 +4350,8 @@ function joinPaths(prefix, suffix) {
|
|
|
4221
4350
|
if (!prefix && !suffix) return "/";
|
|
4222
4351
|
if (!prefix) return suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4223
4352
|
if (!suffix) return prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4224
|
-
const
|
|
4353
|
+
const withLeadingSlash = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4354
|
+
const p = withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
4225
4355
|
const s = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4226
4356
|
const combined = p + s;
|
|
4227
4357
|
return combined === "" ? "/" : combined;
|
|
@@ -4275,7 +4405,8 @@ function buildRoute(args) {
|
|
|
4275
4405
|
methodAs,
|
|
4276
4406
|
sourceFile,
|
|
4277
4407
|
seenNames,
|
|
4278
|
-
contractSource
|
|
4408
|
+
contractSource,
|
|
4409
|
+
mixin
|
|
4279
4410
|
} = args;
|
|
4280
4411
|
const routeName = resolveRouteName(className, methodName, classAs, methodAs);
|
|
4281
4412
|
const qualifiedRef = `${className}.${methodName}`;
|
|
@@ -4291,7 +4422,12 @@ function buildRoute(args) {
|
|
|
4291
4422
|
path: combinedPath,
|
|
4292
4423
|
name: routeName,
|
|
4293
4424
|
params: extractParams(combinedPath),
|
|
4294
|
-
controllerRef: {
|
|
4425
|
+
controllerRef: {
|
|
4426
|
+
className,
|
|
4427
|
+
methodName,
|
|
4428
|
+
filePath: sourceFile.getFilePath(),
|
|
4429
|
+
...mixin ? { mixin } : {}
|
|
4430
|
+
},
|
|
4295
4431
|
contract: { contractSource }
|
|
4296
4432
|
};
|
|
4297
4433
|
}
|
|
@@ -4305,16 +4441,17 @@ function extractContractRoute(args) {
|
|
|
4305
4441
|
className,
|
|
4306
4442
|
sourceFile,
|
|
4307
4443
|
project,
|
|
4308
|
-
seenNames
|
|
4444
|
+
seenNames,
|
|
4445
|
+
mixin
|
|
4309
4446
|
} = args;
|
|
4310
4447
|
const firstDecoratorArg = applyContractDecorator.getArguments()[0];
|
|
4311
4448
|
if (!firstDecoratorArg) return null;
|
|
4312
4449
|
let contractDef = null;
|
|
4313
4450
|
let bodyZodRef = null;
|
|
4314
4451
|
let queryZodRef = null;
|
|
4315
|
-
if (
|
|
4452
|
+
if (import_ts_morph10.Node.isCallExpression(firstDecoratorArg)) {
|
|
4316
4453
|
contractDef = parseDefineContractCall(firstDecoratorArg);
|
|
4317
|
-
} else if (
|
|
4454
|
+
} else if (import_ts_morph10.Node.isIdentifier(firstDecoratorArg)) {
|
|
4318
4455
|
const identName = firstDecoratorArg.getText();
|
|
4319
4456
|
const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
|
|
4320
4457
|
if (!resolvedVar) {
|
|
@@ -4357,6 +4494,7 @@ function extractContractRoute(args) {
|
|
|
4357
4494
|
methodAs,
|
|
4358
4495
|
sourceFile,
|
|
4359
4496
|
seenNames,
|
|
4497
|
+
mixin,
|
|
4360
4498
|
contractSource: {
|
|
4361
4499
|
query: contractDef.query,
|
|
4362
4500
|
body: contractDef.body,
|
|
@@ -4373,13 +4511,14 @@ function extractContractRoute(args) {
|
|
|
4373
4511
|
});
|
|
4374
4512
|
}
|
|
4375
4513
|
function extractDtoRoute(args) {
|
|
4376
|
-
const { cls, method, verb, prefix, className, sourceFile, project, seenNames } = args;
|
|
4514
|
+
const { cls, method, verb, prefix, className, sourceFile, project, seenNames, mixin } = args;
|
|
4377
4515
|
if (!verb) return null;
|
|
4378
4516
|
const combined = joinPaths(prefix, verb.handlerPath);
|
|
4379
4517
|
const methodName = method.getName();
|
|
4380
4518
|
const classAs = readAsDecorator(cls, `class ${className}`);
|
|
4381
4519
|
const methodAs = readAsDecorator(method, `${className}.${methodName}`);
|
|
4382
|
-
const dtoContract = extractDtoContract(method, sourceFile, project);
|
|
4520
|
+
const dtoContract = extractDtoContract(method, sourceFile, project, mixin);
|
|
4521
|
+
const mixinResponse = mixin ? resolveInstantiatedReturnType(cls, methodName) : void 0;
|
|
4383
4522
|
return buildRoute({
|
|
4384
4523
|
className,
|
|
4385
4524
|
methodName,
|
|
@@ -4389,10 +4528,11 @@ function extractDtoRoute(args) {
|
|
|
4389
4528
|
methodAs,
|
|
4390
4529
|
sourceFile,
|
|
4391
4530
|
seenNames,
|
|
4531
|
+
mixin,
|
|
4392
4532
|
contractSource: {
|
|
4393
4533
|
query: dtoContract?.query ?? null,
|
|
4394
4534
|
body: dtoContract?.body ?? null,
|
|
4395
|
-
response: dtoContract?.response ?? "unknown",
|
|
4535
|
+
response: mixinResponse ?? dtoContract?.response ?? "unknown",
|
|
4396
4536
|
error: dtoContract?.error ?? null,
|
|
4397
4537
|
queryRef: dtoContract?.queryRef ?? null,
|
|
4398
4538
|
bodyRef: dtoContract?.bodyRef ?? null,
|
|
@@ -4421,7 +4561,17 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4421
4561
|
const firstArg2 = controllerDecorator.getArguments()[0];
|
|
4422
4562
|
const prefix = decoratorStringArg(firstArg2) ?? "";
|
|
4423
4563
|
const className = cls.getName() ?? "Unknown";
|
|
4424
|
-
|
|
4564
|
+
const inherited = resolveInheritedMethods(cls);
|
|
4565
|
+
const mixinBinding = inherited ? {
|
|
4566
|
+
factoryName: inherited.factoryName,
|
|
4567
|
+
factoryFilePath: inherited.factoryFilePath,
|
|
4568
|
+
classArgs: inherited.classArgs
|
|
4569
|
+
} : void 0;
|
|
4570
|
+
const methods = [
|
|
4571
|
+
...cls.getMethods().map((method) => ({ method })),
|
|
4572
|
+
...(inherited?.methods ?? []).map((method) => ({ method, mixin: mixinBinding }))
|
|
4573
|
+
];
|
|
4574
|
+
for (const { method, mixin } of methods) {
|
|
4425
4575
|
const verb = resolveVerb(method);
|
|
4426
4576
|
const applyContractDecorator = method.getDecorator("ApplyContract");
|
|
4427
4577
|
const route = applyContractDecorator ? extractContractRoute({
|
|
@@ -4433,7 +4583,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4433
4583
|
className,
|
|
4434
4584
|
sourceFile,
|
|
4435
4585
|
project,
|
|
4436
|
-
seenNames
|
|
4586
|
+
seenNames,
|
|
4587
|
+
mixin
|
|
4437
4588
|
}) : extractDtoRoute({
|
|
4438
4589
|
cls,
|
|
4439
4590
|
method,
|
|
@@ -4442,7 +4593,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4442
4593
|
className,
|
|
4443
4594
|
sourceFile,
|
|
4444
4595
|
project,
|
|
4445
|
-
seenNames
|
|
4596
|
+
seenNames,
|
|
4597
|
+
mixin
|
|
4446
4598
|
});
|
|
4447
4599
|
if (route) routes.push(route);
|
|
4448
4600
|
}
|
|
@@ -4643,7 +4795,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
4643
4795
|
}
|
|
4644
4796
|
|
|
4645
4797
|
// src/index.ts
|
|
4646
|
-
var VERSION = "0.
|
|
4798
|
+
var VERSION = "0.16.0";
|
|
4647
4799
|
|
|
4648
4800
|
// src/generate-manifest.ts
|
|
4649
4801
|
var MANIFEST_FILE = ".codegen-manifest.json";
|
|
@@ -4843,11 +4995,27 @@ var NestjsCodegenModule = class {
|
|
|
4843
4995
|
NestjsCodegenModule = __decorateClass([
|
|
4844
4996
|
(0, import_common.Module)({})
|
|
4845
4997
|
], NestjsCodegenModule);
|
|
4998
|
+
|
|
4999
|
+
// src/nest/query-list.ts
|
|
5000
|
+
var import_common2 = require("@nestjs/common");
|
|
5001
|
+
function toStringList(raw) {
|
|
5002
|
+
if (raw === void 0 || raw === null) return [];
|
|
5003
|
+
const arr = Array.isArray(raw) ? raw : String(raw).split(",");
|
|
5004
|
+
return arr.map((entry) => String(entry).trim()).filter((entry) => entry.length > 0);
|
|
5005
|
+
}
|
|
5006
|
+
function resolveQueryList(key, ctx) {
|
|
5007
|
+
const request = ctx.switchToHttp().getRequest();
|
|
5008
|
+
return toStringList(key ? request.query?.[key] : void 0);
|
|
5009
|
+
}
|
|
5010
|
+
var QueryList = (0, import_common2.createParamDecorator)(resolveQueryList);
|
|
4846
5011
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4847
5012
|
0 && (module.exports = {
|
|
4848
5013
|
CODEGEN_MODULE_OPTIONS,
|
|
4849
5014
|
NestjsCodegenModule,
|
|
4850
5015
|
NestjsCodegenService,
|
|
4851
|
-
|
|
5016
|
+
QueryList,
|
|
5017
|
+
resolveQueryList,
|
|
5018
|
+
shouldRun,
|
|
5019
|
+
toStringList
|
|
4852
5020
|
});
|
|
4853
5021
|
//# sourceMappingURL=index.cjs.map
|