jet-schema
Version:
Simple, typescript-first schema validation tool
105 lines (104 loc) • 5.05 kB
TypeScript
import { TEnum } from './util';
import { TFormatError, TOnError } from './error-stuff';
type TStaticObj<Prop> = string extends keyof Prop ? never : {
[key: string]: string | number | boolean | TStaticObj<Prop>;
};
type TConvertInterfaceToType<Prop> = {
[K in keyof Prop]: Prop[K];
};
type IsStaticObj<P, Prop = NonNullable<P>> = (TConvertInterfaceToType<Prop> extends TStaticObj<Prop> ? true : false);
type NotUndef<T> = Exclude<T, undefined>;
type AddNullablesHelper<T, isN> = isN extends true ? NonNullable<T> | null : NonNullable<T>;
type AddNullables<T, isU, isN> = (isU extends true ? AddNullablesHelper<NotUndef<T>, isN> | undefined : AddNullablesHelper<NotUndef<T>, isN>);
type GetTypePredicate<T> = T extends (x: unknown) => x is infer U ? U : never;
export interface IValidatorObj<T = unknown> {
vf: TValidatorFn<T>;
default?: T;
transform?: (arg: unknown) => T;
formatError?: TFormatError;
}
type TValidatorFn<T = unknown> = (arg: unknown) => arg is T;
type IValidatorFnOrObj<T> = TValidatorFn<T> | IValidatorObj<T>;
type TPickRetVal<T, NnT = NonNullable<T>> = {
test: (arg: unknown) => arg is T;
default: () => T;
} & (IsStaticObj<T> extends true ? {
pick: <K extends keyof NnT>(prop: K) => TPickRetVal<NnT[K]>;
new: (arg?: Partial<NonNullable<T>>) => NonNullable<T>;
schema: () => ISchema<T>;
} : unknown);
export interface ISchema<T = unknown> {
new: (arg?: Partial<NonNullable<T>>) => NonNullable<T>;
test: (arg: unknown) => arg is T;
pick: <K extends keyof T>(prop: K) => TPickRetVal<T[K]>;
parse: (arg: unknown) => NonNullable<T>;
_schemaOptions: {
optional: boolean;
nullable: boolean;
init: boolean | null;
id?: string;
safety?: 'pass' | 'filter' | 'strict';
};
}
export type TSchemaFnObjArg<T> = Required<{
[K in keyof T]: (T[K] extends (string | number) ? (IValidatorFnOrObj<T[K]> | TEnum) : T[K] extends Date ? (DateConstructor | IValidatorFnOrObj<T[K]>) : IsStaticObj<T[K]> extends true ? ISchema<T[K]> : IValidatorFnOrObj<T[K]>);
}>;
interface IJetOptions<M> {
globals?: M extends IValidatorObj[] ? M : never;
cloneFn?: (value: unknown) => unknown;
onError?: TOnError;
}
type TGlobalsArr<M> = {
[K in keyof M]: {
vf: TValidatorFn;
} & ('vf' extends keyof M[K] ? {
default?: GetTypePredicate<M[K]['vf']>;
transform?: (arg: unknown) => GetTypePredicate<M[K]['vf']>;
formatError?: TFormatError;
} : never);
};
type TSchemaOptions<T = unknown> = (unknown extends T ? (IOptNul | IOptNotNul | INotOptButNul | INotOptOrNul | INullish) : (undefined extends T ? (null extends T ? (IOptNul | INullish) : IOptNotNul) : (null extends T ? INotOptButNul : INotOptOrNul)));
interface ISchemaOptionsBase {
id?: string;
safety?: 'pass' | 'filter' | 'strict';
}
export interface IOptNul extends ISchemaOptionsBase {
optional: true;
nullable: true;
init?: null | boolean;
nullish?: undefined;
}
export interface IOptNotNul extends ISchemaOptionsBase {
optional: true;
nullable?: false;
init?: boolean;
}
export interface INotOptButNul extends ISchemaOptionsBase {
optional?: false;
nullable: true;
init?: null | true;
}
export interface INotOptOrNul extends ISchemaOptionsBase {
optional?: false;
nullable?: false;
init?: true;
}
export interface INullish extends ISchemaOptionsBase {
nullish: true;
optional?: undefined;
nullable?: undefined;
init?: null | boolean;
}
type TSchemaOptionsHelper<T, R> = (unknown extends T ? ([] | [R]) : undefined extends T ? [R] : null extends T ? [R] : ([] | [R]));
export type PublicInferType<S> = (S extends ISchema<infer X> ? X : never);
type InferTypes<U, R, Schema = MakeKeysOptIfUndef<InferTypesHelper<U>>> = ('nullish' extends keyof R ? AddNullables<Schema, true, true> : AddNullables<Schema, 'optional' extends keyof R ? R['optional'] : false, 'nullable' extends keyof R ? R['nullable'] : false>);
type MakeKeysOptIfUndef<T> = {
[K in keyof T]-?: (x: undefined extends T[K] ? Partial<Record<K, T[K]>> : Record<K, T[K]>) => void;
}[keyof T] extends (x: infer I) => void ? I extends infer U ? {
[K in keyof U]: U[K];
} : never : never;
type InferTypesHelper<U> = {
[K in keyof U]: (U[K] extends DateConstructor ? Date : U[K] extends IValidatorFnOrObj<infer X> ? X : U[K] extends ISchema<infer X> ? X : U[K] extends unknown[] ? never : U[K] extends TEnum ? U[K][keyof U[K]] : never);
};
declare function jetSchema<M extends TGlobalsArr<M>>(options?: IJetOptions<M>): <T, U extends TSchemaFnObjArg<T> = Required<{ [K in keyof T]: T[K] extends string | number ? TEnum | IValidatorFnOrObj<T[K]> : T[K] extends Date ? DateConstructor | IValidatorFnOrObj<T[K]> : IsStaticObj<T[K], NonNullable<T[K]>> extends true ? ISchema<T[K]> : IValidatorFnOrObj<T[K]>; }>, R extends TSchemaOptions<T> = TSchemaOptions<T>>(schemaFnObjArg: U, ...options: TSchemaOptionsHelper<T, R>) => unknown extends T ? ISchema<InferTypes<U, R>> : ISchema<T>;
export default jetSchema;