UNPKG

fluentvalidation-ts

Version:

A TypeScript-first library for building strongly-typed validation rules

158 lines (137 loc) 12.9 kB
type ArrayType<TEachValue> = Array<TEachValue> | ReadonlyArray<TEachValue> | Readonly<Array<TEachValue>>; type ValueValidationResult<TValue> = (TValue extends ArrayType<infer TEachValue> ? Array<ValueValidationResult<TEachValue>> | string | null : TValue extends object ? { [propertyName in keyof TValue]?: ValueValidationResult<TValue[propertyName]>; } | string | null : string | null) | string | null; type ValidationErrors<TModel> = { [propertyName in keyof TModel]?: ValueValidationResult<TModel[propertyName]>; }; type AppliesTo = 'AppliesToAllValidators' | 'AppliesToCurrentValidator'; type MessageGenerator<TModel, TTransformedValue> = (value: TTransformedValue, model: TModel) => string; type Message<TModel, TTransformedValue> = string | MessageGenerator<TModel, TTransformedValue>; type SimplePredicate<TModel, TTransformedValue> = (value: TTransformedValue, model: TModel) => boolean; type SimpleAsyncPredicate<TModel, TTransformedValue> = (value: TTransformedValue, model: TModel) => Promise<boolean>; type SimplePredicateWithMessage<TModel, TTransformedValue> = { predicate: SimplePredicate<TModel, TTransformedValue>; message: Message<TModel, TTransformedValue>; }; type SimpleAsyncPredicateWithMessage<TModel, TTransformedValue> = { predicate: SimpleAsyncPredicate<TModel, TTransformedValue>; message: Message<TModel, TTransformedValue>; }; type Predicate<TModel, TTransformedValue> = SimplePredicate<TModel, TTransformedValue> | SimplePredicateWithMessage<TModel, TTransformedValue> | Array<SimplePredicate<TModel, TTransformedValue> | SimplePredicateWithMessage<TModel, TTransformedValue>>; type AsyncPredicate<TModel, TTransformedValue> = SimpleAsyncPredicate<TModel, TTransformedValue> | SimpleAsyncPredicateWithMessage<TModel, TTransformedValue> | Array<SimpleAsyncPredicate<TModel, TTransformedValue> | SimpleAsyncPredicateWithMessage<TModel, TTransformedValue>>; interface IValidator<TModel> { validate: (model: TModel) => ValidationErrors<TModel>; } type IfString<TValue, TOut> = TValue extends string ? TOut : never; type IfNumber<TValue, TOut> = TValue extends number ? TOut : never; type IfObject<TValue, TOut> = TValue extends object ? TOut : never; type NotNullRuleOptions = { includeUndefined?: boolean; }; type NullRuleOptions = { includeUndefined: boolean; }; type RuleValidators<TModel, TValue> = { notEqual: (forbiddenValue: TValue) => RuleValidatorsAndExtensions<TModel, TValue>; equal: (requiredValue: TValue) => RuleValidatorsAndExtensions<TModel, TValue>; must: (predicate: Predicate<TModel, TValue>) => RuleValidatorsAndExtensions<TModel, TValue>; notNull: (options?: NotNullRuleOptions) => RuleValidatorsAndExtensions<TModel, TValue>; notUndefined: () => RuleValidatorsAndExtensions<TModel, TValue>; null: (ruleOptions?: NullRuleOptions) => RuleValidatorsAndExtensions<TModel, TValue>; undefined: () => RuleValidatorsAndExtensions<TModel, TValue>; notEmpty: IfString<TValue, () => RuleValidatorsAndExtensions<TModel, TValue>>; length: IfString<TValue, (minLength: number, maxLength: number) => RuleValidatorsAndExtensions<TModel, TValue>>; maxLength: IfString<TValue, (maxLength: number) => RuleValidatorsAndExtensions<TModel, TValue>>; minLength: IfString<TValue, (minLength: number) => RuleValidatorsAndExtensions<TModel, TValue>>; matches: IfString<TValue, (pattern: RegExp) => RuleValidatorsAndExtensions<TModel, TValue>>; emailAddress: IfString<TValue, () => RuleValidatorsAndExtensions<TModel, TValue>>; lessThan: IfNumber<TValue, (threshold: number) => RuleValidatorsAndExtensions<TModel, TValue>>; lessThanOrEqualTo: IfNumber<TValue, (threshold: number) => RuleValidatorsAndExtensions<TModel, TValue>>; greaterThan: IfNumber<TValue, (threshold: number) => RuleValidatorsAndExtensions<TModel, TValue>>; greaterThanOrEqualTo: IfNumber<TValue, (threshold: number) => RuleValidatorsAndExtensions<TModel, TValue>>; exclusiveBetween: IfNumber<TValue, (lowerBound: number, upperBound: number) => RuleValidatorsAndExtensions<TModel, TValue>>; inclusiveBetween: IfNumber<TValue, (lowerBound: number, upperBound: number) => RuleValidatorsAndExtensions<TModel, TValue>>; precisionScale: IfNumber<TValue, (precision: number, scale: number) => RuleValidatorsAndExtensions<TModel, TValue>>; setValidator: IfObject<TValue, (validatorProducer: (model: TModel) => IValidator<NonNullable<TValue>>) => RuleValidatorsAndExtensions<TModel, TValue>>; }; type WhenCondition<TModel, TValue> = (condition: (model: TModel) => boolean, appliesTo?: AppliesTo) => RuleValidators<TModel, TValue>; type UnlessCondition<TModel, TValue> = (condition: (model: TModel) => boolean, appliesTo?: AppliesTo) => RuleValidators<TModel, TValue>; type RuleValidatorsAndConditionExtensions<TModel, TValue> = RuleValidators<TModel, TValue> & { when: WhenCondition<TModel, TValue>; unless: UnlessCondition<TModel, TValue>; }; type WithMessage<TModel, TValue> = (message: string) => RuleValidatorsAndConditionExtensions<TModel, TValue>; type RuleValidatorsAndExtensions<TModel, TValue> = RuleValidatorsAndConditionExtensions<TModel, TValue> & { withMessage: WithMessage<TModel, TValue>; }; /** * Constrain * @desc Constrains type `T` to only those properties that exist in type `U` */ type Constrain<T, U> = { [key in keyof T]: key extends keyof U ? T[key] : never; }; type FlatType = string | number | boolean | symbol; type TransformedValue<TValue> = TValue | FlatType | null | undefined; type Optional<T> = T | null | undefined; type IfNotNeverThen<TValue, TOut> = TValue extends never ? never : TOut; declare class SyncValidator<TModel> { private valueValidatorBuildersByPropertyName; protected _validate: (value: TModel) => ValidationErrors<TModel>; validate: (value: TModel) => ValidationErrors<TModel>; private rebuildValidate; protected ruleFor: <TPropertyName extends keyof TModel, TValue extends TModel[TPropertyName]>(propertyName: TPropertyName) => RuleValidators<TModel, TValue>; protected ruleForTransformed: <TPropertyName extends keyof TModel, TValue extends TModel[TPropertyName], TTransformedValue extends TransformedValue<TValue>>(propertyName: TPropertyName, transformValue: (value: TValue) => TTransformedValue extends object ? Constrain<TTransformedValue, TValue> : TTransformedValue) => RuleValidators<TModel, TTransformedValue>; protected ruleForEach: <TPropertyName extends keyof TModel, TEachValue extends TModel[TPropertyName] extends Optional<ArrayType<infer TEachValueInferred>> ? TEachValueInferred : never, TValue extends TModel[TPropertyName] & ArrayType<TEachValue>>(propertyName: IfNotNeverThen<TEachValue, TPropertyName>) => IfNotNeverThen<TEachValue, RuleValidators<TModel, TEachValue>>; protected ruleForEachTransformed: <TPropertyName extends keyof TModel, TEachValue extends TModel[TPropertyName] extends Optional<ArrayType<infer TEachValueInferred>> ? TEachValueInferred : never, TValue extends TModel[TPropertyName] & ArrayType<TEachValue>, TEachTransformedValue extends TransformedValue<TEachValue>>(propertyName: IfNotNeverThen<TEachValue, TPropertyName>, transformValue: (value: TEachValue) => TEachTransformedValue extends object ? Constrain<TEachTransformedValue, TEachValue> : TEachTransformedValue) => IfNotNeverThen<TEachValue, RuleValidators<TModel, TEachTransformedValue>>; } interface IAsyncValidator<TModel> { validateAsync: (model: TModel) => Promise<ValidationErrors<TModel>>; } type AsyncRuleValidators<TModel, TValue> = { notEqual: (forbiddenValue: TValue) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; equal: (requiredValue: TValue) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; must: (predicate: Predicate<TModel, TValue>) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; mustAsync: (predicate: AsyncPredicate<TModel, TValue>) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; notNull: (ruleOptions?: NotNullRuleOptions) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; notUndefined: () => AsyncRuleValidatorsAndExtensions<TModel, TValue>; null: (ruleOptions?: NullRuleOptions) => AsyncRuleValidatorsAndExtensions<TModel, TValue>; undefined: () => AsyncRuleValidatorsAndExtensions<TModel, TValue>; notEmpty: IfString<TValue, () => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; length: IfString<TValue, (minLength: number, maxLength: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; maxLength: IfString<TValue, (maxLength: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; minLength: IfString<TValue, (minLength: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; matches: IfString<TValue, (pattern: RegExp) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; emailAddress: IfString<TValue, () => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; lessThan: IfNumber<TValue, (threshold: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; lessThanOrEqualTo: IfNumber<TValue, (threshold: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; greaterThan: IfNumber<TValue, (threshold: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; greaterThanOrEqualTo: IfNumber<TValue, (threshold: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; exclusiveBetween: IfNumber<TValue, (lowerBound: number, upperBound: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; inclusiveBetween: IfNumber<TValue, (lowerBound: number, upperBound: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; precisionScale: IfNumber<TValue, (precision: number, scale: number) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; setValidator: IfObject<TValue, (validatorProducer: (model: TModel) => IValidator<NonNullable<TValue>>) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; setAsyncValidator: IfObject<TValue, (validatorProducer: (model: TModel) => IAsyncValidator<NonNullable<TValue>>) => AsyncRuleValidatorsAndExtensions<TModel, TValue>>; }; type AsyncWhenCondition<TModel, TValue> = (condition: (model: TModel) => boolean, appliesTo?: AppliesTo) => AsyncRuleValidators<TModel, TValue>; type AsyncUnlessCondition<TModel, TValue> = (condition: (model: TModel) => boolean, appliesTo?: AppliesTo) => AsyncRuleValidators<TModel, TValue>; type AsyncRuleValidatorsAndConditionExtensions<TModel, TValue> = AsyncRuleValidators<TModel, TValue> & { when: AsyncWhenCondition<TModel, TValue>; unless: AsyncUnlessCondition<TModel, TValue>; }; type AsyncWithMessage<TModel, TValue> = (message: string) => AsyncRuleValidatorsAndConditionExtensions<TModel, TValue>; type AsyncRuleValidatorsAndExtensions<TModel, TValue> = AsyncRuleValidatorsAndConditionExtensions<TModel, TValue> & { withMessage: AsyncWithMessage<TModel, TValue>; }; declare class AsyncValidator<TModel> { private asyncValueValidatorBuildersByPropertyName; protected _validateAsync: (value: TModel) => Promise<ValidationErrors<TModel>>; validateAsync: (value: TModel) => Promise<ValidationErrors<TModel>>; private rebuildValidateAsync; protected ruleFor: <TPropertyName extends keyof TModel, TValue extends TModel[TPropertyName]>(propertyName: TPropertyName) => AsyncRuleValidators<TModel, TValue>; protected ruleForTransformed: <TPropertyName extends keyof TModel, TValue extends TModel[TPropertyName], TTransformedValue extends TransformedValue<TValue>>(propertyName: TPropertyName, transformValue: (value: TValue) => TTransformedValue extends object ? Constrain<TTransformedValue, TValue> : TTransformedValue) => AsyncRuleValidators<TModel, TTransformedValue>; protected ruleForEach: <TPropertyName extends keyof TModel, TEachValue extends TModel[TPropertyName] extends Optional<ArrayType<infer TEachValueInferred>> ? TEachValueInferred : never, TValue extends TModel[TPropertyName] & ArrayType<TEachValue>>(propertyName: IfNotNeverThen<TEachValue, TPropertyName>) => IfNotNeverThen<TEachValue, AsyncRuleValidators<TModel, TEachValue>>; protected ruleForEachTransformed: <TPropertyName extends keyof TModel, TEachValue extends TModel[TPropertyName] extends Optional<ArrayType<infer TEachValueInferred>> ? TEachValueInferred : never, TValue extends TModel[TPropertyName] & ArrayType<TEachValue>, TEachTransformedValue extends TransformedValue<TEachValue>>(propertyName: IfNotNeverThen<TEachValue, TPropertyName>, transformValue: (value: TEachValue) => TEachTransformedValue extends object ? Constrain<TEachTransformedValue, TEachValue> : TEachTransformedValue) => IfNotNeverThen<TEachValue, AsyncRuleValidators<TModel, TEachTransformedValue>>; } export { type AsyncRuleValidators, AsyncValidator, type RuleValidators, type ValidationErrors, SyncValidator as Validator, type ValueValidationResult };