@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/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 Node8,
2413
- Project as Project3
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, sourceFile, project);
3499
- if (resolved && resolved.kind === "class") {
3500
- const classDecl = resolved.decl;
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 extractFilterableEntityFields(filterClass, project) {
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 entityProp = optionsArg.getProperty("entity");
3596
- if (!entityProp || !Node5.isPropertyAssignment(entityProp)) return [];
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 Node7, SyntaxKind as SyntaxKind4 } from "ts-morph";
4238
+ import { Node as Node8, SyntaxKind as SyntaxKind4 } from "ts-morph";
4142
4239
  function zodAstToTs(node) {
4143
- if (!Node7.isCallExpression(node)) return "unknown";
4240
+ if (!Node8.isCallExpression(node)) return "unknown";
4144
4241
  const expr = node.getExpression();
4145
- if (Node7.isPropertyAccessExpression(expr)) {
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 (Node7.isStringLiteral(lit)) return JSON.stringify(lit.getLiteralValue());
4170
- if (Node7.isNumericLiteral(lit)) return lit.getLiteralValue().toString();
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 || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
4274
+ if (!arrArg || !Node8.isArrayLiteralExpression(arrArg)) return "unknown";
4178
4275
  const members = arrArg.getElements().map(
4179
- (el) => Node7.isStringLiteral(el) ? JSON.stringify(el.getLiteralValue()) : "unknown"
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 || !Node7.isObjectLiteralExpression(objArg)) return "unknown";
4287
+ if (!objArg || !Node8.isObjectLiteralExpression(objArg)) return "unknown";
4191
4288
  const lines = [];
4192
4289
  for (const prop of objArg.getProperties()) {
4193
- if (!Node7.isPropertyAssignment(prop)) continue;
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 || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
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 || !Node7.isArrayLiteralExpression(arrArg)) return "unknown";
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 (!Node7.isCallExpression(node)) return false;
4322
+ if (!Node8.isCallExpression(node)) return false;
4226
4323
  const expr = node.getExpression();
4227
- return Node7.isPropertyAccessExpression(expr) && expr.getName() === "optional";
4324
+ return Node8.isPropertyAccessExpression(expr) && expr.getName() === "optional";
4228
4325
  }
4229
4326
  function parseDefineContractCall(callExpr) {
4230
- if (!Node7.isCallExpression(callExpr)) return null;
4327
+ if (!Node8.isCallExpression(callExpr)) return null;
4231
4328
  const callee = callExpr.getExpression();
4232
- const calleeName = Node7.isIdentifier(callee) ? callee.getText() : Node7.isPropertyAccessExpression(callee) ? callee.getName() : "";
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 || !Node7.isObjectLiteralExpression(optsArg)) return null;
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 (!Node7.isPropertyAssignment(prop)) continue;
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 Project3({
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 Project3({
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 (Node8.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
4400
- if (Node8.isArrayLiteralExpression(decoratorExpr)) {
4498
+ if (Node9.isStringLiteral(decoratorExpr)) return decoratorExpr.getLiteralValue();
4499
+ if (Node9.isArrayLiteralExpression(decoratorExpr)) {
4401
4500
  const first = decoratorExpr.getElements()[0];
4402
- if (first && Node8.isStringLiteral(first)) return first.getLiteralValue();
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 p = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
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: { className, methodName, filePath: sourceFile.getFilePath() },
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 (Node8.isCallExpression(firstDecoratorArg)) {
4622
+ if (Node9.isCallExpression(firstDecoratorArg)) {
4516
4623
  contractDef = parseDefineContractCall(firstDecoratorArg);
4517
- } else if (Node8.isIdentifier(firstDecoratorArg)) {
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
- for (const method of cls.getMethods()) {
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.15.0";
4968
+ var VERSION = "0.16.0";
4847
4969
 
4848
4970
  // src/cli/codegen.ts
4849
4971
  async function runCodegen(opts = {}) {