import { assertSchema, ValidationErrorBuilder } from '../errors' import { AbstractValidator } from '../types' import { getValidator } from '../utilities' import type { InferInput, InferValidation, Validation, ValidationOptions, Validator, } from '../types' /* -------------------------------------------------------------------------- */ export type OneOfArguments = readonly Validation[] export type InferOneOfValidation = A extends readonly [ infer First, ...infer Rest ] ? First extends Validation ? Rest extends OneOfArguments ? InferValidation | InferOneOfValidation : InferValidation : never : A extends readonly (infer Type)[] ? Type extends Validation ? InferValidation : never : never export type InferOneOfInput = A extends readonly [ infer First, ...infer Rest ] ? First extends Validation ? Rest extends OneOfArguments ? InferInput | InferOneOfInput : InferInput : never : A extends readonly (infer Type)[] ? Type extends Validation ? InferInput : never : never /** A `Validator` validating a value as _one of_ the specified arguments. */ export class OneOfValidator extends AbstractValidator, InferOneOfInput> { readonly validators: readonly Validator[] constructor(args: A) { super() this.validators = args.map((validation) => getValidator(validation)) assertSchema(this.validators.length > 0, 'At least one validation required in "oneOf"') } validate(value: unknown, options?: ValidationOptions): InferOneOfValidation { const builder = new ValidationErrorBuilder() for (const validator of this.validators) { try { return validator.validate(value, options) } catch (error) { builder.record(error) } } return builder.assert(value as InferOneOfValidation) } } /** Validate a value as _one of_ the specified arguments */ export function oneOf(...args: A): OneOfValidator { return new OneOfValidator(args) } /* -------------------------------------------------------------------------- */ export type AllOfArguments = readonly [ Validation, ...Validation[] ] export type InferAllOfValidation = A extends readonly [ infer First, ...infer Rest ] ? First extends Validation ? Rest extends AllOfArguments ? InferValidation & InferAllOfValidation : InferValidation : never : never export type InferAllOfInput = A extends readonly [ infer First, ...infer Rest ] ? First extends Validation ? Rest extends AllOfArguments ? InferInput & InferAllOfInput : InferInput : never : never /** A `Validator` validating a value as _all of_ the specified arguments. */ export class AllOfValidator extends AbstractValidator, InferAllOfInput> { readonly validators: readonly Validator[] constructor(args: A) { super() this.validators = args.map((validation) => getValidator(validation)) assertSchema(this.validators.length > 0, 'At least one validation required in "allOf"') } validate(value: unknown, options?: ValidationOptions): InferAllOfValidation { for (const validator of this.validators) { value = validator.validate(value, options) } return value as InferAllOfValidation } } /** Validate a value as _all of_ the specified arguments */ export function allOf(...args: A): AllOfValidator { return new AllOfValidator(args) }