decoders
Version:
Elegant and battle-tested validation library for type-safe input data for TypeScript
938 lines (919 loc) • 25.4 kB
JavaScript
// src/lib/utils.ts
function isNumber(value) {
return typeof value === "number";
}
function isString(value) {
return typeof value === "string";
}
function isBigInt(value) {
return typeof value === "bigint";
}
function isDate(value) {
return !!value && Object.prototype.toString.call(value) === "[object Date]" && !isNaN(value);
}
function isPojo(value) {
return value !== null && value !== void 0 && typeof value === "object" && // This still seems to be the only reliable way to determine whether
// something is a pojo... ¯\_(ツ)_/¯
Object.prototype.toString.call(value) === "[object Object]";
}
// src/core/annotate.ts
var kAnnotationRegistry = Symbol.for("decoders.kAnnotationRegistry");
var _register = globalThis[kAnnotationRegistry] ??= /* @__PURE__ */ new WeakSet();
function brand(ann) {
_register.add(ann);
return ann;
}
function makeObjectAnn(fields, text) {
return brand({ type: "object", fields, text });
}
function makeArrayAnn(items, text) {
return brand({ type: "array", items, text });
}
function makeOpaqueAnn(value, text) {
return brand({ type: "opaque", value, text });
}
function makeScalarAnn(value, text) {
return brand({ type: "scalar", value, text });
}
function updateText(annotation, text) {
if (text !== void 0) {
return brand({ ...annotation, text });
} else {
return annotation;
}
}
function merge(objAnnotation, fields) {
const newFields = new Map([...objAnnotation.fields, ...fields]);
return makeObjectAnn(newFields, objAnnotation.text);
}
function isAnnotation(thing) {
return _register.has(thing);
}
function annotateArray(arr, text, seen) {
seen.add(arr);
const items = [];
for (const value of arr) {
items.push(annotate(value, void 0, seen));
}
return makeArrayAnn(items, text);
}
function annotateObject(obj, text, seen) {
seen.add(obj);
const fields = /* @__PURE__ */ new Map();
for (const key of Object.keys(obj)) {
const value = obj[key];
fields.set(key, annotate(value, void 0, seen));
}
return makeObjectAnn(fields, text);
}
function annotate(value, text, seen) {
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "symbol" || typeof value.getMonth === "function") {
return makeScalarAnn(value, text);
}
if (isAnnotation(value)) {
return updateText(value, text);
}
if (Array.isArray(value)) {
if (seen.has(value)) {
return makeOpaqueAnn("<circular ref>", text);
} else {
return annotateArray(value, text, seen);
}
}
if (isPojo(value)) {
if (seen.has(value)) {
return makeOpaqueAnn("<circular ref>", text);
} else {
return annotateObject(value, text, seen);
}
}
if (typeof value === "function") {
return makeOpaqueAnn("<function>", text);
}
return makeOpaqueAnn("???", text);
}
function public_annotate(value, text) {
return annotate(value, text, /* @__PURE__ */ new WeakSet());
}
function public_annotateObject(obj, text) {
return annotateObject(obj, text, /* @__PURE__ */ new WeakSet());
}
// src/lib/text.ts
var INDENT = " ";
function isMultiline(s) {
return s.includes("\n");
}
function indent(s, prefix = INDENT) {
if (isMultiline(s)) {
return s.split("\n").map((line) => `${prefix}${line}`).join("\n");
} else {
return `${prefix}${s}`;
}
}
var quotePattern = /'/g;
function quote(value) {
return typeof value === "string" ? "'" + value.replace(quotePattern, "\\'") + "'" : JSON.stringify(value);
}
// src/core/format.ts
function summarize(ann, keypath = []) {
const result = [];
if (ann.type === "array") {
const items = ann.items;
let index = 0;
for (const ann2 of items) {
for (const item of summarize(ann2, [...keypath, index++])) {
result.push(item);
}
}
} else if (ann.type === "object") {
const fields = ann.fields;
for (const [key, value] of fields) {
for (const item of summarize(value, [...keypath, key])) {
result.push(item);
}
}
}
const text = ann.text;
if (!text) {
return result;
}
let prefix;
if (keypath.length === 0) {
prefix = "";
} else if (keypath.length === 1) {
prefix = typeof keypath[0] === "number" ? `Value at index ${keypath[0]}: ` : `Value at key ${quote(keypath[0])}: `;
} else {
prefix = `Value at keypath ${quote(keypath.map(String).join("."))}: `;
}
return [...result, `${prefix}${text}`];
}
function serializeString(s, width = 80) {
let ser = JSON.stringify(s);
if (ser.length <= width) {
return ser;
}
const truncated = `${s.substring(0, width - 15)}...`;
ser = `${JSON.stringify(truncated)} [truncated]`;
return ser;
}
function serializeArray(annotation, prefix) {
const { items } = annotation;
if (items.length === 0) {
return "[]";
}
const result = [];
for (const item of items) {
const [ser, ann] = serializeAnnotation(item, `${prefix}${INDENT}`);
result.push(`${prefix}${INDENT}${ser},`);
if (ann !== void 0) {
result.push(indent(ann, `${prefix}${INDENT}`));
}
}
return ["[", ...result, `${prefix}]`].join("\n");
}
function serializeObject(annotation, prefix) {
const { fields } = annotation;
if (fields.size === 0) {
return "{}";
}
const result = [];
for (const [key, valueAnnotation] of fields) {
const kser = serializeValue(key);
const valPrefix = `${prefix}${INDENT}${" ".repeat(kser.length + 2)}`;
const [vser, vann] = serializeAnnotation(valueAnnotation, `${prefix}${INDENT}`);
result.push(`${prefix}${INDENT}${kser}: ${vser},`);
if (vann !== void 0) {
result.push(indent(vann, valPrefix));
}
}
return ["{", ...result, `${prefix}}`].join("\n");
}
function serializeValue(value) {
if (typeof value === "string") {
return serializeString(value);
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "symbol") {
return value.toString();
} else if (value === null) {
return "null";
} else if (value === void 0) {
return "undefined";
} else {
if (isDate(value)) {
return `new Date(${quote(value.toISOString())})`;
} else if (value instanceof Date) {
return "(Invalid Date)";
} else {
return "(unserializable)";
}
}
}
function serializeAnnotation(ann, prefix = "") {
let serialized;
if (ann.type === "array") {
serialized = serializeArray(ann, prefix);
} else if (ann.type === "object") {
serialized = serializeObject(ann, prefix);
} else if (ann.type === "scalar") {
serialized = serializeValue(ann.value);
} else {
/* @__PURE__ */ ((_) => {
})(ann);
serialized = ann.value;
}
const text = ann.text;
if (text !== void 0) {
const sep = "^".repeat(isMultiline(serialized) ? 1 : serialized.length);
return [serialized, [sep, text].join(isMultiline(text) ? "\n" : " ")];
} else {
return [serialized, void 0];
}
}
function formatInline(ann) {
const [serialized, annotation] = serializeAnnotation(ann);
if (annotation !== void 0) {
return `${serialized}
${annotation}`;
} else {
return serialized;
}
}
function formatShort(ann) {
return summarize(ann, []).join("\n");
}
function* iterAnnotation(ann, stack) {
if (ann.text) {
if (stack.length > 0) {
yield { message: ann.text, path: [...stack] };
} else {
yield { message: ann.text };
}
}
switch (ann.type) {
case "array": {
let index = 0;
for (const item of ann.items) {
stack.push(index++);
yield* iterAnnotation(item, stack);
stack.pop();
}
break;
}
case "object": {
for (const [key, value] of ann.fields) {
stack.push(key);
yield* iterAnnotation(value, stack);
stack.pop();
}
break;
}
case "scalar":
case "opaque": {
break;
}
}
}
function formatAsIssues(ann) {
return Array.from(iterAnnotation(ann, []));
}
// src/core/Result.ts
function ok(value) {
return { ok: true, value, error: void 0 };
}
function err(error) {
return { ok: false, value: void 0, error };
}
// src/core/Decoder.ts
function noThrow(fn) {
return (t) => {
try {
const v = fn(t);
return ok(v);
} catch (e) {
return err(public_annotate(t, e instanceof Error ? e.message : String(e)));
}
};
}
function format(err2, formatter) {
const formatted = formatter(err2);
if (typeof formatted === "string") {
const err3 = new Error(`
${formatted}`);
err3.name = "Decoding error";
return err3;
} else {
return formatted;
}
}
function define(fn) {
function decode(blob) {
const makeFlexErr = (msg) => err(isAnnotation(msg) ? msg : public_annotate(blob, msg));
return fn(blob, ok, makeFlexErr);
}
function verify(blob, formatter = formatInline) {
const result = decode(blob);
if (result.ok) {
return result.value;
} else {
throw format(result.error, formatter);
}
}
function value(blob) {
return decode(blob).value;
}
function transform(transformFn) {
return then(noThrow(transformFn));
}
function refine(predicateFn, errmsg) {
return reject(
(value2) => predicateFn(value2) ? (
// Don't reject
null
) : (
// Reject with the given error message
errmsg
)
);
}
function refineType() {
return self;
}
function then(next) {
return define((blob, ok2, err2) => {
const r1 = decode(blob);
if (!r1.ok) return r1;
const r2 = isDecoder(next) ? next : next(r1.value, ok2, err2);
return isDecoder(r2) ? r2.decode(r1.value) : r2;
});
}
function pipe(next) {
return then(next);
}
function reject(rejectFn) {
return then((blob, ok2, err2) => {
const errmsg = rejectFn(blob);
return errmsg === null ? ok2(blob) : err2(typeof errmsg === "string" ? public_annotate(blob, errmsg) : errmsg);
});
}
function describe(message) {
return define((blob, _, err2) => {
const result = decode(blob);
if (result.ok) {
return result;
} else {
return err2(public_annotate(result.error, message));
}
});
}
const unregistered = {
verify,
value,
decode,
transform,
refine,
refineType,
reject,
describe,
then,
pipe,
"~standard": {
version: 1,
vendor: "decoders",
validate: (blob) => {
const result = decode(blob);
if (result.ok) {
return { value: result.value };
} else {
const issues = formatAsIssues(result.error);
return { issues };
}
}
}
};
const self = brand2(unregistered);
return self;
}
var kDecoderRegistry = Symbol.for("decoders.kDecoderRegistry");
var _register2 = globalThis[kDecoderRegistry] ??= /* @__PURE__ */ new WeakSet();
function brand2(decoder) {
_register2.add(decoder);
return decoder;
}
function isDecoder(thing) {
return _register2.has(thing);
}
// src/arrays.ts
var poja = define((blob, ok2, err2) => {
if (!Array.isArray(blob)) {
return err2("Must be an array");
}
return ok2(blob);
});
function array(decoder) {
const decodeFn = decoder.decode;
return poja.then((inputs, ok2, err2) => {
const results = [];
for (let i = 0; i < inputs.length; ++i) {
const blob = inputs[i];
const result = decodeFn(blob);
if (result.ok) {
results.push(result.value);
} else {
results.length = 0;
const ann = result.error;
const clone = inputs.slice();
clone.splice(
i,
1,
public_annotate(ann, ann.text ? `${ann.text} (at index ${i})` : `index ${i}`)
);
return err2(public_annotate(clone));
}
}
return ok2(results);
});
}
function isNonEmpty(arr) {
return arr.length > 0;
}
function nonEmptyArray(decoder) {
return array(decoder).refine(isNonEmpty, "Must be non-empty array");
}
var ntuple = (n) => poja.refine((arr) => arr.length === n, `Must be a ${n}-tuple`);
function tuple(...decoders) {
return ntuple(decoders.length).then((blobs, ok2, err2) => {
let allOk = true;
const rvs = decoders.map((decoder, i) => {
const blob = blobs[i];
const result = decoder.decode(blob);
if (result.ok) {
return result.value;
} else {
allOk = false;
return result.error;
}
});
if (allOk) {
return ok2(rvs);
} else {
return err2(public_annotate(rvs));
}
});
}
// src/misc.ts
function instanceOf(klass) {
return define(
(blob, ok2, err2) => (
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
blob instanceof klass ? ok2(blob) : err2(`Must be ${klass.name} instance`)
)
);
}
function lazy(decoderFn) {
return define((blob) => decoderFn().decode(blob));
}
function prep(mapperFn, decoder) {
return define((originalInput, _, err2) => {
let blob;
try {
blob = mapperFn(originalInput);
} catch (e) {
return err2(
public_annotate(
originalInput,
// istanbul ignore next
e instanceof Error ? e.message : String(e)
)
);
}
const r = decoder.decode(blob);
return r.ok ? r : err2(public_annotate(originalInput, r.error.text));
});
}
// src/lib/set-methods.ts
function difference(xs, ys) {
const result = /* @__PURE__ */ new Set();
for (const x of xs) {
if (!ys.has(x)) {
result.add(x);
}
}
return result;
}
// src/objects.ts
var pojo = define(
(blob, ok2, err2) => isPojo(blob) ? ok2(blob) : err2("Must be an object")
);
function object(decoders) {
const knownKeys = new Set(Object.keys(decoders));
return pojo.then((plainObj, ok2, err2) => {
const actualKeys = new Set(Object.keys(plainObj));
const missingKeys = difference(knownKeys, actualKeys);
const record2 = {};
let errors = null;
for (const key of Object.keys(decoders)) {
const decoder = decoders[key];
const rawValue = plainObj[key];
const result = decoder.decode(rawValue);
if (result.ok) {
const value = result.value;
if (value !== void 0) {
record2[key] = value;
}
missingKeys.delete(key);
} else {
const ann = result.error;
if (rawValue === void 0) {
missingKeys.add(key);
} else {
errors ??= /* @__PURE__ */ new Map();
errors.set(key, ann);
}
}
}
if (errors || missingKeys.size > 0) {
let objAnn = public_annotateObject(plainObj);
if (errors) {
objAnn = merge(objAnn, errors);
}
if (missingKeys.size > 0) {
const errMsg = Array.from(missingKeys).map(quote).join(", ");
const pluralized = missingKeys.size > 1 ? "keys" : "key";
objAnn = updateText(objAnn, `Missing ${pluralized}: ${errMsg}`);
}
return err2(objAnn);
}
return ok2(record2);
});
}
function exact(decoders) {
const allowedKeys = new Set(Object.keys(decoders));
const checked = pojo.reject((plainObj) => {
const actualKeys = new Set(Object.keys(plainObj));
const extraKeys = difference(actualKeys, allowedKeys);
return extraKeys.size > 0 ? `Unexpected extra keys: ${Array.from(extraKeys).map(quote).join(", ")}` : null;
});
return checked.pipe(object(decoders));
}
function inexact(decoders) {
return pojo.pipe((plainObj) => {
const allkeys = new Set(Object.keys(plainObj));
return object(decoders).transform((safepart) => {
const safekeys = new Set(Object.keys(decoders));
for (const k of safekeys) allkeys.add(k);
const rv = {};
for (const k of allkeys) {
if (safekeys.has(k)) {
const value = safepart[k];
if (value !== void 0) {
rv[k] = value;
}
} else {
rv[k] = plainObj[k];
}
}
return rv;
});
});
}
// src/unions.ts
var EITHER_PREFIX = "Either:\n";
function itemize(s) {
return `-${indent(s).substring(1)}`;
}
function nest(errText) {
return errText.startsWith(EITHER_PREFIX) ? errText.substring(EITHER_PREFIX.length) : itemize(errText);
}
function either(...decoders) {
if (decoders.length === 0) {
throw new Error("Pass at least one decoder to either()");
}
return define((blob, _, err2) => {
const errors = [];
for (const decoder of decoders) {
const result = decoder.decode(blob);
if (result.ok) {
return result;
} else {
errors.push(result.error);
}
}
const text = EITHER_PREFIX + errors.map((err3) => nest(summarize(err3).join("\n"))).join("\n");
return err2(text);
});
}
function oneOf(constants) {
return define((blob, ok2, err2) => {
const winner = constants.find((c) => c === blob);
if (winner !== void 0) {
return ok2(winner);
}
return err2(`Must be one of ${constants.map((value) => quote(value)).join(", ")}`);
});
}
function enum_(enumObj) {
const values = Object.values(enumObj);
if (!values.some(isNumber)) {
return oneOf(values);
} else {
const nums = values.filter(isNumber);
const ignore = new Set(nums.map((val) => enumObj[val]));
const strings = values.filter(isString).filter((val) => !ignore.has(val));
return oneOf([...nums, ...strings]);
}
}
function taggedUnion(field, mapping2) {
const scout = object({
[field]: prep(String, oneOf(Object.keys(mapping2)))
}).transform((o) => o[field]);
return select(
scout,
// peek...
(key) => mapping2[key]
// ...then select
);
}
function select(scout, selectFn) {
return define((blob) => {
const result = scout.decode(blob);
return result.ok ? selectFn(result.value).decode(blob) : result;
});
}
// src/basics.ts
function lazyval(value) {
return typeof value === "function" ? value() : value;
}
var null_ = constant(null);
var undefined_ = constant(void 0);
var nullish_ = define(
(blob, ok2, err2) => (
// Equiv to either(undefined_, null_), but combined for better error message
blob == null ? ok2(blob) : err2("Must be undefined or null")
)
);
function optional(decoder, defaultValue) {
const rv = either(undefined_, decoder);
return arguments.length >= 2 ? rv.transform((value) => value ?? lazyval(defaultValue)) : rv;
}
function nullable(decoder, defaultValue) {
const rv = either(null_, decoder);
return arguments.length >= 2 ? rv.transform((value) => value ?? lazyval(defaultValue)) : rv;
}
var maybe = nullish;
function nullish(decoder, defaultValue) {
const rv = either(nullish_, decoder);
return arguments.length >= 2 ? rv.transform((value) => value ?? lazyval(defaultValue)) : rv;
}
function constant(value) {
return define(
(blob, ok2, err2) => blob === value ? ok2(value) : err2(`Must be ${typeof value === "symbol" ? String(value) : quote(value)}`)
);
}
function always(value) {
return define(
typeof value === "function" ? (_, ok2) => ok2(value()) : (_, ok2) => ok2(value)
);
}
function never(msg) {
return define((_, __, err2) => err2(msg));
}
var fail = never;
var hardcoded = always;
var unknown = define((blob, ok2, _) => ok2(blob));
var mixed = unknown;
// src/booleans.ts
var boolean = define((blob, ok2, err2) => {
return typeof blob === "boolean" ? ok2(blob) : err2("Must be boolean");
});
var truthy = define((blob, ok2, _) => ok2(!!blob));
// src/collections.ts
function record(fst, snd) {
const keyDecoder = snd !== void 0 ? fst : void 0;
const valueDecoder = snd ?? fst;
return pojo.then((input, ok2, err2) => {
let rv = {};
const errors = /* @__PURE__ */ new Map();
for (const key of Object.keys(input)) {
const value = input[key];
const keyResult = keyDecoder?.decode(key);
if (keyResult?.ok === false) {
return err2(
public_annotate(input, `Invalid key ${quote(key)}: ${formatShort(keyResult.error)}`)
);
}
const k = keyResult?.value ?? key;
const result = valueDecoder.decode(value);
if (result.ok) {
if (errors.size === 0) {
rv[k] = result.value;
}
} else {
errors.set(key, result.error);
rv = {};
}
}
if (errors.size > 0) {
return err2(merge(public_annotateObject(input), errors));
} else {
return ok2(rv);
}
});
}
var dict = record;
function setFromArray(decoder) {
return array(decoder).transform((items) => new Set(items));
}
var set = setFromArray;
function mapping(decoder) {
return record(decoder).transform((obj) => new Map(Object.entries(obj)));
}
// src/lib/size-options.ts
function bySizeOptions(options) {
const size = options.size;
const min = size ?? options.min;
const max = size ?? options.max;
const atLeast = min === max ? "" : "at least ";
const atMost = min === max ? "" : "at most ";
const tooShort = min !== void 0 && `Too short, must be ${atLeast}${min} chars`;
const tooLong = max !== void 0 && `Too long, must be ${atMost}${max} chars`;
return tooShort && tooLong ? (s) => s.length < min ? tooShort : s.length > max ? tooLong : null : tooShort ? (s) => s.length < min ? tooShort : null : tooLong ? (s) => s.length > max ? tooLong : null : () => null;
}
// src/strings.ts
var url_re = /^([A-Za-z]{3,9}(?:[+][A-Za-z]{3,9})?):\/\/(?:([-;:&=+$,\w]+)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,/\w]*)?(?:#[.,!/\w]*)?)?$/;
var string = define(
(blob, ok2, err2) => isString(blob) ? ok2(blob) : err2("Must be string")
);
var nonEmptyString = regex(/\S/, "Must be non-empty string");
function regex(regex2, msg) {
return string.refine((s) => regex2.test(s), msg);
}
function startsWith(prefix) {
return string.refine(
(s) => s.startsWith(prefix),
`Must start with '${prefix}'`
);
}
function endsWith(suffix) {
return string.refine(
(s) => s.endsWith(suffix),
`Must end with '${suffix}'`
);
}
var email = regex(
// The almost perfect email regex, taken from https://emailregex.com/
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
"Must be email"
);
var url = either(
regex(url_re, "Must be URL").transform((value) => new URL(value)),
instanceOf(URL)
);
var httpsUrl = url.refine(
(value) => value.protocol === "https:",
"Must be an HTTPS URL"
);
var identifier = regex(
/^[a-z_][a-z0-9_]*$/i,
"Must be valid identifier"
);
function nanoid(options) {
return regex(/^[a-z0-9_-]+$/i, "Must be nano ID").reject(
bySizeOptions(options ?? { size: 21 })
);
}
var uuid = regex(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
"Must be uuid"
);
var uuidv1 = (
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)
uuid.refine((value) => value[14] === "1", "Must be uuidv1")
);
var uuidv4 = (
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
uuid.refine((value) => value[14] === "4", "Must be uuidv4")
);
var decimal = regex(/^[0-9]+$/, "Must only contain digits");
var hexadecimal = regex(
/^[0-9a-f]+$/i,
"Must only contain hexadecimal digits"
);
var numeric = decimal.transform(Number);
// src/dates.ts
var iso8601_re = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
var date = define((blob, ok2, err2) => {
return isDate(blob) ? ok2(blob) : err2("Must be a Date");
});
var dateString = regex(
iso8601_re,
"Must be ISO8601 format"
).refine(
(value) => !isNaN(new Date(value).getTime()),
"Must be valid date/time value"
);
var iso8601 = dateString.transform((value) => new Date(value));
var datelike = either(date, iso8601).describe("Must be a Date or date string");
// src/numbers.ts
var anyNumber = define(
(blob, ok2, err2) => isNumber(blob) ? ok2(blob) : err2("Must be number")
);
var number = anyNumber.refine(
(n) => Number.isFinite(n),
"Number must be finite"
);
var integer = number.refine(
(n) => Number.isInteger(n),
"Number must be an integer"
);
var positiveNumber = number.refine(
(n) => n >= 0 && !Object.is(n, -0),
"Number must be positive"
);
var positiveInteger = integer.refine(
(n) => n >= 0 && !Object.is(n, -0),
"Number must be positive"
);
var bigint = define(
(blob, ok2, err2) => isBigInt(blob) ? ok2(blob) : err2("Must be bigint")
);
// src/json.ts
var jsonObject = lazy(() => record(json));
var jsonArray = lazy(() => array(json));
var json = either(
null_,
string,
number,
boolean,
jsonObject,
jsonArray
).describe("Must be valid JSON value");
export {
always,
anyNumber,
array,
bigint,
boolean,
constant,
date,
datelike,
decimal,
define,
dict,
either,
email,
endsWith,
enum_,
err,
exact,
fail,
formatInline,
formatShort,
hardcoded,
hexadecimal,
httpsUrl,
identifier,
inexact,
instanceOf,
integer,
iso8601,
json,
jsonArray,
jsonObject,
lazy,
mapping,
maybe,
mixed,
nanoid,
never,
nonEmptyArray,
nonEmptyString,
null_,
nullable,
nullish,
number,
numeric,
object,
ok,
oneOf,
optional,
poja,
pojo,
positiveInteger,
positiveNumber,
prep,
record,
regex,
select,
set,
setFromArray,
startsWith,
string,
taggedUnion,
truthy,
tuple,
undefined_,
unknown,
url,
uuid,
uuidv1,
uuidv4
};