@valkyriestudios/validator
Version:
A lightweight configurable javascript validator
106 lines (105 loc) • 4.35 kB
TypeScript
/**
* 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 {};