🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@kenyip/joi

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kenyip/joi - npm Package Compare versions

Comparing version
0.0.1
to
0.0.2
+2
-1
.editorconfig

@@ -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) {

@@ -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 @@

{
"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",

@@ -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"
// }
// }
// }
```