UNPKG

narrows

Version:

Super lean and simple object validation with TypeScript support.

67 lines 3.56 kB
const isObject = (x) => typeof x === "object" && x !== null; // -------------------------------- // // - - - PRIMITIVE VALIDATORS - - - // // -------------------------------- // /** Returns true if and only if x is a boolean. */ export const boolean = (x) => typeof x === "boolean"; /** Returns true if and only if x is a string. */ export const string = (x) => typeof x === "string"; /** Returns true if and only if x is a number. */ export const number = (x) => typeof x === "number"; /** Returns true if and only if x is undefined. */ export const empty = (x) => x === undefined; /** Returns true if and only if x is null. */ export const nil = (x) => x === null; /** Returns true if and only if x is strictly equal to y. */ export const literal = (y) => (x) => x === y; // ------------------------------ // // - - - COMPLEX VALIDATORS - - - // // ------------------------------ // /** Returns true if and only if x is an object where each value matches the given validator. */ export const object = (validator) => (x) => isObject(x) && Object.values(x).every(validator); /** Returns true if and only if x is an array where each element matches the given validator. */ export const array = (validator) => (x) => Array.isArray(x) && x.every(validator); /** Returns true if and only if x is an instance of the given type. */ export const instance = (base) => (x) => x instanceof base; // ------------------------------// // - - - SCHEMA VALIDATORS - - - // // ------------------------------// /** Returns true if and only if x is an object where each value matches the validator at the corresponding key in the schema. */ export const record = (schema) => (x) => isObject(x) && Object.entries(schema).every(([key, validate]) => validate(x[key])); /** Returns true if and only if x is an array where each element matches the validator at the corresponding index in the schema. */ export const tuple = (...schema) => (x) => Array.isArray(x) && schema.every((validator, i) => validator(x[i])); // ----------------------- // // - - - COMBINATORS - - - // // ----------------------- // /** Returns true if and only if x matches any of the given validators. */ export const any = (...validators) => (x) => validators.some(validator => validator(x)); /** Returns true if and only if x matches all of the given validators. */ export const all = (...validators) => (x) => validators.every(validator => validator(x)); /** Returns true if and only if x matches the given validator or is undefined. */ export const optional = (validator) => any(empty, validator); /** Returns true if and only if x matches the given validator or is null. */ export const nullable = (validator) => any(nil, validator); // --------------------- // // - - - REPORTING - - - // // --------------------- // const canProxy = (x) => x !== null && (typeof x === "object" || typeof x === "function"); function spy(source, report, path = []) { if (!canProxy(source)) return source; return new Proxy(source, { get(target, property) { const value = target[property]; const next = [...path, property]; report(next); return canProxy(value) ? spy(value, report, next) : value; } }); } /** Takes a validator and an object to be validated. Returns null if the object is valid, or the path to the invalid property. */ export function report(validate, object) { let path = []; const passed = validate(spy(object, current => (path = current))); return passed ? null : path; } //# sourceMappingURL=index.js.map