@dudousxd/nestjs-codegen 0.19.0 → 0.21.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
@@ -3634,10 +3634,15 @@ function resolveInstantiatedReturnType(cls, methodName) {
3634
3634
 
3635
3635
  // src/discovery/filter-for.ts
3636
3636
  function resolveMixinEntityClass(mixin, project) {
3637
- const entityArg = mixin?.namedClassArgs?.entity ?? mixin?.classArgs[0];
3638
- if (!entityArg) return void 0;
3639
- const file = project.getSourceFile(entityArg.filePath) ?? project.addSourceFileAtPathIfExists(entityArg.filePath);
3640
- return file?.getClass(entityArg.name);
3637
+ return resolveClassRef(mixin?.namedClassArgs?.entity ?? mixin?.classArgs[0], project);
3638
+ }
3639
+ function resolveMixinFilterClass(mixin, project) {
3640
+ return resolveClassRef(mixin?.namedClassArgs?.filter, project);
3641
+ }
3642
+ function resolveClassRef(ref, project) {
3643
+ if (!ref) return void 0;
3644
+ const file = project.getSourceFile(ref.filePath) ?? project.addSourceFileAtPathIfExists(ref.filePath);
3645
+ return file?.getClass(ref.name);
3641
3646
  }
3642
3647
  function classifyFilterForHint(typeInit) {
3643
3648
  if (Node6.isStringLiteral(typeInit)) {
@@ -3712,7 +3717,7 @@ function extractFilterForHints(classDecl, project) {
3712
3717
  }
3713
3718
  return hints;
3714
3719
  }
3715
- function extractApplyFilterInfo(method, sourceFile, project, mixin) {
3720
+ function extractApplyFilterInfo(method, sourceFile, project, mixin, controllerClass) {
3716
3721
  const declFile = method.getSourceFile();
3717
3722
  const mixinEntity = resolveMixinEntityClass(mixin, project);
3718
3723
  for (const param of method.getParameters()) {
@@ -3737,31 +3742,55 @@ function extractApplyFilterInfo(method, sourceFile, project, mixin) {
3737
3742
  }
3738
3743
  const filterClassName = filterClassArg.getText();
3739
3744
  const resolved = factoryStaticClass ? void 0 : findType(filterClassName, declFile, project);
3740
- const classDecl = factoryStaticClass ?? (resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg));
3741
- if (classDecl) {
3742
- let fieldTypes = extractClassPropertyTypes(classDecl, project);
3743
- if (fieldTypes.length === 0) {
3744
- fieldTypes = extractFilterableEntityFields(classDecl, project, mixinEntity);
3745
- }
3746
- const filterForHints = extractFilterForHints(classDecl, project);
3747
- if (filterForHints.size > 0) {
3748
- const byName = new Map(fieldTypes.map((f) => [f.name, f]));
3749
- for (const [key, classified] of filterForHints) {
3750
- byName.set(key, toFilterFieldType(key, classified));
3751
- }
3752
- fieldTypes = [...byName.values()];
3753
- }
3754
- if (fieldTypes.length === 0) return null;
3755
- const fieldNames = fieldTypes.map((f) => f.name);
3745
+ const declaredClass = factoryStaticClass ?? (resolved?.kind === "class" ? resolved.decl : resolveLocalClassDeclaration(filterClassArg));
3746
+ const ownRoute = !mixin || (controllerClass ? method.getParent() === controllerClass : declFile.getFilePath() !== mixin.factoryFilePath);
3747
+ const namedByRoute = ownRoute && Node6.isIdentifier(filterClassArg) ? declaredClass : void 0;
3748
+ for (const candidate of orderFilterCandidates({
3749
+ namedByRoute,
3750
+ supplied: resolveMixinFilterClass(mixin, project),
3751
+ declared: declaredClass
3752
+ })) {
3753
+ const fieldTypes = collectFilterFields(candidate, project, mixinEntity);
3754
+ if (fieldTypes.length === 0) continue;
3756
3755
  return {
3757
- fieldNames,
3756
+ fieldNames: fieldTypes.map((f) => f.name),
3758
3757
  fieldTypes,
3759
3758
  source
3760
3759
  };
3761
3760
  }
3761
+ if (declaredClass) return null;
3762
3762
  }
3763
3763
  return null;
3764
3764
  }
3765
+ function orderFilterCandidates(sources) {
3766
+ const ordered = [];
3767
+ const seen = /* @__PURE__ */ new Set();
3768
+ const push = (decl, preferDeclaredEntity) => {
3769
+ if (!decl || seen.has(decl)) return;
3770
+ seen.add(decl);
3771
+ ordered.push({ decl, preferDeclaredEntity });
3772
+ };
3773
+ push(sources.namedByRoute, true);
3774
+ push(sources.supplied, true);
3775
+ push(sources.declared, false);
3776
+ return ordered;
3777
+ }
3778
+ function collectFilterFields(candidate, project, mixinEntity) {
3779
+ const { decl, preferDeclaredEntity } = candidate;
3780
+ let fieldTypes = extractClassPropertyTypes(decl, project);
3781
+ if (fieldTypes.length === 0) {
3782
+ fieldTypes = extractFilterableEntityFields(decl, project, mixinEntity, preferDeclaredEntity);
3783
+ }
3784
+ const filterForHints = extractFilterForHints(decl, project);
3785
+ if (filterForHints.size > 0) {
3786
+ const byName = new Map(fieldTypes.map((f) => [f.name, f]));
3787
+ for (const [key, classified] of filterForHints) {
3788
+ byName.set(key, toFilterFieldType(key, classified));
3789
+ }
3790
+ fieldTypes = [...byName.values()];
3791
+ }
3792
+ return fieldTypes;
3793
+ }
3765
3794
  var RELATION_DECORATORS = /* @__PURE__ */ new Set(["OneToMany", "ManyToOne", "ManyToMany", "OneToOne"]);
3766
3795
  function collectEntityFields(entityDecl, sourceFile, project, prefix, visited) {
3767
3796
  const entityName = entityDecl.getName() ?? "";
@@ -3840,21 +3869,53 @@ function resolveDeclaredEntity(optionsArg, filterClass, project) {
3840
3869
  if (!resolved || resolved.kind !== "class") return void 0;
3841
3870
  return resolved.decl;
3842
3871
  }
3843
- function extractFilterableEntityFields(filterClass, project, entityOverride) {
3872
+ function readFieldNameList(optionsArg, key) {
3873
+ if (!Node6.isObjectLiteralExpression(optionsArg)) return void 0;
3874
+ const prop = optionsArg.getProperty(key);
3875
+ if (!prop || !Node6.isPropertyAssignment(prop)) return void 0;
3876
+ const init = prop.getInitializer();
3877
+ if (!init || !Node6.isArrayLiteralExpression(init)) return void 0;
3878
+ const names = /* @__PURE__ */ new Set();
3879
+ for (const el of init.getElements()) {
3880
+ if (Node6.isStringLiteral(el)) {
3881
+ names.add(el.getLiteralValue());
3882
+ continue;
3883
+ }
3884
+ if (Node6.isObjectLiteralExpression(el)) {
3885
+ const fieldProp = el.getProperty("field");
3886
+ if (fieldProp && Node6.isPropertyAssignment(fieldProp)) {
3887
+ const fieldInit = fieldProp.getInitializer();
3888
+ if (fieldInit && Node6.isStringLiteral(fieldInit)) {
3889
+ names.add(fieldInit.getLiteralValue());
3890
+ continue;
3891
+ }
3892
+ }
3893
+ }
3894
+ return void 0;
3895
+ }
3896
+ return names;
3897
+ }
3898
+ function narrowToDeclaredFields(fields, optionsArg) {
3899
+ const allowed = readFieldNameList(optionsArg, "allowed");
3900
+ const blocked = readFieldNameList(optionsArg, "blocked");
3901
+ if (!allowed && !blocked) return fields;
3902
+ return fields.filter(
3903
+ (f) => (!allowed || allowed.has(f.name)) && !(blocked?.has(f.name) ?? false)
3904
+ );
3905
+ }
3906
+ function extractFilterableEntityFields(filterClass, project, entityOverride, preferDeclaredEntity = false) {
3844
3907
  const filterableDecorator = filterClass.getDecorators().find((d) => d.getName() === "Filterable");
3845
3908
  if (!filterableDecorator) return [];
3846
3909
  const args = filterableDecorator.getArguments();
3847
3910
  if (args.length === 0) return [];
3848
3911
  const optionsArg = args[0];
3849
3912
  if (!Node6.isObjectLiteralExpression(optionsArg)) return [];
3850
- const entityDecl = entityOverride ?? resolveDeclaredEntity(optionsArg, filterClass, project);
3913
+ const declaredEntity = resolveDeclaredEntity(optionsArg, filterClass, project);
3914
+ const entityDecl = preferDeclaredEntity ? declaredEntity ?? entityOverride : entityOverride ?? declaredEntity;
3851
3915
  if (!entityDecl) return [];
3852
- const fields = collectEntityFields(
3853
- entityDecl,
3854
- entityDecl.getSourceFile(),
3855
- project,
3856
- "",
3857
- /* @__PURE__ */ new Set()
3916
+ const fields = narrowToDeclaredFields(
3917
+ collectEntityFields(entityDecl, entityDecl.getSourceFile(), project, "", /* @__PURE__ */ new Set()),
3918
+ optionsArg
3858
3919
  );
3859
3920
  const relationsDecorator = filterClass.getDecorators().find((d) => d.getName() === "Relations");
3860
3921
  if (relationsDecorator) {
@@ -4273,9 +4334,9 @@ function unwrapNamedContainer(node, names) {
4273
4334
  }
4274
4335
  return node;
4275
4336
  }
4276
- function extractDtoContract(method, sourceFile, project, mixin) {
4337
+ function extractDtoContract(method, sourceFile, project, mixin, controllerClass) {
4277
4338
  let body = extractBodyType(method, sourceFile, project);
4278
- const filterInfo = extractApplyFilterInfo(method, sourceFile, project, mixin);
4339
+ const filterInfo = extractApplyFilterInfo(method, sourceFile, project, mixin, controllerClass);
4279
4340
  const query = extractQueryType(method, sourceFile, project);
4280
4341
  const uploads = extractUploadedFiles(method);
4281
4342
  const multipartBody = uploads.fields ? `{ ${uploads.fields} }` : null;
@@ -4838,7 +4899,7 @@ function extractDtoRoute(args) {
4838
4899
  const methodName = method.getName();
4839
4900
  const classAs = readAsDecorator(cls, `class ${className}`);
4840
4901
  const methodAs = readAsDecorator(method, `${className}.${methodName}`);
4841
- const dtoContract = extractDtoContract(method, sourceFile, project, mixin);
4902
+ const dtoContract = extractDtoContract(method, sourceFile, project, mixin, cls);
4842
4903
  const mixinResponse = mixin ? resolveInstantiatedReturnType(cls, methodName) : void 0;
4843
4904
  return buildRoute({
4844
4905
  className,
@@ -5119,7 +5180,7 @@ async function watch(config, onChange, options = {}) {
5119
5180
  }
5120
5181
 
5121
5182
  // src/index.ts
5122
- var VERSION = "0.19.0";
5183
+ var VERSION = "0.21.0";
5123
5184
 
5124
5185
  // src/cli/codegen.ts
5125
5186
  async function runCodegen(opts = {}) {