UNPKG

alinea

Version:

[![npm](https://img.shields.io/npm/v/alinea.svg)](https://npmjs.org/package/alinea) [![install size](https://packagephobia.com/badge?p=alinea)](https://packagephobia.com/result?p=alinea)

237 lines (235 loc) 5.93 kB
// node_modules/cito/dist/index.js var { assign, entries, keys, values, setPrototypeOf } = Object; var { stringify } = JSON; var Context = class { value = void 0; path = []; expected = ""; at(name) { this.path.push(this.path.length > 0 ? `.${name}` : name); } index(index) { this.path.push(`[${index}]`); } back() { this.path.pop(); } expect(e, v) { this.expected = e; this.value = v; } err() { let at = this.path.length ? `@ ${this.path.join("")} ` : ""; return `Expected ${this.expected} ${at}(got: ${stringify(this.value)})`; } }; var arg = "v"; var ctx = new Context(); var Type = class { narrow() { return this; } new(value) { return value; } check(input) { ctx = new Context(); return this.validate(input, ctx); } assert(input) { if (!this.check(input)) throw new TypeError(ctx.err()); } and(that) { return type( (value) => this.validate(value, ctx) && that.validate(value, ctx), (path) => `${this.gen(path)} && ${that.gen(path)}` ); } or(that) { return type( (value) => this.validate(value, ctx) || that.validate(value, ctx), (path) => `(${this.gen(path)} || ${that.gen(path)})` ); } get nullable() { return nullable(this); } get optional() { return optional(this); } }; var noGen = () => { throw new Error(`This type cannot be generated`); }; var type = (validate, gen = noGen) => { const inst = assign( setPrototypeOf((value) => { inst.assert(value); return value; }, Type.prototype), { validate, gen } ); return inst; }; var literal = (literal2) => type( (value) => (ctx.expect(stringify(literal2), value), literal2 === value), (path) => `${path} === ${stringify(literal2)}` ); var nullable = (inner) => literal(null).or(inner); var optional = (inner) => literal(void 0).or(inner); var primitive = (primitive2) => type( (value) => (ctx.expect(primitive2, value), typeof value === primitive2), (path) => `typeof ${path} === '${primitive2}'` ); var instance = (constructor) => type( (value, ctx2) => (ctx2.expect(constructor.name, value), value instanceof constructor), (path) => `${path} instanceof ${constructor.name}` ); var string = primitive("string"); var number = primitive("number").and( type( (value) => !isNaN(value), (path) => `!isNaN(${path})` ) ); var bigint = primitive("bigint"); var boolean = primitive("boolean"); var symbol = primitive("symbol"); var any = type( (value) => true, () => `!0` ); var date = instance(Date).and( type( (value) => !isNaN(value.getTime()), (path) => `!isNaN(${path}.getTime())` ) ); var isFunction = (f) => typeof f === "function"; var isObject = type( (value) => (ctx.expect("object", value), typeof value === "object" && value != null), (path) => `typeof ${path} === 'object' && ${path} !== null` ); var isArray = type( (value) => (ctx.expect("array", value), Array.isArray(value)), (path) => `Array.isArray(${path})` ); var tuple = (...types) => isArray.and( type( (value) => { if (value.length !== types.length) return false; for (let i = 0; i < types.length; i++) { ctx.index(i); if (!types[i].validate(value[i], ctx)) return false; ctx.back(); } return true; }, (path) => `${path}.length === ${types.length} && ${types.map((type2, i) => type2.gen(`${path}[${i}]`)).join(" && ")}` ) ); var record = (inner) => isObject.and( type( (value) => { for (let [key, item] of entries(value)) { ctx.at(key); if (!inner.validate(item, ctx)) return false; ctx.back(); } return true; }, (path) => `Object.values(${path}).every(${arg} => ${inner.gen(arg)})` ) ); var object = (definition) => { let inst = definition; return isObject.and( type( (value) => { if (isFunction(inst)) inst = new inst(); for (let key in inst) { ctx.at(key); if (!inst[key].validate(value[key], ctx)) return false; ctx.back(); } return true; }, (path) => { if (isFunction(inst)) inst = new inst(); const types = keys(inst).map((key) => [key, inst[key]]); return types.map(([key, inner]) => inner.gen(`${path}.${key}`)).join(" && "); } ) ); }; var union = (...types) => { let definitions = types.map( (type2) => type2 instanceof Type ? type2 : object(type2) ); return type( (value) => { let current = ctx.path.length; let relevancy = 0; let expectation = void 0; for (let type2 of definitions) { ctx.path.splice(current, Infinity); if (type2.validate(value, ctx)) return true; if (ctx.path.length >= relevancy) { relevancy = ctx.path.length; expectation = [ctx.path.slice(), ctx.expected, ctx.value]; } } if (expectation) { ctx.path = expectation[0]; ctx.expected = expectation[1]; ctx.value = expectation[2]; } return false; }, (path) => `(${definitions.map((type2) => `${type2.gen(path)}`).join(" || ")})` ); }; var array = (inner) => isArray.and( type( (value, ctx2) => { for (let i = 0; i < value.length; i++) { ctx2.index(i); if (!inner.validate(value[i], ctx2)) return false; ctx2.back(); } return true; }, (path) => `${path}.every(${arg} => ${inner.gen(arg)})` ) ); var enums = (types) => { const options = values(types); const desc = options.join(" | "); return type( (value) => (ctx.expect(desc, value), options.includes(value)), (path) => `${stringify(options)}.includes(${path})` ); }; export { type, literal, string, number, boolean, any, tuple, record, object, union, array, enums };