'use strict'; 
 | 
  
 | 
const Hoek = require('@hapi/hoek'); 
 | 
  
 | 
const Any = require('../any'); 
 | 
const Cast = require('../../cast'); 
 | 
const Ref = require('../../ref'); 
 | 
  
 | 
  
 | 
const internals = {}; 
 | 
  
 | 
  
 | 
internals.Alternatives = class extends Any { 
 | 
  
 | 
    constructor() { 
 | 
  
 | 
        super(); 
 | 
        this._type = 'alternatives'; 
 | 
        this._invalids.remove(null); 
 | 
        this._inner.matches = []; 
 | 
    } 
 | 
  
 | 
    _init(...args) { 
 | 
  
 | 
        return args.length ? this.try(...args) : this; 
 | 
    } 
 | 
  
 | 
    _base(value, state, options) { 
 | 
  
 | 
        const errors = []; 
 | 
        const il = this._inner.matches.length; 
 | 
        const baseType = this._baseType; 
 | 
  
 | 
        for (let i = 0; i < il; ++i) { 
 | 
            const item = this._inner.matches[i]; 
 | 
            if (!item.schema) { 
 | 
                const schema = item.peek || item.is; 
 | 
                const input = item.is ? item.ref(state.reference || state.parent, options) : value; 
 | 
                const failed = schema._validate(input, null, options, state.parent).errors; 
 | 
  
 | 
                if (failed) { 
 | 
                    if (item.otherwise) { 
 | 
                        return item.otherwise._validate(value, state, options); 
 | 
                    } 
 | 
                } 
 | 
                else if (item.then) { 
 | 
                    return item.then._validate(value, state, options); 
 | 
                } 
 | 
  
 | 
                if (i === (il - 1) && baseType) { 
 | 
                    return baseType._validate(value, state, options); 
 | 
                } 
 | 
  
 | 
                continue; 
 | 
            } 
 | 
  
 | 
            const result = item.schema._validate(value, state, options); 
 | 
            if (!result.errors) {     // Found a valid match 
 | 
                return result; 
 | 
            } 
 | 
  
 | 
            errors.push(...result.errors); 
 | 
        } 
 | 
  
 | 
        if (errors.length) { 
 | 
            return { errors: this.createError('alternatives.child', { reason: errors }, state, options) }; 
 | 
        } 
 | 
  
 | 
        return { errors: this.createError('alternatives.base', null, state, options) }; 
 | 
    } 
 | 
  
 | 
    try(...schemas) { 
 | 
  
 | 
        schemas = Hoek.flatten(schemas); 
 | 
        Hoek.assert(schemas.length, 'Cannot add other alternatives without at least one schema'); 
 | 
  
 | 
        const obj = this.clone(); 
 | 
  
 | 
        for (let i = 0; i < schemas.length; ++i) { 
 | 
            const cast = Cast.schema(this._currentJoi, schemas[i]); 
 | 
            if (cast._refs.length) { 
 | 
                obj._refs.push(...cast._refs); 
 | 
            } 
 | 
  
 | 
            obj._inner.matches.push({ schema: cast }); 
 | 
        } 
 | 
  
 | 
        return obj; 
 | 
    } 
 | 
  
 | 
    when(condition, options) { 
 | 
  
 | 
        let schemaCondition = false; 
 | 
        Hoek.assert(Ref.isRef(condition) || typeof condition === 'string' || (schemaCondition = condition instanceof Any), 'Invalid condition:', condition); 
 | 
        Hoek.assert(options, 'Missing options'); 
 | 
        Hoek.assert(typeof options === 'object', 'Invalid options'); 
 | 
        if (schemaCondition) { 
 | 
            Hoek.assert(!options.hasOwnProperty('is'), '"is" can not be used with a schema condition'); 
 | 
        } 
 | 
        else { 
 | 
            Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive'); 
 | 
        } 
 | 
  
 | 
        Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"'); 
 | 
  
 | 
        const obj = this.clone(); 
 | 
        let is; 
 | 
        if (!schemaCondition) { 
 | 
            is = Cast.schema(this._currentJoi, options.is); 
 | 
  
 | 
            if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) { 
 | 
  
 | 
                // Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing 
 | 
                is = is.required(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        const item = { 
 | 
            ref: schemaCondition ? null : Cast.ref(condition), 
 | 
            peek: schemaCondition ? condition : null, 
 | 
            is, 
 | 
            then: options.then !== undefined ? Cast.schema(this._currentJoi, options.then) : undefined, 
 | 
            otherwise: options.otherwise !== undefined ? Cast.schema(this._currentJoi, options.otherwise) : undefined 
 | 
        }; 
 | 
  
 | 
        if (obj._baseType) { 
 | 
  
 | 
            item.then = item.then && obj._baseType.concat(item.then); 
 | 
            item.otherwise = item.otherwise && obj._baseType.concat(item.otherwise); 
 | 
        } 
 | 
  
 | 
        if (!schemaCondition) { 
 | 
            Ref.push(obj._refs, item.ref); 
 | 
            obj._refs.push(...item.is._refs); 
 | 
        } 
 | 
  
 | 
        if (item.then && item.then._refs.length) { 
 | 
            obj._refs.push(...item.then._refs); 
 | 
        } 
 | 
  
 | 
        if (item.otherwise && item.otherwise._refs.length) { 
 | 
            obj._refs.push(...item.otherwise._refs); 
 | 
        } 
 | 
  
 | 
        obj._inner.matches.push(item); 
 | 
  
 | 
        return obj; 
 | 
    } 
 | 
  
 | 
    label(name) { 
 | 
  
 | 
        const obj = super.label(name); 
 | 
        obj._inner.matches = obj._inner.matches.map((match) => { 
 | 
  
 | 
            if (match.schema) { 
 | 
                return { schema: match.schema.label(name) }; 
 | 
            } 
 | 
  
 | 
            match = Object.assign({}, match); 
 | 
            if (match.then) { 
 | 
                match.then = match.then.label(name); 
 | 
            } 
 | 
  
 | 
            if (match.otherwise) { 
 | 
                match.otherwise = match.otherwise.label(name); 
 | 
            } 
 | 
  
 | 
            return match; 
 | 
        }); 
 | 
        return obj; 
 | 
    } 
 | 
  
 | 
    describe() { 
 | 
  
 | 
        const description = super.describe(); 
 | 
        const alternatives = []; 
 | 
        for (let i = 0; i < this._inner.matches.length; ++i) { 
 | 
            const item = this._inner.matches[i]; 
 | 
            if (item.schema) { 
 | 
  
 | 
                // try() 
 | 
  
 | 
                alternatives.push(item.schema.describe()); 
 | 
            } 
 | 
            else { 
 | 
  
 | 
                // when() 
 | 
  
 | 
                const when = item.is ? { 
 | 
                    ref: item.ref.toString(), 
 | 
                    is: item.is.describe() 
 | 
                } : { 
 | 
                    peek: item.peek.describe() 
 | 
                }; 
 | 
  
 | 
                if (item.then) { 
 | 
                    when.then = item.then.describe(); 
 | 
                } 
 | 
  
 | 
                if (item.otherwise) { 
 | 
                    when.otherwise = item.otherwise.describe(); 
 | 
                } 
 | 
  
 | 
                alternatives.push(when); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        description.alternatives = alternatives; 
 | 
        return description; 
 | 
    } 
 | 
  
 | 
}; 
 | 
  
 | 
  
 | 
module.exports = new internals.Alternatives(); 
 |