UNPKG

@apizr-io/class-utils

Version:

Package containing all class-validator function with all custom apizr class validation functions

473 lines (323 loc) 10.2 kB
# class-utils This package contains all `class-validator` and `class-tranformer` functions with custom class decorators that can be used to validate a class. ## Usage ```javascript import { IsString } from '@apizr/class-utils/validators'; import { Transform } from '@apizr/class-utils/transformers'; class MyClass { @IsString() myString: string; @Transform((value) => value === 'true') myBoolean: boolean; } ``` ## Dependencies This package depends on `jsonpath-plus` to be able to use some decorators (e.g. `ValidateSubKeyExistIf`). See [documentation](https://www.npmjs.com/package/jsonpath-plus) for more information. ## class-validator decorators and class-transformer See [documentation](https://github.com/typestack/class-validator/blob/develop/README.md) of `class-validator` for the list of default exports. See [documentation](https://github.com/typestack/class-transformer/blob/develop/README.md) of `class-transformer` for the list of default export. ## Custom transformers ### SplitString `SplitString(separator: string = ',')` Will transform a string received to an array of string split by separator. #### Usage ```javascript import { SplitString } from '@apizr/class-utils/tranformers'; class MyStringClass { @SplitString() myString: string[]; } ``` ## Custom decorators ### IsBeforeDate `IsBeforeDate(property: string, options: ValidationOptions)` Checks if the date is before the date present in the same objet at the specified key. #### Usage ```javascript import { IsBeforeDate } from '@apizr/class-utils/validators'; class Dates { @IsBeforeDate('end') start: Date; end: Date; } ``` If the other date is optional, you can specify a flag to prevent an error if no date is present ```javascript import { IsBeforeDate } from '@apizr/class-utils/validators'; class Dates { @IsBeforeDate('end', { context: { otherDateIsOptional: true } }) start: Date; end?: Date; } ``` ### IsAfterDate `IsAfterDate(property: string, options: ValidationOptions)` Checks if the date is after the date present in the same objet at the specified key. #### Usage ```javascript import { IsAfterDate } from '@apizr/class-utils/validators'; class Dates { start: Date; @IsAfterDate('start') end: Date; } ``` If the other date is optional, you can specify a flag to prevent an error if no date is present ```javascript import { IsAfterDate } from '@apizr/class-utils/validators'; class Dates { start?: Date; @IsAfterDate('start', { context: { otherDateIsOptional: true } }) end: Date; } ``` ### IsFutureDate `IsFutureDate(void)` Checks if the date is in the future. #### Usage ```javascript import { IsFutureDate } from '@apizr/class-utils/validators'; class Date { @IsFutureDate() end: Date; } ``` ### StartsWith `StartsWith(startValue: string | string[])` Checks if the string starts with the specified value #### Usage ```javascript import { StartsWith } from '@apizr/class-utils/validators'; class Order { @StartsWith('PROD-') id: string; } ``` ### OneOfKeysIsDefined `OneOfKeysIsDefined(keysToValidate: string[])` Checks if at least one of the key has value (not `null` or `undefined`). #### Usage ```javascript import { OneOfKeysIsDefined } from '@apizr/class-utils/validators'; class Product { id: string; description?: string; name?: string; } class Order { @ValidateNested({ each: true }) @Type(() => Product) @OneOfKeysIsDefined(['description', 'name'], { each: true }) products: Product[]; } ``` ### ValidateSort `ValidateSort(allowedSort: string | string[])` Checks that the string array contains valid keys with valid sorting directions (`asc` or `desc`). #### usage ```javascript import { ValidateSort } from '@apizr/class-utils/validators'; class Filters { @ValidateSort(['date.creation', 'date.modification']) sort: string[]; } ``` This will allow `date.creation:asc` or `date.modification:desc` for example. ### ValidateAtLeastOneKeyGroupExists `ValidateAtLeastOneKeyGroupExists(groups: string[][])` Checks if one of the keys groups exist in class. #### Usage ```javascript @ValidateAtLeastOneKeyGroupExists([ ['key1', 'key2'], ['key2', 'key3'] ]) ``` Will validate that (`key1` and `key2`) or (`key2` and `key3`) exists in the class. #### Usage ```javascript import { ValidateAtLeastOneKeyGroupExists } from '@apizr/class-utils/validators'; @ValidateAtLeastOneKeyGroupExists([ ['email', 'birthday'], ['firstname', 'lastname'], ]) class Customer { email: string; firstname: string; lastname: string; birthday: string; } ``` ### ValidateOnlyOneKeyGroupExists `ValidateOnlyOneKeyGroupExists(groups: string[][])` Checks if keys of a key groups exist in class. #### Usage ```javascript @ValidateOneKeyGroupExists([ ['key1', 'key2'], ['key2', 'key3'] ]) ``` Will validate that (`key1` and `key2`) xor (exclusive or) (`key2` and `key3`) exists in the class. #### Usage ```javascript import { ValidateOnlyOneKeyGroupExists } from '@apizr/class-utils/validators'; @ValidateOnlyOneKeyGroupExists([ ['email', 'birthday'], ['firstname', 'lastname'], ]) class Customer { email: string; firstname: string; lastname: string; birthday: string; } ``` ### ValidateSubKeyExistIf `ValidateSubKeyExistIf(path: string, condition: (value: any) => boolean)` Allows validating the presence of a specified key in a child object based on a given condition. The child value described by the path option must have the @IsOptional() decorator (see example below). #### Usage ```typescript import { ValidateSubKeyExistIf } from '@apizr/class-utils/validators'; class ChildClass { @IsOptional() // Mandatory when this decorator is used targetedValue?: any; } @ValidateSubKeyExistIf( 'child.targetedValue', (o) => o.conditionalValue !== false, ) class ParentClass { @IsString() conditionalValue: boolean; @ValidateNested({ each: true }) @Type(() => ChildClass) child: ChildClass; } ``` You can also use `jsonpath-plus` to validate a key in an array of objects: ```typescript import { ValidateSubKeyExistIf } from '@apizr/class-utils/validators'; class LittleChildClass { @IsOptional() // Mandatory when this decorator is used targetedValue?: string; } class ChildClass { @IsOptional() @ValidateNested({ each: true }) @Type(() => LittleChildClass) myOtherValue?: LittleChildClass[]; } @ValidateSubKeyExistIf( 'child.myOtherValue[*].targetedValue', (o) => o.conditionalValue !== false, ) class ParentClass { conditionalValue: boolean; @ValidateNested({ each: true }) @Type(() => ChildClass) child: ChildClass; } ``` ### IsRecord `IsRecord(allowedRecordType: AllowedType | AllowedType[], options: IsRecordValidateOptions)` Check if the record is compliant to specified definition. By default, the key type will be checked to be a string. #### Usage ```typescript import { IsRecord } from '@apizr/class-utils/validators'; class ChildClass { @IsString() key: string; } class ExampleClass { @IsRecord('boolean') record: Record<string, boolean>; @IsRecord(['string', 'undefined']) record: Record<string, string | undefined>; @IsRecord(ChildClass) record: Record<string, ChildClass>; @IsRecord('string', { key: 'number' }) record: Record<number, string>; @IsRecord(ChildClass, { each: true }) records: Record<string, ChildClass>[]; @IsRecord([ChildClass, ChildClass2, 'undefined']) record: Record<string, ChildClass | ChildClass2 | undefined>; @IsRecord([{ type: ChildClass, array: true }, ChildClass2]) record: Record<string, ChildClass[] | ChildClass2>; @IsRecord([{ type: [ChildClass, ChildClass2], array: true }, ChildClass3]) record: Record<string, (Class1 | ChildClass2)[] | ChildClass3>; } ``` ### MustNotExistIf `MustNotExistIf(condition: (value: any) => boolean, jsonpath?: string, options?: ValidationOptions)` Check if the value must not exist if the condition is met. #### Usage ```typescript import { MustNotExistIf } from '@apizr/class-utils/validators'; class User { @MustNotExistIf((o) => o.isGuest) password: string; isGuest: boolean; } const user = new User(); user.isGuest = true; user.password = 'securePassword'; // Validation will fail because `isGuest` is true. ``` You can also use jsonpath-plus to validate a nested key: ```typescript import { MustNotExistIf } from '@apizr/class-utils/validators'; class UserProfile { @MustNotExistIf( (jsonpathValue) => Array.isArray(jsonpathValue) && jsonpathValue.includes('restricted'), '$.roles[*]' ) adminSettings: string; roles: string[]; } const profile = new UserProfile(); profile.roles = ['user', 'restricted']; profile.adminSettings = 'Some Settings'; // Validation will fail because "roles" contains "restricted". ``` Default error message is `Property {{property}} must not exist if {{condition}} is true` but you can override it by passing a `message` option in the `ValidationOptions` object. ### IsUnion `IsUnion(allowedUnionType: AllowedType[], options: IsUnionValidateOptions)` Check if the union is compliant to specified definition. #### Usage ```typescript import { IsUnion } from '@apizr/class-utils/validators'; class ChildClass { @IsString() key: string; } class ExampleClass { @IsUnion(['string', 'undefined']) record: string | undefined; @IsUnion(['string', 'number'], { each: true }) records: (string | number)[]; @IsUnion([ChildClass, ChildClass2, 'undefined']) record: ChildClass | ChildClass2 | undefined; @IsUnion([{ type: ChildClass, array: true }, ChildClass2]) record: ChildClass[] | ChildClass2; @IsUnion([{ type: [ChildClass, ChildClass2], array: true }, ChildClass3]) record: (Class1 | ChildClass2)[] | ChildClass3; } ``` ### IsCron `IsCron(inputOptions?: InputOptions['override'])` Checks if the string is cron expression valid See [documentation](https://github.com/Airfooox/cron-validate) of cron-validate lib to see the options. #### Usage ```javascript import { IsCron } from '@apizr/class-utils/validators'; class ExampleClass { @IsCron() cronExpression: string; @IsCron({ useSeconds: true, }) cronExpression: string; } ```