@kenyip/joi
Advanced tools
+2
-1
@@ -16,2 +16,3 @@ root = true | ||
| max_line_length = off | ||
| trim_trailing_whitespace = false | ||
| trim_trailing_whitespace = false | ||
| indent_size = 2 |
@@ -648,4 +648,2 @@ 'use strict'; | ||
| // Check allowed and denied values using the converted value | ||
| match = this._valids.get(value, state, options, this._flags.insensitive); | ||
@@ -652,0 +650,0 @@ if (match) { |
+683
-682
@@ -20,366 +20,367 @@ 'use strict'; | ||
| constructor() { | ||
| constructor() { | ||
| super(); | ||
| this._type = 'object'; | ||
| this._inner.children = null; | ||
| this._inner.renames = []; | ||
| this._inner.dependencies = []; | ||
| this._inner.patterns = []; | ||
| } | ||
| super(); | ||
| this._type = 'object'; | ||
| this._inner.children = null; | ||
| this._inner.renames = []; | ||
| this._inner.dependencies = []; | ||
| this._inner.patterns = []; | ||
| } | ||
| _init(...args) { | ||
| _init(...args) { | ||
| return args.length ? this.keys(...args) : this; | ||
| } | ||
| return args.length ? this.keys(...args) : this; | ||
| } | ||
| _base(value, state, options) { | ||
| _base(value, state, options) { | ||
| let target = value; | ||
| const errors = []; | ||
| const finish = () => { | ||
| let target = value; | ||
| const errors = []; | ||
| const finish = () => { | ||
| return { | ||
| value: target, | ||
| errors: errors.length ? errors : null | ||
| }; | ||
| }; | ||
| return { | ||
| value: target, | ||
| errors: errors.length ? errors : null | ||
| }; | ||
| }; | ||
| if (typeof value === 'string' && | ||
| options.convert) { | ||
| if (typeof value === 'string' && | ||
| options.convert) { | ||
| value = internals.safeParse(value); | ||
| } | ||
| value = internals.safeParse(value); | ||
| } | ||
| const type = this._flags.func ? 'function' : 'object'; | ||
| if (!value || | ||
| typeof value !== type || | ||
| Array.isArray(value)) { | ||
| const type = this._flags.func ? 'function' : 'object'; | ||
| if (!value || | ||
| typeof value !== type || | ||
| Array.isArray(value)) { | ||
| errors.push(this.createError(type + '.base', { value }, state, options)); | ||
| return finish(); | ||
| } | ||
| errors.push(this.createError(type + '.base', { value }, state, options)); | ||
| return finish(); | ||
| } | ||
| // Skip if there are no other rules to test | ||
| // 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) { | ||
| if (!this._inner.renames.length && | ||
| !this._inner.dependencies.length && | ||
| !this._inner.children && // null allows any keys | ||
| !this._inner.patterns.length) { | ||
| target = value; | ||
| return finish(); | ||
| } | ||
| target = value; | ||
| return finish(); | ||
| } | ||
| // Ensure target is a local copy (parsed) or shallow copy | ||
| // 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 (...args) { | ||
| if (target === value) { | ||
| if (type === 'object') { | ||
| target = Object.create(Object.getPrototypeOf(value)); | ||
| } | ||
| else { | ||
| target = function (...args) { | ||
| return value.apply(this, args); | ||
| }; | ||
| return value.apply(this, args); | ||
| }; | ||
| target.prototype = Hoek.clone(value.prototype); | ||
| } | ||
| 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; | ||
| } | ||
| const valueKeys = Object.keys(value); | ||
| for (let i = 0; i < valueKeys.length; ++i) { | ||
| target[valueKeys[i]] = value[valueKeys[i]]; | ||
| } | ||
| } | ||
| else { | ||
| target = value; | ||
| } | ||
| // Rename keys | ||
| // Rename keys | ||
| const renamed = {}; | ||
| for (let i = 0; i < this._inner.renames.length; ++i) { | ||
| const rename = this._inner.renames[i]; | ||
| 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 = []; | ||
| 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]); | ||
| } | ||
| } | ||
| 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; | ||
| } | ||
| const allUndefined = matchedTargetKeys.every((key) => target[key] === undefined); | ||
| if (rename.options.ignoreUndefined && allUndefined) { | ||
| continue; | ||
| } | ||
| if (!rename.options.multiple && | ||
| renamed[rename.to]) { | ||
| 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(); | ||
| } | ||
| } | ||
| 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]) { | ||
| 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(); | ||
| } | ||
| } | ||
| 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]]; | ||
| } | ||
| if (allUndefined) { | ||
| delete target[rename.to]; | ||
| } | ||
| else { | ||
| target[rename.to] = target[matchedTargetKeys[matchedTargetKeys.length - 1]]; | ||
| } | ||
| renamed[rename.to] = true; | ||
| 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.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]) { | ||
| 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(); | ||
| } | ||
| } | ||
| 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]) { | ||
| 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(); | ||
| } | ||
| } | ||
| 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]; | ||
| } | ||
| if (target[rename.from] === undefined) { | ||
| delete target[rename.to]; | ||
| } | ||
| else { | ||
| target[rename.to] = target[rename.from]; | ||
| } | ||
| renamed[rename.to] = true; | ||
| renamed[rename.to] = true; | ||
| if (!rename.options.alias) { | ||
| delete target[rename.from]; | ||
| } | ||
| } | ||
| } | ||
| if (!rename.options.alias) { | ||
| delete target[rename.from]; | ||
| } | ||
| } | ||
| } | ||
| // Validate schema | ||
| // Validate schema | ||
| if (!this._inner.children && // null allows any keys | ||
| !this._inner.patterns.length && | ||
| !this._inner.dependencies.length) { | ||
| if (!this._inner.children && // null allows any keys | ||
| !this._inner.patterns.length && | ||
| !this._inner.dependencies.length) { | ||
| return finish(); | ||
| } | ||
| return finish(); | ||
| } | ||
| const unprocessed = new Set(Object.keys(target)); | ||
| const unprocessed = new Set(Object.keys(target)); | ||
| if (this._inner.children) { | ||
| const stripProps = []; | ||
| 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]; | ||
| for (let i = 0; i < this._inner.children.length; ++i) { | ||
| const child = this._inner.children[i]; | ||
| const key = child.key; | ||
| const item = target[key]; | ||
| unprocessed.delete(key); | ||
| unprocessed.delete(key); | ||
| const localState = new State(key, [...state.path, key], target, 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)); | ||
| const localState = new State(key, [...state.path, key], target, 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; | ||
| } | ||
| } | ||
| } | ||
| 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]]; | ||
| } | ||
| } | ||
| for (let i = 0; i < stripProps.length; ++i) { | ||
| delete target[stripProps[i]]; | ||
| } | ||
| } | ||
| // Unknown keys | ||
| // Unknown keys | ||
| if (unprocessed.size && this._inner.patterns.length) { | ||
| if (unprocessed.size && this._inner.patterns.length) { | ||
| for (const key of unprocessed) { | ||
| const localState = new State(key, [...state.path, key], target, state.reference); | ||
| const item = target[key]; | ||
| for (const key of unprocessed) { | ||
| const localState = new State(key, [...state.path, key], target, state.reference); | ||
| const item = target[key]; | ||
| for (let i = 0; i < this._inner.patterns.length; ++i) { | ||
| const pattern = this._inner.patterns[i]; | ||
| for (let i = 0; i < this._inner.patterns.length; ++i) { | ||
| const pattern = this._inner.patterns[i]; | ||
| if (pattern.regex ? | ||
| pattern.regex.test(key) : | ||
| !pattern.schema.validate(key).error) { | ||
| if (pattern.regex ? | ||
| pattern.regex.test(key) : | ||
| !pattern.schema.validate(key).error) { | ||
| unprocessed.delete(key); | ||
| unprocessed.delete(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)); | ||
| 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 (options.abortEarly) { | ||
| return finish(); | ||
| } | ||
| } | ||
| target[key] = result.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| target[key] = result.value; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (unprocessed.size && (this._inner.children || this._inner.patterns.length)) { | ||
| if ((options.stripUnknown && this._flags.allowUnknown !== true) || | ||
| options.skipFunctions) { | ||
| if (unprocessed.size && (this._inner.children || this._inner.patterns.length)) { | ||
| if ((options.stripUnknown && this._flags.allowUnknown !== true) || | ||
| options.skipFunctions) { | ||
| const stripUnknown = options.stripUnknown | ||
| ? (options.stripUnknown === true ? true : !!options.stripUnknown.objects) | ||
| : false; | ||
| const stripUnknown = options.stripUnknown | ||
| ? (options.stripUnknown === true ? true : !!options.stripUnknown.objects) | ||
| : false; | ||
| for (const key of unprocessed) { | ||
| if (stripUnknown) { | ||
| delete target[key]; | ||
| unprocessed.delete(key); | ||
| } | ||
| else if (typeof target[key] === 'function') { | ||
| unprocessed.delete(key); | ||
| } | ||
| } | ||
| } | ||
| for (const key of unprocessed) { | ||
| if (stripUnknown) { | ||
| delete target[key]; | ||
| unprocessed.delete(key); | ||
| } | ||
| else if (typeof target[key] === 'function') { | ||
| unprocessed.delete(key); | ||
| } | ||
| } | ||
| } | ||
| if ((this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) { | ||
| if ((this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) { | ||
| for (const unprocessedKey of unprocessed) { | ||
| errors.push(this.createError('object.allowUnknown', { child: unprocessedKey, value: target[unprocessedKey] }, { | ||
| key: unprocessedKey, | ||
| path: [...state.path, unprocessedKey] | ||
| }, options, {})); | ||
| } | ||
| } | ||
| } | ||
| for (const unprocessedKey of unprocessed) { | ||
| errors.push(this.createError('object.allowUnknown', { child: unprocessedKey, value: target[unprocessedKey] }, { | ||
| key: unprocessedKey, | ||
| path: [...state.path, unprocessedKey] | ||
| }, options, {})); | ||
| } | ||
| } | ||
| } | ||
| // Validate dependencies | ||
| // Validate dependencies | ||
| for (let i = 0; i < this._inner.dependencies.length; ++i) { | ||
| const dep = this._inner.dependencies[i]; | ||
| const hasKey = dep.key !== null; | ||
| const splitKey = hasKey && dep.key.split('.'); | ||
| const localState = hasKey ? new State(splitKey[splitKey.length - 1], [...state.path, ...splitKey]) : new State(null, state.path); | ||
| const err = internals[dep.type].call(this, dep.key, hasKey && Hoek.reach(target, dep.key, { functions: true }), dep.peers, target, localState, options); | ||
| if (err instanceof Errors.Err) { | ||
| errors.push(err); | ||
| if (options.abortEarly) { | ||
| return finish(); | ||
| } | ||
| } | ||
| } | ||
| for (let i = 0; i < this._inner.dependencies.length; ++i) { | ||
| const dep = this._inner.dependencies[i]; | ||
| const hasKey = dep.key !== null; | ||
| const splitKey = hasKey && dep.key.split('.'); | ||
| const localState = hasKey ? new State(splitKey[splitKey.length - 1], [...state.path, ...splitKey]) : new State(null, state.path); | ||
| const err = internals[dep.type].call(this, dep.key, hasKey && Hoek.reach(target, dep.key, { functions: true }), dep.peers, target, localState, options); | ||
| if (err instanceof Errors.Err) { | ||
| errors.push(err); | ||
| if (options.abortEarly) { | ||
| return finish(); | ||
| } | ||
| } | ||
| } | ||
| return finish(); | ||
| } | ||
| return finish(); | ||
| } | ||
| keys(schema) { | ||
| 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'); | ||
| 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(); | ||
| const obj = this.clone(); | ||
| if (!schema) { | ||
| obj._inner.children = null; | ||
| return obj; | ||
| } | ||
| if (!schema) { | ||
| obj._inner.children = null; | ||
| return obj; | ||
| } | ||
| const children = Object.keys(schema); | ||
| const children = Object.keys(schema); | ||
| if (!children.length) { | ||
| obj._inner.children = []; | ||
| return obj; | ||
| } | ||
| 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]; | ||
| 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.includes(child.key)) { | ||
| topo.add(child, { after: child._refs, group: child.key }); | ||
| } | ||
| } | ||
| } | ||
| // Only add the key if we are not going to replace it later | ||
| if (!children.includes(child.key)) { | ||
| 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; | ||
| } | ||
| 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; | ||
| } | ||
| } | ||
| throw castErr; | ||
| } | ||
| } | ||
| obj._inner.children = topo.nodes; | ||
| obj._inner.children = topo.nodes; | ||
| return obj; | ||
| } | ||
| return obj; | ||
| } | ||
| removeKey(key){ | ||
| remove(keys) { | ||
| Hoek.assert(typeof key === 'string', 'The key should be an valid string'); | ||
| Hoek.assert(Array.isArray(keys), 'The keys parameter should be an valid array'); | ||
| Hoek.assert(keys.every(key => typeof key === "string"), 'The key in keys array should be a valid string'); | ||
| const obj = this.clone(); | ||
| obj._inner.children = obj._inner.children.filter(item => item.key !== key); | ||
| let obj = this.clone(); | ||
| obj._inner.children = obj._inner.children.filter(item => !keys.includes(item.key)); | ||
@@ -389,351 +390,351 @@ return obj; | ||
| append(schema) { | ||
| // Skip any changes | ||
| if (schema === null || schema === undefined || Object.keys(schema).length === 0) { | ||
| return this; | ||
| } | ||
| append(schema) { | ||
| // Skip any changes | ||
| if (schema === null || schema === undefined || Object.keys(schema).length === 0) { | ||
| return this; | ||
| } | ||
| return this.keys(schema); | ||
| } | ||
| return this.keys(schema); | ||
| } | ||
| unknown(allow) { | ||
| unknown(allow) { | ||
| const value = allow !== false; | ||
| const value = allow !== false; | ||
| if (this._flags.allowUnknown === value) { | ||
| return this; | ||
| } | ||
| if (this._flags.allowUnknown === value) { | ||
| return this; | ||
| } | ||
| const obj = this.clone(); | ||
| obj._flags.allowUnknown = value; | ||
| return obj; | ||
| } | ||
| const obj = this.clone(); | ||
| obj._flags.allowUnknown = value; | ||
| return obj; | ||
| } | ||
| length(limit) { | ||
| length(limit) { | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| return this._test('length', limit, function (value, state, options) { | ||
| return this._test('length', limit, function (value, state, options) { | ||
| if (Object.keys(value).length === limit) { | ||
| return value; | ||
| } | ||
| if (Object.keys(value).length === limit) { | ||
| return value; | ||
| } | ||
| return this.createError('object.length', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| return this.createError('object.length', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| min(limit) { | ||
| min(limit) { | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| return this._test('min', limit, function (value, state, options) { | ||
| return this._test('min', limit, function (value, state, options) { | ||
| if (Object.keys(value).length >= limit) { | ||
| return value; | ||
| } | ||
| if (Object.keys(value).length >= limit) { | ||
| return value; | ||
| } | ||
| return this.createError('object.min', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| return this.createError('object.min', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| max(limit) { | ||
| max(limit) { | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer'); | ||
| return this._test('max', limit, function (value, state, options) { | ||
| return this._test('max', limit, function (value, state, options) { | ||
| if (Object.keys(value).length <= limit) { | ||
| return value; | ||
| } | ||
| if (Object.keys(value).length <= limit) { | ||
| return value; | ||
| } | ||
| return this.createError('object.max', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| return this.createError('object.max', { limit, value }, state, options); | ||
| }); | ||
| } | ||
| pattern(pattern, schema) { | ||
| pattern(pattern, schema) { | ||
| const isRegExp = pattern instanceof RegExp; | ||
| Hoek.assert(isRegExp || pattern instanceof Any, 'pattern must be a regex or schema'); | ||
| Hoek.assert(schema !== undefined, 'Invalid rule'); | ||
| const isRegExp = pattern instanceof RegExp; | ||
| Hoek.assert(isRegExp || pattern instanceof Any, 'pattern must be a regex or schema'); | ||
| Hoek.assert(schema !== undefined, 'Invalid rule'); | ||
| if (isRegExp) { | ||
| Hoek.assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode'); | ||
| } | ||
| if (isRegExp) { | ||
| Hoek.assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode'); | ||
| } | ||
| try { | ||
| schema = Cast.schema(this._currentJoi, schema); | ||
| } | ||
| catch (castErr) { | ||
| if (castErr.hasOwnProperty('path')) { | ||
| castErr.message = `${castErr.message}(${castErr.path})`; | ||
| } | ||
| try { | ||
| schema = Cast.schema(this._currentJoi, schema); | ||
| } | ||
| catch (castErr) { | ||
| if (castErr.hasOwnProperty('path')) { | ||
| castErr.message = `${castErr.message}(${castErr.path})`; | ||
| } | ||
| throw castErr; | ||
| } | ||
| throw castErr; | ||
| } | ||
| const obj = this.clone(); | ||
| if (isRegExp) { | ||
| obj._inner.patterns.push({ regex: pattern, rule: schema }); | ||
| } | ||
| else { | ||
| obj._inner.patterns.push({ schema: pattern, rule: schema }); | ||
| } | ||
| const obj = this.clone(); | ||
| if (isRegExp) { | ||
| obj._inner.patterns.push({ regex: pattern, rule: schema }); | ||
| } | ||
| else { | ||
| obj._inner.patterns.push({ schema: pattern, rule: schema }); | ||
| } | ||
| return obj; | ||
| } | ||
| return obj; | ||
| } | ||
| schema() { | ||
| schema() { | ||
| return this._test('schema', null, function (value, state, options) { | ||
| return this._test('schema', null, function (value, state, options) { | ||
| if (value instanceof Any) { | ||
| return value; | ||
| } | ||
| if (value instanceof Any) { | ||
| return value; | ||
| } | ||
| return this.createError('object.schema', null, state, options); | ||
| }); | ||
| } | ||
| return this.createError('object.schema', null, state, options); | ||
| }); | ||
| } | ||
| with(key, peers) { | ||
| with(key, peers) { | ||
| Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.'); | ||
| Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.'); | ||
| return this._dependency('with', key, peers); | ||
| } | ||
| return this._dependency('with', key, peers); | ||
| } | ||
| without(key, peers) { | ||
| without(key, peers) { | ||
| Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.'); | ||
| Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.'); | ||
| return this._dependency('without', key, peers); | ||
| } | ||
| return this._dependency('without', key, peers); | ||
| } | ||
| xor(...peers) { | ||
| xor(...peers) { | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('xor', null, peers); | ||
| } | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('xor', null, peers); | ||
| } | ||
| oxor(...peers) { | ||
| oxor(...peers) { | ||
| return this._dependency('oxor', null, peers); | ||
| } | ||
| return this._dependency('oxor', null, peers); | ||
| } | ||
| or(...peers) { | ||
| or(...peers) { | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('or', null, peers); | ||
| } | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('or', null, peers); | ||
| } | ||
| and(...peers) { | ||
| and(...peers) { | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('and', null, peers); | ||
| } | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('and', null, peers); | ||
| } | ||
| nand(...peers) { | ||
| nand(...peers) { | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('nand', null, peers); | ||
| } | ||
| peers = Hoek.flatten(peers); | ||
| return this._dependency('nand', null, peers); | ||
| } | ||
| requiredKeys(...children) { | ||
| requiredKeys(...children) { | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'required'); | ||
| } | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'required'); | ||
| } | ||
| optionalKeys(...children) { | ||
| optionalKeys(...children) { | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'optional'); | ||
| } | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'optional'); | ||
| } | ||
| forbiddenKeys(...children) { | ||
| forbiddenKeys(...children) { | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'forbidden'); | ||
| } | ||
| children = Hoek.flatten(children); | ||
| return this.applyFunctionToChildren(children, 'forbidden'); | ||
| } | ||
| rename(from, to, options) { | ||
| 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); | ||
| 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'); | ||
| } | ||
| 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(); | ||
| const obj = this.clone(); | ||
| obj._inner.renames.push({ | ||
| from, | ||
| to, | ||
| options: Hoek.applyToDefaults(internals.renameDefaults, options || {}), | ||
| isRegExp: from instanceof RegExp | ||
| }); | ||
| obj._inner.renames.push({ | ||
| from, | ||
| to, | ||
| options: Hoek.applyToDefaults(internals.renameDefaults, options || {}), | ||
| isRegExp: from instanceof RegExp | ||
| }); | ||
| return obj; | ||
| } | ||
| return obj; | ||
| } | ||
| applyFunctionToChildren(children, fn, args = [], root) { | ||
| applyFunctionToChildren(children, fn, args = [], root) { | ||
| children = [].concat(children); | ||
| Hoek.assert(children.length > 0, 'expected at least one children'); | ||
| children = [].concat(children); | ||
| Hoek.assert(children.length > 0, 'expected at least one children'); | ||
| const groupedChildren = internals.groupChildren(children); | ||
| let obj; | ||
| const groupedChildren = internals.groupChildren(children); | ||
| let obj; | ||
| if ('' in groupedChildren) { | ||
| obj = this[fn](...args); | ||
| delete groupedChildren['']; | ||
| } | ||
| else { | ||
| obj = this.clone(); | ||
| } | ||
| if ('' in groupedChildren) { | ||
| obj = this[fn](...args); | ||
| delete groupedChildren['']; | ||
| } | ||
| else { | ||
| obj = this.clone(); | ||
| } | ||
| if (obj._inner.children) { | ||
| root = root ? (root + '.') : ''; | ||
| 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]; | ||
| 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) | ||
| }; | ||
| 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]; | ||
| } | ||
| } | ||
| } | ||
| delete groupedChildren[child.key]; | ||
| } | ||
| } | ||
| } | ||
| const remaining = Object.keys(groupedChildren); | ||
| Hoek.assert(remaining.length === 0, 'unknown key(s)', remaining.join(', ')); | ||
| const remaining = Object.keys(groupedChildren); | ||
| Hoek.assert(remaining.length === 0, 'unknown key(s)', remaining.join(', ')); | ||
| return obj; | ||
| } | ||
| return obj; | ||
| } | ||
| _dependency(type, key, peers) { | ||
| _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'); | ||
| } | ||
| 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; | ||
| } | ||
| const obj = this.clone(); | ||
| obj._inner.dependencies.push({ type, key, peers }); | ||
| return obj; | ||
| } | ||
| describe(shallow) { | ||
| describe(shallow) { | ||
| const description = super.describe(); | ||
| const description = super.describe(); | ||
| 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 (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) { | ||
| 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(); | ||
| } | ||
| } | ||
| 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.dependencies.length) { | ||
| description.dependencies = Hoek.clone(this._inner.dependencies); | ||
| } | ||
| if (this._inner.patterns.length) { | ||
| description.patterns = []; | ||
| if (this._inner.patterns.length) { | ||
| description.patterns = []; | ||
| for (let i = 0; i < this._inner.patterns.length; ++i) { | ||
| const pattern = this._inner.patterns[i]; | ||
| if (pattern.regex) { | ||
| description.patterns.push({ regex: pattern.regex.toString(), rule: pattern.rule.describe() }); | ||
| } | ||
| else { | ||
| description.patterns.push({ schema: pattern.schema.describe(), rule: pattern.rule.describe() }); | ||
| } | ||
| } | ||
| } | ||
| for (let i = 0; i < this._inner.patterns.length; ++i) { | ||
| const pattern = this._inner.patterns[i]; | ||
| if (pattern.regex) { | ||
| description.patterns.push({ regex: pattern.regex.toString(), rule: pattern.rule.describe() }); | ||
| } | ||
| else { | ||
| description.patterns.push({ schema: pattern.schema.describe(), rule: pattern.rule.describe() }); | ||
| } | ||
| } | ||
| } | ||
| if (this._inner.renames.length > 0) { | ||
| description.renames = Hoek.clone(this._inner.renames); | ||
| } | ||
| if (this._inner.renames.length > 0) { | ||
| description.renames = Hoek.clone(this._inner.renames); | ||
| } | ||
| return description; | ||
| } | ||
| return description; | ||
| } | ||
| assert(ref, schema, message) { | ||
| 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'; | ||
| Hoek.assert(typeof message === 'string', 'Message must be a string'); | ||
| 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'; | ||
| Hoek.assert(typeof message === 'string', 'Message must be a string'); | ||
| try { | ||
| schema = Cast.schema(this._currentJoi, schema); | ||
| } | ||
| catch (castErr) { | ||
| if (castErr.hasOwnProperty('path')) { | ||
| castErr.message = `${castErr.message}(${castErr.path})`; | ||
| } | ||
| try { | ||
| schema = Cast.schema(this._currentJoi, schema); | ||
| } | ||
| catch (castErr) { | ||
| if (castErr.hasOwnProperty('path')) { | ||
| castErr.message = `${castErr.message}(${castErr.path})`; | ||
| } | ||
| throw castErr; | ||
| } | ||
| throw castErr; | ||
| } | ||
| const key = ref.path[ref.path.length - 1]; | ||
| const path = ref.path.join('.'); | ||
| const key = ref.path[ref.path.length - 1]; | ||
| const path = ref.path.join('.'); | ||
| return this._test('assert', { schema, ref }, function (value, state, options) { | ||
| 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 result = schema._validate(ref(value), null, options, value); | ||
| if (!result.errors) { | ||
| return value; | ||
| } | ||
| const localState = new State(key, ref.path, state.parent, state.reference); | ||
| return this.createError('object.assert', { ref: path, message }, localState, options); | ||
| }); | ||
| } | ||
| const localState = new State(key, ref.path, state.parent, state.reference); | ||
| return this.createError('object.assert', { ref: path, message }, localState, options); | ||
| }); | ||
| } | ||
| type(constructor, name = constructor.name) { | ||
| type(constructor, name = constructor.name) { | ||
| Hoek.assert(typeof constructor === 'function', 'type must be a constructor function'); | ||
| const typeData = { | ||
| name, | ||
| ctor: constructor | ||
| }; | ||
| Hoek.assert(typeof constructor === 'function', 'type must be a constructor function'); | ||
| const typeData = { | ||
| name, | ||
| ctor: constructor | ||
| }; | ||
| return this._test('type', typeData, function (value, state, options) { | ||
| return this._test('type', typeData, function (value, state, options) { | ||
| if (value instanceof constructor) { | ||
| return value; | ||
| } | ||
| if (value instanceof constructor) { | ||
| return value; | ||
| } | ||
| return this.createError('object.type', { type: typeData.name, value }, state, options); | ||
| }); | ||
| } | ||
| return this.createError('object.type', { type: typeData.name, value }, state, options); | ||
| }); | ||
| } | ||
| }; | ||
@@ -743,8 +744,8 @@ | ||
| try { | ||
| return JSON.parse(value); | ||
| } | ||
| catch (parseErr) {} | ||
| try { | ||
| return JSON.parse(value); | ||
| } | ||
| catch (parseErr) { } | ||
| return value; | ||
| return value; | ||
| }; | ||
@@ -754,5 +755,5 @@ | ||
| 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 | ||
| alias: false, // Keep old value in place | ||
| multiple: false, // Allow renaming multiple keys into the same target | ||
| override: false // Overrides an existing key | ||
| }; | ||
@@ -763,15 +764,15 @@ | ||
| children.sort(); | ||
| children.sort(); | ||
| const grouped = {}; | ||
| 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)); | ||
| } | ||
| 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; | ||
| return grouped; | ||
| }; | ||
@@ -782,19 +783,19 @@ | ||
| const children = schema._inner.children; | ||
| const children = schema._inner.children; | ||
| if (!children) { | ||
| return keys; | ||
| } | ||
| if (!children) { | ||
| return keys; | ||
| } | ||
| const findLabel = function (key) { | ||
| const findLabel = function (key) { | ||
| const matchingChild = schema._currentJoi.reach(schema, key); | ||
| return matchingChild ? matchingChild._getLabel(key) : key; | ||
| }; | ||
| const matchingChild = schema._currentJoi.reach(schema, key); | ||
| return matchingChild ? matchingChild._getLabel(key) : key; | ||
| }; | ||
| if (Array.isArray(keys)) { | ||
| return keys.map(findLabel); | ||
| } | ||
| if (Array.isArray(keys)) { | ||
| return keys.map(findLabel); | ||
| } | ||
| return findLabel(keys); | ||
| return findLabel(keys); | ||
| }; | ||
@@ -805,20 +806,20 @@ | ||
| if (value === undefined) { | ||
| return; | ||
| } | ||
| if (value === undefined) { | ||
| return; | ||
| } | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist === undefined) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist === undefined) { | ||
| return this.createError('object.with', { | ||
| main: key, | ||
| mainWithLabel: internals.keysToLabels(this, key), | ||
| peer, | ||
| peerWithLabel: internals.keysToLabels(this, peer) | ||
| }, state, options); | ||
| } | ||
| } | ||
| return this.createError('object.with', { | ||
| main: key, | ||
| mainWithLabel: internals.keysToLabels(this, key), | ||
| peer, | ||
| peerWithLabel: internals.keysToLabels(this, peer) | ||
| }, state, options); | ||
| } | ||
| } | ||
| }; | ||
@@ -829,19 +830,19 @@ | ||
| if (value === undefined) { | ||
| return; | ||
| } | ||
| if (value === undefined) { | ||
| return; | ||
| } | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| return this.createError('object.without', { | ||
| main: key, | ||
| mainWithLabel: internals.keysToLabels(this, key), | ||
| peer, | ||
| peerWithLabel: internals.keysToLabels(this, peer) | ||
| }, state, options); | ||
| } | ||
| } | ||
| return this.createError('object.without', { | ||
| main: key, | ||
| mainWithLabel: internals.keysToLabels(this, key), | ||
| peer, | ||
| peerWithLabel: internals.keysToLabels(this, peer) | ||
| }, state, options); | ||
| } | ||
| } | ||
| }; | ||
@@ -852,25 +853,25 @@ | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| if (present.length === 1) { | ||
| return; | ||
| } | ||
| if (present.length === 1) { | ||
| return; | ||
| } | ||
| const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) }; | ||
| const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) }; | ||
| if (present.length === 0) { | ||
| return this.createError('object.missing', context, state, options); | ||
| } | ||
| if (present.length === 0) { | ||
| return this.createError('object.missing', context, state, options); | ||
| } | ||
| context.present = present; | ||
| context.presentWithLabels = internals.keysToLabels(this, present); | ||
| context.present = present; | ||
| context.presentWithLabels = internals.keysToLabels(this, present); | ||
| return this.createError('object.xor', context, state, options); | ||
| return this.createError('object.xor', context, state, options); | ||
| }; | ||
@@ -881,22 +882,22 @@ | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| if (!present.length || | ||
| present.length === 1) { | ||
| if (!present.length || | ||
| present.length === 1) { | ||
| return; | ||
| } | ||
| return; | ||
| } | ||
| const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) }; | ||
| context.present = present; | ||
| context.presentWithLabels = internals.keysToLabels(this, present); | ||
| const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) }; | ||
| context.present = present; | ||
| context.presentWithLabels = internals.keysToLabels(this, present); | ||
| return this.createError('object.oxor', context, state, options); | ||
| return this.createError('object.oxor', context, state, options); | ||
| }; | ||
@@ -907,14 +908,14 @@ | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| return; | ||
| } | ||
| } | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| return; | ||
| } | ||
| } | ||
| return this.createError('object.missing', { | ||
| peers, | ||
| peersWithLabels: internals.keysToLabels(this, peers) | ||
| }, state, options); | ||
| return this.createError('object.missing', { | ||
| peers, | ||
| peersWithLabels: internals.keysToLabels(this, peers) | ||
| }, state, options); | ||
| }; | ||
@@ -925,28 +926,28 @@ | ||
| const missing = []; | ||
| const present = []; | ||
| const count = peers.length; | ||
| for (let i = 0; i < count; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist === undefined) { | ||
| const missing = []; | ||
| const present = []; | ||
| const count = peers.length; | ||
| for (let i = 0; i < count; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist === undefined) { | ||
| missing.push(peer); | ||
| } | ||
| else { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| missing.push(peer); | ||
| } | ||
| else { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| const aon = (missing.length === count || present.length === count); | ||
| const aon = (missing.length === count || present.length === count); | ||
| if (!aon) { | ||
| if (!aon) { | ||
| return this.createError('object.and', { | ||
| present, | ||
| presentWithLabels: internals.keysToLabels(this, present), | ||
| missing, | ||
| missingWithLabels: internals.keysToLabels(this, missing) | ||
| }, state, options); | ||
| } | ||
| return this.createError('object.and', { | ||
| present, | ||
| presentWithLabels: internals.keysToLabels(this, present), | ||
| missing, | ||
| missingWithLabels: internals.keysToLabels(this, missing) | ||
| }, state, options); | ||
| } | ||
| }; | ||
@@ -957,21 +958,21 @@ | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| const present = []; | ||
| for (let i = 0; i < peers.length; ++i) { | ||
| const peer = peers[i]; | ||
| const keysExist = Hoek.reach(parent, peer, { functions: true }); | ||
| if (keysExist !== undefined) { | ||
| present.push(peer); | ||
| } | ||
| } | ||
| present.push(peer); | ||
| } | ||
| } | ||
| const main = peers[0]; | ||
| const values = peers.slice(1); | ||
| 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; | ||
| const main = peers[0]; | ||
| const values = peers.slice(1); | ||
| 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; | ||
| }; | ||
@@ -978,0 +979,0 @@ |
+1
-1
| { | ||
| "name": "@kenyip/joi", | ||
| "description": "Object schema validation", | ||
| "version": "0.0.1", | ||
| "version": "0.0.2", | ||
| "homepage": "https://github.com/hapijs/joi", | ||
@@ -6,0 +6,0 @@ "repository": "git://github.com/hapijs/joi", |
+28
-0
@@ -31,2 +31,30 @@ # @kenyip/joi | ||
| // } | ||
| ``` | ||
| ### remove | ||
| Remove keys from the existing schema | ||
| ```js | ||
| const objectA = Joi.object({ | ||
| hello: Joi.string(), | ||
| world: Joi.string(), | ||
| }); | ||
| const objectB = objectA | ||
| .keys({ foo: Joi.string() }) | ||
| .remove(["hello"]); | ||
| console.log(JSON.stringify(objectB.toSwagger(), null, 4)); | ||
| // { | ||
| // "type": "object", | ||
| // "properties": { | ||
| // "world": { | ||
| // "type": "string" | ||
| // }, | ||
| // "foo": { | ||
| // "type": "string" | ||
| // } | ||
| // } | ||
| // } | ||
| ``` |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
59
90.32%186311
-2.74%