Skip to content

Commit

Permalink
Merge branch 'iifawzi-feat/validator-assignments'
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Oct 23, 2024
2 parents 5aa6078 + 35bd06f commit c45d942
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 60 deletions.
129 changes: 70 additions & 59 deletions lib/plugin/visitors/model-class.visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import {
} from '../utils/plugin-utils';
import { typeReferenceToIdentifier } from '../utils/type-reference-to-identifier.util';
import { AbstractFileVisitor } from './abstract.visitor';
import {
decoratorsProperties,
decoratorsPropertiesMappingType
} from '../../services/decorators-properties';

type ClassMetadata = Record<string, ts.ObjectLiteralExpression>;

Expand Down Expand Up @@ -641,66 +645,73 @@ export class ModelClassVisitor extends AbstractFileVisitor {
options
);
}
this.addPropertyByValidationDecorator(
factory,
'Min',
'minimum',
decorators,
assignments,
options
);
this.addPropertyByValidationDecorator(
factory,
'Max',
'maximum',
decorators,
assignments,
options
);
this.addPropertyByValidationDecorator(
factory,
'MinLength',
'minLength',
decorators,
assignments,
options
);
this.addPropertyByValidationDecorator(
factory,
'MaxLength',
'maxLength',
decorators,
assignments,
options
);
this.addPropertiesByValidationDecorator(
factory,
'IsPositive',
decorators,
assignments,
() => {
return [
factory.createPropertyAssignment(
'minimum',
createPrimitiveLiteral(factory, 1)
)
];
}
);
this.addPropertiesByValidationDecorator(
factory,
'IsNegative',
decorators,
assignments,
() => {
return [
factory.createPropertyAssignment(
'maximum',
createPrimitiveLiteral(factory, -1)
)
];

decoratorsProperties.forEach((decoratorProperty) => {
if (
decoratorProperty.mappingType === decoratorsPropertiesMappingType.DIRECT
) {
this.addPropertyByValidationDecorator(
factory,
decoratorProperty.decorator,
decoratorProperty.property,
decorators,
assignments,
options
);
} else if (
decoratorProperty.mappingType ===
decoratorsPropertiesMappingType.INDIRECT_VALUE
) {
this.addPropertiesByValidationDecorator(
factory,
decoratorProperty.decorator,
decorators,
assignments,
() => {
return [
factory.createPropertyAssignment(
decoratorProperty.property,
createPrimitiveLiteral(factory, decoratorProperty.value)
)
];
}
);
} else if (
decoratorProperty.mappingType ===
decoratorsPropertiesMappingType.INDIRECT_ARGUMENT
) {
this.addPropertiesByValidationDecorator(
factory,
decoratorProperty.decorator,
decorators,
assignments,
(decoratorRef: ts.Decorator) => {
const decoratorArguments = getDecoratorArguments(decoratorRef);
const result = [];

const argumentValue = head(decoratorArguments);
if (!canReferenceNode(argumentValue, options)) {
return result;
}

const clonedArgumentValue = this.clonePrimitiveLiteral(
factory,
argumentValue
);
if (clonedArgumentValue) {
result.push(
factory.createPropertyAssignment(
decoratorProperty.property,
clonedArgumentValue
)
);
}
return result;
}
);
}
);
});

this.addPropertiesByValidationDecorator(
factory,
'Length',
Expand Down
145 changes: 145 additions & 0 deletions lib/services/decorators-properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
export enum decoratorsPropertiesMappingType {
DIRECT,
INDIRECT_VALUE,
INDIRECT_ARGUMENT
}
export const decoratorsProperties = [
{
mappingType: decoratorsPropertiesMappingType.DIRECT,
decorator: 'Min',
property: 'minimum',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.DIRECT,
decorator: 'Max',
property: 'maximum',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.DIRECT,
decorator: 'MinLength',
property: 'minLength',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.DIRECT,
decorator: 'MaxLength',
property: 'maxLength',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'ArrayNotEmpty',
property: 'minItems',
value: 1
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsPositive',
property: 'minimum',
value: 1
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsNegative',
property: 'maximum',
value: -1
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'ArrayUnique',
property: 'uniqueItems',
value: true
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsBase64',
property: 'format',
value: 'base64'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsCreditCard',
property: 'format',
value: 'credit-card'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsCurrency',
property: 'format',
value: 'currency'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsEmail',
property: 'format',
value: 'email'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsJSON',
property: 'format',
value: 'json'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsUrl',
property: 'format',
value: 'uri'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsUuid',
property: 'format',
value: 'uuid'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsMobilePhone',
property: 'format',
value: 'mobile-phone'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsAscii',
property: 'pattern',
value: '^[\\x00-\\x7F]+$'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsHexColor',
property: 'pattern',
value: '^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_VALUE,
decorator: 'IsHexadecimal',
property: 'pattern',
value: '^(0x|0h)?[0-9A-F]+$'
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_ARGUMENT,
decorator: 'ArrayMinSize',
property: 'minItems',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_ARGUMENT,
decorator: 'ArrayMaxSize',
property: 'maxItems',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_ARGUMENT,
decorator: 'IsDivisibleBy',
property: 'multipleOf',
value: undefined
},
{
mappingType: decoratorsPropertiesMappingType.INDIRECT_ARGUMENT,
decorator: 'Contains',
property: 'pattern',
value: undefined
}
];
81 changes: 80 additions & 1 deletion test/plugin/fixtures/create-cat.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,38 @@ export class CreateCatDto {
lengthMin: string;
@Length(3, 5)
lengthMinMax: string;
@ArrayNotEmpty()
@ArrayUnique()
@ArrayMaxSize(10)
names: string[];
@ArrayMinSize(1)
employees: string[];
@IsDivisibleBy(2)
nominator: string;
@IsBase64()
encodedInfo: string;
@IsCreditCard()
creditCard: string;
@IsCurrency()
currency: string;
@IsEmail()
email: string;
@IsJSON()
response: Record<string, any>;
@IsUrl()
githubAccount: string;
@IsUuid()
transactionId: string;
@IsMobilePhone()
phoneNumber: string;
@IsAscii()
char: string;
@IsHexColor()
color: string;
@IsHexadecimal()
hex: string;
@Contains('log_')
searchBy: string;
tags: string[];
status: Status = Status.ENABLED;
status2?: Status;
Expand Down Expand Up @@ -90,7 +122,7 @@ export class CreateCatDto {
this.status = Status.ENABLED;
}
static _OPENAPI_METADATA_FACTORY() {
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 }, 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] } };
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 }, 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] } };
}
}
__decorate([
Expand All @@ -115,6 +147,53 @@ __decorate([
__decorate([
Length(3, 5)
], CreateCatDto.prototype, \"lengthMinMax\", void 0);
__decorate([
ArrayNotEmpty(),
ArrayUnique(),
ArrayMaxSize(10)
], CreateCatDto.prototype, \"names\", void 0);
__decorate([
ArrayMinSize(1)
], CreateCatDto.prototype, \"employees\", void 0);
__decorate([
IsDivisibleBy(2)
], CreateCatDto.prototype, \"nominator\", void 0);
__decorate([
IsBase64()
], CreateCatDto.prototype, "encodedInfo", void 0);
__decorate([
IsCreditCard()
], CreateCatDto.prototype, "creditCard", void 0);
__decorate([
IsCurrency()
], CreateCatDto.prototype, "currency", void 0);
__decorate([
IsEmail()
], CreateCatDto.prototype, "email", void 0);
__decorate([
IsJSON()
], CreateCatDto.prototype, "response", void 0);
__decorate([
IsUrl()
], CreateCatDto.prototype, "githubAccount", void 0);
__decorate([
IsUuid()
], CreateCatDto.prototype, "transactionId", void 0);
__decorate([
IsMobilePhone()
], CreateCatDto.prototype, "phoneNumber", void 0);
__decorate([
IsAscii()
], CreateCatDto.prototype, \"char\", void 0);
__decorate([
IsHexColor()
], CreateCatDto.prototype, \"color\", void 0);
__decorate([
IsHexadecimal()
], CreateCatDto.prototype, \"hex\", void 0);
__decorate([
Contains('log_')
], CreateCatDto.prototype, \"searchBy\", void 0);
__decorate([
ApiProperty({ description: "this is breed", type: String }),
IsString()
Expand Down

0 comments on commit c45d942

Please sign in to comment.