284 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
const Assert = require('@hapi/hoek/lib/assert');
 | 
						|
const Clone = require('@hapi/hoek/lib/clone');
 | 
						|
 | 
						|
const Cache = require('./cache');
 | 
						|
const Common = require('./common');
 | 
						|
const Compile = require('./compile');
 | 
						|
const Errors = require('./errors');
 | 
						|
const Extend = require('./extend');
 | 
						|
const Manifest = require('./manifest');
 | 
						|
const Ref = require('./ref');
 | 
						|
const Template = require('./template');
 | 
						|
const Trace = require('./trace');
 | 
						|
 | 
						|
let Schemas;
 | 
						|
 | 
						|
 | 
						|
const internals = {
 | 
						|
    types: {
 | 
						|
        alternatives: require('./types/alternatives'),
 | 
						|
        any: require('./types/any'),
 | 
						|
        array: require('./types/array'),
 | 
						|
        boolean: require('./types/boolean'),
 | 
						|
        date: require('./types/date'),
 | 
						|
        function: require('./types/function'),
 | 
						|
        link: require('./types/link'),
 | 
						|
        number: require('./types/number'),
 | 
						|
        object: require('./types/object'),
 | 
						|
        string: require('./types/string'),
 | 
						|
        symbol: require('./types/symbol')
 | 
						|
    },
 | 
						|
    aliases: {
 | 
						|
        alt: 'alternatives',
 | 
						|
        bool: 'boolean',
 | 
						|
        func: 'function'
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
if (Buffer) {                                                           // $lab:coverage:ignore$
 | 
						|
    internals.types.binary = require('./types/binary');
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
internals.root = function () {
 | 
						|
 | 
						|
    const root = {
 | 
						|
        _types: new Set(Object.keys(internals.types))
 | 
						|
    };
 | 
						|
 | 
						|
    // Types
 | 
						|
 | 
						|
    for (const type of root._types) {
 | 
						|
        root[type] = function (...args) {
 | 
						|
 | 
						|
            Assert(!args.length || ['alternatives', 'link', 'object'].includes(type), 'The', type, 'type does not allow arguments');
 | 
						|
            return internals.generate(this, internals.types[type], args);
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    // Shortcuts
 | 
						|
 | 
						|
    for (const method of ['allow', 'custom', 'disallow', 'equal', 'exist', 'forbidden', 'invalid', 'not', 'only', 'optional', 'options', 'prefs', 'preferences', 'required', 'strip', 'valid', 'when']) {
 | 
						|
        root[method] = function (...args) {
 | 
						|
 | 
						|
            return this.any()[method](...args);
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    // Methods
 | 
						|
 | 
						|
    Object.assign(root, internals.methods);
 | 
						|
 | 
						|
    // Aliases
 | 
						|
 | 
						|
    for (const alias in internals.aliases) {
 | 
						|
        const target = internals.aliases[alias];
 | 
						|
        root[alias] = root[target];
 | 
						|
    }
 | 
						|
 | 
						|
    root.x = root.expression;
 | 
						|
 | 
						|
    // Trace
 | 
						|
 | 
						|
    if (Trace.setup) {                                          // $lab:coverage:ignore$
 | 
						|
        Trace.setup(root);
 | 
						|
    }
 | 
						|
 | 
						|
    return root;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
internals.methods = {
 | 
						|
 | 
						|
    ValidationError: Errors.ValidationError,
 | 
						|
    version: Common.version,
 | 
						|
    cache: Cache.provider,
 | 
						|
 | 
						|
    assert(value, schema, ...args /* [message], [options] */) {
 | 
						|
 | 
						|
        internals.assert(value, schema, true, args);
 | 
						|
    },
 | 
						|
 | 
						|
    attempt(value, schema, ...args /* [message], [options] */) {
 | 
						|
 | 
						|
        return internals.assert(value, schema, false, args);
 | 
						|
    },
 | 
						|
 | 
						|
    build(desc) {
 | 
						|
 | 
						|
        Assert(typeof Manifest.build === 'function', 'Manifest functionality disabled');
 | 
						|
        return Manifest.build(this, desc);
 | 
						|
    },
 | 
						|
 | 
						|
    checkPreferences(prefs) {
 | 
						|
 | 
						|
        Common.checkPreferences(prefs);
 | 
						|
    },
 | 
						|
 | 
						|
    compile(schema, options) {
 | 
						|
 | 
						|
        return Compile.compile(this, schema, options);
 | 
						|
    },
 | 
						|
 | 
						|
    defaults(modifier) {
 | 
						|
 | 
						|
        Assert(typeof modifier === 'function', 'modifier must be a function');
 | 
						|
 | 
						|
        const joi = Object.assign({}, this);
 | 
						|
        for (const type of joi._types) {
 | 
						|
            const schema = modifier(joi[type]());
 | 
						|
            Assert(Common.isSchema(schema), 'modifier must return a valid schema object');
 | 
						|
 | 
						|
            joi[type] = function (...args) {
 | 
						|
 | 
						|
                return internals.generate(this, schema, args);
 | 
						|
            };
 | 
						|
        }
 | 
						|
 | 
						|
        return joi;
 | 
						|
    },
 | 
						|
 | 
						|
    expression(...args) {
 | 
						|
 | 
						|
        return new Template(...args);
 | 
						|
    },
 | 
						|
 | 
						|
    extend(...extensions) {
 | 
						|
 | 
						|
        Common.verifyFlat(extensions, 'extend');
 | 
						|
 | 
						|
        Schemas = Schemas || require('./schemas');
 | 
						|
 | 
						|
        Assert(extensions.length, 'You need to provide at least one extension');
 | 
						|
        this.assert(extensions, Schemas.extensions);
 | 
						|
 | 
						|
        const joi = Object.assign({}, this);
 | 
						|
        joi._types = new Set(joi._types);
 | 
						|
 | 
						|
        for (let extension of extensions) {
 | 
						|
            if (typeof extension === 'function') {
 | 
						|
                extension = extension(joi);
 | 
						|
            }
 | 
						|
 | 
						|
            this.assert(extension, Schemas.extension);
 | 
						|
 | 
						|
            const expanded = internals.expandExtension(extension, joi);
 | 
						|
            for (const item of expanded) {
 | 
						|
                Assert(joi[item.type] === undefined || joi._types.has(item.type), 'Cannot override name', item.type);
 | 
						|
 | 
						|
                const base = item.base || this.any();
 | 
						|
                const schema = Extend.type(base, item);
 | 
						|
 | 
						|
                joi._types.add(item.type);
 | 
						|
                joi[item.type] = function (...args) {
 | 
						|
 | 
						|
                    return internals.generate(this, schema, args);
 | 
						|
                };
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return joi;
 | 
						|
    },
 | 
						|
 | 
						|
    isError: Errors.ValidationError.isError,
 | 
						|
    isExpression: Template.isTemplate,
 | 
						|
    isRef: Ref.isRef,
 | 
						|
    isSchema: Common.isSchema,
 | 
						|
 | 
						|
    in(...args) {
 | 
						|
 | 
						|
        return Ref.in(...args);
 | 
						|
    },
 | 
						|
 | 
						|
    override: Common.symbols.override,
 | 
						|
 | 
						|
    ref(...args) {
 | 
						|
 | 
						|
        return Ref.create(...args);
 | 
						|
    },
 | 
						|
 | 
						|
    types() {
 | 
						|
 | 
						|
        const types = {};
 | 
						|
        for (const type of this._types) {
 | 
						|
            types[type] = this[type]();
 | 
						|
        }
 | 
						|
 | 
						|
        for (const target in internals.aliases) {
 | 
						|
            types[target] = this[target]();
 | 
						|
        }
 | 
						|
 | 
						|
        return types;
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
// Helpers
 | 
						|
 | 
						|
internals.assert = function (value, schema, annotate, args /* [message], [options] */) {
 | 
						|
 | 
						|
    const message = args[0] instanceof Error || typeof args[0] === 'string' ? args[0] : null;
 | 
						|
    const options = message !== null ? args[1] : args[0];
 | 
						|
    const result = schema.validate(value, Common.preferences({ errors: { stack: true } }, options || {}));
 | 
						|
 | 
						|
    let error = result.error;
 | 
						|
    if (!error) {
 | 
						|
        return result.value;
 | 
						|
    }
 | 
						|
 | 
						|
    if (message instanceof Error) {
 | 
						|
        throw message;
 | 
						|
    }
 | 
						|
 | 
						|
    const display = annotate && typeof error.annotate === 'function' ? error.annotate() : error.message;
 | 
						|
 | 
						|
    if (error instanceof Errors.ValidationError === false) {
 | 
						|
        error = Clone(error);
 | 
						|
    }
 | 
						|
 | 
						|
    error.message = message ? `${message} ${display}` : display;
 | 
						|
    throw error;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
internals.generate = function (root, schema, args) {
 | 
						|
 | 
						|
    Assert(root, 'Must be invoked on a Joi instance.');
 | 
						|
 | 
						|
    schema.$_root = root;
 | 
						|
 | 
						|
    if (!schema._definition.args ||
 | 
						|
        !args.length) {
 | 
						|
 | 
						|
        return schema;
 | 
						|
    }
 | 
						|
 | 
						|
    return schema._definition.args(schema, ...args);
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
internals.expandExtension = function (extension, joi) {
 | 
						|
 | 
						|
    if (typeof extension.type === 'string') {
 | 
						|
        return [extension];
 | 
						|
    }
 | 
						|
 | 
						|
    const extended = [];
 | 
						|
    for (const type of joi._types) {
 | 
						|
        if (extension.type.test(type)) {
 | 
						|
            const item = Object.assign({}, extension);
 | 
						|
            item.type = type;
 | 
						|
            item.base = joi[type]();
 | 
						|
            extended.push(item);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return extended;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
module.exports = internals.root();
 |