UNPKG

stnl

Version:

A simple, opinionated type validator built for performance

283 lines (237 loc) 5.52 kB
A simple, opinionated type validator built for performance. ## Features - Types work across languages - Efficient representation format - Fast compilation time ## Builder `stnl` schema builder. ```ts import { t, l } from 'stnl'; // or import { type, limit } from 'stnl'; ``` ### Type inference To infer payload type of a schema built using the schema builder: ```ts const schema = t.list(t.int); // number[] type T = t.TInfer<typeof schema>; ``` ### Primitives - `t.int`: integer - `t.float`: floating-point number - `t.string`: string - `t.bool`: boolean - `t.any`: any type ```ts t.int; // integer t.float; // floating-point number t.string; // strings t.bool; // boolean t.any; // any type l.int(l.min(5)); // integer >= 5 l.int(l.max(9)); // integer <= 9 l.int(l.min(5), l.max(9)); // 5 <= integer <= 9 l.float(l.min(5)); // float >= 5 l.float(l.max(9)); // float <= 9 l.float(l.min(5), l.max(9)); // 5 <= float <= 9 l.string(l.minLen(5)); // string.length >= 5 l.string(l.maxLen(9)); // string.length <= 9 l.string(l.minLen(5), l.maxLen(9)); // 5 <= string.length <= 9 ``` ### Unions ```ts // Match 'admin' or 'user' t.union(['admin', 'user']); ``` ### Constants `t.value()` only accepts `number`, `string`, or `boolean`. ```ts // Match only 0 t.value(0); // Match only 'str' t.value('str'); // Match only true t.value(true); ``` ### Lists ```ts // A list of integers t.list(t.int); // A list of string with list.length >= 1 t.list(t.string, l.minLen(1)); // A list of float with list.length <= 10 t.list(t.float, l.maxLen(10)); // A list of float with 1 <= list.length <= 10 t.list(t.float, l.minLen(1), l.maxLen(10)); ``` ### Objects ```ts // { id: number, name: string, display_names?: string[] } t.dict( // Required properties { id: t.int, name: t.string }, // Optional properties { display_names: t.list(t.string) } ); ``` ### Tuples ```ts // [number, string] t.tuple([ t.int, t.string ]); ``` ### Tagged unions ```ts // { role: 'admin', id: string } | { role: 'user', name: string } t.tag('role', { admin: t.dict({ id: t.string }), user: t.dict({ name: t.string }) }); ``` ### Nullable types To make a schema accepts `null`: ```ts // { name: string, id: number } | null t.nullable( t.dict({ name: t.string, id: t.int }) ); ``` ### Scopes & references Recursive types with scope: ```ts // interface Node { value: string, next: Node | null } const node = t.scope( t.dict( { value: t.string }, { next: t.self } // Reference to the root type of the scope ) ); ``` References defined types in scope: ```ts const user = t.scope( t.dict({ name: t.ref('name') }), { name: t.string } }; ``` Generics with scope: ```ts // node is an unresolved type const node = t.dict( { value: t.ref('type') }, { next: t.self } ); // This will error as not all references of node has been resolved type Node = t.TInfer<typeof node>; // int_node is a resolved type const int_node = t.scope(node, { type: t.int }); ``` ### Modules Modules can also be used for storing types that depends on other types. ```ts const mod = t.module({ value: t.string, node: t.dict({ prefix: t.string, store: t.ref('value') }, { param: t.ref('param_node'), child: t.ref('node') }), param_node: t.dict({ name: t.string }, { store: t.ref('value'), child: t.ref('node') }), }); // Use module schemas const schema = t.dict({ root: mod.node, param_root: mod.param_node }); ``` You should only use `t.module()` when you need to re-use types in a scope. ## Compatibility Translate `stnl` schema to other formats. ```ts import { compat, build, t, l } from 'stnl'; // Used for examples below const user = t.dict({ name: l.string(l.minLen(3), l.maxLen(16)), code: l.string(l.minLen(8), l.maxLen(32)) }); ``` ### JSON schema Convert `stnl` schema to a [JSON schema](https://json-schema.org/). ```ts // 2020-12 spec schema const schema = compat.toJSONSchema(user); // Set schema version for root schema (has type hint) schema.$schema = 'https://json-schema.org/draft/2020-12/schema'; ``` Due to the inference strategy of the current system, type inference for JSON schema is impossible. ### Standard schema Convert `stnl` to a [standard schema](https://standardschema.dev) (require `Function` for code generation). ```ts const schema = compat.standardSchema.toV1(user, 'User validation failed'); // Use standard schema console.log(schema['~standard'].validate({})); ``` ## Compilers `stnl` schema compilers. ```ts import { build, t, l } from 'stnl'; // Used for examples below const schema = t.dict({ name: l.string(l.minLen(3), l.maxLen(16)), code: l.string(l.minLen(8), l.maxLen(32)) }); const user = { name: 'reve', code: '1234567890' }; ``` ### Assert JSON To compile a schema to a JSON type assertion function (require `Function` for code generation): ```ts const isUser = build.json.assert(schema); if (isUser(user)) { console.log('Name', user.name); console.log('Code', user.code); } ``` ### Stringify JSON To compile a schema to an optimized JSON stringifier function: ```ts const stringifyUser = build.json.stringify(schema); if (isUser(user)) console.log(stringifyUser(user) === JSON.stringify(user)); // true ``` ### Usage with `runtime-compiler` Some `build` module supports `runtime-compiler`. ```ts // runtime-compiler compatible modules ends with .rt import build from 'stnl/build/json/stringify.rt'; // Build to a value string, eg $0(o) build(schema, 'o'); ```