UNPKG

stnl

Version:

A simple, opinionated schema library built for performance

145 lines (144 loc) 4.87 kB
import type { Evaluate } from "./types"; export interface Ref<T extends string> { "~ref": T; } export type SelfRef = Ref<"">; export type ResolveRef< RefMap extends Record<string, any>, RootType, CurrentType > = CurrentType extends SelfRef ? ResolveRef<RefMap, RootType, RootType> : CurrentType extends Ref<infer Id extends Extract<keyof RefMap, string>> ? ResolveRef<RefMap, RootType, RefMap[Id]> : CurrentType extends Record<string, any> | any[] ? { [K in keyof CurrentType] : ResolveRef<RefMap, RootType, CurrentType[K]> } : CurrentType; export interface Limit<Type> { "~type": Type; } export type AnyLimit = Limit<any>; export interface Schema< Type, Refs extends string > extends Ref<Refs> { "~type": Type; } export interface ExtendableSchema< Type, Refs extends string > extends Schema<Type, Refs> { concat: <Limits extends Limit<Type>[]>(limits: Limits) => this; } export type AnySchema = Schema<any, any>; export type InferScopeSchema< T extends Schema<any, any>, ResolveMap extends { [K in T["~ref"]]? : Schema<any, any> } | undefined = undefined > = ResolveMap extends {} ? Schema<ResolveRef<{ [K in keyof ResolveMap] : (ResolveMap[K] & {})["~type"] }, T["~type"], T["~type"]>, Exclude<T["~ref"] | (ResolveMap[keyof ResolveMap] & {})["~ref"], "" | keyof ResolveMap>> : Schema<T["~type"], Exclude<T["~ref"], "">>; /** * Any type */ export declare const any: ExtendableSchema<unknown, never>; /** * A float */ export declare const float: ExtendableSchema<number, never>; /** * An integer */ export declare const int: typeof float; /** * A boolean */ export declare const bool: Schema<boolean, never>; /** * A string */ export declare const string: ExtendableSchema<string, never>; /** * Make a type nullable * @param schema */ export declare const nullable: <T extends AnySchema>(schema: T) => Schema<null | T["~type"], T["~ref"]>; /** * Create an enum schema * @param values */ export declare const discrete: <const T extends [string, string, ...string[]]>(values: T) => Schema<T[number], never>; /** * Create an array schema * @param item */ export declare const list: <T extends AnySchema>(item: T) => ExtendableSchema<T["~type"][], T["~ref"]>; /** * Create an object schema * @param required * @param optional */ export declare const dict: < Required extends Record<string, AnySchema>, Optional extends Record<string, AnySchema> | undefined = undefined >(required: Required, optional?: Optional) => Optional extends {} ? Schema<Evaluate<{ [K in keyof Required] : Required[K]["~type"] } & { [K in keyof Optional]? : Optional[K]["~type"] }>, (Required[keyof Required] | Optional[keyof Optional])["~ref"]> : Schema<Evaluate<{ [K in keyof Required] : Required[K]["~type"] }>, Required[keyof Required]["~ref"]>; /** * Create a tuple schema * @param items */ export declare const tuple: <const T extends [AnySchema, AnySchema, ...AnySchema[]]>(items: T) => Schema<[...{ [K in keyof T] : T[K]["~type"] }], T[number]["~ref"]>; /** * Create a tagged union schema * @param prop * @param tags * @param map */ export declare const union: < const Discriminator extends string, Map extends Record<string, Schema<Record<string, AnySchema>, any>> >(prop: Discriminator, map: Map) => Schema<Evaluate<{ [K in keyof Map] : Map[K]["~type"] & Record<Discriminator, K> }[keyof Map]>, Map[keyof Map]["~ref"]>; /** * Create a reference schema */ export declare const ref: <const T extends string>(name: T) => Schema<Ref<T>, T>; /** * Reference to the parent scope schema */ export declare const self: Schema<SelfRef, "">; /** * Resolve unknown references of a schema * @param schema * @param map */ export declare const scope: < T extends AnySchema, ResolveMap extends { [K in T["~ref"]]? : AnySchema } | undefined = undefined >(schema: T, map?: ResolveMap) => InferScopeSchema<T, ResolveMap>; /** * Attach metadata to a schema */ export declare const describe: <T extends AnySchema>(schema: T, meta: {}) => Schema<T["~type"], T["~ref"]>; /** * Create a schema module * @param mod */ export declare const module: <const T extends Record<string, AnySchema>>(mod: T) => { [K in keyof T] : InferScopeSchema<T[K], T> }; /** * Define the length upper bound */ export declare const maxLen: (len: number) => Limit<string & any[]>; /** * Define the length lower bound */ export declare const minLen: (len: number) => Limit<string & any[]>; /** * Define the string prefix */ export declare const startsWith: <const T extends string>(str: T) => Limit<string>; /** * Define maximum value of a type */ export declare const max: <T>(value: T) => Limit<T>; /** * Define minimum value of a type */ export declare const min: <T>(value: T) => Limit<T>; /** * Define exclusive maximum value of a type */ export declare const exclusiveMax: <T>(value: T) => Limit<T>; /** * Define exclusive minimum value of a type */ export declare const exclusiveMin: <T>(value: T) => Limit<T>;