stnl
Version:
A simple, opinionated schema library built for performance
145 lines (144 loc) • 4.87 kB
TypeScript
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>;