| 'use strict'; | 
|   | 
| const Hoek = require('@hapi/hoek'); | 
|   | 
| const Any = require('./types/any'); | 
| const Cast = require('./cast'); | 
| const Errors = require('./errors'); | 
| const Lazy = require('./types/lazy'); | 
| const Ref = require('./ref'); | 
|   | 
|   | 
| const internals = { | 
|     alternatives: require('./types/alternatives'), | 
|     array: require('./types/array'), | 
|     boolean: require('./types/boolean'), | 
|     binary: require('./types/binary'), | 
|     date: require('./types/date'), | 
|     func: require('./types/func'), | 
|     number: require('./types/number'), | 
|     object: require('./types/object'), | 
|     string: require('./types/string'), | 
|     symbol: require('./types/symbol') | 
| }; | 
|   | 
|   | 
| internals.callWithDefaults = function (schema, args) { | 
|   | 
|     Hoek.assert(this, 'Must be invoked on a Joi instance.'); | 
|   | 
|     if (this._defaults) { | 
|         schema = this._defaults(schema); | 
|     } | 
|   | 
|     schema._currentJoi = this; | 
|   | 
|     return schema._init(...args); | 
| }; | 
|   | 
|   | 
| internals.root = function () { | 
|   | 
|     const any = new Any(); | 
|   | 
|     const root = any.clone(); | 
|     Any.prototype._currentJoi = root; | 
|     root._currentJoi = root; | 
|     root._binds = new Set(['any', 'alternatives', 'alt', 'array', 'bool', 'boolean', 'binary', 'date', 'func', 'number', 'object', 'string', 'symbol', 'validate', 'describe', 'compile', 'assert', 'attempt', 'lazy', 'defaults', 'extend', 'allow', 'valid', 'only', 'equal', 'invalid', 'disallow', 'not', 'required', 'exist', 'optional', 'forbidden', 'strip', 'when', 'empty', 'default']); | 
|   | 
|     root.any = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.any() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, any, args); | 
|     }; | 
|   | 
|     root.alternatives = root.alt = function (...args) { | 
|   | 
|         return internals.callWithDefaults.call(this, internals.alternatives, args); | 
|     }; | 
|   | 
|     root.array = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.array() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.array, args); | 
|     }; | 
|   | 
|     root.boolean = root.bool = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.boolean() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.boolean, args); | 
|     }; | 
|   | 
|     root.binary = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.binary() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.binary, args); | 
|     }; | 
|   | 
|     root.date = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.date() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.date, args); | 
|     }; | 
|   | 
|     root.func = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.func() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.func, args); | 
|     }; | 
|   | 
|     root.number = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.number() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.number, args); | 
|     }; | 
|   | 
|     root.object = function (...args) { | 
|   | 
|         return internals.callWithDefaults.call(this, internals.object, args); | 
|     }; | 
|   | 
|     root.string = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.string() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.string, args); | 
|     }; | 
|   | 
|     root.symbol = function (...args) { | 
|   | 
|         Hoek.assert(args.length === 0, 'Joi.symbol() does not allow arguments.'); | 
|   | 
|         return internals.callWithDefaults.call(this, internals.symbol, args); | 
|     }; | 
|   | 
|     root.ref = function (...args) { | 
|   | 
|         return Ref.create(...args); | 
|     }; | 
|   | 
|     root.isRef = function (ref) { | 
|   | 
|         return Ref.isRef(ref); | 
|     }; | 
|   | 
|     root.validate = function (value, ...args /*, [schema], [options], callback */) { | 
|   | 
|         const last = args[args.length - 1]; | 
|         const callback = typeof last === 'function' ? last : null; | 
|   | 
|         const count = args.length - (callback ? 1 : 0); | 
|         if (count === 0) { | 
|             return any.validate(value, callback); | 
|         } | 
|   | 
|         const options = count === 2 ? args[1] : undefined; | 
|         const schema = this.compile(args[0]); | 
|   | 
|         return schema._validateWithOptions(value, options, callback); | 
|     }; | 
|   | 
|     root.describe = function (...args) { | 
|   | 
|         const schema = args.length ? this.compile(args[0]) : any; | 
|         return schema.describe(); | 
|     }; | 
|   | 
|     root.compile = function (schema) { | 
|   | 
|         try { | 
|             return Cast.schema(this, schema); | 
|         } | 
|         catch (err) { | 
|             if (err.hasOwnProperty('path')) { | 
|                 err.message = err.message + '(' + err.path + ')'; | 
|             } | 
|   | 
|             throw err; | 
|         } | 
|     }; | 
|   | 
|     root.assert = function (value, schema, message) { | 
|   | 
|         this.attempt(value, schema, message); | 
|     }; | 
|   | 
|     root.attempt = function (value, schema, message) { | 
|   | 
|         const result = this.validate(value, schema); | 
|         const error = result.error; | 
|         if (error) { | 
|             if (!message) { | 
|                 if (typeof error.annotate === 'function') { | 
|                     error.message = error.annotate(); | 
|                 } | 
|   | 
|                 throw error; | 
|             } | 
|   | 
|             if (!(message instanceof Error)) { | 
|                 if (typeof error.annotate === 'function') { | 
|                     error.message = `${message} ${error.annotate()}`; | 
|                 } | 
|   | 
|                 throw error; | 
|             } | 
|   | 
|             throw message; | 
|         } | 
|   | 
|         return result.value; | 
|     }; | 
|   | 
|     root.reach = function (schema, path) { | 
|   | 
|         Hoek.assert(schema && schema instanceof Any, 'you must provide a joi schema'); | 
|         Hoek.assert(Array.isArray(path) || typeof path === 'string', 'path must be a string or an array of strings'); | 
|   | 
|         const reach = (sourceSchema, schemaPath) => { | 
|   | 
|             if (!schemaPath.length) { | 
|                 return sourceSchema; | 
|             } | 
|   | 
|             const children = sourceSchema._inner.children; | 
|             if (!children) { | 
|                 return; | 
|             } | 
|   | 
|             const key = schemaPath.shift(); | 
|             for (let i = 0; i < children.length; ++i) { | 
|                 const child = children[i]; | 
|                 if (child.key === key) { | 
|                     return reach(child.schema, schemaPath); | 
|                 } | 
|             } | 
|         }; | 
|   | 
|         const schemaPath = typeof path === 'string' ? (path ? path.split('.') : []) : path.slice(); | 
|   | 
|         return reach(schema, schemaPath); | 
|     }; | 
|   | 
|     root.lazy = function (...args) { | 
|   | 
|         return internals.callWithDefaults.call(this, Lazy, args); | 
|     }; | 
|   | 
|     root.defaults = function (fn) { | 
|   | 
|         Hoek.assert(typeof fn === 'function', 'Defaults must be a function'); | 
|   | 
|         let joi = Object.create(this.any()); | 
|         joi = fn(joi); | 
|   | 
|         Hoek.assert(joi && joi instanceof this.constructor, 'defaults() must return a schema'); | 
|   | 
|         Object.assign(joi, this, joi.clone()); // Re-add the types from `this` but also keep the settings from joi's potential new defaults | 
|   | 
|         joi._defaults = (schema) => { | 
|   | 
|             if (this._defaults) { | 
|                 schema = this._defaults(schema); | 
|                 Hoek.assert(schema instanceof this.constructor, 'defaults() must return a schema'); | 
|             } | 
|   | 
|             schema = fn(schema); | 
|             Hoek.assert(schema instanceof this.constructor, 'defaults() must return a schema'); | 
|             return schema; | 
|         }; | 
|   | 
|         return joi; | 
|     }; | 
|   | 
|     root.bind = function () { | 
|   | 
|         const joi = Object.create(this); | 
|   | 
|         joi._binds.forEach((bind) => { | 
|   | 
|             joi[bind] = joi[bind].bind(joi); | 
|         }); | 
|   | 
|         return joi; | 
|     }; | 
|   | 
|     root.extend = function (...args) { | 
|   | 
|         const extensions = Hoek.flatten(args); | 
|         Hoek.assert(extensions.length > 0, 'You need to provide at least one extension'); | 
|   | 
|         this.assert(extensions, root.extensionsSchema); | 
|   | 
|         const joi = Object.create(this.any()); | 
|         Object.assign(joi, this); | 
|         joi._currentJoi = joi; | 
|         joi._binds = new Set(joi._binds); | 
|   | 
|         for (let i = 0; i < extensions.length; ++i) { | 
|             let extension = extensions[i]; | 
|   | 
|             if (typeof extension === 'function') { | 
|                 extension = extension(joi); | 
|             } | 
|   | 
|             this.assert(extension, root.extensionSchema); | 
|   | 
|             const base = (extension.base || this.any()).clone(); // Cloning because we're going to override language afterwards | 
|             const ctor = base.constructor; | 
|             const type = class extends ctor { // eslint-disable-line no-loop-func | 
|   | 
|                 constructor() { | 
|   | 
|                     super(); | 
|                     if (extension.base) { | 
|                         Object.assign(this, base); | 
|                     } | 
|   | 
|                     this._type = extension.name; | 
|                 } | 
|   | 
|             }; | 
|   | 
|             if (extension.language) { | 
|                 const lang = { | 
|                     [extension.name]: extension.language | 
|                 }; | 
|                 type.prototype._language = Hoek.applyToDefaults(type.prototype._language || (base._settings && base._settings.language) || {}, lang); | 
|             } | 
|   | 
|   | 
|             if (extension.coerce) { | 
|                 type.prototype._coerce = function (value, state, options) { | 
|   | 
|                     if (ctor.prototype._coerce) { | 
|                         const baseRet = ctor.prototype._coerce.call(this, value, state, options); | 
|   | 
|                         if (baseRet.errors) { | 
|                             return baseRet; | 
|                         } | 
|   | 
|                         value = baseRet.value; | 
|                     } | 
|   | 
|                     const ret = extension.coerce.call(this, value, state, options); | 
|                     if (ret instanceof Errors.Err) { | 
|                         return { value, errors: ret }; | 
|                     } | 
|   | 
|                     return { value: ret }; | 
|                 }; | 
|             } | 
|   | 
|             if (extension.pre) { | 
|                 type.prototype._base = function (value, state, options) { | 
|   | 
|                     if (ctor.prototype._base) { | 
|                         const baseRet = ctor.prototype._base.call(this, value, state, options); | 
|   | 
|                         if (baseRet.errors) { | 
|                             return baseRet; | 
|                         } | 
|   | 
|                         value = baseRet.value; | 
|                     } | 
|   | 
|                     const ret = extension.pre.call(this, value, state, options); | 
|                     if (ret instanceof Errors.Err) { | 
|                         return { value, errors: ret }; | 
|                     } | 
|   | 
|                     return { value: ret }; | 
|                 }; | 
|             } | 
|   | 
|             if (extension.rules) { | 
|                 for (let j = 0; j < extension.rules.length; ++j) { | 
|                     const rule = extension.rules[j]; | 
|                     const ruleArgs = rule.params ? | 
|                         (rule.params instanceof Any ? rule.params._inner.children.map((k) => k.key) : Object.keys(rule.params)) : | 
|                         []; | 
|                     const validateArgs = rule.params ? Cast.schema(this, rule.params) : null; | 
|   | 
|                     type.prototype[rule.name] = function (...rArgs) { // eslint-disable-line no-loop-func | 
|   | 
|                         if (rArgs.length > ruleArgs.length) { | 
|                             throw new Error('Unexpected number of arguments'); | 
|                         } | 
|   | 
|                         let hasRef = false; | 
|                         let arg = {}; | 
|   | 
|                         for (let k = 0; k < ruleArgs.length; ++k) { | 
|                             arg[ruleArgs[k]] = rArgs[k]; | 
|                             if (!hasRef && Ref.isRef(rArgs[k])) { | 
|                                 hasRef = true; | 
|                             } | 
|                         } | 
|   | 
|                         if (validateArgs) { | 
|                             arg = joi.attempt(arg, validateArgs); | 
|                         } | 
|   | 
|                         let schema; | 
|                         if (rule.validate && !rule.setup) { | 
|                             const validate = function (value, state, options) { | 
|   | 
|                                 return rule.validate.call(this, arg, value, state, options); | 
|                             }; | 
|   | 
|                             schema = this._test(rule.name, arg, validate, { | 
|                                 description: rule.description, | 
|                                 hasRef | 
|                             }); | 
|                         } | 
|                         else { | 
|                             schema = this.clone(); | 
|                         } | 
|   | 
|                         if (rule.setup) { | 
|                             const newSchema = rule.setup.call(schema, arg); | 
|                             if (newSchema !== undefined) { | 
|                                 Hoek.assert(newSchema instanceof Any, `Setup of extension Joi.${this._type}().${rule.name}() must return undefined or a Joi object`); | 
|                                 schema = newSchema; | 
|                             } | 
|   | 
|                             if (rule.validate) { | 
|                                 const validate = function (value, state, options) { | 
|   | 
|                                     return rule.validate.call(this, arg, value, state, options); | 
|                                 }; | 
|   | 
|                                 schema = schema._test(rule.name, arg, validate, { | 
|                                     description: rule.description, | 
|                                     hasRef | 
|                                 }); | 
|                             } | 
|                         } | 
|   | 
|                         return schema; | 
|                     }; | 
|                 } | 
|             } | 
|   | 
|             if (extension.describe) { | 
|                 type.prototype.describe = function () { | 
|   | 
|                     const description = ctor.prototype.describe.call(this); | 
|                     return extension.describe.call(this, description); | 
|                 }; | 
|             } | 
|   | 
|             const instance = new type(); | 
|             joi[extension.name] = function (...extArgs) { | 
|   | 
|                 return internals.callWithDefaults.call(this, instance, extArgs); | 
|             }; | 
|   | 
|             joi._binds.add(extension.name); | 
|         } | 
|   | 
|         return joi; | 
|     }; | 
|   | 
|     root.extensionSchema = internals.object.keys({ | 
|         base: internals.object.type(Any, 'Joi object'), | 
|         name: internals.string.required(), | 
|         coerce: internals.func.arity(3), | 
|         pre: internals.func.arity(3), | 
|         language: internals.object, | 
|         describe: internals.func.arity(1), | 
|         rules: internals.array.items(internals.object.keys({ | 
|             name: internals.string.required(), | 
|             setup: internals.func.arity(1), | 
|             validate: internals.func.arity(4), | 
|             params: [ | 
|                 internals.object.pattern(/.*/, internals.object.type(Any, 'Joi object')), | 
|                 internals.object.type(internals.object.constructor, 'Joi object') | 
|             ], | 
|             description: [internals.string, internals.func.arity(1)] | 
|         }).or('setup', 'validate')) | 
|     }).strict(); | 
|   | 
|     root.extensionsSchema = internals.array.items([internals.object, internals.func.arity(1)]).strict(); | 
|   | 
|     root.version = require('../package.json').version; | 
|   | 
|     return root; | 
| }; | 
|   | 
|   | 
| module.exports = internals.root(); |