Comparing version 13.2.0 to 13.3.0
@@ -146,2 +146,3 @@ 'use strict'; | ||
hex: 'must only contain hexadecimal characters', | ||
hexAlign: 'hex decoded representation must be byte aligned', | ||
base64: 'must be a valid base64 string', | ||
@@ -148,0 +149,0 @@ hostname: 'must be a valid hostname', |
143
lib/set.js
@@ -5,14 +5,50 @@ 'use strict'; | ||
module.exports = class Set { | ||
constructor() { | ||
const internals = {}; | ||
this._set = []; | ||
internals.extendedCheckForValue = function (value, insensitive) { | ||
const valueType = typeof value; | ||
if (valueType === 'object') { | ||
if (value instanceof Date) { | ||
return (item) => { | ||
return item instanceof Date && value.getTime() === item.getTime(); | ||
}; | ||
} | ||
if (Buffer.isBuffer(value)) { | ||
return (item) => { | ||
return Buffer.isBuffer(item) && value.length === item.length && value.toString('binary') === item.toString('binary'); | ||
}; | ||
} | ||
} | ||
else if (insensitive && valueType === 'string') { | ||
const lowercaseValue = value.toLowerCase(); | ||
return (item) => { | ||
return typeof item === 'string' && lowercaseValue === item.toLowerCase(); | ||
}; | ||
} | ||
return null; | ||
}; | ||
module.exports = class InternalSet { | ||
constructor(from) { | ||
this._set = new Set(from); | ||
this._hasRef = false; | ||
} | ||
add(value, refs) { | ||
if (!Ref.isRef(value) && this.has(value, null, null, false)) { | ||
const isRef = Ref.isRef(value); | ||
if (!isRef && this.has(value, null, null, false)) { | ||
return; | ||
return this; | ||
} | ||
@@ -24,3 +60,6 @@ | ||
this._set.push(value); | ||
this._set.add(value); | ||
this._hasRef |= isRef; | ||
return this; | ||
@@ -31,8 +70,8 @@ } | ||
for (let i = 0; i < add._set.length; ++i) { | ||
this.add(add._set[i]); | ||
for (const item of add._set) { | ||
this.add(item); | ||
} | ||
for (let i = 0; i < remove._set.length; ++i) { | ||
this.remove(remove._set[i]); | ||
for (const item of remove._set) { | ||
this.remove(item); | ||
} | ||
@@ -45,3 +84,3 @@ | ||
this._set = this._set.filter((item) => value !== item); | ||
this._set.delete(value); | ||
return this; | ||
@@ -52,27 +91,58 @@ } | ||
for (let i = 0; i < this._set.length; ++i) { | ||
let items = this._set[i]; | ||
if (!this._set.size) { | ||
return false; | ||
} | ||
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); | ||
const hasValue = this._set.has(value); | ||
if (hasValue) { | ||
return hasValue; | ||
} | ||
const extendedCheck = internals.extendedCheckForValue(value, insensitive); | ||
if (!extendedCheck) { | ||
if (state && this._hasRef) { | ||
for (let item of this._set) { | ||
if (Ref.isRef(item)) { | ||
item = item(state.reference || state.parent, options); | ||
if (value === item || (Array.isArray(item) && item.includes(value))) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
if (!Array.isArray(items)) { | ||
items = [items]; | ||
return false; | ||
} | ||
return this._has(value, state, options, extendedCheck); | ||
} | ||
_has(value, state, options, check) { | ||
const checkRef = !!(state && this._hasRef); | ||
const isReallyEqual = function (item) { | ||
if (value === item) { | ||
return true; | ||
} | ||
for (let j = 0; j < items.length; ++j) { | ||
const item = items[j]; | ||
if (typeof value !== typeof item) { | ||
continue; | ||
} | ||
return check(item); | ||
}; | ||
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'))) { | ||
for (let item of this._set) { | ||
if (checkRef && Ref.isRef(item)) { // Only resolve references if there is a state, otherwise it's a merge | ||
item = item(state.reference || state.parent, options); | ||
return true; | ||
if (Array.isArray(item)) { | ||
if (item.find(isReallyEqual)) { | ||
return true; | ||
} | ||
continue; | ||
} | ||
} | ||
if (isReallyEqual(item)) { | ||
return true; | ||
} | ||
} | ||
@@ -88,4 +158,3 @@ | ||
for (let i = 0; i < this._set.length; ++i) { | ||
const item = this._set[i]; | ||
for (const item of this._set) { | ||
if (item !== undefined) { | ||
@@ -99,3 +168,3 @@ values.push(item); | ||
return this._set.slice(); | ||
return Array.from(this._set); | ||
} | ||
@@ -105,6 +174,5 @@ | ||
const newSet = new Set(); | ||
newSet._set = this._set.slice(); | ||
return newSet; | ||
const set = new InternalSet(this._set); | ||
set._hasRef = this._hasRef; | ||
return set; | ||
} | ||
@@ -114,7 +182,6 @@ | ||
const newSet = new Set(); | ||
newSet._set = this._set.concat(source._set); | ||
return newSet; | ||
const set = new InternalSet([...this._set, ...source._set]); | ||
set._hasRef = !!(this._hasRef | source._hasRef); | ||
return set; | ||
} | ||
}; |
@@ -598,3 +598,3 @@ 'use strict'; | ||
if (this._invalids.has(value, state, options, this._flags.insensitive)) { | ||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', null, state, options)); | ||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', { value, invalids: this._invalids.values({ stripUndefined: true }) }, state, options)); | ||
if (options.abortEarly || | ||
@@ -627,3 +627,3 @@ value === undefined) { // No reason to keep validating missing value | ||
if (this._invalids.has(value, state, options, this._flags.insensitive)) { | ||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', null, state, options)); | ||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', { value, invalids: this._invalids.values({ stripUndefined: true }) }, state, options)); | ||
if (options.abortEarly) { | ||
@@ -639,3 +639,3 @@ return finish(); | ||
if (this._flags.allowOnly) { | ||
errors.push(this.createError('any.allowOnly', { valids: this._valids.values({ stripUndefined: true }) }, state, options)); | ||
errors.push(this.createError('any.allowOnly', { value, valids: this._valids.values({ stripUndefined: true }) }, state, options)); | ||
if (options.abortEarly) { | ||
@@ -646,3 +646,3 @@ return finish(); | ||
// Helper.validate tests | ||
// Validate tests | ||
@@ -649,0 +649,0 @@ for (let i = 0; i < this._tests.length; ++i) { |
@@ -194,3 +194,3 @@ 'use strict'; | ||
const unprocessed = Hoek.mapToObject(Object.keys(target)); | ||
const unprocessed = new Set(Object.keys(target)); | ||
@@ -205,3 +205,3 @@ if (this._inner.children) { | ||
delete unprocessed[key]; | ||
unprocessed.delete(key); | ||
@@ -235,20 +235,26 @@ const localState = { key, path: state.path.concat(key), parent: target, reference: state.reference }; | ||
let unprocessedKeys = Object.keys(unprocessed); | ||
if (unprocessedKeys.length && | ||
this._inner.patterns.length) { | ||
if (unprocessed.size && 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 }; | ||
for (const key of unprocessed) { | ||
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]; | ||
for (let i = 0; i < this._inner.patterns.length; ++i) { | ||
const pattern = this._inner.patterns[i]; | ||
if (pattern.regex.test(key)) { | ||
delete unprocessed[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)); | ||
errors.push(this.createError('object.child', { | ||
key, | ||
child: pattern.rule._getLabel(key), | ||
reason: result.errors | ||
}, localState, options)); | ||
@@ -264,7 +270,5 @@ if (options.abortEarly) { | ||
} | ||
unprocessedKeys = Object.keys(unprocessed); | ||
} | ||
if ((this._inner.children || this._inner.patterns.length) && unprocessedKeys.length) { | ||
if (unprocessed.size && (this._inner.children || this._inner.patterns.length)) { | ||
if ((options.stripUnknown && this._flags.allowUnknown !== true) || | ||
@@ -278,23 +282,20 @@ options.skipFunctions) { | ||
for (let i = 0; i < unprocessedKeys.length; ++i) { | ||
const key = unprocessedKeys[i]; | ||
for (const key of unprocessed) { | ||
if (stripUnknown) { | ||
delete target[key]; | ||
delete unprocessed[key]; | ||
unprocessed.delete(key); | ||
} | ||
else if (typeof target[key] === 'function') { | ||
delete unprocessed[key]; | ||
unprocessed.delete(key); | ||
} | ||
} | ||
unprocessedKeys = Object.keys(unprocessed); | ||
} | ||
if (unprocessedKeys.length && | ||
(this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) { | ||
if ((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, {})); | ||
for (const unprocessedKey of unprocessed) { | ||
errors.push(this.createError('object.allowUnknown', { child: unprocessedKey }, { | ||
key: unprocessedKey, | ||
path: state.path.concat(unprocessedKey) | ||
}, options, {})); | ||
} | ||
@@ -301,0 +302,0 @@ } |
@@ -76,2 +76,6 @@ 'use strict'; | ||
} | ||
if (this._flags.byteAligned && value.length % 2 !== 0) { | ||
value = `0${value}`; | ||
} | ||
} | ||
@@ -403,9 +407,17 @@ | ||
hex() { | ||
hex(hexOptions = {}) { | ||
Hoek.assert(typeof hexOptions === 'object', 'hex options must be an object'); | ||
Hoek.assert(typeof hexOptions.byteAligned === 'undefined' || typeof hexOptions.byteAligned === 'boolean', | ||
'byteAligned must be boolean'); | ||
const byteAligned = hexOptions.byteAligned === true; | ||
const regex = /^[a-f0-9]+$/i; | ||
return this._test('hex', regex, function (value, state, options) { | ||
const obj = this._test('hex', regex, function (value, state, options) { | ||
if (regex.test(value)) { | ||
if (byteAligned && value.length % 2 !== 0) { | ||
return this.createError('string.hexAlign', { value }, state, options); | ||
} | ||
return value; | ||
@@ -416,2 +428,8 @@ } | ||
}); | ||
if (byteAligned) { | ||
obj._flags.byteAligned = true; | ||
} | ||
return obj; | ||
} | ||
@@ -418,0 +436,0 @@ |
{ | ||
"name": "joi", | ||
"description": "Object schema validation", | ||
"version": "13.2.0", | ||
"version": "13.3.0", | ||
"homepage": "https://github.com/hapijs/joi", | ||
@@ -6,0 +6,0 @@ "repository": "git://github.com/hapijs/joi", |
@@ -19,3 +19,3 @@ ![joi Logo](https://raw.github.com/hapijs/joi/master/images/joi.png) | ||
# API | ||
See the detailed [API Reference](https://github.com/hapijs/joi/blob/v13.2.0/API.md). | ||
See the detailed [API Reference](https://github.com/hapijs/joi/blob/v13.3.0/API.md). | ||
@@ -22,0 +22,0 @@ # Example |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
176040
4175