@dudousxd/nestjs-codegen 0.15.0 → 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 +42 -0
- package/dist/cli/main.cjs +177 -55
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.js +176 -54
- 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-CjIDPMsV.d.cts → index-LQNP7Ms3.d.cts} +23 -0
- package/dist/{index-CjIDPMsV.d.ts → index-LQNP7Ms3.d.ts} +23 -0
- package/dist/index.cjs +177 -55
- 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 +176 -54
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +176 -55
- 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 +175 -54
- package/dist/nest/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -2409,8 +2409,8 @@ import chokidar from "chokidar";
|
|
|
2409
2409
|
import { join as join14, resolve as resolve3 } from "path";
|
|
2410
2410
|
import fg3 from "fast-glob";
|
|
2411
2411
|
import {
|
|
2412
|
-
Node as
|
|
2413
|
-
Project as
|
|
2412
|
+
Node as Node9,
|
|
2413
|
+
Project as Project4
|
|
2414
2414
|
} from "ts-morph";
|
|
2415
2415
|
|
|
2416
2416
|
// src/discovery/dto-type-resolver.ts
|
|
@@ -3402,6 +3402,12 @@ function toFilterFieldType(name, r) {
|
|
|
3402
3402
|
}
|
|
3403
3403
|
|
|
3404
3404
|
// src/discovery/filter-for.ts
|
|
3405
|
+
function resolveMixinEntityClass(mixin, project) {
|
|
3406
|
+
const entityArg = mixin?.classArgs[0];
|
|
3407
|
+
if (!entityArg) return void 0;
|
|
3408
|
+
const file = project.getSourceFile(entityArg.filePath) ?? project.addSourceFileAtPathIfExists(entityArg.filePath);
|
|
3409
|
+
return file?.getClass(entityArg.name);
|
|
3410
|
+
}
|
|
3405
3411
|
function classifyFilterForHint(typeInit) {
|
|
3406
3412
|
if (Node5.isStringLiteral(typeInit)) {
|
|
3407
3413
|
switch (typeInit.getLiteralValue()) {
|
|
@@ -3475,7 +3481,9 @@ function extractFilterForHints(classDecl, project) {
|
|
|
3475
3481
|
}
|
|
3476
3482
|
return hints;
|
|
3477
3483
|
}
|
|
3478
|
-
function extractApplyFilterInfo(method, sourceFile, project) {
|
|
3484
|
+
function extractApplyFilterInfo(method, sourceFile, project, mixin) {
|
|
3485
|
+
const declFile = method.getSourceFile();
|
|
3486
|
+
const mixinEntity = resolveMixinEntityClass(mixin, project);
|
|
3479
3487
|
for (const param of method.getParameters()) {
|
|
3480
3488
|
const filterDecorator = param.getDecorators().find((d) => d.getName() === "ApplyFilter");
|
|
3481
3489
|
if (!filterDecorator) continue;
|
|
@@ -3495,12 +3503,12 @@ function extractApplyFilterInfo(method, sourceFile, project) {
|
|
|
3495
3503
|
}
|
|
3496
3504
|
}
|
|
3497
3505
|
const filterClassName = filterClassArg.getText();
|
|
3498
|
-
const resolved = findType(filterClassName,
|
|
3499
|
-
|
|
3500
|
-
|
|
3506
|
+
const resolved = findType(filterClassName, declFile, project);
|
|
3507
|
+
const classDecl = resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg);
|
|
3508
|
+
if (classDecl) {
|
|
3501
3509
|
let fieldTypes = extractClassPropertyTypes(classDecl, project);
|
|
3502
3510
|
if (fieldTypes.length === 0) {
|
|
3503
|
-
fieldTypes = extractFilterableEntityFields(classDecl, project);
|
|
3511
|
+
fieldTypes = extractFilterableEntityFields(classDecl, project, mixinEntity);
|
|
3504
3512
|
}
|
|
3505
3513
|
const filterForHints = extractFilterForHints(classDecl, project);
|
|
3506
3514
|
if (filterForHints.size > 0) {
|
|
@@ -3585,22 +3593,29 @@ function extractClassPropertyTypes(classDecl, project) {
|
|
|
3585
3593
|
}
|
|
3586
3594
|
return fields;
|
|
3587
3595
|
}
|
|
3588
|
-
function
|
|
3596
|
+
function resolveLocalClassDeclaration(identifier) {
|
|
3597
|
+
if (!Node5.isIdentifier(identifier)) return void 0;
|
|
3598
|
+
return identifier.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => n !== void 0 && Node5.isClassDeclaration(n));
|
|
3599
|
+
}
|
|
3600
|
+
function resolveDeclaredEntity(optionsArg, filterClass, project) {
|
|
3601
|
+
if (!Node5.isObjectLiteralExpression(optionsArg)) return void 0;
|
|
3602
|
+
const entityProp = optionsArg.getProperty("entity");
|
|
3603
|
+
if (!entityProp || !Node5.isPropertyAssignment(entityProp)) return void 0;
|
|
3604
|
+
const entityInit = entityProp.getInitializer();
|
|
3605
|
+
if (!entityInit || !Node5.isIdentifier(entityInit)) return void 0;
|
|
3606
|
+
const resolved = findType(entityInit.getText(), filterClass.getSourceFile(), project);
|
|
3607
|
+
if (!resolved || resolved.kind !== "class") return void 0;
|
|
3608
|
+
return resolved.decl;
|
|
3609
|
+
}
|
|
3610
|
+
function extractFilterableEntityFields(filterClass, project, entityOverride) {
|
|
3589
3611
|
const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
|
|
3590
3612
|
if (!filterableDecorator) return [];
|
|
3591
3613
|
const args = filterableDecorator.getArguments();
|
|
3592
3614
|
if (args.length === 0) return [];
|
|
3593
3615
|
const optionsArg = args[0];
|
|
3594
3616
|
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;
|
|
3617
|
+
const entityDecl = entityOverride ?? resolveDeclaredEntity(optionsArg, filterClass, project);
|
|
3618
|
+
if (!entityDecl) return [];
|
|
3604
3619
|
const fields = collectEntityFields(
|
|
3605
3620
|
entityDecl,
|
|
3606
3621
|
entityDecl.getSourceFile(),
|
|
@@ -4025,9 +4040,9 @@ function unwrapNamedContainer(node, names) {
|
|
|
4025
4040
|
}
|
|
4026
4041
|
return node;
|
|
4027
4042
|
}
|
|
4028
|
-
function extractDtoContract(method, sourceFile, project) {
|
|
4043
|
+
function extractDtoContract(method, sourceFile, project, mixin) {
|
|
4029
4044
|
let body = extractBodyType(method, sourceFile, project);
|
|
4030
|
-
const filterInfo = extractApplyFilterInfo(method, sourceFile, project);
|
|
4045
|
+
const filterInfo = extractApplyFilterInfo(method, sourceFile, project, mixin);
|
|
4031
4046
|
const query = extractQueryType(method, sourceFile, project);
|
|
4032
4047
|
const uploads = extractUploadedFiles(method);
|
|
4033
4048
|
const multipartBody = uploads.fields ? `{ ${uploads.fields} }` : null;
|
|
@@ -4137,12 +4152,94 @@ function resolveParamClass(method, decoratorName, sourceFile, project) {
|
|
|
4137
4152
|
return null;
|
|
4138
4153
|
}
|
|
4139
4154
|
|
|
4155
|
+
// src/discovery/heritage.ts
|
|
4156
|
+
import { Node as Node7, Project as Project3 } from "ts-morph";
|
|
4157
|
+
function unwrapExpression(node) {
|
|
4158
|
+
let current = node;
|
|
4159
|
+
while (Node7.isAsExpression(current) || Node7.isSatisfiesExpression(current) || Node7.isParenthesizedExpression(current) || Node7.isTypeAssertion(current)) {
|
|
4160
|
+
current = current.getExpression();
|
|
4161
|
+
}
|
|
4162
|
+
return current;
|
|
4163
|
+
}
|
|
4164
|
+
function resolveReturnedClass(factoryDecl) {
|
|
4165
|
+
const body = factoryDecl.getBody();
|
|
4166
|
+
if (!body) return void 0;
|
|
4167
|
+
const returns = body.getDescendants().filter((n) => Node7.isReturnStatement(n));
|
|
4168
|
+
for (const ret of returns) {
|
|
4169
|
+
const expr = ret.getExpression();
|
|
4170
|
+
if (!expr) continue;
|
|
4171
|
+
const inner = unwrapExpression(expr);
|
|
4172
|
+
if (Node7.isClassExpression(inner)) {
|
|
4173
|
+
return inner;
|
|
4174
|
+
}
|
|
4175
|
+
if (Node7.isIdentifier(inner)) {
|
|
4176
|
+
const name = inner.getText();
|
|
4177
|
+
const decl = body.getDescendants().find((n) => Node7.isClassDeclaration(n) && n.getName() === name);
|
|
4178
|
+
if (decl) return decl;
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
return void 0;
|
|
4182
|
+
}
|
|
4183
|
+
function resolveInheritedMethods(cls) {
|
|
4184
|
+
const expr = cls.getExtends()?.getExpression();
|
|
4185
|
+
if (!expr || !Node7.isCallExpression(expr)) return void 0;
|
|
4186
|
+
const callee = expr.getExpression();
|
|
4187
|
+
if (!Node7.isIdentifier(callee)) return void 0;
|
|
4188
|
+
const factoryDecl = callee.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => Node7.isFunctionDeclaration(n));
|
|
4189
|
+
if (!factoryDecl) return void 0;
|
|
4190
|
+
const returnedClass = resolveReturnedClass(factoryDecl);
|
|
4191
|
+
if (!returnedClass) return void 0;
|
|
4192
|
+
const classArgs = [];
|
|
4193
|
+
for (const arg of expr.getArguments()) {
|
|
4194
|
+
if (!Node7.isIdentifier(arg)) continue;
|
|
4195
|
+
const decl = arg.getDefinitions().map((d) => d.getDeclarationNode()).find((n) => Node7.isClassDeclaration(n));
|
|
4196
|
+
if (decl) {
|
|
4197
|
+
classArgs.push({
|
|
4198
|
+
name: decl.getName() ?? arg.getText(),
|
|
4199
|
+
filePath: decl.getSourceFile().getFilePath()
|
|
4200
|
+
});
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
return {
|
|
4204
|
+
methods: returnedClass.getMethods(),
|
|
4205
|
+
factoryName: callee.getText(),
|
|
4206
|
+
factoryFilePath: factoryDecl.getSourceFile().getFilePath(),
|
|
4207
|
+
classArgs
|
|
4208
|
+
};
|
|
4209
|
+
}
|
|
4210
|
+
var mixinTypeProject;
|
|
4211
|
+
function getMixinTypeProject() {
|
|
4212
|
+
mixinTypeProject ??= new Project3({
|
|
4213
|
+
skipAddingFilesFromTsConfig: true,
|
|
4214
|
+
compilerOptions: { strict: true }
|
|
4215
|
+
});
|
|
4216
|
+
return mixinTypeProject;
|
|
4217
|
+
}
|
|
4218
|
+
function clearMixinTypeProject() {
|
|
4219
|
+
mixinTypeProject = void 0;
|
|
4220
|
+
}
|
|
4221
|
+
function resolveInstantiatedReturnType(cls, methodName) {
|
|
4222
|
+
const filePath = cls.getSourceFile().getFilePath();
|
|
4223
|
+
const className = cls.getName();
|
|
4224
|
+
if (!className) return void 0;
|
|
4225
|
+
const project = getMixinTypeProject();
|
|
4226
|
+
const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPathIfExists(filePath);
|
|
4227
|
+
const typedCls = sourceFile?.getClass(className);
|
|
4228
|
+
if (!typedCls) return void 0;
|
|
4229
|
+
const prop = typedCls.getType().getProperty(methodName);
|
|
4230
|
+
if (!prop) return void 0;
|
|
4231
|
+
const returnType = prop.getTypeAtLocation(typedCls).getCallSignatures()[0]?.getReturnType();
|
|
4232
|
+
if (!returnType) return void 0;
|
|
4233
|
+
const unwrapped = returnType.getSymbol()?.getName() === "Promise" ? returnType.getTypeArguments()[0] ?? returnType : returnType;
|
|
4234
|
+
return unwrapped.getText(typedCls);
|
|
4235
|
+
}
|
|
4236
|
+
|
|
4140
4237
|
// src/discovery/zod-ast-to-ts.ts
|
|
4141
|
-
import { Node as
|
|
4238
|
+
import { Node as Node8, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
4142
4239
|
function zodAstToTs(node) {
|
|
4143
|
-
if (!
|
|
4240
|
+
if (!Node8.isCallExpression(node)) return "unknown";
|
|
4144
4241
|
const expr = node.getExpression();
|
|
4145
|
-
if (
|
|
4242
|
+
if (Node8.isPropertyAccessExpression(expr)) {
|
|
4146
4243
|
const methodName = expr.getName();
|
|
4147
4244
|
const receiver = expr.getExpression();
|
|
4148
4245
|
if (methodName === "optional") {
|
|
@@ -4166,17 +4263,17 @@ function zodAstToTs(node) {
|
|
|
4166
4263
|
case "literal": {
|
|
4167
4264
|
const lit = args[0];
|
|
4168
4265
|
if (!lit) return "unknown";
|
|
4169
|
-
if (
|
|
4170
|
-
if (
|
|
4266
|
+
if (Node8.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
|
|
4267
|
+
if (Node8.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
|
|
4171
4268
|
if (lit.getKind() === SyntaxKind4.TrueKeyword) return "true";
|
|
4172
4269
|
if (lit.getKind() === SyntaxKind4.FalseKeyword) return "false";
|
|
4173
4270
|
return "unknown";
|
|
4174
4271
|
}
|
|
4175
4272
|
case "enum": {
|
|
4176
4273
|
const arrArg = args[0];
|
|
4177
|
-
if (!arrArg || !
|
|
4274
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4178
4275
|
const members = arrArg.getElements().map(
|
|
4179
|
-
(el) =>
|
|
4276
|
+
(el) => Node8.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
|
|
4180
4277
|
);
|
|
4181
4278
|
return members.join(" | ");
|
|
4182
4279
|
}
|
|
@@ -4187,10 +4284,10 @@ function zodAstToTs(node) {
|
|
|
4187
4284
|
}
|
|
4188
4285
|
case "object": {
|
|
4189
4286
|
const objArg = args[0];
|
|
4190
|
-
if (!objArg || !
|
|
4287
|
+
if (!objArg || !Node8.isObjectLiteralExpression(objArg)) return "unknown";
|
|
4191
4288
|
const lines = [];
|
|
4192
4289
|
for (const prop of objArg.getProperties()) {
|
|
4193
|
-
if (!
|
|
4290
|
+
if (!Node8.isPropertyAssignment(prop)) continue;
|
|
4194
4291
|
const key = prop.getName();
|
|
4195
4292
|
const valNode = prop.getInitializer();
|
|
4196
4293
|
if (!valNode) continue;
|
|
@@ -4202,7 +4299,7 @@ function zodAstToTs(node) {
|
|
|
4202
4299
|
}
|
|
4203
4300
|
case "union": {
|
|
4204
4301
|
const arrArg = args[0];
|
|
4205
|
-
if (!arrArg || !
|
|
4302
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4206
4303
|
return arrArg.getElements().map(zodAstToTs).join(" | ");
|
|
4207
4304
|
}
|
|
4208
4305
|
case "record": {
|
|
@@ -4212,7 +4309,7 @@ function zodAstToTs(node) {
|
|
|
4212
4309
|
}
|
|
4213
4310
|
case "tuple": {
|
|
4214
4311
|
const arrArg = args[0];
|
|
4215
|
-
if (!arrArg || !
|
|
4312
|
+
if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
|
|
4216
4313
|
return `[${arrArg.getElements().map(zodAstToTs).join(", ")}]`;
|
|
4217
4314
|
}
|
|
4218
4315
|
default:
|
|
@@ -4222,18 +4319,18 @@ function zodAstToTs(node) {
|
|
|
4222
4319
|
return "unknown";
|
|
4223
4320
|
}
|
|
4224
4321
|
function isOptionalChain(node) {
|
|
4225
|
-
if (!
|
|
4322
|
+
if (!Node8.isCallExpression(node)) return false;
|
|
4226
4323
|
const expr = node.getExpression();
|
|
4227
|
-
return
|
|
4324
|
+
return Node8.isPropertyAccessExpression(expr) && expr.getName() === "optional";
|
|
4228
4325
|
}
|
|
4229
4326
|
function parseDefineContractCall(callExpr) {
|
|
4230
|
-
if (!
|
|
4327
|
+
if (!Node8.isCallExpression(callExpr)) return null;
|
|
4231
4328
|
const callee = callExpr.getExpression();
|
|
4232
|
-
const calleeName =
|
|
4329
|
+
const calleeName = Node8.isIdentifier(callee) ? callee.getText() : Node8.isPropertyAccessExpression(callee) ? callee.getName() : "";
|
|
4233
4330
|
if (calleeName !== "defineContract") return null;
|
|
4234
4331
|
const args = callExpr.getArguments();
|
|
4235
4332
|
const optsArg = args[0];
|
|
4236
|
-
if (!optsArg || !
|
|
4333
|
+
if (!optsArg || !Node8.isObjectLiteralExpression(optsArg)) return null;
|
|
4237
4334
|
let query = null;
|
|
4238
4335
|
let body = null;
|
|
4239
4336
|
let response = "unknown";
|
|
@@ -4241,7 +4338,7 @@ function parseDefineContractCall(callExpr) {
|
|
|
4241
4338
|
let bodyZodText = null;
|
|
4242
4339
|
let queryZodText = null;
|
|
4243
4340
|
for (const prop of optsArg.getProperties()) {
|
|
4244
|
-
if (!
|
|
4341
|
+
if (!Node8.isPropertyAssignment(prop)) continue;
|
|
4245
4342
|
const propName = prop.getName();
|
|
4246
4343
|
const val = prop.getInitializer();
|
|
4247
4344
|
if (!val) continue;
|
|
@@ -4270,6 +4367,7 @@ async function discoverContractsFast(opts) {
|
|
|
4270
4367
|
project.addSourceFileAtPath(f);
|
|
4271
4368
|
}
|
|
4272
4369
|
bindDiscoveryContext(project, cwd, tsconfigPath);
|
|
4370
|
+
clearMixinTypeProject();
|
|
4273
4371
|
return extractAllRoutes(project);
|
|
4274
4372
|
}
|
|
4275
4373
|
function resolveTsconfigPath(cwd, tsconfig) {
|
|
@@ -4277,14 +4375,14 @@ function resolveTsconfigPath(cwd, tsconfig) {
|
|
|
4277
4375
|
}
|
|
4278
4376
|
function createDiscoveryProject(tsconfigPath) {
|
|
4279
4377
|
try {
|
|
4280
|
-
return new
|
|
4378
|
+
return new Project4({
|
|
4281
4379
|
tsConfigFilePath: tsconfigPath,
|
|
4282
4380
|
skipAddingFilesFromTsConfig: true,
|
|
4283
4381
|
skipLoadingLibFiles: true,
|
|
4284
4382
|
skipFileDependencyResolution: true
|
|
4285
4383
|
});
|
|
4286
4384
|
} catch {
|
|
4287
|
-
return new
|
|
4385
|
+
return new Project4({
|
|
4288
4386
|
skipAddingFilesFromTsConfig: true,
|
|
4289
4387
|
skipLoadingLibFiles: true,
|
|
4290
4388
|
skipFileDependencyResolution: true,
|
|
@@ -4391,15 +4489,16 @@ var PersistentDiscovery = class _PersistentDiscovery {
|
|
|
4391
4489
|
runExtraction() {
|
|
4392
4490
|
clearTypeResolutionCaches(this.project);
|
|
4393
4491
|
clearEnumCache(this.project);
|
|
4492
|
+
clearMixinTypeProject();
|
|
4394
4493
|
return extractRoutesFrom(this.project, this.controllerPaths);
|
|
4395
4494
|
}
|
|
4396
4495
|
};
|
|
4397
4496
|
function decoratorStringArg(decoratorExpr) {
|
|
4398
4497
|
if (!decoratorExpr) return void 0;
|
|
4399
|
-
if (
|
|
4400
|
-
if (
|
|
4498
|
+
if (Node9.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
|
|
4499
|
+
if (Node9.isArrayLiteralExpression(decoratorExpr)) {
|
|
4401
4500
|
const first = decoratorExpr.getElements()[0];
|
|
4402
|
-
if (first &&
|
|
4501
|
+
if (first && Node9.isStringLiteral(first)) return first.getLiteralValue();
|
|
4403
4502
|
}
|
|
4404
4503
|
return void 0;
|
|
4405
4504
|
}
|
|
@@ -4421,7 +4520,8 @@ function joinPaths(prefix, suffix) {
|
|
|
4421
4520
|
if (!prefix && !suffix) return "/";
|
|
4422
4521
|
if (!prefix) return suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4423
4522
|
if (!suffix) return prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4424
|
-
const
|
|
4523
|
+
const withLeadingSlash = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
4524
|
+
const p = withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
4425
4525
|
const s = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
4426
4526
|
const combined = p + s;
|
|
4427
4527
|
return combined === "" ? "/" : combined;
|
|
@@ -4475,7 +4575,8 @@ function buildRoute(args) {
|
|
|
4475
4575
|
methodAs,
|
|
4476
4576
|
sourceFile,
|
|
4477
4577
|
seenNames,
|
|
4478
|
-
contractSource
|
|
4578
|
+
contractSource,
|
|
4579
|
+
mixin
|
|
4479
4580
|
} = args;
|
|
4480
4581
|
const routeName = resolveRouteName(className, methodName, classAs, methodAs);
|
|
4481
4582
|
const qualifiedRef = `${className}.${methodName}`;
|
|
@@ -4491,7 +4592,12 @@ function buildRoute(args) {
|
|
|
4491
4592
|
path: combinedPath,
|
|
4492
4593
|
name: routeName,
|
|
4493
4594
|
params: extractParams(combinedPath),
|
|
4494
|
-
controllerRef: {
|
|
4595
|
+
controllerRef: {
|
|
4596
|
+
className,
|
|
4597
|
+
methodName,
|
|
4598
|
+
filePath: sourceFile.getFilePath(),
|
|
4599
|
+
...mixin ? { mixin } : {}
|
|
4600
|
+
},
|
|
4495
4601
|
contract: { contractSource }
|
|
4496
4602
|
};
|
|
4497
4603
|
}
|
|
@@ -4505,16 +4611,17 @@ function extractContractRoute(args) {
|
|
|
4505
4611
|
className,
|
|
4506
4612
|
sourceFile,
|
|
4507
4613
|
project,
|
|
4508
|
-
seenNames
|
|
4614
|
+
seenNames,
|
|
4615
|
+
mixin
|
|
4509
4616
|
} = args;
|
|
4510
4617
|
const firstDecoratorArg = applyContractDecorator.getArguments()[0];
|
|
4511
4618
|
if (!firstDecoratorArg) return null;
|
|
4512
4619
|
let contractDef = null;
|
|
4513
4620
|
let bodyZodRef = null;
|
|
4514
4621
|
let queryZodRef = null;
|
|
4515
|
-
if (
|
|
4622
|
+
if (Node9.isCallExpression(firstDecoratorArg)) {
|
|
4516
4623
|
contractDef = parseDefineContractCall(firstDecoratorArg);
|
|
4517
|
-
} else if (
|
|
4624
|
+
} else if (Node9.isIdentifier(firstDecoratorArg)) {
|
|
4518
4625
|
const identName = firstDecoratorArg.getText();
|
|
4519
4626
|
const resolvedVar = resolveImportedVariable(identName, sourceFile, project);
|
|
4520
4627
|
if (!resolvedVar) {
|
|
@@ -4557,6 +4664,7 @@ function extractContractRoute(args) {
|
|
|
4557
4664
|
methodAs,
|
|
4558
4665
|
sourceFile,
|
|
4559
4666
|
seenNames,
|
|
4667
|
+
mixin,
|
|
4560
4668
|
contractSource: {
|
|
4561
4669
|
query: contractDef.query,
|
|
4562
4670
|
body: contractDef.body,
|
|
@@ -4573,13 +4681,14 @@ function extractContractRoute(args) {
|
|
|
4573
4681
|
});
|
|
4574
4682
|
}
|
|
4575
4683
|
function extractDtoRoute(args) {
|
|
4576
|
-
const { cls, method, verb, prefix, className, sourceFile, project, seenNames } = args;
|
|
4684
|
+
const { cls, method, verb, prefix, className, sourceFile, project, seenNames, mixin } = args;
|
|
4577
4685
|
if (!verb) return null;
|
|
4578
4686
|
const combined = joinPaths(prefix, verb.handlerPath);
|
|
4579
4687
|
const methodName = method.getName();
|
|
4580
4688
|
const classAs = readAsDecorator(cls, `class ${className}`);
|
|
4581
4689
|
const methodAs = readAsDecorator(method, `${className}.${methodName}`);
|
|
4582
|
-
const dtoContract = extractDtoContract(method, sourceFile, project);
|
|
4690
|
+
const dtoContract = extractDtoContract(method, sourceFile, project, mixin);
|
|
4691
|
+
const mixinResponse = mixin ? resolveInstantiatedReturnType(cls, methodName) : void 0;
|
|
4583
4692
|
return buildRoute({
|
|
4584
4693
|
className,
|
|
4585
4694
|
methodName,
|
|
@@ -4589,10 +4698,11 @@ function extractDtoRoute(args) {
|
|
|
4589
4698
|
methodAs,
|
|
4590
4699
|
sourceFile,
|
|
4591
4700
|
seenNames,
|
|
4701
|
+
mixin,
|
|
4592
4702
|
contractSource: {
|
|
4593
4703
|
query: dtoContract?.query ?? null,
|
|
4594
4704
|
body: dtoContract?.body ?? null,
|
|
4595
|
-
response: dtoContract?.response ?? "unknown",
|
|
4705
|
+
response: mixinResponse ?? dtoContract?.response ?? "unknown",
|
|
4596
4706
|
error: dtoContract?.error ?? null,
|
|
4597
4707
|
queryRef: dtoContract?.queryRef ?? null,
|
|
4598
4708
|
bodyRef: dtoContract?.bodyRef ?? null,
|
|
@@ -4621,7 +4731,17 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4621
4731
|
const firstArg2 = controllerDecorator.getArguments()[0];
|
|
4622
4732
|
const prefix = decoratorStringArg(firstArg2) ?? "";
|
|
4623
4733
|
const className = cls.getName() ?? "Unknown";
|
|
4624
|
-
|
|
4734
|
+
const inherited = resolveInheritedMethods(cls);
|
|
4735
|
+
const mixinBinding = inherited ? {
|
|
4736
|
+
factoryName: inherited.factoryName,
|
|
4737
|
+
factoryFilePath: inherited.factoryFilePath,
|
|
4738
|
+
classArgs: inherited.classArgs
|
|
4739
|
+
} : void 0;
|
|
4740
|
+
const methods = [
|
|
4741
|
+
...cls.getMethods().map((method) => ({ method })),
|
|
4742
|
+
...(inherited?.methods ?? []).map((method) => ({ method, mixin: mixinBinding }))
|
|
4743
|
+
];
|
|
4744
|
+
for (const { method, mixin } of methods) {
|
|
4625
4745
|
const verb = resolveVerb(method);
|
|
4626
4746
|
const applyContractDecorator = method.getDecorator("ApplyContract");
|
|
4627
4747
|
const route = applyContractDecorator ? extractContractRoute({
|
|
@@ -4633,7 +4753,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4633
4753
|
className,
|
|
4634
4754
|
sourceFile,
|
|
4635
4755
|
project,
|
|
4636
|
-
seenNames
|
|
4756
|
+
seenNames,
|
|
4757
|
+
mixin
|
|
4637
4758
|
}) : extractDtoRoute({
|
|
4638
4759
|
cls,
|
|
4639
4760
|
method,
|
|
@@ -4642,7 +4763,8 @@ function extractFromSourceFile(sourceFile, project) {
|
|
|
4642
4763
|
className,
|
|
4643
4764
|
sourceFile,
|
|
4644
4765
|
project,
|
|
4645
|
-
seenNames
|
|
4766
|
+
seenNames,
|
|
4767
|
+
mixin
|
|
4646
4768
|
});
|
|
4647
4769
|
if (route) routes.push(route);
|
|
4648
4770
|
}
|
|
@@ -4843,7 +4965,7 @@ async function watch(config, onChange, options = {}) {
|
|
|
4843
4965
|
}
|
|
4844
4966
|
|
|
4845
4967
|
// src/index.ts
|
|
4846
|
-
var VERSION = "0.
|
|
4968
|
+
var VERSION = "0.16.0";
|
|
4847
4969
|
|
|
4848
4970
|
// src/cli/codegen.ts
|
|
4849
4971
|
async function runCodegen(opts = {}) {
|