Skip to content

Commit eb5bc19

Browse files
committed
fix(plugin): wrap enum property values in functions
- Check identifierText.includes('await ') instead of typeName.includes('import(') - Update test fixtures to conditionally add async based on esmCompatible - Add regression test for same-file array types (#3630)
1 parent ef0173b commit eb5bc19

11 files changed

+161
-28
lines changed

lib/plugin/visitors/model-class.visitor.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,14 @@ export class ModelClassVisitor extends AbstractFileVisitor {
536536
this._typeImports
537537
);
538538

539+
// Only add async modifier if the identifier contains await (for ESM dynamic imports)
540+
const identifierText = identifier.text || '';
541+
const modifiers = identifierText.includes('await ')
542+
? [factory.createModifier(ts.SyntaxKind.AsyncKeyword)]
543+
: undefined;
544+
539545
const initializer = factory.createArrowFunction(
540-
undefined,
546+
modifiers,
541547
undefined,
542548
[],
543549
undefined,
@@ -714,6 +720,7 @@ export class ModelClassVisitor extends AbstractFileVisitor {
714720
}
715721

716722
const typeReferenceDescriptor = { typeName: getText(type, typeChecker) };
723+
717724
const enumIdentifier = typeReferenceToIdentifier(
718725
typeReferenceDescriptor,
719726
hostFilename,
@@ -723,7 +730,22 @@ export class ModelClassVisitor extends AbstractFileVisitor {
723730
this._typeImports
724731
);
725732

726-
const enumProperty = factory.createPropertyAssignment(key, enumIdentifier);
733+
// Only add async modifier if the identifier contains await (for ESM dynamic imports)
734+
const enumIdentifierText = enumIdentifier.text || '';
735+
const modifiers = enumIdentifierText.includes('await ')
736+
? [factory.createModifier(ts.SyntaxKind.AsyncKeyword)]
737+
: undefined;
738+
739+
const initializer = factory.createArrowFunction(
740+
modifiers,
741+
undefined,
742+
[],
743+
undefined,
744+
undefined,
745+
enumIdentifier
746+
);
747+
748+
const enumProperty = factory.createPropertyAssignment(key, initializer);
727749

728750
if (isArrayType) {
729751
const isArrayKey = 'isArray';

test/plugin/fixtures/create-cat-alt.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class CreateCatDto2 {
6363
_CreateCatDto2_privateProperty.set(this, void 0);
6464
}
6565
static _OPENAPI_METADATA_FACTORY() {
66-
return { name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: Status }, breed: { required: false, type: () => String }, nodes: { required: true, type: () => [Object] }, alias: { required: true, type: () => Object }, numberAlias: { required: true, type: () => Number, description: "NumberAlias" }, union: { required: true, type: () => Object }, intersection: { required: true, type: () => Object }, str: { required: true, type: () => [String] }, rawArray: { required: true, type: () => [({ foo: { required: true, type: () => String } })] }, nested: { required: true, type: () => ({ first: { required: true, type: () => String }, second: { required: true, type: () => Number }, status: { required: true, enum: Status }, tags: { required: true, type: () => [String] }, nodes: { required: true, type: () => [Object] }, alias: { required: true, type: () => Object }, numberAlias: { required: true, type: () => Number } }) }, amount: { required: true, type: () => BigInt } };
66+
return { name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: () => Status }, breed: { required: false, type: () => String }, nodes: { required: true, type: () => [Object] }, alias: { required: true, type: () => Object }, numberAlias: { required: true, type: () => Number, description: "NumberAlias" }, union: { required: true, type: () => Object }, intersection: { required: true, type: () => Object }, str: { required: true, type: () => [String] }, rawArray: { required: true, type: () => [({ foo: { required: true, type: () => String } })] }, nested: { required: true, type: () => ({ first: { required: true, type: () => String }, second: { required: true, type: () => Number }, status: { required: true, enum: () => Status }, tags: { required: true, type: () => [String] }, nodes: { required: true, type: () => [Object] }, alias: { required: true, type: () => Object }, numberAlias: { required: true, type: () => Number } }) }, amount: { required: true, type: () => BigInt } };
6767
}
6868
}
6969
_CreateCatDto2_privateProperty = new WeakMap();

test/plugin/fixtures/create-cat-exclude.dto.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export class CreateCatDto {
8888
this.status = Status.ENABLED;
8989
}
9090
static _OPENAPI_METADATA_FACTORY() {
91-
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: Status }, status2: { required: false, enum: Status }, statusArr: { required: false, enum: Status, isArray: true }, oneValueEnum: { required: false, enum: OneValueEnum }, oneValueEnumArr: { required: false, enum: OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] } };
91+
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: () => Status }, status2: { required: false, enum: () => Status }, statusArr: { required: false, enum: () => Status, isArray: true }, oneValueEnum: { required: false, enum: () => OneValueEnum }, oneValueEnumArr: { required: false, enum: () => OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] } };
9292
}
9393
}
9494
__decorate([
@@ -149,7 +149,7 @@ export class CreateCatDto {
149149
this.status = Status.ENABLED;
150150
}
151151
static _OPENAPI_METADATA_FACTORY() {
152-
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: Status }, status2: { required: false, enum: Status }, statusArr: { required: false, enum: Status, isArray: true }, oneValueEnum: { required: false, enum: OneValueEnum }, oneValueEnumArr: { required: false, enum: OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] }, excluded: { required: true, type: () => Number } };
152+
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: () => Status }, status2: { required: false, enum: () => Status }, statusArr: { required: false, enum: () => Status, isArray: true }, oneValueEnum: { required: false, enum: () => OneValueEnum }, oneValueEnumArr: { required: false, enum: () => OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] }, excluded: { required: true, type: () => Number } };
153153
}
154154
}
155155
__decorate([

test/plugin/fixtures/create-cat-priority.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class CreateCatDto {
8989
this.status = Status.ENABLED;
9090
}
9191
static _OPENAPI_METADATA_FACTORY() {
92-
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: Status }, status2: { required: false, enum: Status }, statusArr: { required: false, enum: Status, isArray: true }, oneValueEnum: { required: false, enum: OneValueEnum }, oneValueEnumArr: { required: false, enum: OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] } };
92+
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: () => Status }, status2: { required: false, enum: () => Status }, statusArr: { required: false, enum: () => Status, isArray: true }, oneValueEnum: { required: false, enum: () => OneValueEnum }, oneValueEnumArr: { required: false, enum: () => OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] } };
9393
}
9494
}
9595
__decorate([

test/plugin/fixtures/create-cat.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export class CreateCatDto {
126126
_CreateCatDto_privateProperty.set(this, void 0);
127127
}
128128
static _OPENAPI_METADATA_FACTORY() {
129-
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, names: { required: true, type: () => [String], minItems: 1, uniqueItems: true, maxItems: 10 }, employees: { required: true, type: () => [String], minItems: 1 }, nominator: { required: true, type: () => String, multipleOf: 2 }, encodedInfo: { required: true, type: () => String, format: "base64" }, creditCard: { required: true, type: () => String, format: "credit-card" }, currency: { required: true, type: () => String, format: "currency" }, email: { required: true, type: () => String, format: "email" }, response: { required: true, type: () => Object, format: "json" }, githubAccount: { required: true, type: () => String, format: "uri" }, transactionId: { required: true, type: () => String, format: "uuid" }, phoneNumber: { required: true, type: () => String, format: "mobile-phone" }, char: { required: true, type: () => String, pattern: "^[\\\\x00-\\\\x7F]+$" }, color: { required: true, type: () => String, pattern: "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$" }, hex: { required: true, type: () => String, pattern: "^(0x|0h)?[0-9A-F]+$" }, searchBy: { required: true, type: () => String, pattern: "log_" }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: Status }, status2: { required: false, enum: Status }, statusArr: { required: false, enum: Status, isArray: true }, oneValueEnum: { required: false, enum: OneValueEnum }, oneValueEnumArr: { required: false, enum: OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] }, cryptoUUIDProperty: { required: true, type: () => String }, arrayOfUUIDs: { required: true, type: () => [String] } };
129+
return { isIn: { required: true, type: () => String, enum: ['a', 'b'] }, pattern: { required: true, type: () => String, pattern: "/^[+]?abc$/" }, name: { required: true, type: () => String }, age: { required: true, type: () => Number, default: 3, minimum: 0, maximum: 10 }, positive: { required: true, type: () => Number, default: 5, minimum: 1 }, negative: { required: true, type: () => Number, default: -1, maximum: -1 }, lengthMin: { required: true, type: () => String, minLength: 2 }, lengthMinMax: { required: true, type: () => String, minLength: 3, maxLength: 5 }, names: { required: true, type: () => [String], minItems: 1, uniqueItems: true, maxItems: 10 }, employees: { required: true, type: () => [String], minItems: 1 }, nominator: { required: true, type: () => String, multipleOf: 2 }, encodedInfo: { required: true, type: () => String, format: "base64" }, creditCard: { required: true, type: () => String, format: "credit-card" }, currency: { required: true, type: () => String, format: "currency" }, email: { required: true, type: () => String, format: "email" }, response: { required: true, type: () => Object, format: "json" }, githubAccount: { required: true, type: () => String, format: "uri" }, transactionId: { required: true, type: () => String, format: "uuid" }, phoneNumber: { required: true, type: () => String, format: "mobile-phone" }, char: { required: true, type: () => String, pattern: "^[\\\\x00-\\\\x7F]+$" }, color: { required: true, type: () => String, pattern: "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$" }, hex: { required: true, type: () => String, pattern: "^(0x|0h)?[0-9A-F]+$" }, searchBy: { required: true, type: () => String, pattern: "log_" }, tags: { required: true, type: () => [String] }, status: { required: true, default: Status.ENABLED, enum: () => Status }, status2: { required: false, enum: () => Status }, statusArr: { required: false, enum: () => Status, isArray: true }, oneValueEnum: { required: false, enum: () => OneValueEnum }, oneValueEnumArr: { required: false, enum: () => OneValueEnum, isArray: true }, breed: { required: false, type: () => String, title: "this is breed im comment" }, nodes: { required: true, type: () => [Object] }, optionalBoolean: { required: false, type: () => Boolean }, date: { required: true, type: () => Date }, twoDimensionPrimitives: { required: true, type: () => [[String]] }, twoDimensionNodes: { required: true, type: () => [[OtherNode]] }, cryptoUUIDProperty: { required: true, type: () => String }, arrayOfUUIDs: { required: true, type: () => [String] } };
130130
}
131131
}
132132
_CreateCatDto_privateProperty = new WeakMap();

