'use strict' const symbols = require('./lib/symbols') const number = require('./lib/number') const string = require('./lib/string') const object = require('./lib/object') const typePredicates = { number, string, object } const createOw = ({ validators = [], predicates = typePredicates, type = null } = { }) => { const ow = new Proxy(function () { }, { get: (obj, key) => { if (key === symbols.validate) { return (value, label = 'argument') => { if (!type) { return new Error('missing required type specifier') } for (let i = 0; i < validators.length; ++i) { const validator = validators[i] const result = validator.fn(value) if (!result) { if (i === 0) { throw new Error(`Expected ${label} \`${value}\` to be of type \`${type}\`, but received type \`${typeof value}\``) } else { throw new Error(`Expected ${type} \`${label}\` \`${value}\` failed predicate \`${validator.key}\``) } } } } } const predicate = predicates[key] if (predicate) { if (typeof predicate === 'function') { validators.push({ key, fn: predicate }) return ow } else { return createOw({ type: key, validators: [ { key, fn: predicate.validator } ], predicates: predicate.predicates }) } } else { const fn = predicates[symbols.func] && predicates[symbols.func][key] if (fn) { return new Proxy(function () { }, { get: () => { throw new Error(`invalid use of functional predicate "${key}"`) }, apply: (obj, thisArg, args) => { validators.push({ key, fn: fn(...args) }) return ow } }) } else { if (key === 'default' || key === '__esModule') { return ow } return ow // throw new Error(`unrecognized predicate "${key}"`) } } }, apply: (obj, thisArg, args) => { if (args.length !== 2 && args.length !== 3) { throw new Error('invalid number of arguments to "ow"') } else { args[1][symbols.validate](args[0], args[2]) } } }) return ow } module.exports = createOw()