UNPKG

@valkyriestudios/validator

Version:

A lightweight configurable javascript validator

106 lines (105 loc) 4.35 kB
/** * MARK: Data */ export type DataVal = string | number | boolean | Date | symbol | null | unknown | DataObject | DataVal[]; export type DataObject = { [key: string]: DataVal; }; export type GenericObject = { [key: string]: any; }; export type TV<T> = { [K in keyof T]: T[K] extends Array<any> ? string : T[K] extends Record<string, any> ? TV<T[K]> | string : string; }; export type RulesRawVal = string | (string | RulesRaw)[] | RulesRaw; export type RulesRaw = { [key: string]: RulesRawVal; }; export type RuleFn = (...args: any[]) => boolean; export type RuleExtension = RuleFn | RegExp | (string | number)[] | TV<GenericObject>; export type DeepMutable<T> = T extends string ? T : T extends number ? T : T extends boolean ? T : T extends bigint ? T : T extends symbol ? T : T extends null ? T : T extends Date ? T : T extends undefined ? T : T extends Function ? T : T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]>; } : T; /** * MARK: Inferrence */ type ExtractGuard<T> = T extends (val: unknown, ...args: any[]) => val is infer R ? R : never; type RuleMap<Rules extends Record<string, any>> = { [K in keyof Rules]: ExtractGuard<Rules[K]>; }; type ExtractRuleName<S extends string> = S extends `${infer Word}|${infer _}` ? Word : S extends `${infer Word}:${infer _}` ? Word : S; type RemoveNegation<S extends string> = S extends `!${infer Rest}` ? Rest : S; /** * Recursively infer the type for a schema. * - If the schema value is a string, we use InferRuleTypeFromStore. * - If it’s an array (conditional group), we take the union of the inferences. * - If it’s an object, we recursively map its keys. */ export type InferredSchema<S, Rules extends Record<string, any> = {}> = S extends string ? S extends `?${infer Rest}` ? (Rest extends '' ? undefined : InferredSchema<RemoveNegation<Rest>, Rules> | undefined) : (S extends `literal:${infer Literal}` ? Literal : S extends `[${infer Inner}]${infer Rest}` ? InferredSchema<Rest, Rules>[] : S extends `{${infer Inner}}${infer Rest}` ? { [key: string]: InferredSchema<Rest, Rules>; } : ExtractRuleName<RemoveNegation<S>> extends keyof RuleMap<Rules> ? RuleMap<Rules>[ExtractRuleName<RemoveNegation<S>>] : unknown) : S extends Array<infer U> ? InferredSchema<U, Rules> : S extends object ? { [K in keyof S]: InferredSchema<S[K], Rules>; } : unknown; export type MappedExtensions<Ext extends Record<string, RuleExtension>, Rules extends Record<string, any> = {}> = { [K in keyof Ext]: Ext[K] extends RegExp ? (val: unknown, ...args: any[]) => val is string : Ext[K] extends (infer U)[] ? (val: unknown, ...args: any[]) => val is U : Ext[K] extends (...args: any[]) => any ? Ext[K] : Ext[K] extends Record<string, any> ? (val: unknown, ...args: any[]) => val is DeepMutable<InferredSchema<Ext[K], Rules>> : unknown; }; export type MergeExtensions<E1 extends Record<string, unknown>, E2 extends Record<string, unknown>> = Omit<E1, keyof E2> & E2; /** * MARK: Validation */ export type ValidationError = { idx?: number; msg: string; params: DataVal[]; }; export type ValidationIterable = { unique: boolean; max: number; min: number; handler: (v: unknown) => null | { len: number; values: unknown[]; }; }; export type ValidationRules = { nested: false; iterable: ValidationIterable | false; list: { type: string; params: [unknown, boolean][]; params_length: number; not: boolean; msg: string; }[]; list_length: number; }; export type ValidationGroup = { key: string; sometimes: boolean; rules: (ValidationRules | ValidationNested)[]; }; export type ValidationNested = { nested: true; plan: ValidationGroup[]; }; export type ValidationResult = { /** * Whether or not the validation was valid */ is_valid: boolean; /** * Integer value defining how many fields were invalid in the provided data object */ count: number; /** * Errors object which will be filled with the errors of the validation result if there are any. * * Take note: 'NO_DATA' is set when no data was passed to the validator. * * Example: {b: [{msg: 'number', params: []}]} */ errors: 'NO_DATA' | { [key: string]: ValidationError[]; }; }; export {};