1
0
Fork 0
arangodb/js/node/node_modules/joi/lib/alternatives.js

168 lines
4.9 KiB
JavaScript
Executable File

'use strict';
// Load modules
const Hoek = require('hoek');
const Any = require('./any');
const Cast = require('./cast');
const Ref = require('./ref');
// Declare internals
const internals = {};
internals.Alternatives = class extends Any {
constructor() {
super();
this._type = 'alternatives';
this._invalids.remove(null);
this._inner.matches = [];
}
_base(value, state, options) {
let errors = [];
const il = this._inner.matches.length;
const baseType = this._settings && this._settings.baseType;
for (let i = 0; i < il; ++i) {
const item = this._inner.matches[i];
const schema = item.schema;
if (!schema) {
const failed = item.is._validate(item.ref(state.parent, options), null, options, state.parent).errors;
if (failed) {
if (item.otherwise) {
return item.otherwise._validate(value, state, options);
}
else if (baseType && i === (il - 1)) {
return baseType._validate(value, state, options);
}
}
else if (item.then || baseType) {
return (item.then || baseType)._validate(value, state, options);
}
continue;
}
const result = schema._validate(value, state, options);
if (!result.errors) { // Found a valid match
return result;
}
errors = errors.concat(result.errors);
}
return { errors: errors.length ? errors : this.createError('alternatives.base', null, state, options) };
}
try(/* schemas */) {
const schemas = Hoek.flatten(Array.prototype.slice.call(arguments));
Hoek.assert(schemas.length, 'Cannot add other alternatives without at least one schema');
const obj = this.clone();
for (let i = 0; i < schemas.length; ++i) {
const cast = Cast.schema(schemas[i]);
if (cast._refs.length) {
obj._refs = obj._refs.concat(cast._refs);
}
obj._inner.matches.push({ schema: cast });
}
return obj;
}
when(ref, options) {
Hoek.assert(Ref.isRef(ref) || typeof ref === 'string', 'Invalid reference:', ref);
Hoek.assert(options, 'Missing options');
Hoek.assert(typeof options === 'object', 'Invalid options');
Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
const obj = this.clone();
let is = Cast.schema(options.is);
if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) {
// Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing
is = is.required();
}
const item = {
ref: Cast.ref(ref),
is,
then: options.then !== undefined ? Cast.schema(options.then) : undefined,
otherwise: options.otherwise !== undefined ? Cast.schema(options.otherwise) : undefined
};
if (obj._settings && obj._settings.baseType) {
item.then = item.then && obj._settings.baseType.concat(item.then);
item.otherwise = item.otherwise && obj._settings.baseType.concat(item.otherwise);
}
Ref.push(obj._refs, item.ref);
obj._refs = obj._refs.concat(item.is._refs);
if (item.then && item.then._refs) {
obj._refs = obj._refs.concat(item.then._refs);
}
if (item.otherwise && item.otherwise._refs) {
obj._refs = obj._refs.concat(item.otherwise._refs);
}
obj._inner.matches.push(item);
return obj;
}
describe() {
const description = Any.prototype.describe.call(this);
const alternatives = [];
for (let i = 0; i < this._inner.matches.length; ++i) {
const item = this._inner.matches[i];
if (item.schema) {
// try()
alternatives.push(item.schema.describe());
}
else {
// when()
const when = {
ref: item.ref.toString(),
is: item.is.describe()
};
if (item.then) {
when.then = item.then.describe();
}
if (item.otherwise) {
when.otherwise = item.otherwise.describe();
}
alternatives.push(when);
}
}
description.alternatives = alternatives;
return description;
}
};
module.exports = new internals.Alternatives();