aboutsummaryrefslogtreecommitdiff
path: root/node_modules/joi
diff options
context:
space:
mode:
authorruki <waruqi@gmail.com>2018-11-08 00:38:48 +0800
committerruki <waruqi@gmail.com>2018-11-07 21:53:09 +0800
commit26105034da4fcce7ac883c899d781f016559310d (patch)
treec459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/joi
parent2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff)
downloadxmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz
xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip
switch to vuepress
Diffstat (limited to 'node_modules/joi')
-rw-r--r--node_modules/joi/CHANGELOG.md3
-rw-r--r--node_modules/joi/LICENSE29
-rw-r--r--node_modules/joi/README.md131
-rw-r--r--node_modules/joi/lib/cast.js64
-rwxr-xr-xnode_modules/joi/lib/errors.js357
-rw-r--r--node_modules/joi/lib/index.js434
-rw-r--r--node_modules/joi/lib/language.js156
-rw-r--r--node_modules/joi/lib/ref.js53
-rw-r--r--node_modules/joi/lib/schemas.js24
-rw-r--r--node_modules/joi/lib/set.js111
-rw-r--r--node_modules/joi/lib/types/alternatives/index.js188
-rw-r--r--node_modules/joi/lib/types/any/index.js916
-rw-r--r--node_modules/joi/lib/types/array/index.js658
-rw-r--r--node_modules/joi/lib/types/binary/index.js100
-rw-r--r--node_modules/joi/lib/types/boolean/index.js98
-rw-r--r--node_modules/joi/lib/types/date/index.js177
-rw-r--r--node_modules/joi/lib/types/func/index.js90
-rw-r--r--node_modules/joi/lib/types/lazy/index.js53
-rw-r--r--node_modules/joi/lib/types/number/index.js173
-rw-r--r--node_modules/joi/lib/types/object/index.js896
-rwxr-xr-xnode_modules/joi/lib/types/string/index.js632
-rw-r--r--node_modules/joi/lib/types/string/ip.js54
-rw-r--r--node_modules/joi/lib/types/string/rfc3986.js209
-rw-r--r--node_modules/joi/lib/types/string/uri.js46
-rw-r--r--node_modules/joi/package.json33
25 files changed, 5685 insertions, 0 deletions
diff --git a/node_modules/joi/CHANGELOG.md b/node_modules/joi/CHANGELOG.md
new file mode 100644
index 00000000..5771955a
--- /dev/null
+++ b/node_modules/joi/CHANGELOG.md
@@ -0,0 +1,3 @@
+Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/joi/issues?q=is%3Aissue+label%3A%22release+notes%22).
+
+If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/joi/milestones?state=closed&direction=asc&sort=due_date).
diff --git a/node_modules/joi/LICENSE b/node_modules/joi/LICENSE
new file mode 100644
index 00000000..7c9733d9
--- /dev/null
+++ b/node_modules/joi/LICENSE
@@ -0,0 +1,29 @@
+Copyright (c) 2012-2017, Project contributors
+Copyright (c) 2012-2014, Walmart
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The names of any contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ * * *
+
+The complete list of contributors can be found at: https://github.com/hapijs/joi/graphs/contributors
diff --git a/node_modules/joi/README.md b/node_modules/joi/README.md
new file mode 100644
index 00000000..d175fbdd
--- /dev/null
+++ b/node_modules/joi/README.md
@@ -0,0 +1,131 @@
+![joi Logo](https://raw.github.com/hapijs/joi/master/images/joi.png)
+
+Object schema description language and validator for JavaScript objects.
+
+[![npm version](https://badge.fury.io/js/joi.svg)](http://badge.fury.io/js/joi)
+[![Build Status](https://secure.travis-ci.org/hapijs/joi.svg?branch=master)](http://travis-ci.org/hapijs/joi)
+<!--
+
+Remove those badges until they work properly on semver.
+
+[![Dependencies Status](https://david-dm.org/hapijs/joi.svg)](https://david-dm.org/hapijs/joi)
+[![DevDependencies Status](https://david-dm.org/hapijs/joi/dev-status.svg)](https://david-dm.org/hapijs/joi#info=devDependencies)
+
+-->
+[![NSP Status](https://nodesecurity.io/orgs/hapijs/projects/0394bf83-b5bc-410b-878c-e8cf1b92033e/badge)](https://nodesecurity.io/orgs/hapijs/projects/0394bf83-b5bc-410b-878c-e8cf1b92033e)
+[![Known Vulnerabilities](https://snyk.io/test/github/hapijs/joi/badge.svg)](https://snyk.io/test/github/hapijs/joi)
+
+[![Join the chat at https://gitter.im/hapijs/joi](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hapijs/joi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+Lead Maintainer: [Nicolas Morel](https://github.com/marsup)
+
+# Introduction
+
+Imagine you run facebook and you want visitors to sign up on the website with real names and not something like `l337_p@nda` in the first name field. How would you define the limitations of what can be inputted and validate it against the set rules?
+
+This is joi, joi allows you to create *blueprints* or *schemas* for JavaScript objects (an object that stores information) to ensure *validation* of key information.
+
+# API
+See the detailed [API Reference](https://github.com/hapijs/joi/blob/v11.4.0/API.md).
+
+# Example
+
+```javascript
+const Joi = require('joi');
+
+const schema = Joi.object().keys({
+ username: Joi.string().alphanum().min(3).max(30).required(),
+ password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
+ access_token: [Joi.string(), Joi.number()],
+ birthyear: Joi.number().integer().min(1900).max(2013),
+ email: Joi.string().email()
+}).with('username', 'birthyear').without('password', 'access_token');
+
+// Return result.
+const result = Joi.validate({ username: 'abc', birthyear: 1994 }, schema);
+// result.error === null -> valid
+
+// You can also pass a callback which will be called synchronously with the validation result.
+Joi.validate({ username: 'abc', birthyear: 1994 }, schema, function (err, value) { }); // err === null -> valid
+
+```
+
+The above schema defines the following constraints:
+* `username`
+ * a required string
+ * must contain only alphanumeric characters
+ * at least 3 characters long but no more than 30
+ * must be accompanied by `birthyear`
+* `password`
+ * an optional string
+ * must satisfy the custom regex
+ * cannot appear together with `access_token`
+* `access_token`
+ * an optional, unconstrained string or number
+* `birthyear`
+ * an integer between 1900 and 2013
+* `email`
+ * a valid email address string
+
+# Usage
+
+Usage is a two steps process. First, a schema is constructed using the provided types and constraints:
+
+```javascript
+const schema = {
+ a: Joi.string()
+};
+```
+
+Note that **joi** schema objects are immutable which means every additional rule added (e.g. `.min(5)`) will return a
+new schema object.
+
+Then the value is validated against the schema:
+
+```javascript
+const {error, value} = Joi.validate({ a: 'a string' }, schema);
+
+// or
+
+Joi.validate({ a: 'a string' }, schema, function (err, value) { });
+```
+
+If the input is valid, then the error will be `null`, otherwise it will be an Error object.
+
+The schema can be a plain JavaScript object where every key is assigned a **joi** type, or it can be a **joi** type directly:
+
+```javascript
+const schema = Joi.string().min(10);
+```
+
+If the schema is a **joi** type, the `schema.validate(value, callback)` can be called directly on the type. When passing a non-type schema object,
+the module converts it internally to an object() type equivalent to:
+
+```javascript
+const schema = Joi.object().keys({
+ a: Joi.string()
+});
+```
+
+When validating a schema:
+
+* Values (or keys in case of objects) are optional by default.
+
+ ```javascript
+ Joi.validate(undefined, Joi.string()); // validates fine
+ ```
+
+ To disallow this behavior, you can either set the schema as `required()`, or set `presence` to `"required"` when passing `options`:
+
+ ```javascript
+ Joi.validate(undefined, Joi.string().required());
+ // or
+ Joi.validate(undefined, Joi.string(), /* options */ { presence: "required" });
+ ```
+
+* Strings are utf-8 encoded by default.
+* Rules are defined in an additive fashion and evaluated in order after whitelist and blacklist checks.
+
+# Browsers
+
+Joi doesn't directly support browsers, but you could use [joi-browser](https://github.com/jeffbski/joi-browser) for an ES5 build of Joi that works in browsers, or as a source of inspiration for your own builds.
diff --git a/node_modules/joi/lib/cast.js b/node_modules/joi/lib/cast.js
new file mode 100644
index 00000000..19c4a677
--- /dev/null
+++ b/node_modules/joi/lib/cast.js
@@ -0,0 +1,64 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Ref = require('./ref');
+
+// Type modules are delay-loaded to prevent circular dependencies
+
+
+// Declare internals
+
+const internals = {};
+
+
+exports.schema = function (Joi, config) {
+
+ if (config !== undefined && config !== null && typeof config === 'object') {
+
+ if (config.isJoi) {
+ return config;
+ }
+
+ if (Array.isArray(config)) {
+ return Joi.alternatives().try(config);
+ }
+
+ if (config instanceof RegExp) {
+ return Joi.string().regex(config);
+ }
+
+ if (config instanceof Date) {
+ return Joi.date().valid(config);
+ }
+
+ return Joi.object().keys(config);
+ }
+
+ if (typeof config === 'string') {
+ return Joi.string().valid(config);
+ }
+
+ if (typeof config === 'number') {
+ return Joi.number().valid(config);
+ }
+
+ if (typeof config === 'boolean') {
+ return Joi.boolean().valid(config);
+ }
+
+ if (Ref.isRef(config)) {
+ return Joi.valid(config);
+ }
+
+ Hoek.assert(config === null, 'Invalid schema content:', config);
+
+ return Joi.valid(null);
+};
+
+
+exports.ref = function (id) {
+
+ return Ref.isRef(id) ? id : Ref.create(id);
+};
diff --git a/node_modules/joi/lib/errors.js b/node_modules/joi/lib/errors.js
new file mode 100755
index 00000000..f080afb2
--- /dev/null
+++ b/node_modules/joi/lib/errors.js
@@ -0,0 +1,357 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Language = require('./language');
+
+
+// Declare internals
+
+const internals = {
+ annotations: Symbol('joi-annotations')
+};
+
+internals.stringify = function (value, wrapArrays) {
+
+ const type = typeof value;
+
+ if (value === null) {
+ return 'null';
+ }
+
+ if (type === 'string') {
+ return value;
+ }
+
+ if (value instanceof exports.Err || type === 'function' || type === 'symbol') {
+ return value.toString();
+ }
+
+ if (type === 'object') {
+ if (Array.isArray(value)) {
+ let partial = '';
+
+ for (let i = 0; i < value.length; ++i) {
+ partial = partial + (partial.length ? ', ' : '') + internals.stringify(value[i], wrapArrays);
+ }
+
+ return wrapArrays ? '[' + partial + ']' : partial;
+ }
+
+ return value.toString();
+ }
+
+ return JSON.stringify(value);
+};
+
+exports.Err = class {
+
+ constructor(type, context, state, options, flags, message, template) {
+
+ this.isJoi = true;
+ this.type = type;
+ this.context = context || {};
+ this.context.key = state.path[state.path.length - 1];
+ this.context.label = state.key;
+ this.path = state.path;
+ this.options = options;
+ this.flags = flags;
+ this.message = message;
+ this.template = template;
+
+ const localized = this.options.language;
+
+ if (this.flags.label) {
+ this.context.label = this.flags.label;
+ }
+ else if (localized && // language can be null for arrays exclusion check
+ (this.context.label === '' ||
+ this.context.label === null)) {
+ this.context.label = localized.root || Language.errors.root;
+ }
+ }
+
+ toString() {
+
+ if (this.message) {
+ return this.message;
+ }
+
+ let format;
+
+ if (this.template) {
+ format = this.template;
+ }
+
+ const localized = this.options.language;
+
+ format = format || Hoek.reach(localized, this.type) || Hoek.reach(Language.errors, this.type);
+
+ if (format === undefined) {
+ return `Error code "${this.type}" is not defined, your custom type is missing the correct language definition`;
+ }
+
+ let wrapArrays = Hoek.reach(localized, 'messages.wrapArrays');
+ if (typeof wrapArrays !== 'boolean') {
+ wrapArrays = Language.errors.messages.wrapArrays;
+ }
+
+ if (format === null) {
+ const childrenString = internals.stringify(this.context.reason, wrapArrays);
+ if (wrapArrays) {
+ return childrenString.slice(1, -1);
+ }
+ return childrenString;
+ }
+
+ const hasKey = /\{\{\!?label\}\}/.test(format);
+ const skipKey = format.length > 2 && format[0] === '!' && format[1] === '!';
+
+ if (skipKey) {
+ format = format.slice(2);
+ }
+
+ if (!hasKey && !skipKey) {
+ format = (Hoek.reach(localized, 'key') || Hoek.reach(Language.errors, 'key')) + format;
+ }
+
+ return format.replace(/\{\{(\!?)([^}]+)\}\}/g, ($0, isSecure, name) => {
+
+ const value = Hoek.reach(this.context, name);
+ const normalized = internals.stringify(value, wrapArrays);
+ return (isSecure ? Hoek.escapeHtml(normalized) : normalized);
+ });
+ }
+
+};
+
+
+exports.create = function (type, context, state, options, flags, message, template) {
+
+ return new exports.Err(type, context, state, options, flags, message, template);
+};
+
+
+exports.process = function (errors, object) {
+
+ if (!errors || !errors.length) {
+ return null;
+ }
+
+ // Construct error
+
+ let message = '';
+ const details = [];
+
+ const processErrors = function (localErrors, parent) {
+
+ for (let i = 0; i < localErrors.length; ++i) {
+ const item = localErrors[i];
+
+ if (item instanceof Error) {
+ return item;
+ }
+
+ if (item.flags.error && typeof item.flags.error !== 'function') {
+ return item.flags.error;
+ }
+
+ let itemMessage;
+ if (parent === undefined) {
+ itemMessage = item.toString();
+ message = message + (message ? '. ' : '') + itemMessage;
+ }
+
+ // Do not push intermediate errors, we're only interested in leafs
+
+ if (item.context.reason && item.context.reason.length) {
+ const override = processErrors(item.context.reason, item.path);
+ if (override) {
+ return override;
+ }
+ }
+ else {
+ details.push({
+ message: itemMessage || item.toString(),
+ path: item.path,
+ type: item.type,
+ context: item.context
+ });
+ }
+ }
+ };
+
+ const override = processErrors(errors);
+ if (override) {
+ return override;
+ }
+
+ const error = new Error(message);
+ error.isJoi = true;
+ error.name = 'ValidationError';
+ error.details = details;
+ error._object = object;
+ error.annotate = internals.annotate;
+ return error;
+};
+
+
+// Inspired by json-stringify-safe
+internals.safeStringify = function (obj, spaces) {
+
+ return JSON.stringify(obj, internals.serializer(), spaces);
+};
+
+internals.serializer = function () {
+
+ const keys = [];
+ const stack = [];
+
+ const cycleReplacer = (key, value) => {
+
+ if (stack[0] === value) {
+ return '[Circular ~]';
+ }
+
+ return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
+ };
+
+ return function (key, value) {
+
+ if (stack.length > 0) {
+ const thisPos = stack.indexOf(this);
+ if (~thisPos) {
+ stack.length = thisPos + 1;
+ keys.length = thisPos + 1;
+ keys[thisPos] = key;
+ }
+ else {
+ stack.push(this);
+ keys.push(key);
+ }
+
+ if (~stack.indexOf(value)) {
+ value = cycleReplacer.call(this, key, value);
+ }
+ }
+ else {
+ stack.push(value);
+ }
+
+ if (value) {
+ const annotations = value[internals.annotations];
+ if (annotations) {
+ if (Array.isArray(value)) {
+ const annotated = [];
+
+ for (let i = 0; i < value.length; ++i) {
+ if (annotations.errors[i]) {
+ annotated.push(`_$idx$_${annotations.errors[i].sort().join(', ')}_$end$_`);
+ }
+ annotated.push(value[i]);
+ }
+
+ value = annotated;
+ }
+ else {
+ const errorKeys = Object.keys(annotations.errors);
+ for (let i = 0; i < errorKeys.length; ++i) {
+ const errorKey = errorKeys[i];
+ value[`${errorKey}_$key$_${annotations.errors[errorKey].sort().join(', ')}_$end$_`] = value[errorKey];
+ value[errorKey] = undefined;
+ }
+
+ const missingKeys = Object.keys(annotations.missing);
+ for (let i = 0; i < missingKeys.length; ++i) {
+ const missingKey = missingKeys[i];
+ value[`_$miss$_${missingKey}|${annotations.missing[missingKey]}_$end$_`] = '__missing__';
+ }
+ }
+
+ return value;
+ }
+ }
+
+ if (value === Infinity || value === -Infinity || Number.isNaN(value) ||
+ typeof value === 'function' || typeof value === 'symbol') {
+ return '[' + value.toString() + ']';
+ }
+
+ return value;
+ };
+};
+
+
+internals.annotate = function (stripColorCodes) {
+
+ const redFgEscape = stripColorCodes ? '' : '\u001b[31m';
+ const redBgEscape = stripColorCodes ? '' : '\u001b[41m';
+ const endColor = stripColorCodes ? '' : '\u001b[0m';
+
+ if (typeof this._object !== 'object') {
+ return this.details[0].message;
+ }
+
+ const obj = Hoek.clone(this._object || {});
+
+ for (let i = this.details.length - 1; i >= 0; --i) { // Reverse order to process deepest child first
+ const pos = i + 1;
+ const error = this.details[i];
+ const path = error.path;
+ let ref = obj;
+ for (let j = 0; ; ++j) {
+ const seg = path[j];
+
+ if (ref.isImmutable) {
+ ref = ref.clone(); // joi schemas are not cloned by hoek, we have to take this extra step
+ }
+
+ if (j + 1 < path.length &&
+ ref[seg] &&
+ typeof ref[seg] !== 'string') {
+
+ ref = ref[seg];
+ }
+ else {
+ const refAnnotations = ref[internals.annotations] = ref[internals.annotations] || { errors: {}, missing: {} };
+ const value = ref[seg];
+ const cacheKey = seg || error.context.label;
+
+ if (value !== undefined) {
+ refAnnotations.errors[cacheKey] = refAnnotations.errors[cacheKey] || [];
+ refAnnotations.errors[cacheKey].push(pos);
+ }
+ else {
+ refAnnotations.missing[cacheKey] = pos;
+ }
+
+ break;
+ }
+ }
+ }
+
+ const replacers = {
+ key: /_\$key\$_([, \d]+)_\$end\$_\"/g,
+ missing: /\"_\$miss\$_([^\|]+)\|(\d+)_\$end\$_\"\: \"__missing__\"/g,
+ arrayIndex: /\s*\"_\$idx\$_([, \d]+)_\$end\$_\",?\n(.*)/g,
+ specials: /"\[(NaN|Symbol.*|-?Infinity|function.*|\(.*)\]"/g
+ };
+
+ let message = internals.safeStringify(obj, 2)
+ .replace(replacers.key, ($0, $1) => `" ${redFgEscape}[${$1}]${endColor}`)
+ .replace(replacers.missing, ($0, $1, $2) => `${redBgEscape}"${$1}"${endColor}${redFgEscape} [${$2}]: -- missing --${endColor}`)
+ .replace(replacers.arrayIndex, ($0, $1, $2) => `\n${$2} ${redFgEscape}[${$1}]${endColor}`)
+ .replace(replacers.specials, ($0, $1) => $1);
+
+ message = `${message}\n${redFgEscape}`;
+
+ for (let i = 0; i < this.details.length; ++i) {
+ const pos = i + 1;
+ message = `${message}\n[${pos}] ${this.details[i].message}`;
+ }
+
+ message = message + endColor;
+
+ return message;
+};
diff --git a/node_modules/joi/lib/index.js b/node_modules/joi/lib/index.js
new file mode 100644
index 00000000..24022fdf
--- /dev/null
+++ b/node_modules/joi/lib/index.js
@@ -0,0 +1,434 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Any = require('./types/any');
+const Cast = require('./cast');
+const Errors = require('./errors');
+const Lazy = require('./types/lazy');
+const Ref = require('./ref');
+
+
+// Declare internals
+
+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')
+};
+
+internals.applyDefaults = function (schema) {
+
+ Hoek.assert(this, 'Must be invoked on a Joi instance.');
+
+ if (this._defaults) {
+ schema = this._defaults(schema);
+ }
+
+ schema._currentJoi = this;
+
+ return schema;
+};
+
+internals.root = function () {
+
+ const any = new Any();
+
+ const root = any.clone();
+ Any.prototype._currentJoi = root;
+ root._currentJoi = root;
+
+ root.any = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.any() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, any);
+ };
+
+ root.alternatives = root.alt = function () {
+
+ const alternatives = internals.applyDefaults.call(this, internals.alternatives);
+ return arguments.length ? alternatives.try.apply(alternatives, arguments) : alternatives;
+ };
+
+ root.array = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.array() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.array);
+ };
+
+ root.boolean = root.bool = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.boolean() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.boolean);
+ };
+
+ root.binary = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.binary() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.binary);
+ };
+
+ root.date = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.date() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.date);
+ };
+
+ root.func = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.func() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.func);
+ };
+
+ root.number = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.number() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.number);
+ };
+
+ root.object = function () {
+
+ const object = internals.applyDefaults.call(this, internals.object);
+ return arguments.length ? object.keys.apply(object, arguments) : object;
+ };
+
+ root.string = function () {
+
+ Hoek.assert(arguments.length === 0, 'Joi.string() does not allow arguments.');
+
+ return internals.applyDefaults.call(this, internals.string);
+ };
+
+ root.ref = function () {
+
+ return Ref.create.apply(null, arguments);
+ };
+
+ root.isRef = function (ref) {
+
+ return Ref.isRef(ref);
+ };
+
+ root.validate = function (value /*, [schema], [options], callback */) {
+
+ const last = arguments[arguments.length - 1];
+ const callback = typeof last === 'function' ? last : null;
+
+ const count = arguments.length - (callback ? 1 : 0);
+ if (count === 1) {
+ return any.validate(value, callback);
+ }
+
+ const options = count === 3 ? arguments[2] : {};
+ const schema = root.compile(arguments[1]);
+
+ return schema._validateWithOptions(value, options, callback);
+ };
+
+ root.describe = function () {
+
+ const schema = arguments.length ? root.compile(arguments[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) {
+
+ root.attempt(value, schema, message);
+ };
+
+ root.attempt = function (value, schema, message) {
+
+ const result = root.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(typeof path === 'string', 'path must be a string');
+
+ if (path === '') {
+ return schema;
+ }
+
+ const parts = path.split('.');
+ const children = schema._inner.children;
+ if (!children) {
+ return;
+ }
+
+ const key = parts[0];
+ for (let i = 0; i < children.length; ++i) {
+ const child = children[i];
+ if (child.key === key) {
+ return this.reach(child.schema, path.substr(key.length + 1));
+ }
+ }
+ };
+
+ root.lazy = function (fn) {
+
+ return Lazy.set(fn);
+ };
+
+ 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.extend = function () {
+
+ const extensions = Hoek.flatten(Array.prototype.slice.call(arguments));
+ 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);
+
+ 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) {
+ this._settings = this._settings || { language: {} };
+ this._settings.language = Hoek.applyToDefaults(this._settings.language, {
+ [extension.name]: extension.language
+ });
+ }
+ }
+
+ };
+
+ 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 () { // eslint-disable-line no-loop-func
+
+ if (arguments.length > ruleArgs.length) {
+ throw new Error('Unexpected number of arguments');
+ }
+
+ const args = Array.prototype.slice.call(arguments);
+ let hasRef = false;
+ let arg = {};
+
+ for (let k = 0; k < ruleArgs.length; ++k) {
+ arg[ruleArgs[k]] = args[k];
+ if (!hasRef && Ref.isRef(args[k])) {
+ hasRef = true;
+ }
+ }
+
+ if (validateArgs) {
+ arg = joi.attempt(arg, validateArgs);
+ }
+
+ let schema;
+ if (rule.validate) {
+ 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;
+ }
+ }
+
+ 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 () {
+
+ return internals.applyDefaults.call(this, instance);
+ };
+ }
+
+ 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();
diff --git a/node_modules/joi/lib/language.js b/node_modules/joi/lib/language.js
new file mode 100644
index 00000000..5cf937c7
--- /dev/null
+++ b/node_modules/joi/lib/language.js
@@ -0,0 +1,156 @@
+'use strict';
+
+// Load modules
+
+
+// Declare internals
+
+const internals = {};
+
+
+exports.errors = {
+ root: 'value',
+ key: '"{{!label}}" ',
+ messages: {
+ wrapArrays: true
+ },
+ any: {
+ unknown: 'is not allowed',
+ invalid: 'contains an invalid value',
+ empty: 'is not allowed to be empty',
+ required: 'is required',
+ allowOnly: 'must be one of {{valids}}',
+ default: 'threw an error when running default method'
+ },
+ alternatives: {
+ base: 'not matching any of the allowed alternatives',
+ child: null
+ },
+ array: {
+ base: 'must be an array',
+ includes: 'at position {{pos}} does not match any of the allowed types',
+ includesSingle: 'single value of "{{!label}}" does not match any of the allowed types',
+ includesOne: 'at position {{pos}} fails because {{reason}}',
+ includesOneSingle: 'single value of "{{!label}}" fails because {{reason}}',
+ includesRequiredUnknowns: 'does not contain {{unknownMisses}} required value(s)',
+ includesRequiredKnowns: 'does not contain {{knownMisses}}',
+ includesRequiredBoth: 'does not contain {{knownMisses}} and {{unknownMisses}} other required value(s)',
+ excludes: 'at position {{pos}} contains an excluded value',
+ excludesSingle: 'single value of "{{!label}}" contains an excluded value',
+ min: 'must contain at least {{limit}} items',
+ max: 'must contain less than or equal to {{limit}} items',
+ length: 'must contain {{limit}} items',
+ ordered: 'at position {{pos}} fails because {{reason}}',
+ orderedLength: 'at position {{pos}} fails because array must contain at most {{limit}} items',
+ ref: 'references "{{ref}}" which is not a positive integer',
+ sparse: 'must not be a sparse array',
+ unique: 'position {{pos}} contains a duplicate value'
+ },
+ boolean: {
+ base: 'must be a boolean'
+ },
+ binary: {
+ base: 'must be a buffer or a string',
+ min: 'must be at least {{limit}} bytes',
+ max: 'must be less than or equal to {{limit}} bytes',
+ length: 'must be {{limit}} bytes'
+ },
+ date: {
+ base: 'must be a number of milliseconds or valid date string',
+ format: 'must be a string with one of the following formats {{format}}',
+ strict: 'must be a valid date',
+ min: 'must be larger than or equal to "{{limit}}"',
+ max: 'must be less than or equal to "{{limit}}"',
+ isoDate: 'must be a valid ISO 8601 date',
+ timestamp: {
+ javascript: 'must be a valid timestamp or number of milliseconds',
+ unix: 'must be a valid timestamp or number of seconds'
+ },
+ ref: 'references "{{ref}}" which is not a date'
+ },
+ function: {
+ base: 'must be a Function',
+ arity: 'must have an arity of {{n}}',
+ minArity: 'must have an arity greater or equal to {{n}}',
+ maxArity: 'must have an arity lesser or equal to {{n}}',
+ ref: 'must be a Joi reference',
+ class: 'must be a class'
+ },
+ lazy: {
+ base: '!!schema error: lazy schema must be set',
+ schema: '!!schema error: lazy schema function must return a schema'
+ },
+ object: {
+ base: 'must be an object',
+ child: '!!child "{{!child}}" fails because {{reason}}',
+ min: 'must have at least {{limit}} children',
+ max: 'must have less than or equal to {{limit}} children',
+ length: 'must have {{limit}} children',
+ allowUnknown: '!!"{{!child}}" is not allowed',
+ with: '!!"{{mainWithLabel}}" missing required peer "{{peerWithLabel}}"',
+ without: '!!"{{mainWithLabel}}" conflict with forbidden peer "{{peerWithLabel}}"',
+ missing: 'must contain at least one of {{peersWithLabels}}',
+ xor: 'contains a conflict between exclusive peers {{peersWithLabels}}',
+ or: 'must contain at least one of {{peersWithLabels}}',
+ and: 'contains {{presentWithLabels}} without its required peers {{missingWithLabels}}',
+ nand: '!!"{{mainWithLabel}}" must not exist simultaneously with {{peersWithLabels}}',
+ assert: '!!"{{ref}}" validation failed because "{{ref}}" failed to {{message}}',
+ rename: {
+ multiple: 'cannot rename child "{{from}}" because multiple renames are disabled and another key was already renamed to "{{to}}"',
+ override: 'cannot rename child "{{from}}" because override is disabled and target "{{to}}" exists',
+ regex: {
+ multiple: 'cannot rename children {{from}} because multiple renames are disabled and another key was already renamed to "{{to}}"',
+ override: 'cannot rename children {{from}} because override is disabled and target "{{to}}" exists'
+ }
+ },
+ type: 'must be an instance of "{{type}}"',
+ schema: 'must be a Joi instance'
+ },
+ number: {
+ base: 'must be a number',
+ min: 'must be larger than or equal to {{limit}}',
+ max: 'must be less than or equal to {{limit}}',
+ less: 'must be less than {{limit}}',
+ greater: 'must be greater than {{limit}}',
+ float: 'must be a float or double',
+ integer: 'must be an integer',
+ negative: 'must be a negative number',
+ positive: 'must be a positive number',
+ precision: 'must have no more than {{limit}} decimal places',
+ ref: 'references "{{ref}}" which is not a number',
+ multiple: 'must be a multiple of {{multiple}}'
+ },
+ string: {
+ base: 'must be a string',
+ min: 'length must be at least {{limit}} characters long',
+ max: 'length must be less than or equal to {{limit}} characters long',
+ length: 'length must be {{limit}} characters long',
+ alphanum: 'must only contain alpha-numeric characters',
+ token: 'must only contain alpha-numeric and underscore characters',
+ regex: {
+ base: 'with value "{{!value}}" fails to match the required pattern: {{pattern}}',
+ name: 'with value "{{!value}}" fails to match the {{name}} pattern',
+ invert: {
+ base: 'with value "{{!value}}" matches the inverted pattern: {{pattern}}',
+ name: 'with value "{{!value}}" matches the inverted {{name}} pattern'
+ }
+ },
+ email: 'must be a valid email',
+ uri: 'must be a valid uri',
+ uriRelativeOnly: 'must be a valid relative uri',
+ uriCustomScheme: 'must be a valid uri with a scheme matching the {{scheme}} pattern',
+ isoDate: 'must be a valid ISO 8601 date',
+ guid: 'must be a valid GUID',
+ hex: 'must only contain hexadecimal characters',
+ base64: 'must be a valid base64 string',
+ hostname: 'must be a valid hostname',
+ normalize: 'must be unicode normalized in the {{form}} form',
+ lowercase: 'must only contain lowercase characters',
+ uppercase: 'must only contain uppercase characters',
+ trim: 'must not have leading or trailing whitespace',
+ creditCard: 'must be a credit card',
+ ref: 'references "{{ref}}" which is not a number',
+ ip: 'must be a valid ip address with a {{cidr}} CIDR',
+ ipVersion: 'must be a valid ip address of one of the following versions {{version}} with a {{cidr}} CIDR'
+ }
+};
diff --git a/node_modules/joi/lib/ref.js b/node_modules/joi/lib/ref.js
new file mode 100644
index 00000000..f0bcd87e
--- /dev/null
+++ b/node_modules/joi/lib/ref.js
@@ -0,0 +1,53 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {};
+
+
+exports.create = function (key, options) {
+
+ Hoek.assert(typeof key === 'string', 'Invalid reference key:', key);
+
+ const settings = Hoek.clone(options); // options can be reused and modified
+
+ const ref = function (value, validationOptions) {
+
+ return Hoek.reach(ref.isContext ? validationOptions.context : value, ref.key, settings);
+ };
+
+ ref.isContext = (key[0] === ((settings && settings.contextPrefix) || '$'));
+ ref.key = (ref.isContext ? key.slice(1) : key);
+ ref.path = ref.key.split((settings && settings.separator) || '.');
+ ref.depth = ref.path.length;
+ ref.root = ref.path[0];
+ ref.isJoi = true;
+
+ ref.toString = function () {
+
+ return (ref.isContext ? 'context:' : 'ref:') + ref.key;
+ };
+
+ return ref;
+};
+
+
+exports.isRef = function (ref) {
+
+ return typeof ref === 'function' && ref.isJoi;
+};
+
+
+exports.push = function (array, ref) {
+
+ if (exports.isRef(ref) &&
+ !ref.isContext) {
+
+ array.push(ref.root);
+ }
+};
diff --git a/node_modules/joi/lib/schemas.js b/node_modules/joi/lib/schemas.js
new file mode 100644
index 00000000..efbd028f
--- /dev/null
+++ b/node_modules/joi/lib/schemas.js
@@ -0,0 +1,24 @@
+'use strict';
+
+// Load modules
+
+const Joi = require('../');
+
+
+// Declare internals
+
+const internals = {};
+
+exports.options = Joi.object({
+ abortEarly: Joi.boolean(),
+ convert: Joi.boolean(),
+ allowUnknown: Joi.boolean(),
+ skipFunctions: Joi.boolean(),
+ stripUnknown: [Joi.boolean(), Joi.object({ arrays: Joi.boolean(), objects: Joi.boolean() }).or('arrays', 'objects')],
+ language: Joi.object(),
+ presence: Joi.string().only('required', 'optional', 'forbidden', 'ignore'),
+ raw: Joi.boolean(),
+ context: Joi.object(),
+ strip: Joi.boolean(),
+ noDefaults: Joi.boolean()
+}).strict();
diff --git a/node_modules/joi/lib/set.js b/node_modules/joi/lib/set.js
new file mode 100644
index 00000000..5a9b6550
--- /dev/null
+++ b/node_modules/joi/lib/set.js
@@ -0,0 +1,111 @@
+'use strict';
+
+const Ref = require('./ref');
+
+module.exports = class Set {
+
+ constructor() {
+
+ this._set = [];
+ }
+
+ add(value, refs) {
+
+ if (!Ref.isRef(value) && this.has(value, null, null, false)) {
+
+ return;
+ }
+
+ if (refs !== undefined) { // If it's a merge, we don't have any refs
+ Ref.push(refs, value);
+ }
+
+ this._set.push(value);
+ return this;
+ }
+
+ merge(add, remove) {
+
+ for (let i = 0; i < add._set.length; ++i) {
+ this.add(add._set[i]);
+ }
+
+ for (let i = 0; i < remove._set.length; ++i) {
+ this.remove(remove._set[i]);
+ }
+
+ return this;
+ }
+
+ remove(value) {
+
+ this._set = this._set.filter((item) => value !== item);
+ return this;
+ }
+
+ has(value, state, options, insensitive) {
+
+ for (let i = 0; i < this._set.length; ++i) {
+ let items = this._set[i];
+
+ if (state && Ref.isRef(items)) { // Only resolve references if there is a state, otherwise it's a merge
+ items = items(state.reference || state.parent, options);
+ }
+
+ if (!Array.isArray(items)) {
+ items = [items];
+ }
+
+ for (let j = 0; j < items.length; ++j) {
+ const item = items[j];
+ if (typeof value !== typeof item) {
+ continue;
+ }
+
+ if (value === item ||
+ (value instanceof Date && item instanceof Date && value.getTime() === item.getTime()) ||
+ (insensitive && typeof value === 'string' && value.toLowerCase() === item.toLowerCase()) ||
+ (Buffer.isBuffer(value) && Buffer.isBuffer(item) && value.length === item.length && value.toString('binary') === item.toString('binary'))) {
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ values(options) {
+
+ if (options && options.stripUndefined) {
+ const values = [];
+
+ for (let i = 0; i < this._set.length; ++i) {
+ const item = this._set[i];
+ if (item !== undefined) {
+ values.push(item);
+ }
+ }
+
+ return values;
+ }
+
+ return this._set.slice();
+ }
+
+ slice() {
+
+ const newSet = new Set();
+ newSet._set = this._set.slice();
+
+ return newSet;
+ }
+
+ concat(source) {
+
+ const newSet = new Set();
+ newSet._set = this._set.concat(source._set);
+
+ return newSet;
+ }
+};
diff --git a/node_modules/joi/lib/types/alternatives/index.js b/node_modules/joi/lib/types/alternatives/index.js
new file mode 100644
index 00000000..fcbf1fb9
--- /dev/null
+++ b/node_modules/joi/lib/types/alternatives/index.js
@@ -0,0 +1,188 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Any = require('../any');
+const Cast = require('../../cast');
+const Ref = require('../../ref');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.Alternatives = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'alternatives';
+ this._invalids.remove(null);
+ this._inner.matches = [];
+ }
+
+ _base(value, state, options) {
+
+ let errors = [];
+ const il = this._inner.matches.length;
+ const baseType = this._baseType;
+
+ for (let i = 0; i < il; ++i) {
+ const item = this._inner.matches[i];
+ if (!item.schema) {
+ const schema = item.peek || item.is;
+ const input = item.is ? item.ref(state.reference || state.parent, options) : value;
+ const failed = schema._validate(input, null, options, state.parent).errors;
+
+ if (failed) {
+ if (item.otherwise) {
+ return item.otherwise._validate(value, state, options);
+ }
+ }
+ else if (item.then) {
+ return item.then._validate(value, state, options);
+ }
+
+ if (i === (il - 1) && baseType) {
+ return baseType._validate(value, state, options);
+ }
+
+ continue;
+ }
+
+ const result = item.schema._validate(value, state, options);
+ if (!result.errors) { // Found a valid match
+ return result;
+ }
+
+ errors = errors.concat(result.errors);
+ }
+
+ if (errors.length) {
+ return { errors: this.createError('alternatives.child', { reason: errors }, state, options) };
+ }
+
+ return { errors: this.createError('alternatives.base', null, state, options) };
+ }
+
+ try(/* schemas */) {
+
+ const schemas = Hoek.flatten(Array.prototype.slice.call(arguments));
+ Hoek.assert(schemas.length, 'Cannot add other alternatives without at least one schema');
+
+ const obj = this.clone();
+
+ for (let i = 0; i < schemas.length; ++i) {
+ const cast = Cast.schema(this._currentJoi, schemas[i]);
+ if (cast._refs.length) {
+ obj._refs = obj._refs.concat(cast._refs);
+ }
+ obj._inner.matches.push({ schema: cast });
+ }
+
+ return obj;
+ }
+
+ when(condition, options) {
+
+ let schemaCondition = false;
+ Hoek.assert(Ref.isRef(condition) || typeof condition === 'string' || (schemaCondition = condition instanceof Any), 'Invalid condition:', condition);
+ Hoek.assert(options, 'Missing options');
+ Hoek.assert(typeof options === 'object', 'Invalid options');
+ if (schemaCondition) {
+ Hoek.assert(!options.hasOwnProperty('is'), '"is" can not be used with a schema condition');
+ }
+ else {
+ Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
+ }
+ Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
+
+ const obj = this.clone();
+ let is;
+ if (!schemaCondition) {
+ is = Cast.schema(this._currentJoi, options.is);
+
+ if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) {
+
+ // Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing
+ is = is.required();
+ }
+ }
+
+ const item = {
+ ref: schemaCondition ? null : Cast.ref(condition),
+ peek: schemaCondition ? condition : null,
+ is,
+ then: options.then !== undefined ? Cast.schema(this._currentJoi, options.then) : undefined,
+ otherwise: options.otherwise !== undefined ? Cast.schema(this._currentJoi, options.otherwise) : undefined
+ };
+
+ if (obj._baseType) {
+
+ item.then = item.then && obj._baseType.concat(item.then);
+ item.otherwise = item.otherwise && obj._baseType.concat(item.otherwise);
+ }
+
+ if (!schemaCondition) {
+ Ref.push(obj._refs, item.ref);
+ obj._refs = obj._refs.concat(item.is._refs);
+ }
+
+ if (item.then && item.then._refs) {
+ obj._refs = obj._refs.concat(item.then._refs);
+ }
+
+ if (item.otherwise && item.otherwise._refs) {
+ obj._refs = obj._refs.concat(item.otherwise._refs);
+ }
+
+ obj._inner.matches.push(item);
+
+ return obj;
+ }
+
+ describe() {
+
+ const description = Any.prototype.describe.call(this);
+ const alternatives = [];
+ for (let i = 0; i < this._inner.matches.length; ++i) {
+ const item = this._inner.matches[i];
+ if (item.schema) {
+
+ // try()
+
+ alternatives.push(item.schema.describe());
+ }
+ else {
+
+ // when()
+
+ const when = item.is ? {
+ ref: item.ref.toString(),
+ is: item.is.describe()
+ } : {
+ peek: item.peek.describe()
+ };
+
+ if (item.then) {
+ when.then = item.then.describe();
+ }
+
+ if (item.otherwise) {
+ when.otherwise = item.otherwise.describe();
+ }
+
+ alternatives.push(when);
+ }
+ }
+
+ description.alternatives = alternatives;
+ return description;
+ }
+
+};
+
+
+module.exports = new internals.Alternatives();
diff --git a/node_modules/joi/lib/types/any/index.js b/node_modules/joi/lib/types/any/index.js
new file mode 100644
index 00000000..56afbb15
--- /dev/null
+++ b/node_modules/joi/lib/types/any/index.js
@@ -0,0 +1,916 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Ref = require('../../ref');
+const Errors = require('../../errors');
+let Alternatives = null; // Delay-loaded to prevent circular dependencies
+let Cast = null;
+
+
+// Declare internals
+
+const internals = {
+ Set: require('../../set')
+};
+
+
+internals.defaults = {
+ abortEarly: true,
+ convert: true,
+ allowUnknown: false,
+ skipFunctions: false,
+ stripUnknown: false,
+ language: {},
+ presence: 'optional',
+ strip: false,
+ noDefaults: false
+
+ // context: null
+};
+
+
+module.exports = internals.Any = class {
+
+ constructor() {
+
+ Cast = Cast || require('../../cast');
+
+ this.isJoi = true;
+ this._type = 'any';
+ this._settings = null;
+ this._valids = new internals.Set();
+ this._invalids = new internals.Set();
+ this._tests = [];
+ this._refs = [];
+ this._flags = {
+ /*
+ presence: 'optional', // optional, required, forbidden, ignore
+ allowOnly: false,
+ allowUnknown: undefined,
+ default: undefined,
+ forbidden: false,
+ encoding: undefined,
+ insensitive: false,
+ trim: false,
+ normalize: undefined, // NFC, NFD, NFKC, NFKD
+ case: undefined, // upper, lower
+ empty: undefined,
+ func: false,
+ raw: false
+ */
+ };
+
+ this._description = null;
+ this._unit = null;
+ this._notes = [];
+ this._tags = [];
+ this._examples = [];
+ this._meta = [];
+
+ this._inner = {}; // Hash of arrays of immutable objects
+ }
+
+ get schemaType() {
+
+ return this._type;
+ }
+
+ createError(type, context, state, options, flags) {
+
+ return Errors.create(type, context, state, options, flags || this._flags);
+ }
+
+ createOverrideError(type, context, state, options, message, template) {
+
+ return Errors.create(type, context, state, options, this._flags, message, template);
+ }
+
+ checkOptions(options) {
+
+ const Schemas = require('../../schemas');
+ const result = Schemas.options.validate(options);
+ if (result.error) {
+ throw new Error(result.error.details[0].message);
+ }
+ }
+
+ clone() {
+
+ const obj = Object.create(Object.getPrototypeOf(this));
+
+ obj.isJoi = true;
+ obj._currentJoi = this._currentJoi;
+ obj._type = this._type;
+ obj._settings = internals.concatSettings(this._settings);
+ obj._baseType = this._baseType;
+ obj._valids = Hoek.clone(this._valids);
+ obj._invalids = Hoek.clone(this._invalids);
+ obj._tests = this._tests.slice();
+ obj._refs = this._refs.slice();
+ obj._flags = Hoek.clone(this._flags);
+
+ obj._description = this._description;
+ obj._unit = this._unit;
+ obj._notes = this._notes.slice();
+ obj._tags = this._tags.slice();
+ obj._examples = this._examples.slice();
+ obj._meta = this._meta.slice();
+
+ obj._inner = {};
+ const inners = Object.keys(this._inner);
+ for (let i = 0; i < inners.length; ++i) {
+ const key = inners[i];
+ obj._inner[key] = this._inner[key] ? this._inner[key].slice() : null;
+ }
+
+ return obj;
+ }
+
+ concat(schema) {
+
+ Hoek.assert(schema instanceof internals.Any, 'Invalid schema object');
+ Hoek.assert(this._type === 'any' || schema._type === 'any' || schema._type === this._type, 'Cannot merge type', this._type, 'with another type:', schema._type);
+
+ let obj = this.clone();
+
+ if (this._type === 'any' && schema._type !== 'any') {
+
+ // Reset values as if we were "this"
+ const tmpObj = schema.clone();
+ const keysToRestore = ['_settings', '_valids', '_invalids', '_tests', '_refs', '_flags', '_description', '_unit',
+ '_notes', '_tags', '_examples', '_meta', '_inner'];
+
+ for (let i = 0; i < keysToRestore.length; ++i) {
+ tmpObj[keysToRestore[i]] = obj[keysToRestore[i]];
+ }
+
+ obj = tmpObj;
+ }
+
+ obj._settings = obj._settings ? internals.concatSettings(obj._settings, schema._settings) : schema._settings;
+ obj._valids.merge(schema._valids, schema._invalids);
+ obj._invalids.merge(schema._invalids, schema._valids);
+ obj._tests = obj._tests.concat(schema._tests);
+ obj._refs = obj._refs.concat(schema._refs);
+ Hoek.merge(obj._flags, schema._flags);
+
+ obj._description = schema._description || obj._description;
+ obj._unit = schema._unit || obj._unit;
+ obj._notes = obj._notes.concat(schema._notes);
+ obj._tags = obj._tags.concat(schema._tags);
+ obj._examples = obj._examples.concat(schema._examples);
+ obj._meta = obj._meta.concat(schema._meta);
+
+ const inners = Object.keys(schema._inner);
+ const isObject = obj._type === 'object';
+ for (let i = 0; i < inners.length; ++i) {
+ const key = inners[i];
+ const source = schema._inner[key];
+ if (source) {
+ const target = obj._inner[key];
+ if (target) {
+ if (isObject && key === 'children') {
+ const keys = {};
+
+ for (let j = 0; j < target.length; ++j) {
+ keys[target[j].key] = j;
+ }
+
+ for (let j = 0; j < source.length; ++j) {
+ const sourceKey = source[j].key;
+ if (keys[sourceKey] >= 0) {
+ target[keys[sourceKey]] = {
+ key: sourceKey,
+ schema: target[keys[sourceKey]].schema.concat(source[j].schema)
+ };
+ }
+ else {
+ target.push(source[j]);
+ }
+ }
+ }
+ else {
+ obj._inner[key] = obj._inner[key].concat(source);
+ }
+ }
+ else {
+ obj._inner[key] = source.slice();
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ _test(name, arg, func, options) {
+
+ const obj = this.clone();
+ obj._tests.push({ func, name, arg, options });
+ return obj;
+ }
+
+ options(options) {
+
+ Hoek.assert(!options.context, 'Cannot override context');
+ this.checkOptions(options);
+
+ const obj = this.clone();
+ obj._settings = internals.concatSettings(obj._settings, options);
+ return obj;
+ }
+
+ strict(isStrict) {
+
+ const obj = this.clone();
+ obj._settings = obj._settings || {};
+ obj._settings.convert = isStrict === undefined ? false : !isStrict;
+ return obj;
+ }
+
+ raw(isRaw) {
+
+ const value = isRaw === undefined ? true : isRaw;
+
+ if (this._flags.raw === value) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.raw = value;
+ return obj;
+ }
+
+ error(err) {
+
+ Hoek.assert(err && (err instanceof Error || typeof err === 'function'), 'Must provide a valid Error object or a function');
+
+ const obj = this.clone();
+ obj._flags.error = err;
+ return obj;
+ }
+
+ allow() {
+
+ const obj = this.clone();
+ const values = Hoek.flatten(Array.prototype.slice.call(arguments));
+ for (let i = 0; i < values.length; ++i) {
+ const value = values[i];
+
+ Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
+ obj._invalids.remove(value);
+ obj._valids.add(value, obj._refs);
+ }
+ return obj;
+ }
+
+ valid() {
+
+ const obj = this.allow.apply(this, arguments);
+ obj._flags.allowOnly = true;
+ return obj;
+ }
+
+ invalid(value) {
+
+ const obj = this.clone();
+ const values = Hoek.flatten(Array.prototype.slice.call(arguments));
+ for (let i = 0; i < values.length; ++i) {
+ value = values[i];
+
+ Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
+ obj._valids.remove(value);
+ obj._invalids.add(value, obj._refs);
+ }
+
+ return obj;
+ }
+
+ required() {
+
+ if (this._flags.presence === 'required') {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.presence = 'required';
+ return obj;
+ }
+
+ optional() {
+
+ if (this._flags.presence === 'optional') {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.presence = 'optional';
+ return obj;
+ }
+
+
+ forbidden() {
+
+ if (this._flags.presence === 'forbidden') {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.presence = 'forbidden';
+ return obj;
+ }
+
+
+ strip() {
+
+ if (this._flags.strip) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.strip = true;
+ return obj;
+ }
+
+ applyFunctionToChildren(children, fn, args, root) {
+
+ children = [].concat(children);
+
+ if (children.length !== 1 || children[0] !== '') {
+ root = root ? (root + '.') : '';
+
+ const extraChildren = (children[0] === '' ? children.slice(1) : children).map((child) => {
+
+ return root + child;
+ });
+
+ throw new Error('unknown key(s) ' + extraChildren.join(', '));
+ }
+
+ return this[fn].apply(this, args);
+ }
+
+ default(value, description) {
+
+ if (typeof value === 'function' &&
+ !Ref.isRef(value)) {
+
+ if (!value.description &&
+ description) {
+
+ value.description = description;
+ }
+
+ if (!this._flags.func) {
+ Hoek.assert(typeof value.description === 'string' && value.description.length > 0, 'description must be provided when default value is a function');
+ }
+ }
+
+ const obj = this.clone();
+ obj._flags.default = value;
+ Ref.push(obj._refs, value);
+ return obj;
+ }
+
+ empty(schema) {
+
+ const obj = this.clone();
+ if (schema === undefined) {
+ delete obj._flags.empty;
+ }
+ else {
+ obj._flags.empty = Cast.schema(this._currentJoi, schema);
+ }
+ return obj;
+ }
+
+ when(condition, options) {
+
+ Hoek.assert(options && typeof options === 'object', 'Invalid options');
+ Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
+
+ const then = options.hasOwnProperty('then') ? this.concat(Cast.schema(this._currentJoi, options.then)) : undefined;
+ const otherwise = options.hasOwnProperty('otherwise') ? this.concat(Cast.schema(this._currentJoi, options.otherwise)) : undefined;
+
+ Alternatives = Alternatives || require('../alternatives');
+
+ const alternativeOptions = { then, otherwise };
+ if (Object.prototype.hasOwnProperty.call(options, 'is')) {
+ alternativeOptions.is = options.is;
+ }
+ const obj = Alternatives.when(condition, alternativeOptions);
+ obj._flags.presence = 'ignore';
+ obj._baseType = this;
+
+ return obj;
+ }
+
+ description(desc) {
+
+ Hoek.assert(desc && typeof desc === 'string', 'Description must be a non-empty string');
+
+ const obj = this.clone();
+ obj._description = desc;
+ return obj;
+ }
+
+ notes(notes) {
+
+ Hoek.assert(notes && (typeof notes === 'string' || Array.isArray(notes)), 'Notes must be a non-empty string or array');
+
+ const obj = this.clone();
+ obj._notes = obj._notes.concat(notes);
+ return obj;
+ }
+
+ tags(tags) {
+
+ Hoek.assert(tags && (typeof tags === 'string' || Array.isArray(tags)), 'Tags must be a non-empty string or array');
+
+ const obj = this.clone();
+ obj._tags = obj._tags.concat(tags);
+ return obj;
+ }
+
+ meta(meta) {
+
+ Hoek.assert(meta !== undefined, 'Meta cannot be undefined');
+
+ const obj = this.clone();
+ obj._meta = obj._meta.concat(meta);
+ return obj;
+ }
+
+ example(value) {
+
+ Hoek.assert(arguments.length, 'Missing example');
+ const result = this._validate(value, null, internals.defaults);
+ Hoek.assert(!result.errors, 'Bad example:', result.errors && Errors.process(result.errors, value));
+
+ const obj = this.clone();
+ obj._examples.push(value);
+ return obj;
+ }
+
+ unit(name) {
+
+ Hoek.assert(name && typeof name === 'string', 'Unit name must be a non-empty string');
+
+ const obj = this.clone();
+ obj._unit = name;
+ return obj;
+ }
+
+ _prepareEmptyValue(value) {
+
+ if (typeof value === 'string' && this._flags.trim) {
+ return value.trim();
+ }
+
+ return value;
+ }
+
+ _validate(value, state, options, reference) {
+
+ const originalValue = value;
+
+ // Setup state and settings
+
+ state = state || { key: '', path: [], parent: null, reference };
+
+ if (this._settings) {
+ options = internals.concatSettings(options, this._settings);
+ }
+
+ let errors = [];
+ const finish = () => {
+
+ let finalValue;
+
+ if (value !== undefined) {
+ finalValue = this._flags.raw ? originalValue : value;
+ }
+ else if (options.noDefaults) {
+ finalValue = value;
+ }
+ else if (Ref.isRef(this._flags.default)) {
+ finalValue = this._flags.default(state.parent, options);
+ }
+ else if (typeof this._flags.default === 'function' &&
+ !(this._flags.func && !this._flags.default.description)) {
+
+ let args;
+
+ if (state.parent !== null &&
+ this._flags.default.length > 0) {
+
+ args = [Hoek.clone(state.parent), options];
+ }
+
+ const defaultValue = internals._try(this._flags.default, args);
+ finalValue = defaultValue.value;
+ if (defaultValue.error) {
+ errors.push(this.createError('any.default', { error: defaultValue.error }, state, options));
+ }
+ }
+ else {
+ finalValue = Hoek.clone(this._flags.default);
+ }
+
+ if (errors.length && typeof this._flags.error === 'function') {
+ const change = this._flags.error.call(this, errors);
+
+ if (typeof change === 'string') {
+ errors = [this.createOverrideError('override', { reason: errors }, state, options, change)];
+ }
+ else {
+ errors = [].concat(change)
+ .map((err) => {
+
+ return err instanceof Error ?
+ err :
+ this.createOverrideError(err.type || 'override', err.context, state, options, err.message, err.template);
+ });
+ }
+ }
+
+ return {
+ value: this._flags.strip ? undefined : finalValue,
+ finalValue,
+ errors: errors.length ? errors : null
+ };
+ };
+
+ if (this._coerce) {
+ const coerced = this._coerce.call(this, value, state, options);
+ if (coerced.errors) {
+ value = coerced.value;
+ errors = errors.concat(coerced.errors);
+ return finish(); // Coerced error always aborts early
+ }
+
+ value = coerced.value;
+ }
+
+ if (this._flags.empty && !this._flags.empty._validate(this._prepareEmptyValue(value), null, internals.defaults).errors) {
+ value = undefined;
+ }
+
+ // Check presence requirements
+
+ const presence = this._flags.presence || options.presence;
+ if (presence === 'optional') {
+ if (value === undefined) {
+ const isDeepDefault = this._flags.hasOwnProperty('default') && this._flags.default === undefined;
+ if (isDeepDefault && this._type === 'object') {
+ value = {};
+ }
+ else {
+ return finish();
+ }
+ }
+ }
+ else if (presence === 'required' &&
+ value === undefined) {
+
+ errors.push(this.createError('any.required', null, state, options));
+ return finish();
+ }
+ else if (presence === 'forbidden') {
+ if (value === undefined) {
+ return finish();
+ }
+
+ errors.push(this.createError('any.unknown', null, state, options));
+ return finish();
+ }
+
+ // Check allowed and denied values using the original value
+
+ if (this._valids.has(value, state, options, this._flags.insensitive)) {
+ return finish();
+ }
+
+ if (this._invalids.has(value, state, options, this._flags.insensitive)) {
+ errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', null, state, options));
+ if (options.abortEarly ||
+ value === undefined) { // No reason to keep validating missing value
+
+ return finish();
+ }
+ }
+
+ // Convert value and validate type
+
+ if (this._base) {
+ const base = this._base.call(this, value, state, options);
+ if (base.errors) {
+ value = base.value;
+ errors = errors.concat(base.errors);
+ return finish(); // Base error always aborts early
+ }
+
+ if (base.value !== value) {
+ value = base.value;
+
+ // Check allowed and denied values using the converted value
+
+ if (this._valids.has(value, state, options, this._flags.insensitive)) {
+ return finish();
+ }
+
+ if (this._invalids.has(value, state, options, this._flags.insensitive)) {
+ errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', null, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+ }
+ }
+
+ // Required values did not match
+
+ if (this._flags.allowOnly) {
+ errors.push(this.createError('any.allowOnly', { valids: this._valids.values({ stripUndefined: true }) }, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ // Helper.validate tests
+
+ for (let i = 0; i < this._tests.length; ++i) {
+ const test = this._tests[i];
+ const ret = test.func.call(this, value, state, options);
+ if (ret instanceof Errors.Err) {
+ errors.push(ret);
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+ else {
+ value = ret;
+ }
+ }
+
+ return finish();
+ }
+
+ _validateWithOptions(value, options, callback) {
+
+ if (options) {
+ this.checkOptions(options);
+ }
+
+ const settings = internals.concatSettings(internals.defaults, options);
+ const result = this._validate(value, null, settings);
+ const errors = Errors.process(result.errors, value);
+
+ if (callback) {
+ return callback(errors, result.value);
+ }
+
+ return {
+ error: errors,
+ value: result.value,
+ then(resolve, reject) {
+
+ if (errors) {
+ return Promise.reject(errors).catch(reject);
+ }
+
+ return Promise.resolve(result.value).then(resolve);
+ },
+ catch(reject) {
+
+ if (errors) {
+ return Promise.reject(errors).catch(reject);
+ }
+
+ return Promise.resolve(result.value);
+ }
+ };
+ }
+
+ validate(value, options, callback) {
+
+ if (typeof options === 'function') {
+ return this._validateWithOptions(value, null, options);
+ }
+
+ return this._validateWithOptions(value, options, callback);
+ }
+
+ describe() {
+
+ const description = {
+ type: this._type
+ };
+
+ const flags = Object.keys(this._flags);
+ if (flags.length) {
+ if (['empty', 'default', 'lazy', 'label'].some((flag) => this._flags.hasOwnProperty(flag))) {
+ description.flags = {};
+ for (let i = 0; i < flags.length; ++i) {
+ const flag = flags[i];
+ if (flag === 'empty') {
+ description.flags[flag] = this._flags[flag].describe();
+ }
+ else if (flag === 'default') {
+ if (Ref.isRef(this._flags[flag])) {
+ description.flags[flag] = this._flags[flag].toString();
+ }
+ else if (typeof this._flags[flag] === 'function') {
+ description.flags[flag] = {
+ description: this._flags[flag].description,
+ function : this._flags[flag]
+ };
+ }
+ else {
+ description.flags[flag] = this._flags[flag];
+ }
+ }
+ else if (flag === 'lazy' || flag === 'label') {
+ // We don't want it in the description
+ }
+ else {
+ description.flags[flag] = this._flags[flag];
+ }
+ }
+ }
+ else {
+ description.flags = this._flags;
+ }
+ }
+
+ if (this._settings) {
+ description.options = Hoek.clone(this._settings);
+ }
+
+ if (this._baseType) {
+ description.base = this._baseType.describe();
+ }
+
+ if (this._description) {
+ description.description = this._description;
+ }
+
+ if (this._notes.length) {
+ description.notes = this._notes;
+ }
+
+ if (this._tags.length) {
+ description.tags = this._tags;
+ }
+
+ if (this._meta.length) {
+ description.meta = this._meta;
+ }
+
+ if (this._examples.length) {
+ description.examples = this._examples;
+ }
+
+ if (this._unit) {
+ description.unit = this._unit;
+ }
+
+ const valids = this._valids.values();
+ if (valids.length) {
+ description.valids = valids.map((v) => {
+
+ return Ref.isRef(v) ? v.toString() : v;
+ });
+ }
+
+ const invalids = this._invalids.values();
+ if (invalids.length) {
+ description.invalids = invalids.map((v) => {
+
+ return Ref.isRef(v) ? v.toString() : v;
+ });
+ }
+
+ description.rules = [];
+
+ for (let i = 0; i < this._tests.length; ++i) {
+ const validator = this._tests[i];
+ const item = { name: validator.name };
+
+ if (validator.arg !== void 0) {
+ item.arg = Ref.isRef(validator.arg) ? validator.arg.toString() : validator.arg;
+ }
+
+ const options = validator.options;
+ if (options) {
+ if (options.hasRef) {
+ item.arg = {};
+ const keys = Object.keys(validator.arg);
+ for (let j = 0; j < keys.length; ++j) {
+ const key = keys[j];
+ const value = validator.arg[key];
+ item.arg[key] = Ref.isRef(value) ? value.toString() : value;
+ }
+ }
+
+ if (typeof options.description === 'string') {
+ item.description = options.description;
+ }
+ else if (typeof options.description === 'function') {
+ item.description = options.description(item.arg);
+ }
+ }
+
+ description.rules.push(item);
+ }
+
+ if (!description.rules.length) {
+ delete description.rules;
+ }
+
+ const label = this._getLabel();
+ if (label) {
+ description.label = label;
+ }
+
+ return description;
+ }
+
+ label(name) {
+
+ Hoek.assert(name && typeof name === 'string', 'Label name must be a non-empty string');
+
+ const obj = this.clone();
+ obj._flags.label = name;
+ return obj;
+ }
+
+ _getLabel(def) {
+
+ return this._flags.label || def;
+ }
+
+};
+
+
+internals.Any.prototype.isImmutable = true; // Prevents Hoek from deep cloning schema objects
+
+// Aliases
+
+internals.Any.prototype.only = internals.Any.prototype.equal = internals.Any.prototype.valid;
+internals.Any.prototype.disallow = internals.Any.prototype.not = internals.Any.prototype.invalid;
+internals.Any.prototype.exist = internals.Any.prototype.required;
+
+
+internals._try = function (fn, args) {
+
+ let err;
+ let result;
+
+ try {
+ result = fn.apply(null, args);
+ }
+ catch (e) {
+ err = e;
+ }
+
+ return {
+ value: result,
+ error: err
+ };
+};
+
+internals.concatSettings = function (target, source) {
+
+ // Used to avoid cloning context
+
+ if (!target &&
+ !source) {
+
+ return null;
+ }
+
+ const obj = {};
+
+ if (target) {
+ Object.assign(obj, target);
+ }
+
+ if (source) {
+ const sKeys = Object.keys(source);
+ for (let i = 0; i < sKeys.length; ++i) {
+ const key = sKeys[i];
+ if (key !== 'language' ||
+ !obj.hasOwnProperty(key)) {
+
+ obj[key] = source[key];
+ }
+ else {
+ obj[key] = Hoek.applyToDefaults(obj[key], source[key]);
+ }
+ }
+ }
+
+ return obj;
+};
diff --git a/node_modules/joi/lib/types/array/index.js b/node_modules/joi/lib/types/array/index.js
new file mode 100644
index 00000000..ff6a148a
--- /dev/null
+++ b/node_modules/joi/lib/types/array/index.js
@@ -0,0 +1,658 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Cast = require('../../cast');
+const Ref = require('../../ref');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.fastSplice = function (arr, i) {
+
+ let pos = i;
+ while (pos < arr.length) {
+ arr[pos++] = arr[pos];
+ }
+
+ --arr.length;
+};
+
+
+internals.Array = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'array';
+ this._inner.items = [];
+ this._inner.ordereds = [];
+ this._inner.inclusions = [];
+ this._inner.exclusions = [];
+ this._inner.requireds = [];
+ this._flags.sparse = false;
+ }
+
+ _base(value, state, options) {
+
+ const result = {
+ value
+ };
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ internals.safeParse(value, result);
+ }
+
+ let isArray = Array.isArray(result.value);
+ const wasArray = isArray;
+ if (options.convert && this._flags.single && !isArray) {
+ result.value = [result.value];
+ isArray = true;
+ }
+
+ if (!isArray) {
+ result.errors = this.createError('array.base', null, state, options);
+ return result;
+ }
+
+ if (this._inner.inclusions.length ||
+ this._inner.exclusions.length ||
+ this._inner.requireds.length ||
+ this._inner.ordereds.length ||
+ !this._flags.sparse) {
+
+ // Clone the array so that we don't modify the original
+ if (wasArray) {
+ result.value = result.value.slice(0);
+ }
+
+ result.errors = this._checkItems.call(this, result.value, wasArray, state, options);
+
+ if (result.errors && wasArray && options.convert && this._flags.single) {
+
+ // Attempt a 2nd pass by putting the array inside one.
+ const previousErrors = result.errors;
+
+ result.value = [result.value];
+ result.errors = this._checkItems.call(this, result.value, wasArray, state, options);
+
+ if (result.errors) {
+
+ // Restore previous errors and value since this didn't validate either.
+ result.errors = previousErrors;
+ result.value = result.value[0];
+ }
+ }
+ }
+
+ return result;
+ }
+
+ _checkItems(items, wasArray, state, options) {
+
+ const errors = [];
+ let errored;
+
+ const requireds = this._inner.requireds.slice();
+ const ordereds = this._inner.ordereds.slice();
+ const inclusions = this._inner.inclusions.concat(requireds);
+
+ let il = items.length;
+ for (let i = 0; i < il; ++i) {
+ errored = false;
+ const item = items[i];
+ let isValid = false;
+ const key = wasArray ? i : state.key;
+ const path = wasArray ? state.path.concat(i) : state.path;
+ const localState = { key, path, parent: state.parent, reference: state.reference };
+ let res;
+
+ // Sparse
+
+ if (!this._flags.sparse && item === undefined) {
+ errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
+
+ if (options.abortEarly) {
+ return errors;
+ }
+
+ continue;
+ }
+
+ // Exclusions
+
+ for (let j = 0; j < this._inner.exclusions.length; ++j) {
+ res = this._inner.exclusions[j]._validate(item, localState, {}); // Not passing options to use defaults
+
+ if (!res.errors) {
+ errors.push(this.createError(wasArray ? 'array.excludes' : 'array.excludesSingle', { pos: i, value: item }, { key: state.key, path: localState.path }, options));
+ errored = true;
+
+ if (options.abortEarly) {
+ return errors;
+ }
+
+ break;
+ }
+ }
+
+ if (errored) {
+ continue;
+ }
+
+ // Ordered
+ if (this._inner.ordereds.length) {
+ if (ordereds.length > 0) {
+ const ordered = ordereds.shift();
+ res = ordered._validate(item, localState, options);
+ if (!res.errors) {
+ if (ordered._flags.strip) {
+ internals.fastSplice(items, i);
+ --i;
+ --il;
+ }
+ else if (!this._flags.sparse && res.value === undefined) {
+ errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
+
+ if (options.abortEarly) {
+ return errors;
+ }
+
+ continue;
+ }
+ else {
+ items[i] = res.value;
+ }
+ }
+ else {
+ errors.push(this.createError('array.ordered', { pos: i, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
+ if (options.abortEarly) {
+ return errors;
+ }
+ }
+ continue;
+ }
+ else if (!this._inner.items.length) {
+ errors.push(this.createError('array.orderedLength', { pos: i, limit: this._inner.ordereds.length }, { key: state.key, path: localState.path }, options));
+ if (options.abortEarly) {
+ return errors;
+ }
+ continue;
+ }
+ }
+
+ // Requireds
+
+ const requiredChecks = [];
+ let jl = requireds.length;
+ for (let j = 0; j < jl; ++j) {
+ res = requiredChecks[j] = requireds[j]._validate(item, localState, options);
+ if (!res.errors) {
+ items[i] = res.value;
+ isValid = true;
+ internals.fastSplice(requireds, j);
+ --j;
+ --jl;
+
+ if (!this._flags.sparse && res.value === undefined) {
+ errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
+
+ if (options.abortEarly) {
+ return errors;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (isValid) {
+ continue;
+ }
+
+ // Inclusions
+
+ const stripUnknown = options.stripUnknown
+ ? (options.stripUnknown === true ? true : !!options.stripUnknown.arrays)
+ : false;
+
+ jl = inclusions.length;
+ for (let j = 0; j < jl; ++j) {
+ const inclusion = inclusions[j];
+
+ // Avoid re-running requireds that already didn't match in the previous loop
+ const previousCheck = requireds.indexOf(inclusion);
+ if (previousCheck !== -1) {
+ res = requiredChecks[previousCheck];
+ }
+ else {
+ res = inclusion._validate(item, localState, options);
+
+ if (!res.errors) {
+ if (inclusion._flags.strip) {
+ internals.fastSplice(items, i);
+ --i;
+ --il;
+ }
+ else if (!this._flags.sparse && res.value === undefined) {
+ errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
+ errored = true;
+ }
+ else {
+ items[i] = res.value;
+ }
+ isValid = true;
+ break;
+ }
+ }
+
+ // Return the actual error if only one inclusion defined
+ if (jl === 1) {
+ if (stripUnknown) {
+ internals.fastSplice(items, i);
+ --i;
+ --il;
+ isValid = true;
+ break;
+ }
+
+ errors.push(this.createError(wasArray ? 'array.includesOne' : 'array.includesOneSingle', { pos: i, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
+ errored = true;
+
+ if (options.abortEarly) {
+ return errors;
+ }
+
+ break;
+ }
+ }
+
+ if (errored) {
+ continue;
+ }
+
+ if (this._inner.inclusions.length && !isValid) {
+ if (stripUnknown) {
+ internals.fastSplice(items, i);
+ --i;
+ --il;
+ continue;
+ }
+
+ errors.push(this.createError(wasArray ? 'array.includes' : 'array.includesSingle', { pos: i, value: item }, { key: state.key, path: localState.path }, options));
+
+ if (options.abortEarly) {
+ return errors;
+ }
+ }
+ }
+
+ if (requireds.length) {
+ this._fillMissedErrors.call(this, errors, requireds, state, options);
+ }
+
+ if (ordereds.length) {
+ this._fillOrderedErrors.call(this, errors, ordereds, state, options);
+ }
+
+ return errors.length ? errors : null;
+ }
+
+ describe() {
+
+ const description = Any.prototype.describe.call(this);
+
+ if (this._inner.ordereds.length) {
+ description.orderedItems = [];
+
+ for (let i = 0; i < this._inner.ordereds.length; ++i) {
+ description.orderedItems.push(this._inner.ordereds[i].describe());
+ }
+ }
+
+ if (this._inner.items.length) {
+ description.items = [];
+
+ for (let i = 0; i < this._inner.items.length; ++i) {
+ description.items.push(this._inner.items[i].describe());
+ }
+ }
+
+ return description;
+ }
+
+ items() {
+
+ const obj = this.clone();
+
+ Hoek.flatten(Array.prototype.slice.call(arguments)).forEach((type, index) => {
+
+ try {
+ type = Cast.schema(this._currentJoi, type);
+ }
+ catch (castErr) {
+ if (castErr.hasOwnProperty('path')) {
+ castErr.path = index + '.' + castErr.path;
+ }
+ else {
+ castErr.path = index;
+ }
+ castErr.message = castErr.message + '(' + castErr.path + ')';
+ throw castErr;
+ }
+
+ obj._inner.items.push(type);
+
+ if (type._flags.presence === 'required') {
+ obj._inner.requireds.push(type);
+ }
+ else if (type._flags.presence === 'forbidden') {
+ obj._inner.exclusions.push(type.optional());
+ }
+ else {
+ obj._inner.inclusions.push(type);
+ }
+ });
+
+ return obj;
+ }
+
+ ordered() {
+
+ const obj = this.clone();
+
+ Hoek.flatten(Array.prototype.slice.call(arguments)).forEach((type, index) => {
+
+ try {
+ type = Cast.schema(this._currentJoi, type);
+ }
+ catch (castErr) {
+ if (castErr.hasOwnProperty('path')) {
+ castErr.path = index + '.' + castErr.path;
+ }
+ else {
+ castErr.path = index;
+ }
+ castErr.message = castErr.message + '(' + castErr.path + ')';
+ throw castErr;
+ }
+ obj._inner.ordereds.push(type);
+ });
+
+ return obj;
+ }
+
+ min(limit) {
+
+ const isRef = Ref.isRef(limit);
+
+ Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
+
+ return this._test('min', limit, function (value, state, options) {
+
+ let compareTo;
+ if (isRef) {
+ compareTo = limit(state.reference || state.parent, options);
+
+ if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
+ return this.createError('array.ref', { ref: limit.key }, state, options);
+ }
+ }
+ else {
+ compareTo = limit;
+ }
+
+ if (value.length >= compareTo) {
+ return value;
+ }
+
+ return this.createError('array.min', { limit, value }, state, options);
+ });
+ }
+
+ max(limit) {
+
+ const isRef = Ref.isRef(limit);
+
+ Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
+
+ return this._test('max', limit, function (value, state, options) {
+
+ let compareTo;
+ if (isRef) {
+ compareTo = limit(state.reference || state.parent, options);
+
+ if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
+ return this.createError('array.ref', { ref: limit.key }, state, options);
+ }
+ }
+ else {
+ compareTo = limit;
+ }
+
+ if (value.length <= compareTo) {
+ return value;
+ }
+
+ return this.createError('array.max', { limit, value }, state, options);
+ });
+ }
+
+ length(limit) {
+
+ const isRef = Ref.isRef(limit);
+
+ Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
+
+ return this._test('length', limit, function (value, state, options) {
+
+ let compareTo;
+ if (isRef) {
+ compareTo = limit(state.reference || state.parent, options);
+
+ if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
+ return this.createError('array.ref', { ref: limit.key }, state, options);
+ }
+ }
+ else {
+ compareTo = limit;
+ }
+
+ if (value.length === compareTo) {
+ return value;
+ }
+
+ return this.createError('array.length', { limit, value }, state, options);
+ });
+ }
+
+ unique(comparator) {
+
+ Hoek.assert(comparator === undefined ||
+ typeof comparator === 'function' ||
+ typeof comparator === 'string', 'comparator must be a function or a string');
+
+ const settings = {};
+
+ if (typeof comparator === 'string') {
+ settings.path = comparator;
+ }
+ else if (typeof comparator === 'function') {
+ settings.comparator = comparator;
+ }
+
+ return this._test('unique', settings, function (value, state, options) {
+
+ const found = {
+ string: {},
+ number: {},
+ undefined: {},
+ boolean: {},
+ object: new Map(),
+ function: new Map(),
+ custom: new Map()
+ };
+
+ const compare = settings.comparator || Hoek.deepEqual;
+
+ for (let i = 0; i < value.length; ++i) {
+ const item = settings.path ? Hoek.reach(value[i], settings.path) : value[i];
+ const records = settings.comparator ? found.custom : found[typeof item];
+
+ // All available types are supported, so it's not possible to reach 100% coverage without ignoring this line.
+ // I still want to keep the test for future js versions with new types (eg. Symbol).
+ if (/* $lab:coverage:off$ */ records /* $lab:coverage:on$ */) {
+ if (records instanceof Map) {
+ const entries = records.entries();
+ let current;
+ while (!(current = entries.next()).done) {
+ if (compare(current.value[0], item)) {
+ const localState = {
+ key: state.key,
+ path: state.path.concat(i),
+ parent: state.parent,
+ reference: state.reference
+ };
+
+ const context = {
+ pos: i,
+ value: value[i],
+ dupePos: current.value[1],
+ dupeValue: value[current.value[1]]
+ };
+
+ if (settings.path) {
+ context.path = settings.path;
+ }
+
+ return this.createError('array.unique', context, localState, options);
+ }
+ }
+
+ records.set(item, i);
+ }
+ else {
+ if (records[item] !== undefined) {
+ const localState = {
+ key: state.key,
+ path: state.path.concat(i),
+ parent: state.parent,
+ reference: state.reference
+ };
+
+ const context = {
+ pos: i,
+ value: value[i],
+ dupePos: records[item],
+ dupeValue: value[records[item]]
+ };
+
+ if (settings.path) {
+ context.path = settings.path;
+ }
+
+ return this.createError('array.unique', context, localState, options);
+ }
+
+ records[item] = i;
+ }
+ }
+ }
+
+ return value;
+ });
+ }
+
+ sparse(enabled) {
+
+ const value = enabled === undefined ? true : !!enabled;
+
+ if (this._flags.sparse === value) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.sparse = value;
+ return obj;
+ }
+
+ single(enabled) {
+
+ const value = enabled === undefined ? true : !!enabled;
+
+ if (this._flags.single === value) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.single = value;
+ return obj;
+ }
+
+ _fillMissedErrors(errors, requireds, state, options) {
+
+ const knownMisses = [];
+ let unknownMisses = 0;
+ for (let i = 0; i < requireds.length; ++i) {
+ const label = requireds[i]._getLabel();
+ if (label) {
+ knownMisses.push(label);
+ }
+ else {
+ ++unknownMisses;
+ }
+ }
+
+ if (knownMisses.length) {
+ if (unknownMisses) {
+ errors.push(this.createError('array.includesRequiredBoth', { knownMisses, unknownMisses }, { key: state.key, path: state.path }, options));
+ }
+ else {
+ errors.push(this.createError('array.includesRequiredKnowns', { knownMisses }, { key: state.key, path: state.path }, options));
+ }
+ }
+ else {
+ errors.push(this.createError('array.includesRequiredUnknowns', { unknownMisses }, { key: state.key, path: state.path }, options));
+ }
+ }
+
+
+ _fillOrderedErrors(errors, ordereds, state, options) {
+
+ const requiredOrdereds = [];
+
+ for (let i = 0; i < ordereds.length; ++i) {
+ const presence = Hoek.reach(ordereds[i], '_flags.presence');
+ if (presence === 'required') {
+ requiredOrdereds.push(ordereds[i]);
+ }
+ }
+
+ if (requiredOrdereds.length) {
+ this._fillMissedErrors.call(this, errors, requiredOrdereds, state, options);
+ }
+ }
+
+};
+
+
+internals.safeParse = function (value, result) {
+
+ try {
+ const converted = JSON.parse(value);
+ if (Array.isArray(converted)) {
+ result.value = converted;
+ }
+ }
+ catch (e) { }
+};
+
+
+module.exports = new internals.Array();
diff --git a/node_modules/joi/lib/types/binary/index.js b/node_modules/joi/lib/types/binary/index.js
new file mode 100644
index 00000000..e93f0a46
--- /dev/null
+++ b/node_modules/joi/lib/types/binary/index.js
@@ -0,0 +1,100 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.Binary = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'binary';
+ }
+
+ _base(value, state, options) {
+
+ const result = {
+ value
+ };
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ try {
+ result.value = new Buffer(value, this._flags.encoding);
+ }
+ catch (e) {
+ }
+ }
+
+ result.errors = Buffer.isBuffer(result.value) ? null : this.createError('binary.base', null, state, options);
+ return result;
+ }
+
+ encoding(encoding) {
+
+ Hoek.assert(Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
+
+ if (this._flags.encoding === encoding) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.encoding = encoding;
+ return obj;
+ }
+
+ min(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('min', limit, function (value, state, options) {
+
+ if (value.length >= limit) {
+ return value;
+ }
+
+ return this.createError('binary.min', { limit, value }, state, options);
+ });
+ }
+
+ max(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('max', limit, function (value, state, options) {
+
+ if (value.length <= limit) {
+ return value;
+ }
+
+ return this.createError('binary.max', { limit, value }, state, options);
+ });
+ }
+
+ length(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('length', limit, function (value, state, options) {
+
+ if (value.length === limit) {
+ return value;
+ }
+
+ return this.createError('binary.length', { limit, value }, state, options);
+ });
+ }
+
+};
+
+
+module.exports = new internals.Binary();
diff --git a/node_modules/joi/lib/types/boolean/index.js b/node_modules/joi/lib/types/boolean/index.js
new file mode 100644
index 00000000..3f909998
--- /dev/null
+++ b/node_modules/joi/lib/types/boolean/index.js
@@ -0,0 +1,98 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {
+ Set: require('../../set')
+};
+
+
+internals.Boolean = class extends Any {
+ constructor() {
+
+ super();
+ this._type = 'boolean';
+ this._flags.insensitive = true;
+ this._inner.truthySet = new internals.Set();
+ this._inner.falsySet = new internals.Set();
+ }
+
+ _base(value, state, options) {
+
+ const result = {
+ value
+ };
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ const normalized = this._flags.insensitive ? value.toLowerCase() : value;
+ result.value = (normalized === 'true' ? true
+ : (normalized === 'false' ? false : value));
+ }
+
+ if (typeof result.value !== 'boolean') {
+ result.value = (this._inner.truthySet.has(value, null, null, this._flags.insensitive) ? true
+ : (this._inner.falsySet.has(value, null, null, this._flags.insensitive) ? false : value));
+ }
+
+ result.errors = (typeof result.value === 'boolean') ? null : this.createError('boolean.base', null, state, options);
+ return result;
+ }
+
+ truthy() {
+
+ const obj = this.clone();
+ const values = Hoek.flatten(Array.prototype.slice.call(arguments));
+ for (let i = 0; i < values.length; ++i) {
+ const value = values[i];
+
+ Hoek.assert(value !== undefined, 'Cannot call truthy with undefined');
+ obj._inner.truthySet.add(value);
+ }
+ return obj;
+ }
+
+ falsy() {
+
+ const obj = this.clone();
+ const values = Hoek.flatten(Array.prototype.slice.call(arguments));
+ for (let i = 0; i < values.length; ++i) {
+ const value = values[i];
+
+ Hoek.assert(value !== undefined, 'Cannot call falsy with undefined');
+ obj._inner.falsySet.add(value);
+ }
+ return obj;
+ }
+
+ insensitive(enabled) {
+
+ const insensitive = enabled === undefined ? true : !!enabled;
+
+ if (this._flags.insensitive === insensitive) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.insensitive = insensitive;
+ return obj;
+ }
+
+ describe() {
+
+ const description = Any.prototype.describe.call(this);
+ description.truthy = [true].concat(this._inner.truthySet.values());
+ description.falsy = [false].concat(this._inner.falsySet.values());
+ return description;
+ }
+};
+
+
+module.exports = new internals.Boolean();
diff --git a/node_modules/joi/lib/types/date/index.js b/node_modules/joi/lib/types/date/index.js
new file mode 100644
index 00000000..00b93379
--- /dev/null
+++ b/node_modules/joi/lib/types/date/index.js
@@ -0,0 +1,177 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Ref = require('../../ref');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {};
+
+internals.isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
+internals.invalidDate = new Date('');
+internals.isIsoDate = (() => {
+
+ const isoString = internals.isoDate.toString();
+
+ return (date) => {
+
+ return date && (date.toString() === isoString);
+ };
+})();
+
+internals.Date = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'date';
+ }
+
+ _base(value, state, options) {
+
+ const result = {
+ value: (options.convert && internals.Date.toDate(value, this._flags.format, this._flags.timestamp, this._flags.multiplier)) || value
+ };
+
+ if (result.value instanceof Date && !isNaN(result.value.getTime())) {
+ result.errors = null;
+ }
+ else if (!options.convert) {
+ result.errors = this.createError('date.strict', null, state, options);
+ }
+ else {
+ let type;
+ if (internals.isIsoDate(this._flags.format)) {
+ type = 'isoDate';
+ }
+ else if (this._flags.timestamp) {
+ type = `timestamp.${this._flags.timestamp}`;
+ }
+ else {
+ type = 'base';
+ }
+
+ result.errors = this.createError(`date.${type}`, null, state, options);
+ }
+
+ return result;
+ }
+
+ static toDate(value, format, timestamp, multiplier) {
+
+ if (value instanceof Date) {
+ return value;
+ }
+
+ if (typeof value === 'string' ||
+ (typeof value === 'number' && !isNaN(value) && isFinite(value))) {
+
+ if (typeof value === 'string' &&
+ /^[+-]?\d+(\.\d+)?$/.test(value)) {
+
+ value = parseFloat(value);
+ }
+
+ let date;
+ if (format && internals.isIsoDate(format)) {
+ date = format.test(value) ? new Date(value) : internals.invalidDate;
+ }
+ else if (timestamp && multiplier) {
+ date = /^\s*$/.test(value) ? internals.invalidDate : new Date(value * multiplier);
+ }
+ else {
+ date = new Date(value);
+ }
+
+ if (!isNaN(date.getTime())) {
+ return date;
+ }
+ }
+
+ return null;
+ }
+
+ iso() {
+
+ if (this._flags.format === internals.isoDate) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.format = internals.isoDate;
+ return obj;
+ }
+
+ timestamp(type) {
+
+ type = type || 'javascript';
+
+ const allowed = ['javascript', 'unix'];
+ Hoek.assert(allowed.indexOf(type) !== -1, '"type" must be one of "' + allowed.join('", "') + '"');
+
+ if (this._flags.timestamp === type) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.timestamp = type;
+ obj._flags.multiplier = type === 'unix' ? 1000 : 1;
+ return obj;
+ }
+
+ _isIsoDate(value) {
+
+ return internals.isoDate.test(value);
+ }
+
+};
+
+internals.compare = function (type, compare) {
+
+ return function (date) {
+
+ const isNow = date === 'now';
+ const isRef = Ref.isRef(date);
+
+ if (!isNow && !isRef) {
+ date = internals.Date.toDate(date);
+ }
+
+ Hoek.assert(date, 'Invalid date format');
+
+ return this._test(type, date, function (value, state, options) {
+
+ let compareTo;
+ if (isNow) {
+ compareTo = Date.now();
+ }
+ else if (isRef) {
+ compareTo = internals.Date.toDate(date(state.reference || state.parent, options));
+
+ if (!compareTo) {
+ return this.createError('date.ref', { ref: date.key }, state, options);
+ }
+
+ compareTo = compareTo.getTime();
+ }
+ else {
+ compareTo = date.getTime();
+ }
+
+ if (compare(value.getTime(), compareTo)) {
+ return value;
+ }
+
+ return this.createError('date.' + type, { limit: new Date(compareTo) }, state, options);
+ });
+ };
+};
+internals.Date.prototype.min = internals.compare('min', (value, date) => value >= date);
+internals.Date.prototype.max = internals.compare('max', (value, date) => value <= date);
+
+
+module.exports = new internals.Date();
diff --git a/node_modules/joi/lib/types/func/index.js b/node_modules/joi/lib/types/func/index.js
new file mode 100644
index 00000000..e9448386
--- /dev/null
+++ b/node_modules/joi/lib/types/func/index.js
@@ -0,0 +1,90 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const ObjectType = require('../object');
+const Ref = require('../../ref');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.Func = class extends ObjectType.constructor {
+
+ constructor() {
+
+ super();
+ this._flags.func = true;
+ }
+
+ arity(n) {
+
+ Hoek.assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
+
+ return this._test('arity', n, function (value, state, options) {
+
+ if (value.length === n) {
+ return value;
+ }
+
+ return this.createError('function.arity', { n }, state, options);
+ });
+ }
+
+ minArity(n) {
+
+ Hoek.assert(Number.isSafeInteger(n) && n > 0, 'n must be a strict positive integer');
+
+ return this._test('minArity', n, function (value, state, options) {
+
+ if (value.length >= n) {
+ return value;
+ }
+
+ return this.createError('function.minArity', { n }, state, options);
+ });
+ }
+
+ maxArity(n) {
+
+ Hoek.assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
+
+ return this._test('maxArity', n, function (value, state, options) {
+
+ if (value.length <= n) {
+ return value;
+ }
+
+ return this.createError('function.maxArity', { n }, state, options);
+ });
+ }
+
+ ref() {
+
+ return this._test('ref', null, function (value, state, options) {
+
+ if (Ref.isRef(value)) {
+ return value;
+ }
+
+ return this.createError('function.ref', null, state, options);
+ });
+ }
+
+ class() {
+
+ return this._test('class', null, function (value, state, options) {
+
+ if ((/^\s*class\s/).test(value.toString())) {
+ return value;
+ }
+
+ return this.createError('function.class', null, state, options);
+ });
+ }
+};
+
+module.exports = new internals.Func();
diff --git a/node_modules/joi/lib/types/lazy/index.js b/node_modules/joi/lib/types/lazy/index.js
new file mode 100644
index 00000000..b62054c6
--- /dev/null
+++ b/node_modules/joi/lib/types/lazy/index.js
@@ -0,0 +1,53 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.Lazy = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'lazy';
+ }
+
+ _base(value, state, options) {
+
+ const result = { value };
+ const lazy = this._flags.lazy;
+
+ if (!lazy) {
+ result.errors = this.createError('lazy.base', null, state, options);
+ return result;
+ }
+
+ const schema = lazy();
+
+ if (!(schema instanceof Any)) {
+ result.errors = this.createError('lazy.schema', null, state, options);
+ return result;
+ }
+
+ return schema._validate(value, state, options);
+ }
+
+ set(fn) {
+
+ Hoek.assert(typeof fn === 'function', 'You must provide a function as first argument');
+
+ const obj = this.clone();
+ obj._flags.lazy = fn;
+ return obj;
+ }
+
+};
+
+module.exports = new internals.Lazy();
diff --git a/node_modules/joi/lib/types/number/index.js b/node_modules/joi/lib/types/number/index.js
new file mode 100644
index 00000000..c1cfac09
--- /dev/null
+++ b/node_modules/joi/lib/types/number/index.js
@@ -0,0 +1,173 @@
+'use strict';
+
+// Load modules
+
+const Any = require('../any');
+const Ref = require('../../ref');
+const Hoek = require('hoek');
+
+
+// Declare internals
+
+const internals = {
+ precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/
+};
+
+
+internals.Number = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'number';
+ this._invalids.add(Infinity);
+ this._invalids.add(-Infinity);
+ }
+
+ _base(value, state, options) {
+
+ const result = {
+ errors: null,
+ value
+ };
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ const number = parseFloat(value);
+ result.value = (isNaN(number) || !isFinite(value)) ? NaN : number;
+ }
+
+ const isNumber = typeof result.value === 'number' && !isNaN(result.value);
+
+ if (options.convert && 'precision' in this._flags && isNumber) {
+
+ // This is conceptually equivalent to using toFixed but it should be much faster
+ const precision = Math.pow(10, this._flags.precision);
+ result.value = Math.round(result.value * precision) / precision;
+ }
+
+ result.errors = isNumber ? null : this.createError('number.base', null, state, options);
+ return result;
+ }
+
+ multiple(base) {
+
+ const isRef = Ref.isRef(base);
+
+ if (!isRef) {
+ Hoek.assert(typeof base === 'number' && isFinite(base), 'multiple must be a number');
+ Hoek.assert(base > 0, 'multiple must be greater than 0');
+ }
+
+ return this._test('multiple', base, function (value, state, options) {
+
+ const divisor = isRef ? base(state.reference || state.parent, options) : base;
+
+ if (isRef && (typeof divisor !== 'number' || !isFinite(divisor))) {
+ return this.createError('number.ref', { ref: base.key }, state, options);
+ }
+
+ if (value % divisor === 0) {
+ return value;
+ }
+
+ return this.createError('number.multiple', { multiple: base, value }, state, options);
+ });
+ }
+
+ integer() {
+
+ return this._test('integer', undefined, function (value, state, options) {
+
+ return Number.isSafeInteger(value) ? value : this.createError('number.integer', { value }, state, options);
+ });
+ }
+
+ negative() {
+
+ return this._test('negative', undefined, function (value, state, options) {
+
+ if (value < 0) {
+ return value;
+ }
+
+ return this.createError('number.negative', { value }, state, options);
+ });
+ }
+
+ positive() {
+
+ return this._test('positive', undefined, function (value, state, options) {
+
+ if (value > 0) {
+ return value;
+ }
+
+ return this.createError('number.positive', { value }, state, options);
+ });
+ }
+
+ precision(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit), 'limit must be an integer');
+ Hoek.assert(!('precision' in this._flags), 'precision already set');
+
+ const obj = this._test('precision', limit, function (value, state, options) {
+
+ const places = value.toString().match(internals.precisionRx);
+ const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
+ if (decimals <= limit) {
+ return value;
+ }
+
+ return this.createError('number.precision', { limit, value }, state, options);
+ });
+
+ obj._flags.precision = limit;
+ return obj;
+ }
+
+};
+
+
+internals.compare = function (type, compare) {
+
+ return function (limit) {
+
+ const isRef = Ref.isRef(limit);
+ const isNumber = typeof limit === 'number' && !isNaN(limit);
+
+ Hoek.assert(isNumber || isRef, 'limit must be a number or reference');
+
+ return this._test(type, limit, function (value, state, options) {
+
+ let compareTo;
+ if (isRef) {
+ compareTo = limit(state.reference || state.parent, options);
+
+ if (!(typeof compareTo === 'number' && !isNaN(compareTo))) {
+ return this.createError('number.ref', { ref: limit.key }, state, options);
+ }
+ }
+ else {
+ compareTo = limit;
+ }
+
+ if (compare(value, compareTo)) {
+ return value;
+ }
+
+ return this.createError('number.' + type, { limit: compareTo, value }, state, options);
+ });
+ };
+};
+
+
+internals.Number.prototype.min = internals.compare('min', (value, limit) => value >= limit);
+internals.Number.prototype.max = internals.compare('max', (value, limit) => value <= limit);
+internals.Number.prototype.greater = internals.compare('greater', (value, limit) => value > limit);
+internals.Number.prototype.less = internals.compare('less', (value, limit) => value < limit);
+
+
+module.exports = new internals.Number();
diff --git a/node_modules/joi/lib/types/object/index.js b/node_modules/joi/lib/types/object/index.js
new file mode 100644
index 00000000..08b7efb9
--- /dev/null
+++ b/node_modules/joi/lib/types/object/index.js
@@ -0,0 +1,896 @@
+'use strict';
+
+// Load modules
+
+const Hoek = require('hoek');
+const Topo = require('topo');
+const Any = require('../any');
+const Errors = require('../../errors');
+const Cast = require('../../cast');
+
+
+// Declare internals
+
+const internals = {};
+
+
+internals.Object = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'object';
+ this._inner.children = null;
+ this._inner.renames = [];
+ this._inner.dependencies = [];
+ this._inner.patterns = [];
+ }
+
+ _base(value, state, options) {
+
+ let target = value;
+ const errors = [];
+ const finish = () => {
+
+ return {
+ value: target,
+ errors: errors.length ? errors : null
+ };
+ };
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ value = internals.safeParse(value);
+ }
+
+ const type = this._flags.func ? 'function' : 'object';
+ if (!value ||
+ typeof value !== type ||
+ Array.isArray(value)) {
+
+ errors.push(this.createError(type + '.base', null, state, options));
+ return finish();
+ }
+
+ // Skip if there are no other rules to test
+
+ if (!this._inner.renames.length &&
+ !this._inner.dependencies.length &&
+ !this._inner.children && // null allows any keys
+ !this._inner.patterns.length) {
+
+ target = value;
+ return finish();
+ }
+
+ // Ensure target is a local copy (parsed) or shallow copy
+
+ if (target === value) {
+ if (type === 'object') {
+ target = Object.create(Object.getPrototypeOf(value));
+ }
+ else {
+ target = function () {
+
+ return value.apply(this, arguments);
+ };
+
+ target.prototype = Hoek.clone(value.prototype);
+ }
+
+ const valueKeys = Object.keys(value);
+ for (let i = 0; i < valueKeys.length; ++i) {
+ target[valueKeys[i]] = value[valueKeys[i]];
+ }
+ }
+ else {
+ target = value;
+ }
+
+ // Rename keys
+
+ const renamed = {};
+ for (let i = 0; i < this._inner.renames.length; ++i) {
+ const rename = this._inner.renames[i];
+
+ if (rename.isRegExp) {
+ const targetKeys = Object.keys(target);
+ const matchedTargetKeys = [];
+
+ for (let j = 0; j < targetKeys.length; ++j) {
+ if (rename.from.test(targetKeys[j])) {
+ matchedTargetKeys.push(targetKeys[j]);
+ }
+ }
+
+ const allUndefined = matchedTargetKeys.every((key) => target[key] === undefined);
+ if (rename.options.ignoreUndefined && allUndefined) {
+ continue;
+ }
+
+ if (!rename.options.multiple &&
+ renamed[rename.to]) {
+
+ errors.push(this.createError('object.rename.regex.multiple', { from: matchedTargetKeys, to: rename.to }, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ if (Object.prototype.hasOwnProperty.call(target, rename.to) &&
+ !rename.options.override &&
+ !renamed[rename.to]) {
+
+ errors.push(this.createError('object.rename.regex.override', { from: matchedTargetKeys, to: rename.to }, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ if (allUndefined) {
+ delete target[rename.to];
+ }
+ else {
+ target[rename.to] = target[matchedTargetKeys[matchedTargetKeys.length - 1]];
+ }
+
+ renamed[rename.to] = true;
+
+ if (!rename.options.alias) {
+ for (let j = 0; j < matchedTargetKeys.length; ++j) {
+ delete target[matchedTargetKeys[j]];
+ }
+ }
+ }
+ else {
+ if (rename.options.ignoreUndefined && target[rename.from] === undefined) {
+ continue;
+ }
+
+ if (!rename.options.multiple &&
+ renamed[rename.to]) {
+
+ errors.push(this.createError('object.rename.multiple', { from: rename.from, to: rename.to }, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ if (Object.prototype.hasOwnProperty.call(target, rename.to) &&
+ !rename.options.override &&
+ !renamed[rename.to]) {
+
+ errors.push(this.createError('object.rename.override', { from: rename.from, to: rename.to }, state, options));
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ if (target[rename.from] === undefined) {
+ delete target[rename.to];
+ }
+ else {
+ target[rename.to] = target[rename.from];
+ }
+
+ renamed[rename.to] = true;
+
+ if (!rename.options.alias) {
+ delete target[rename.from];
+ }
+ }
+ }
+
+ // Validate schema
+
+ if (!this._inner.children && // null allows any keys
+ !this._inner.patterns.length &&
+ !this._inner.dependencies.length) {
+
+ return finish();
+ }
+
+ const unprocessed = Hoek.mapToObject(Object.keys(target));
+
+ if (this._inner.children) {
+ const stripProps = [];
+
+ for (let i = 0; i < this._inner.children.length; ++i) {
+ const child = this._inner.children[i];
+ const key = child.key;
+ const item = target[key];
+
+ delete unprocessed[key];
+
+ const localState = { key, path: state.path.concat(key), parent: target, reference: state.reference };
+ const result = child.schema._validate(item, localState, options);
+ if (result.errors) {
+ errors.push(this.createError('object.child', { key, child: child.schema._getLabel(key), reason: result.errors }, localState, options));
+
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+ else {
+ if (child.schema._flags.strip || (result.value === undefined && result.value !== item)) {
+ stripProps.push(key);
+ target[key] = result.finalValue;
+ }
+ else if (result.value !== undefined) {
+ target[key] = result.value;
+ }
+ }
+ }
+
+ for (let i = 0; i < stripProps.length; ++i) {
+ delete target[stripProps[i]];
+ }
+ }
+
+ // Unknown keys
+
+ let unprocessedKeys = Object.keys(unprocessed);
+ if (unprocessedKeys.length &&
+ this._inner.patterns.length) {
+
+ for (let i = 0; i < unprocessedKeys.length; ++i) {
+ const key = unprocessedKeys[i];
+ const localState = { key, path: state.path.concat(key), parent: target, reference: state.reference };
+ const item = target[key];
+
+ for (let j = 0; j < this._inner.patterns.length; ++j) {
+ const pattern = this._inner.patterns[j];
+
+ if (pattern.regex.test(key)) {
+ delete unprocessed[key];
+
+ const result = pattern.rule._validate(item, localState, options);
+ if (result.errors) {
+ errors.push(this.createError('object.child', { key, child: pattern.rule._getLabel(key), reason: result.errors }, localState, options));
+
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+
+ if (result.value !== undefined) {
+ target[key] = result.value;
+ }
+ }
+ }
+ }
+
+ unprocessedKeys = Object.keys(unprocessed);
+ }
+
+ if ((this._inner.children || this._inner.patterns.length) && unprocessedKeys.length) {
+ if ((options.stripUnknown && this._flags.allowUnknown !== true) ||
+ options.skipFunctions) {
+
+ const stripUnknown = options.stripUnknown
+ ? (options.stripUnknown === true ? true : !!options.stripUnknown.objects)
+ : false;
+
+
+ for (let i = 0; i < unprocessedKeys.length; ++i) {
+ const key = unprocessedKeys[i];
+
+ if (stripUnknown) {
+ delete target[key];
+ delete unprocessed[key];
+ }
+ else if (typeof target[key] === 'function') {
+ delete unprocessed[key];
+ }
+ }
+
+ unprocessedKeys = Object.keys(unprocessed);
+ }
+
+ if (unprocessedKeys.length &&
+ (this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) {
+
+ for (let i = 0; i < unprocessedKeys.length; ++i) {
+ const unprocessedKey = unprocessedKeys[i];
+ errors.push(this.createError('object.allowUnknown', { child: unprocessedKey }, { key: unprocessedKey, path: state.path.concat(unprocessedKey) }, options, {}));
+ }
+ }
+ }
+
+ // Validate dependencies
+
+ for (let i = 0; i < this._inner.dependencies.length; ++i) {
+ const dep = this._inner.dependencies[i];
+ const err = internals[dep.type].call(this, dep.key !== null && target[dep.key], dep.peers, target, { key: dep.key, path: dep.key === null ? state.path : state.path.concat(dep.key) }, options);
+ if (err instanceof Errors.Err) {
+ errors.push(err);
+ if (options.abortEarly) {
+ return finish();
+ }
+ }
+ }
+
+ return finish();
+ }
+
+ keys(schema) {
+
+ Hoek.assert(schema === null || schema === undefined || typeof schema === 'object', 'Object schema must be a valid object');
+ Hoek.assert(!schema || !(schema instanceof Any), 'Object schema cannot be a joi schema');
+
+ const obj = this.clone();
+
+ if (!schema) {
+ obj._inner.children = null;
+ return obj;
+ }
+
+ const children = Object.keys(schema);
+
+ if (!children.length) {
+ obj._inner.children = [];
+ return obj;
+ }
+
+ const topo = new Topo();
+ if (obj._inner.children) {
+ for (let i = 0; i < obj._inner.children.length; ++i) {
+ const child = obj._inner.children[i];
+
+ // Only add the key if we are not going to replace it later
+ if (children.indexOf(child.key) === -1) {
+ topo.add(child, { after: child._refs, group: child.key });
+ }
+ }
+ }
+
+ for (let i = 0; i < children.length; ++i) {
+ const key = children[i];
+ const child = schema[key];
+ try {
+ const cast = Cast.schema(this._currentJoi, child);
+ topo.add({ key, schema: cast }, { after: cast._refs, group: key });
+ }
+ catch (castErr) {
+ if (castErr.hasOwnProperty('path')) {
+ castErr.path = key + '.' + castErr.path;
+ }
+ else {
+ castErr.path = key;
+ }
+ throw castErr;
+ }
+ }
+
+ obj._inner.children = topo.nodes;
+
+ return obj;
+ }
+
+ unknown(allow) {
+
+ const value = allow !== false;
+
+ if (this._flags.allowUnknown === value) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.allowUnknown = value;
+ return obj;
+ }
+
+ length(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('length', limit, function (value, state, options) {
+
+ if (Object.keys(value).length === limit) {
+ return value;
+ }
+
+ return this.createError('object.length', { limit }, state, options);
+ });
+ }
+
+ min(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('min', limit, function (value, state, options) {
+
+ if (Object.keys(value).length >= limit) {
+ return value;
+ }
+
+ return this.createError('object.min', { limit }, state, options);
+ });
+ }
+
+ max(limit) {
+
+ Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
+
+ return this._test('max', limit, function (value, state, options) {
+
+ if (Object.keys(value).length <= limit) {
+ return value;
+ }
+
+ return this.createError('object.max', { limit }, state, options);
+ });
+ }
+
+ pattern(pattern, schema) {
+
+ Hoek.assert(pattern instanceof RegExp, 'Invalid regular expression');
+ Hoek.assert(schema !== undefined, 'Invalid rule');
+
+ pattern = new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined); // Future version should break this and forbid unsupported regex flags
+
+ try {
+ schema = Cast.schema(this._currentJoi, schema);
+ }
+ catch (castErr) {
+ if (castErr.hasOwnProperty('path')) {
+ castErr.message = castErr.message + '(' + castErr.path + ')';
+ }
+
+ throw castErr;
+ }
+
+
+ const obj = this.clone();
+ obj._inner.patterns.push({ regex: pattern, rule: schema });
+ return obj;
+ }
+
+ schema() {
+
+ return this._test('schema', null, function (value, state, options) {
+
+ if (value instanceof Any) {
+ return value;
+ }
+
+ return this.createError('object.schema', null, state, options);
+ });
+ }
+
+ with(key, peers) {
+
+ return this._dependency('with', key, peers);
+ }
+
+ without(key, peers) {
+
+ return this._dependency('without', key, peers);
+ }
+
+ xor() {
+
+ const peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this._dependency('xor', null, peers);
+ }
+
+ or() {
+
+ const peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this._dependency('or', null, peers);
+ }
+
+ and() {
+
+ const peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this._dependency('and', null, peers);
+ }
+
+ nand() {
+
+ const peers = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this._dependency('nand', null, peers);
+ }
+
+ requiredKeys(children) {
+
+ children = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this.applyFunctionToChildren(children, 'required');
+ }
+
+ optionalKeys(children) {
+
+ children = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this.applyFunctionToChildren(children, 'optional');
+ }
+
+ forbiddenKeys(children) {
+
+ children = Hoek.flatten(Array.prototype.slice.call(arguments));
+ return this.applyFunctionToChildren(children, 'forbidden');
+ }
+
+ rename(from, to, options) {
+
+ Hoek.assert(typeof from === 'string' || from instanceof RegExp, 'Rename missing the from argument');
+ Hoek.assert(typeof to === 'string', 'Rename missing the to argument');
+ Hoek.assert(to !== from, 'Cannot rename key to same name:', from);
+
+ for (let i = 0; i < this._inner.renames.length; ++i) {
+ Hoek.assert(this._inner.renames[i].from !== from, 'Cannot rename the same key multiple times');
+ }
+
+ const obj = this.clone();
+
+ obj._inner.renames.push({
+ from,
+ to,
+ options: Hoek.applyToDefaults(internals.renameDefaults, options || {}),
+ isRegExp: from instanceof RegExp
+ });
+
+ return obj;
+ }
+
+ applyFunctionToChildren(children, fn, args, root) {
+
+ children = [].concat(children);
+ Hoek.assert(children.length > 0, 'expected at least one children');
+
+ const groupedChildren = internals.groupChildren(children);
+ let obj;
+
+ if ('' in groupedChildren) {
+ obj = this[fn].apply(this, args);
+ delete groupedChildren[''];
+ }
+ else {
+ obj = this.clone();
+ }
+
+ if (obj._inner.children) {
+ root = root ? (root + '.') : '';
+
+ for (let i = 0; i < obj._inner.children.length; ++i) {
+ const child = obj._inner.children[i];
+ const group = groupedChildren[child.key];
+
+ if (group) {
+ obj._inner.children[i] = {
+ key: child.key,
+ _refs: child._refs,
+ schema: child.schema.applyFunctionToChildren(group, fn, args, root + child.key)
+ };
+
+ delete groupedChildren[child.key];
+ }
+ }
+ }
+
+ const remaining = Object.keys(groupedChildren);
+ Hoek.assert(remaining.length === 0, 'unknown key(s)', remaining.join(', '));
+
+ return obj;
+ }
+
+ _dependency(type, key, peers) {
+
+ peers = [].concat(peers);
+ for (let i = 0; i < peers.length; ++i) {
+ Hoek.assert(typeof peers[i] === 'string', type, 'peers must be a string or array of strings');
+ }
+
+ const obj = this.clone();
+ obj._inner.dependencies.push({ type, key, peers });
+ return obj;
+ }
+
+ describe(shallow) {
+
+ const description = Any.prototype.describe.call(this);
+
+ if (description.rules) {
+ for (let i = 0; i < description.rules.length; ++i) {
+ const rule = description.rules[i];
+ // Coverage off for future-proof descriptions, only object().assert() is use right now
+ if (/* $lab:coverage:off$ */rule.arg &&
+ typeof rule.arg === 'object' &&
+ rule.arg.schema &&
+ rule.arg.ref /* $lab:coverage:on$ */) {
+ rule.arg = {
+ schema: rule.arg.schema.describe(),
+ ref: rule.arg.ref.toString()
+ };
+ }
+ }
+ }
+
+ if (this._inner.children &&
+ !shallow) {
+
+ description.children = {};
+ for (let i = 0; i < this._inner.children.length; ++i) {
+ const child = this._inner.children[i];
+ description.children[child.key] = child.schema.describe();
+ }
+ }
+
+ if (this._inner.dependencies.length) {
+ description.dependencies = Hoek.clone(this._inner.dependencies);
+ }
+
+ if (this._inner.patterns.length) {
+ description.patterns = [];
+
+ for (let i = 0; i < this._inner.patterns.length; ++i) {
+ const pattern = this._inner.patterns[i];
+ description.patterns.push({ regex: pattern.regex.toString(), rule: pattern.rule.describe() });
+ }
+ }
+
+ if (this._inner.renames.length > 0) {
+ description.renames = Hoek.clone(this._inner.renames);
+ }
+
+ return description;
+ }
+
+ assert(ref, schema, message) {
+
+ ref = Cast.ref(ref);
+ Hoek.assert(ref.isContext || ref.depth > 1, 'Cannot use assertions for root level references - use direct key rules instead');
+ message = message || 'pass the assertion test';
+
+ try {
+ schema = Cast.schema(this._currentJoi, schema);
+ }
+ catch (castErr) {
+ if (castErr.hasOwnProperty('path')) {
+ castErr.message = castErr.message + '(' + castErr.path + ')';
+ }
+
+ throw castErr;
+ }
+
+ const key = ref.path[ref.path.length - 1];
+ const path = ref.path.join('.');
+
+ return this._test('assert', { schema, ref }, function (value, state, options) {
+
+ const result = schema._validate(ref(value), null, options, value);
+ if (!result.errors) {
+ return value;
+ }
+
+ const localState = Hoek.merge({}, state);
+ localState.key = key;
+ localState.path = ref.path;
+ return this.createError('object.assert', { ref: path, message }, localState, options);
+ });
+ }
+
+ type(constructor, name) {
+
+ Hoek.assert(typeof constructor === 'function', 'type must be a constructor function');
+ const typeData = {
+ name: name || constructor.name,
+ ctor: constructor
+ };
+
+ return this._test('type', typeData, function (value, state, options) {
+
+ if (value instanceof constructor) {
+ return value;
+ }
+
+ return this.createError('object.type', { type: typeData.name }, state, options);
+ });
+ }
+};
+
+internals.safeParse = function (value) {
+
+ try {
+ return JSON.parse(value);
+ }
+ catch (parseErr) {}
+
+ return value;
+};
+
+
+internals.renameDefaults = {
+ alias: false, // Keep old value in place
+ multiple: false, // Allow renaming multiple keys into the same target
+ override: false // Overrides an existing key
+};
+
+
+internals.groupChildren = function (children) {
+
+ children.sort();
+
+ const grouped = {};
+
+ for (let i = 0; i < children.length; ++i) {
+ const child = children[i];
+ Hoek.assert(typeof child === 'string', 'children must be strings');
+ const group = child.split('.')[0];
+ const childGroup = grouped[group] = (grouped[group] || []);
+ childGroup.push(child.substring(group.length + 1));
+ }
+
+ return grouped;
+};
+
+
+internals.keysToLabels = function (schema, keys) {
+
+ const children = schema._inner.children;
+
+ if (!children) {
+ return keys;
+ }
+
+ const findLabel = function (key) {
+
+ const matchingChild = children.find((child) => child.key === key);
+ return matchingChild ? matchingChild.schema._getLabel(key) : key;
+ };
+
+ if (Array.isArray(keys)) {
+ return keys.map(findLabel);
+ }
+
+ return findLabel(keys);
+};
+
+
+internals.with = function (value, peers, parent, state, options) {
+
+ if (value === undefined) {
+ return value;
+ }
+
+ for (let i = 0; i < peers.length; ++i) {
+ const peer = peers[i];
+ if (!Object.prototype.hasOwnProperty.call(parent, peer) ||
+ parent[peer] === undefined) {
+
+ return this.createError('object.with', {
+ main: state.key,
+ mainWithLabel: internals.keysToLabels(this, state.key),
+ peer,
+ peerWithLabel: internals.keysToLabels(this, peer)
+ }, state, options);
+ }
+ }
+
+ return value;
+};
+
+
+internals.without = function (value, peers, parent, state, options) {
+
+ if (value === undefined) {
+ return value;
+ }
+
+ for (let i = 0; i < peers.length; ++i) {
+ const peer = peers[i];
+ if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+ parent[peer] !== undefined) {
+
+ return this.createError('object.without', {
+ main: state.key,
+ mainWithLabel: internals.keysToLabels(this, state.key),
+ peer,
+ peerWithLabel: internals.keysToLabels(this, peer)
+ }, state, options);
+ }
+ }
+
+ return value;
+};
+
+
+internals.xor = function (value, peers, parent, state, options) {
+
+ const present = [];
+ for (let i = 0; i < peers.length; ++i) {
+ const peer = peers[i];
+ if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+ parent[peer] !== undefined) {
+
+ present.push(peer);
+ }
+ }
+
+ if (present.length === 1) {
+ return value;
+ }
+
+ const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) };
+
+ if (present.length === 0) {
+ return this.createError('object.missing', context, state, options);
+ }
+
+ return this.createError('object.xor', context, state, options);
+};
+
+
+internals.or = function (value, peers, parent, state, options) {
+
+ for (let i = 0; i < peers.length; ++i) {
+ const peer = peers[i];
+ if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+ parent[peer] !== undefined) {
+ return value;
+ }
+ }
+
+ return this.createError('object.missing', {
+ peers,
+ peersWithLabels: internals.keysToLabels(this, peers)
+ }, state, options);
+};
+
+
+internals.and = function (value, peers, parent, state, options) {
+
+ const missing = [];
+ const present = [];
+ const count = peers.length;
+ for (let i = 0; i < count; ++i) {
+ const peer = peers[i];
+ if (!Object.prototype.hasOwnProperty.call(parent, peer) ||
+ parent[peer] === undefined) {
+
+ missing.push(peer);
+ }
+ else {
+ present.push(peer);
+ }
+ }
+
+ const aon = (missing.length === count || present.length === count);
+
+ if (!aon) {
+
+ return this.createError('object.and', {
+ present,
+ presentWithLabels: internals.keysToLabels(this, present),
+ missing,
+ missingWithLabels: internals.keysToLabels(this, missing)
+ }, state, options);
+ }
+};
+
+
+internals.nand = function (value, peers, parent, state, options) {
+
+ const present = [];
+ for (let i = 0; i < peers.length; ++i) {
+ const peer = peers[i];
+ if (Object.prototype.hasOwnProperty.call(parent, peer) &&
+ parent[peer] !== undefined) {
+
+ present.push(peer);
+ }
+ }
+
+ const values = Hoek.clone(peers);
+ const main = values.splice(0, 1)[0];
+ const allPresent = (present.length === peers.length);
+ return allPresent ? this.createError('object.nand', {
+ main,
+ mainWithLabel: internals.keysToLabels(this, main),
+ peers: values,
+ peersWithLabels: internals.keysToLabels(this, values)
+ }, state, options) : null;
+};
+
+
+module.exports = new internals.Object();
diff --git a/node_modules/joi/lib/types/string/index.js b/node_modules/joi/lib/types/string/index.js
new file mode 100755
index 00000000..e63199d8
--- /dev/null
+++ b/node_modules/joi/lib/types/string/index.js
@@ -0,0 +1,632 @@
+'use strict';
+
+// Load modules
+
+const Net = require('net');
+const Hoek = require('hoek');
+let Isemail; // Loaded on demand
+const Any = require('../any');
+const Ref = require('../../ref');
+const JoiDate = require('../date');
+const Uri = require('./uri');
+const Ip = require('./ip');
+
+// Declare internals
+
+const internals = {
+ uriRegex: Uri.createUriRegex(),
+ ipRegex: Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], 'optional'),
+ guidBrackets: {
+ '{': '}', '[': ']', '(': ')', '': ''
+ },
+ guidVersions: {
+ uuidv1: '1',
+ uuidv2: '2',
+ uuidv3: '3',
+ uuidv4: '4',
+ uuidv5: '5'
+ },
+ cidrPresences: ['required', 'optional', 'forbidden'],
+ normalizationForms: ['NFC', 'NFD', 'NFKC', 'NFKD']
+};
+
+internals.String = class extends Any {
+
+ constructor() {
+
+ super();
+ this._type = 'string';
+ this._invalids.add('');
+ }
+
+ _base(value, state, options) {
+
+ if (typeof value === 'string' &&
+ options.convert) {
+
+ if (this._flags.normalize) {
+ value = value.normalize(this._flags.normalize);
+ }
+
+ if (this._flags.case) {
+ value = (this._flags.case === 'upper' ? value.toLocaleUpperCase() : value.toLocaleLowerCase());
+ }
+
+ if (this._flags.trim) {
+ value = value.trim();
+ }
+
+ if (this._inner.replacements) {
+
+ for (let i = 0; i < this._inner.replacements.length; ++i) {
+ const replacement = this._inner.replacements[i];
+ value = value.replace(replacement.pattern, replacement.replacement);
+ }
+ }
+
+ if (this._flags.truncate) {
+ for (let i = 0; i < this._tests.length; ++i) {
+ const test = this._tests[i];
+ if (test.name === 'max') {
+ value = value.slice(0, test.arg);
+ break;
+ }
+ }
+ }
+ }
+
+ return {
+ value,
+ errors: (typeof value === 'string') ? null : this.createError('string.base', { value }, state, options)
+ };
+ }
+
+ insensitive() {
+
+ if (this._flags.insensitive) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.insensitive = true;
+ return obj;
+ }
+
+ creditCard() {
+
+ return this._test('creditCard', undefined, function (value, state, options) {
+
+ let i = value.length;
+ let sum = 0;
+ let mul = 1;
+
+ while (i--) {
+ const char = value.charAt(i) * mul;
+ sum = sum + (char - (char > 9) * 9);
+ mul = mul ^ 3;
+ }
+
+ const check = (sum % 10 === 0) && (sum > 0);
+ return check ? value : this.createError('string.creditCard', { value }, state, options);
+ });
+ }
+
+ regex(pattern, patternOptions) {
+
+ Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
+
+ const patternObject = {
+ pattern: new RegExp(pattern.source, pattern.ignoreCase ? 'i' : undefined) // Future version should break this and forbid unsupported regex flags
+ };
+
+ if (typeof patternOptions === 'string') {
+ patternObject.name = patternOptions;
+ }
+ else if (typeof patternOptions === 'object') {
+ patternObject.invert = !!patternOptions.invert;
+
+ if (patternOptions.name) {
+ patternObject.name = patternOptions.name;
+ }
+ }
+
+ const errorCode = ['string.regex', patternObject.invert ? '.invert' : '', patternObject.name ? '.name' : '.base'].join('');
+
+ return this._test('regex', patternObject, function (value, state, options) {
+
+ const patternMatch = patternObject.pattern.test(value);
+
+ if (patternMatch ^ patternObject.invert) {
+ return value;
+ }
+
+ return this.createError(errorCode, { name: patternObject.name, pattern: patternObject.pattern, value }, state, options);
+ });
+ }
+
+ alphanum() {
+
+ return this._test('alphanum', undefined, function (value, state, options) {
+
+ if (/^[a-zA-Z0-9]+$/.test(value)) {
+ return value;
+ }
+
+ return this.createError('string.alphanum', { value }, state, options);
+ });
+ }
+
+ token() {
+
+ return this._test('token', undefined, function (value, state, options) {
+
+ if (/^\w+$/.test(value)) {
+ return value;
+ }
+
+ return this.createError('string.token', { value }, state, options);
+ });
+ }
+
+ email(isEmailOptions) {
+
+ if (isEmailOptions) {
+ Hoek.assert(typeof isEmailOptions === 'object', 'email options must be an object');
+ Hoek.assert(typeof isEmailOptions.checkDNS === 'undefined', 'checkDNS option is not supported');
+ Hoek.assert(typeof isEmailOptions.tldWhitelist === 'undefined' ||
+ typeof isEmailOptions.tldWhitelist === 'object', 'tldWhitelist must be an array or object');
+ Hoek.assert(
+ typeof isEmailOptions.minDomainAtoms === 'undefined' ||
+ Number.isSafeInteger(isEmailOptions.minDomainAtoms) &&
+ isEmailOptions.minDomainAtoms > 0,
+ 'minDomainAtoms must be a positive integer'
+ );
+ Hoek.assert(
+ typeof isEmailOptions.errorLevel === 'undefined' ||
+ typeof isEmailOptions.errorLevel === 'boolean' ||
+ (
+ Number.isSafeInteger(isEmailOptions.errorLevel) &&
+ isEmailOptions.errorLevel >= 0
+ ),
+ 'errorLevel must be a non-negative integer or boolean'
+ );
+ }
+
+ return this._test('email', isEmailOptions, function (value, state, options) {
+
+ Isemail = Isemail || require('isemail');
+
+ try {
+ const result = Isemail.validate(value, isEmailOptions);
+ if (result === true || result === 0) {
+ return value;
+ }
+ }
+ catch (e) { }
+
+ return this.createError('string.email', { value }, state, options);
+ });
+ }
+
+ ip(ipOptions) {
+
+ let regex = internals.ipRegex;
+ ipOptions = ipOptions || {};
+ Hoek.assert(typeof ipOptions === 'object', 'options must be an object');
+
+ if (ipOptions.cidr) {
+ Hoek.assert(typeof ipOptions.cidr === 'string', 'cidr must be a string');
+ ipOptions.cidr = ipOptions.cidr.toLowerCase();
+
+ Hoek.assert(Hoek.contain(internals.cidrPresences, ipOptions.cidr), 'cidr must be one of ' + internals.cidrPresences.join(', '));
+
+ // If we only received a `cidr` setting, create a regex for it. But we don't need to create one if `cidr` is "optional" since that is the default
+ if (!ipOptions.version && ipOptions.cidr !== 'optional') {
+ regex = Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], ipOptions.cidr);
+ }
+ }
+ else {
+
+ // Set our default cidr strategy
+ ipOptions.cidr = 'optional';
+ }
+
+ let versions;
+ if (ipOptions.version) {
+ if (!Array.isArray(ipOptions.version)) {
+ ipOptions.version = [ipOptions.version];
+ }
+
+ Hoek.assert(ipOptions.version.length >= 1, 'version must have at least 1 version specified');
+
+ versions = [];
+ for (let i = 0; i < ipOptions.version.length; ++i) {
+ let version = ipOptions.version[i];
+ Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
+ version = version.toLowerCase();
+ Hoek.assert(Ip.versions[version], 'version at position ' + i + ' must be one of ' + Object.keys(Ip.versions).join(', '));
+ versions.push(version);
+ }
+
+ // Make sure we have a set of versions
+ versions = Hoek.unique(versions);
+
+ regex = Ip.createIpRegex(versions, ipOptions.cidr);
+ }
+
+ return this._test('ip', ipOptions, function (value, state, options) {
+
+ if (regex.test(value)) {
+ return value;
+ }
+
+ if (versions) {
+ return this.createError('string.ipVersion', { value, cidr: ipOptions.cidr, version: versions }, state, options);
+ }
+
+ return this.createError('string.ip', { value, cidr: ipOptions.cidr }, state, options);
+ });
+ }
+
+ uri(uriOptions) {
+
+ let customScheme = '';
+ let allowRelative = false;
+ let relativeOnly = false;
+ let regex = internals.uriRegex;
+
+ if (uriOptions) {
+ Hoek.assert(typeof uriOptions === 'object', 'options must be an object');
+
+ if (uriOptions.scheme) {
+ Hoek.assert(uriOptions.scheme instanceof RegExp || typeof uriOptions.scheme === 'string' || Array.isArray(uriOptions.scheme), 'scheme must be a RegExp, String, or Array');
+
+ if (!Array.isArray(uriOptions.scheme)) {
+ uriOptions.scheme = [uriOptions.scheme];
+ }
+
+ Hoek.assert(uriOptions.scheme.length >= 1, 'scheme must have at least 1 scheme specified');
+
+ // Flatten the array into a string to be used to match the schemes.
+ for (let i = 0; i < uriOptions.scheme.length; ++i) {
+ const scheme = uriOptions.scheme[i];
+ Hoek.assert(scheme instanceof RegExp || typeof scheme === 'string', 'scheme at position ' + i + ' must be a RegExp or String');
+
+ // Add OR separators if a value already exists
+ customScheme = customScheme + (customScheme ? '|' : '');
+
+ // If someone wants to match HTTP or HTTPS for example then we need to support both RegExp and String so we don't escape their pattern unknowingly.
+ if (scheme instanceof RegExp) {
+ customScheme = customScheme + scheme.source;
+ }
+ else {
+ Hoek.assert(/[a-zA-Z][a-zA-Z0-9+-\.]*/.test(scheme), 'scheme at position ' + i + ' must be a valid scheme');
+ customScheme = customScheme + Hoek.escapeRegex(scheme);
+ }
+ }
+ }
+
+ if (uriOptions.allowRelative) {
+ allowRelative = true;
+ }
+
+ if (uriOptions.relativeOnly) {
+ relativeOnly = true;
+ }
+ }
+
+ if (customScheme || allowRelative || relativeOnly) {
+ regex = Uri.createUriRegex(customScheme, allowRelative, relativeOnly);
+ }
+
+ return this._test('uri', uriOptions, function (value, state, options) {
+
+ if (regex.test(value)) {
+ return value;
+ }
+
+ if (relativeOnly) {
+ return this.createError('string.uriRelativeOnly', { value }, state, options);
+ }
+
+ if (customScheme) {
+ return this.createError('string.uriCustomScheme', { scheme: customScheme, value }, state, options);
+ }
+
+ return this.createError('string.uri', { value }, state, options);
+ });
+ }
+
+ isoDate() {
+
+ return this._test('isoDate', undefined, function (value, state, options) {
+
+ if (JoiDate._isIsoDate(value)) {
+ if (!options.convert) {
+ return value;
+ }
+
+ const d = new Date(value);
+ if (!isNaN(d.getTime())) {
+ return d.toISOString();
+ }
+ }
+
+ return this.createError('string.isoDate', { value }, state, options);
+ });
+ }
+
+ guid(guidOptions) {
+
+ let versionNumbers = '';
+
+ if (guidOptions && guidOptions.version) {
+ if (!Array.isArray(guidOptions.version)) {
+ guidOptions.version = [guidOptions.version];
+ }
+
+ Hoek.assert(guidOptions.version.length >= 1, 'version must have at least 1 valid version specified');
+ const versions = new Set();
+
+ for (let i = 0; i < guidOptions.version.length; ++i) {
+ let version = guidOptions.version[i];
+ Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
+ version = version.toLowerCase();
+ const versionNumber = internals.guidVersions[version];
+ Hoek.assert(versionNumber, 'version at position ' + i + ' must be one of ' + Object.keys(internals.guidVersions).join(', '));
+ Hoek.assert(!(versions.has(versionNumber)), 'version at position ' + i + ' must not be a duplicate.');
+
+ versionNumbers += versionNumber;
+ versions.add(versionNumber);
+ }
+ }
+
+ const guidRegex = new RegExp(`^([\\[{\\(]?)[0-9A-F]{8}([:-]?)[0-9A-F]{4}\\2?[${versionNumbers || '0-9A-F'}][0-9A-F]{3}\\2?[${versionNumbers ? '89AB' : '0-9A-F'}][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$`, 'i');
+
+ return this._test('guid', guidOptions, function (value, state, options) {
+
+ const results = guidRegex.exec(value);
+
+ if (!results) {
+ return this.createError('string.guid', { value }, state, options);
+ }
+
+ // Matching braces
+ if (internals.guidBrackets[results[1]] !== results[results.length - 1]) {
+ return this.createError('string.guid', { value }, state, options);
+ }
+
+ return value;
+ });
+ }
+
+ hex() {
+
+ const regex = /^[a-f0-9]+$/i;
+
+ return this._test('hex', regex, function (value, state, options) {
+
+ if (regex.test(value)) {
+ return value;
+ }
+
+ return this.createError('string.hex', { value }, state, options);
+ });
+ }
+
+ base64(base64Options) {
+
+ base64Options = base64Options || {};
+
+ // Validation.
+ Hoek.assert(typeof base64Options === 'object', 'base64 options must be an object');
+ Hoek.assert(typeof base64Options.paddingRequired === 'undefined' || typeof base64Options.paddingRequired === 'boolean',
+ 'paddingRequired must be boolean');
+
+ // Determine if padding is required.
+ const paddingRequired = base64Options.paddingRequired === false ?
+ base64Options.paddingRequired
+ : base64Options.paddingRequired || true;
+
+ // Set validation based on preference.
+ const regex = paddingRequired ?
+ // Padding is required.
+ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
+ // Padding is optional.
+ : /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/;
+
+ return this._test('base64', regex, function (value, state, options) {
+
+ if (regex.test(value)) {
+ return value;
+ }
+
+ return this.createError('string.base64', { value }, state, options);
+ });
+ }
+
+ hostname() {
+
+ const regex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
+
+ return this._test('hostname', undefined, function (value, state, options) {
+
+ if ((value.length <= 255 && regex.test(value)) ||
+ Net.isIPv6(value)) {
+
+ return value;
+ }
+
+ return this.createError('string.hostname', { value }, state, options);
+ });
+ }
+
+ normalize(form) {
+
+ form = form || 'NFC';
+ Hoek.assert(Hoek.contain(internals.normalizationForms, form), 'normalization form must be one of ' + internals.normalizationForms.join(', '));
+
+ const obj = this._test('normalize', form, function (value, state, options) {
+
+ if (options.convert ||
+ value === value.normalize(form)) {
+
+ return value;
+ }
+
+ return this.createError('string.normalize', { value, form }, state, options);
+ });
+
+ obj._flags.normalize = form;
+ return obj;
+ }
+
+ lowercase() {
+
+ const obj = this._test('lowercase', undefined, function (value, state, options) {
+
+ if (options.convert ||
+ value === value.toLocaleLowerCase()) {
+
+ return value;
+ }
+
+ return this.createError('string.lowercase', { value }, state, options);
+ });
+
+ obj._flags.case = 'lower';
+ return obj;
+ }
+
+ uppercase() {
+
+ const obj = this._test('uppercase', undefined, function (value, state, options) {
+
+ if (options.convert ||
+ value === value.toLocaleUpperCase()) {
+
+ return value;
+ }
+
+ return this.createError('string.uppercase', { value }, state, options);
+ });
+
+ obj._flags.case = 'upper';
+ return obj;
+ }
+
+ trim() {
+
+ const obj = this._test('trim', undefined, function (value, state, options) {
+
+ if (options.convert ||
+ value === value.trim()) {
+
+ return value;
+ }
+
+ return this.createError('string.trim', { value }, state, options);
+ });
+
+ obj._flags.trim = true;
+ return obj;
+ }
+
+ replace(pattern, replacement) {
+
+ if (typeof pattern === 'string') {
+ pattern = new RegExp(Hoek.escapeRegex(pattern), 'g');
+ }
+
+ Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
+ Hoek.assert(typeof replacement === 'string', 'replacement must be a String');
+
+ // This can not be considere a test like trim, we can't "reject"
+ // anything from this rule, so just clone the current object
+ const obj = this.clone();
+
+ if (!obj._inner.replacements) {
+ obj._inner.replacements = [];
+ }
+
+ obj._inner.replacements.push({
+ pattern,
+ replacement
+ });
+
+ return obj;
+ }
+
+ truncate(enabled) {
+
+ const value = enabled === undefined ? true : !!enabled;
+
+ if (this._flags.truncate === value) {
+ return this;
+ }
+
+ const obj = this.clone();
+ obj._flags.truncate = value;
+ return obj;
+ }
+
+};
+
+internals.compare = function (type, compare) {
+
+ return function (limit, encoding) {
+
+ const isRef = Ref.isRef(limit);
+
+ Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
+ Hoek.assert(!encoding || Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
+
+ return this._test(type, limit, function (value, state, options) {
+
+ let compareTo;
+ if (isRef) {
+ compareTo = limit(state.reference || state.parent, options);
+
+ if (!Number.isSafeInteger(compareTo)) {
+ return this.createError('string.ref', { ref: limit.key }, state, options);
+ }
+ }
+ else {
+ compareTo = limit;
+ }
+
+ if (compare(value, compareTo, encoding)) {
+ return value;
+ }
+
+ return this.createError('string.' + type, { limit: compareTo, value, encoding }, state, options);
+ });
+ };
+};
+
+
+internals.String.prototype.min = internals.compare('min', (value, limit, encoding) => {
+
+ const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+ return length >= limit;
+});
+
+
+internals.String.prototype.max = internals.compare('max', (value, limit, encoding) => {
+
+ const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+ return length <= limit;
+});
+
+
+internals.String.prototype.length = internals.compare('length', (value, limit, encoding) => {
+
+ const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
+ return length === limit;
+});
+
+// Aliases
+
+internals.String.prototype.uuid = internals.String.prototype.guid;
+
+module.exports = new internals.String();
diff --git a/node_modules/joi/lib/types/string/ip.js b/node_modules/joi/lib/types/string/ip.js
new file mode 100644
index 00000000..8478c127
--- /dev/null
+++ b/node_modules/joi/lib/types/string/ip.js
@@ -0,0 +1,54 @@
+'use strict';
+
+// Load modules
+
+const RFC3986 = require('./rfc3986');
+
+
+// Declare internals
+
+const internals = {
+ Ip: {
+ cidrs: {
+ ipv4: {
+ required: '\\/(?:' + RFC3986.ipv4Cidr + ')',
+ optional: '(?:\\/(?:' + RFC3986.ipv4Cidr + '))?',
+ forbidden: ''
+ },
+ ipv6: {
+ required: '\\/' + RFC3986.ipv6Cidr,
+ optional: '(?:\\/' + RFC3986.ipv6Cidr + ')?',
+ forbidden: ''
+ },
+ ipvfuture: {
+ required: '\\/' + RFC3986.ipv6Cidr,
+ optional: '(?:\\/' + RFC3986.ipv6Cidr + ')?',
+ forbidden: ''
+ }
+ },
+ versions: {
+ ipv4: RFC3986.IPv4address,
+ ipv6: RFC3986.IPv6address,
+ ipvfuture: RFC3986.IPvFuture
+ }
+ }
+};
+
+
+internals.Ip.createIpRegex = function (versions, cidr) {
+
+ let regex;
+ for (let i = 0; i < versions.length; ++i) {
+ const version = versions[i];
+ if (!regex) {
+ regex = '^(?:' + internals.Ip.versions[version] + internals.Ip.cidrs[version][cidr];
+ }
+ else {
+ regex += '|' + internals.Ip.versions[version] + internals.Ip.cidrs[version][cidr];
+ }
+ }
+
+ return new RegExp(regex + ')$');
+};
+
+module.exports = internals.Ip;
diff --git a/node_modules/joi/lib/types/string/rfc3986.js b/node_modules/joi/lib/types/string/rfc3986.js
new file mode 100644
index 00000000..106e457a
--- /dev/null
+++ b/node_modules/joi/lib/types/string/rfc3986.js
@@ -0,0 +1,209 @@
+'use strict';
+
+// Load modules
+
+
+// Delcare internals
+
+const internals = {
+ rfc3986: {}
+};
+
+
+internals.generate = function () {
+
+ /**
+ * elements separated by forward slash ("/") are alternatives.
+ */
+ const or = '|';
+
+ /**
+ * Rule to support zero-padded addresses.
+ */
+ const zeroPad = '0?';
+
+ /**
+ * DIGIT = %x30-39 ; 0-9
+ */
+ const digit = '0-9';
+ const digitOnly = '[' + digit + ']';
+
+ /**
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ */
+ const alpha = 'a-zA-Z';
+ const alphaOnly = '[' + alpha + ']';
+
+ /**
+ * IPv4
+ * cidr = DIGIT ; 0-9
+ * / %x31-32 DIGIT ; 10-29
+ * / "3" %x30-32 ; 30-32
+ */
+ internals.rfc3986.ipv4Cidr = digitOnly + or + '[1-2]' + digitOnly + or + '3' + '[0-2]';
+
+ /**
+ * IPv6
+ * cidr = DIGIT ; 0-9
+ * / %x31-39 DIGIT ; 10-99
+ * / "1" %x0-1 DIGIT ; 100-119
+ * / "12" %x0-8 ; 120-128
+ */
+ internals.rfc3986.ipv6Cidr = '(?:' + zeroPad + zeroPad + digitOnly + or + zeroPad + '[1-9]' + digitOnly + or + '1' + '[01]' + digitOnly + or + '12[0-8])';
+
+ /**
+ * HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+ */
+ const hexDigit = digit + 'A-Fa-f';
+ const hexDigitOnly = '[' + hexDigit + ']';
+
+ /**
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ */
+ const unreserved = alpha + digit + '-\\._~';
+
+ /**
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+ */
+ const subDelims = '!\\$&\'\\(\\)\\*\\+,;=';
+
+ /**
+ * pct-encoded = "%" HEXDIG HEXDIG
+ */
+ const pctEncoded = '%' + hexDigit;
+
+ /**
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+ const pchar = unreserved + pctEncoded + subDelims + ':@';
+ const pcharOnly = '[' + pchar + ']';
+
+ /**
+ * dec-octet = DIGIT ; 0-9
+ * / %x31-39 DIGIT ; 10-99
+ * / "1" 2DIGIT ; 100-199
+ * / "2" %x30-34 DIGIT ; 200-249
+ * / "25" %x30-35 ; 250-255
+ */
+ const decOctect = '(?:' + zeroPad + zeroPad + digitOnly + or + zeroPad + '[1-9]' + digitOnly + or + '1' + digitOnly + digitOnly + or + '2' + '[0-4]' + digitOnly + or + '25' + '[0-5])';
+
+ /**
+ * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+ */
+ internals.rfc3986.IPv4address = '(?:' + decOctect + '\\.){3}' + decOctect;
+
+ /**
+ * h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal
+ * ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address
+ * IPv6address = 6( h16 ":" ) ls32
+ * / "::" 5( h16 ":" ) ls32
+ * / [ h16 ] "::" 4( h16 ":" ) ls32
+ * / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ * / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ * / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ * / [ *4( h16 ":" ) h16 ] "::" ls32
+ * / [ *5( h16 ":" ) h16 ] "::" h16
+ * / [ *6( h16 ":" ) h16 ] "::"
+ */
+ const h16 = hexDigitOnly + '{1,4}';
+ const ls32 = '(?:' + h16 + ':' + h16 + '|' + internals.rfc3986.IPv4address + ')';
+ const IPv6SixHex = '(?:' + h16 + ':){6}' + ls32;
+ const IPv6FiveHex = '::(?:' + h16 + ':){5}' + ls32;
+ const IPv6FourHex = '(?:' + h16 + ')?::(?:' + h16 + ':){4}' + ls32;
+ const IPv6ThreeHex = '(?:(?:' + h16 + ':){0,1}' + h16 + ')?::(?:' + h16 + ':){3}' + ls32;
+ const IPv6TwoHex = '(?:(?:' + h16 + ':){0,2}' + h16 + ')?::(?:' + h16 + ':){2}' + ls32;
+ const IPv6OneHex = '(?:(?:' + h16 + ':){0,3}' + h16 + ')?::' + h16 + ':' + ls32;
+ const IPv6NoneHex = '(?:(?:' + h16 + ':){0,4}' + h16 + ')?::' + ls32;
+ const IPv6NoneHex2 = '(?:(?:' + h16 + ':){0,5}' + h16 + ')?::' + h16;
+ const IPv6NoneHex3 = '(?:(?:' + h16 + ':){0,6}' + h16 + ')?::';
+ internals.rfc3986.IPv6address = '(?:' + IPv6SixHex + or + IPv6FiveHex + or + IPv6FourHex + or + IPv6ThreeHex + or + IPv6TwoHex + or + IPv6OneHex + or + IPv6NoneHex + or + IPv6NoneHex2 + or + IPv6NoneHex3 + ')';
+
+ /**
+ * IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+ */
+ internals.rfc3986.IPvFuture = 'v' + hexDigitOnly + '+\\.[' + unreserved + subDelims + ':]+';
+
+ /**
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+ internals.rfc3986.scheme = alphaOnly + '[' + alpha + digit + '+-\\.]*';
+
+ /**
+ * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ */
+ const userinfo = '[' + unreserved + pctEncoded + subDelims + ':]*';
+
+ /**
+ * IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+ */
+ const IPLiteral = '\\[(?:' + internals.rfc3986.IPv6address + or + internals.rfc3986.IPvFuture + ')\\]';
+
+ /**
+ * reg-name = *( unreserved / pct-encoded / sub-delims )
+ */
+ const regName = '[' + unreserved + pctEncoded + subDelims + ']{0,255}';
+
+ /**
+ * host = IP-literal / IPv4address / reg-name
+ */
+ const host = '(?:' + IPLiteral + or + internals.rfc3986.IPv4address + or + regName + ')';
+
+ /**
+ * port = *DIGIT
+ */
+ const port = digitOnly + '*';
+
+ /**
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ */
+ const authority = '(?:' + userinfo + '@)?' + host + '(?::' + port + ')?';
+
+ /**
+ * segment = *pchar
+ * segment-nz = 1*pchar
+ * path = path-abempty ; begins with "/" or is empty
+ * / path-absolute ; begins with "/" but not "//"
+ * / path-noscheme ; begins with a non-colon segment
+ * / path-rootless ; begins with a segment
+ * / path-empty ; zero characters
+ * path-abempty = *( "/" segment )
+ * path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ * path-rootless = segment-nz *( "/" segment )
+ */
+ const segment = pcharOnly + '*';
+ const segmentNz = pcharOnly + '+';
+ const segmentNzNc = '[' + unreserved + pctEncoded + subDelims + '@' + ']+';
+ const pathEmpty = '';
+ const pathAbEmpty = '(?:\\/' + segment + ')*';
+ const pathAbsolute = '\\/(?:' + segmentNz + pathAbEmpty + ')?';
+ const pathRootless = segmentNz + pathAbEmpty;
+ const pathNoScheme = segmentNzNc + pathAbEmpty;
+
+ /**
+ * hier-part = "//" authority path
+ */
+ internals.rfc3986.hierPart = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + or + pathAbsolute + or + pathRootless + ')';
+
+ /**
+ * relative-part = "//" authority path-abempty
+ * / path-absolute
+ * / path-noscheme
+ * / path-empty
+ */
+ internals.rfc3986.relativeRef = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + or + pathAbsolute + or + pathNoScheme + or + pathEmpty + ')';
+
+ /**
+ * query = *( pchar / "/" / "?" )
+ */
+ internals.rfc3986.query = '[' + pchar + '\\/\\?]*(?=#|$)'; //Finish matching either at the fragment part or end of the line.
+
+ /**
+ * fragment = *( pchar / "/" / "?" )
+ */
+ internals.rfc3986.fragment = '[' + pchar + '\\/\\?]*';
+};
+
+
+internals.generate();
+
+module.exports = internals.rfc3986;
diff --git a/node_modules/joi/lib/types/string/uri.js b/node_modules/joi/lib/types/string/uri.js
new file mode 100644
index 00000000..f5622c50
--- /dev/null
+++ b/node_modules/joi/lib/types/string/uri.js
@@ -0,0 +1,46 @@
+'use strict';
+
+// Load Modules
+
+const RFC3986 = require('./rfc3986');
+
+
+// Declare internals
+
+const internals = {
+ Uri: {
+ createUriRegex: function (optionalScheme, allowRelative, relativeOnly) {
+
+ let scheme = RFC3986.scheme;
+ let prefix;
+
+ if (relativeOnly) {
+ prefix = '(?:' + RFC3986.relativeRef + ')';
+ }
+ else {
+ // If we were passed a scheme, use it instead of the generic one
+ if (optionalScheme) {
+
+ // Have to put this in a non-capturing group to handle the OR statements
+ scheme = '(?:' + optionalScheme + ')';
+ }
+
+ const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';
+
+ prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
+ }
+
+ /**
+ * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ *
+ * OR
+ *
+ * relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+ */
+ return new RegExp('^' + prefix + '(?:\\?' + RFC3986.query + ')?' + '(?:#' + RFC3986.fragment + ')?$');
+ }
+ }
+};
+
+
+module.exports = internals.Uri;
diff --git a/node_modules/joi/package.json b/node_modules/joi/package.json
new file mode 100644
index 00000000..89977673
--- /dev/null
+++ b/node_modules/joi/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "joi",
+ "description": "Object schema validation",
+ "version": "11.4.0",
+ "homepage": "https://github.com/hapijs/joi",
+ "repository": "git://github.com/hapijs/joi",
+ "main": "lib/index.js",
+ "keywords": [
+ "hapi",
+ "schema",
+ "validation"
+ ],
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "dependencies": {
+ "hoek": "4.x.x",
+ "isemail": "3.x.x",
+ "topo": "2.x.x"
+ },
+ "devDependencies": {
+ "hapitoc": "1.x.x",
+ "lab": "14.x.x"
+ },
+ "scripts": {
+ "test": "lab -t 100 -a code -L",
+ "test-debug": "lab -a code",
+ "test-cov-html": "lab -r html -o coverage.html -a code",
+ "toc": "hapitoc",
+ "version": "npm run toc && git add API.md README.md"
+ },
+ "license": "BSD-3-Clause"
+}