test/plugin/fixtures/nullable.dto.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ var Status;
4242
})(Status || (Status = {}));
4343
export class NullableDto {
4444
static _OPENAPI_METADATA_FACTORY() {
45-
return { stringValue: { required: true, type: () => String, nullable: true }, stringArr: { required: true, type: () => [String], nullable: true }, optionalString: { required: false, type: () => String }, undefinedString: { required: true, type: () => String }, nullableEnumValue: { required: true, nullable: true, enum: OneValueEnum }, optionalEnumValue: { required: false, enum: OneValueEnum }, undefinedEnumValue: { required: true, enum: OneValueEnum }, enumValue: { required: true, nullable: true, enum: Status }, optionalNullableEnumValue: { required: false, nullable: true, enum: Status } };
45+
return { stringValue: { required: true, type: () => String, nullable: true }, stringArr: { required: true, type: () => [String], nullable: true }, optionalString: { required: false, type: () => String }, undefinedString: { required: true, type: () => String }, nullableEnumValue: { required: true, nullable: true, enum: () => OneValueEnum }, optionalEnumValue: { required: false, enum: () => OneValueEnum }, undefinedEnumValue: { required: true, enum: () => OneValueEnum }, enumValue: { required: true, nullable: true, enum: () => Status }, optionalNullableEnumValue: { required: false, nullable: true, enum: () => Status } };
4646
}
4747
}
4848
__decorate([

test/plugin/fixtures/parameter-property.dto.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class ParameterPropertyDto {
3737
this.protectedValue = protectedValue;
3838
}
3939
static _OPENAPI_METADATA_FACTORY() {
40-
return { readonlyValue: { required: false, type: () => String }, privateValue: { required: true, type: () => String, nullable: true }, publicValue: { required: true, type: () => [${fileImport}.ItemDto] }, protectedValue: { required: true, type: () => String, default: "1234" } };
40+
return { readonlyValue: { required: false, type: () => String }, privateValue: { required: true, type: () => String, nullable: true }, publicValue: { required: true, type: ${esmCompatible ? 'async ' : ''}() => [${fileImport}.ItemDto] }, protectedValue: { required: true, type: () => String, default: "1234" } };
4141
}
4242
}
4343
export var LettersEnum;
@@ -51,7 +51,7 @@ export class ItemDto {
5151
this.enumValue = enumValue;
5252
}
5353
static _OPENAPI_METADATA_FACTORY() {
54-
return { enumValue: { required: true, enum: ${fileImport}.LettersEnum } };
54+
return { enumValue: { required: true, enum: ${esmCompatible ? 'async ' : ''}() => ${fileImport}.LettersEnum } };
5555
}
5656
}
5757
`;

0 commit comments

Comments
 (0)