.
This commit is contained in:
		
							
								
								
									
										301
									
								
								qwen/nodejs/node_modules/@humanwhocodes/object-schema/src/object-schema.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								qwen/nodejs/node_modules/@humanwhocodes/object-schema/src/object-schema.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,301 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @filedescription Object Schema
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Requirements
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const { MergeStrategy } = require("./merge-strategy");
 | 
			
		||||
const { ValidationStrategy } = require("./validation-strategy");
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Private
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const strategies = Symbol("strategies");
 | 
			
		||||
const requiredKeys = Symbol("requiredKeys");
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Validates a schema strategy.
 | 
			
		||||
 * @param {string} name The name of the key this strategy is for.
 | 
			
		||||
 * @param {Object} strategy The strategy for the object key.
 | 
			
		||||
 * @param {boolean} [strategy.required=true] Whether the key is required.
 | 
			
		||||
 * @param {string[]} [strategy.requires] Other keys that are required when
 | 
			
		||||
 *      this key is present.
 | 
			
		||||
 * @param {Function} strategy.merge A method to call when merging two objects
 | 
			
		||||
 *      with the same key.
 | 
			
		||||
 * @param {Function} strategy.validate A method to call when validating an
 | 
			
		||||
 *      object with the key.
 | 
			
		||||
 * @returns {void}
 | 
			
		||||
 * @throws {Error} When the strategy is missing a name.
 | 
			
		||||
 * @throws {Error} When the strategy is missing a merge() method.
 | 
			
		||||
 * @throws {Error} When the strategy is missing a validate() method.
 | 
			
		||||
 */
 | 
			
		||||
function validateDefinition(name, strategy) {
 | 
			
		||||
 | 
			
		||||
    let hasSchema = false;
 | 
			
		||||
    if (strategy.schema) {
 | 
			
		||||
        if (typeof strategy.schema === "object") {
 | 
			
		||||
            hasSchema = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new TypeError("Schema must be an object.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (typeof strategy.merge === "string") {
 | 
			
		||||
        if (!(strategy.merge in MergeStrategy)) {
 | 
			
		||||
            throw new TypeError(`Definition for key "${name}" missing valid merge strategy.`);
 | 
			
		||||
        }
 | 
			
		||||
    } else if (!hasSchema && typeof strategy.merge !== "function") {
 | 
			
		||||
        throw new TypeError(`Definition for key "${name}" must have a merge property.`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (typeof strategy.validate === "string") {
 | 
			
		||||
        if (!(strategy.validate in ValidationStrategy)) {
 | 
			
		||||
            throw new TypeError(`Definition for key "${name}" missing valid validation strategy.`);
 | 
			
		||||
        }
 | 
			
		||||
    } else if (!hasSchema && typeof strategy.validate !== "function") {
 | 
			
		||||
        throw new TypeError(`Definition for key "${name}" must have a validate() method.`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Errors
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Error when an unexpected key is found.
 | 
			
		||||
 */
 | 
			
		||||
class UnexpectedKeyError extends Error {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new instance.
 | 
			
		||||
     * @param {string} key The key that was unexpected. 
 | 
			
		||||
     */
 | 
			
		||||
    constructor(key) {
 | 
			
		||||
        super(`Unexpected key "${key}" found.`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Error when a required key is missing.
 | 
			
		||||
 */
 | 
			
		||||
class MissingKeyError extends Error {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new instance.
 | 
			
		||||
     * @param {string} key The key that was missing. 
 | 
			
		||||
     */
 | 
			
		||||
    constructor(key) {
 | 
			
		||||
        super(`Missing required key "${key}".`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Error when a key requires other keys that are missing.
 | 
			
		||||
 */
 | 
			
		||||
class MissingDependentKeysError extends Error {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new instance.
 | 
			
		||||
     * @param {string} key The key that was unexpected.
 | 
			
		||||
     * @param {Array<string>} requiredKeys The keys that are required.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(key, requiredKeys) {
 | 
			
		||||
        super(`Key "${key}" requires keys "${requiredKeys.join("\", \"")}".`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Wrapper error for errors occuring during a merge or validate operation.
 | 
			
		||||
 */
 | 
			
		||||
class WrapperError extends Error {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new instance.
 | 
			
		||||
     * @param {string} key The object key causing the error. 
 | 
			
		||||
     * @param {Error} source The source error. 
 | 
			
		||||
     */
 | 
			
		||||
    constructor(key, source) {
 | 
			
		||||
        super(`Key "${key}": ${source.message}`, { cause: source });
 | 
			
		||||
 | 
			
		||||
        // copy over custom properties that aren't represented
 | 
			
		||||
        for (const key of Object.keys(source)) {
 | 
			
		||||
            if (!(key in this)) {
 | 
			
		||||
                this[key] = source[key];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Main
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents an object validation/merging schema.
 | 
			
		||||
 */
 | 
			
		||||
class ObjectSchema {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new instance.
 | 
			
		||||
     */
 | 
			
		||||
    constructor(definitions) {
 | 
			
		||||
 | 
			
		||||
        if (!definitions) {
 | 
			
		||||
            throw new Error("Schema definitions missing.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Track all strategies in the schema by key.
 | 
			
		||||
         * @type {Map}
 | 
			
		||||
         * @property strategies
 | 
			
		||||
         */
 | 
			
		||||
        this[strategies] = new Map();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Separately track any keys that are required for faster validation.
 | 
			
		||||
         * @type {Map}
 | 
			
		||||
         * @property requiredKeys
 | 
			
		||||
         */
 | 
			
		||||
        this[requiredKeys] = new Map();
 | 
			
		||||
 | 
			
		||||
        // add in all strategies
 | 
			
		||||
        for (const key of Object.keys(definitions)) {
 | 
			
		||||
            validateDefinition(key, definitions[key]);
 | 
			
		||||
 | 
			
		||||
            // normalize merge and validate methods if subschema is present
 | 
			
		||||
            if (typeof definitions[key].schema === "object") {
 | 
			
		||||
                const schema = new ObjectSchema(definitions[key].schema);
 | 
			
		||||
                definitions[key] = {
 | 
			
		||||
                    ...definitions[key],
 | 
			
		||||
                    merge(first = {}, second = {}) {
 | 
			
		||||
                        return schema.merge(first, second);
 | 
			
		||||
                    },
 | 
			
		||||
                    validate(value) {
 | 
			
		||||
                        ValidationStrategy.object(value);
 | 
			
		||||
                        schema.validate(value);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // normalize the merge method in case there's a string
 | 
			
		||||
            if (typeof definitions[key].merge === "string") {
 | 
			
		||||
                definitions[key] = {
 | 
			
		||||
                    ...definitions[key],
 | 
			
		||||
                    merge: MergeStrategy[definitions[key].merge]
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // normalize the validate method in case there's a string
 | 
			
		||||
            if (typeof definitions[key].validate === "string") {
 | 
			
		||||
                definitions[key] = {
 | 
			
		||||
                    ...definitions[key],
 | 
			
		||||
                    validate: ValidationStrategy[definitions[key].validate]
 | 
			
		||||
                };
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this[strategies].set(key, definitions[key]);
 | 
			
		||||
 | 
			
		||||
            if (definitions[key].required) {
 | 
			
		||||
                this[requiredKeys].set(key, definitions[key]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines if a strategy has been registered for the given object key.
 | 
			
		||||
     * @param {string} key The object key to find a strategy for.
 | 
			
		||||
     * @returns {boolean} True if the key has a strategy registered, false if not. 
 | 
			
		||||
     */
 | 
			
		||||
    hasKey(key) {
 | 
			
		||||
        return this[strategies].has(key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Merges objects together to create a new object comprised of the keys
 | 
			
		||||
     * of the all objects. Keys are merged based on the each key's merge
 | 
			
		||||
     * strategy.
 | 
			
		||||
     * @param {...Object} objects The objects to merge.
 | 
			
		||||
     * @returns {Object} A new object with a mix of all objects' keys.
 | 
			
		||||
     * @throws {Error} If any object is invalid.
 | 
			
		||||
     */
 | 
			
		||||
    merge(...objects) {
 | 
			
		||||
 | 
			
		||||
        // double check arguments
 | 
			
		||||
        if (objects.length < 2) {
 | 
			
		||||
            throw new TypeError("merge() requires at least two arguments.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (objects.some(object => (object == null || typeof object !== "object"))) {
 | 
			
		||||
            throw new TypeError("All arguments must be objects.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return objects.reduce((result, object) => {
 | 
			
		||||
            
 | 
			
		||||
            this.validate(object);
 | 
			
		||||
            
 | 
			
		||||
            for (const [key, strategy] of this[strategies]) {
 | 
			
		||||
                try {
 | 
			
		||||
                    if (key in result || key in object) {
 | 
			
		||||
                        const value = strategy.merge.call(this, result[key], object[key]);
 | 
			
		||||
                        if (value !== undefined) {
 | 
			
		||||
                            result[key] = value;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (ex) {
 | 
			
		||||
                    throw new WrapperError(key, ex);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return result;
 | 
			
		||||
        }, {});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates an object's keys based on the validate strategy for each key.
 | 
			
		||||
     * @param {Object} object The object to validate.
 | 
			
		||||
     * @returns {void}
 | 
			
		||||
     * @throws {Error} When the object is invalid. 
 | 
			
		||||
     */
 | 
			
		||||
    validate(object) {
 | 
			
		||||
 | 
			
		||||
        // check existing keys first
 | 
			
		||||
        for (const key of Object.keys(object)) {
 | 
			
		||||
 | 
			
		||||
            // check to see if the key is defined
 | 
			
		||||
            if (!this.hasKey(key)) {
 | 
			
		||||
                throw new UnexpectedKeyError(key);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // validate existing keys
 | 
			
		||||
            const strategy = this[strategies].get(key);
 | 
			
		||||
 | 
			
		||||
            // first check to see if any other keys are required
 | 
			
		||||
            if (Array.isArray(strategy.requires)) {
 | 
			
		||||
                if (!strategy.requires.every(otherKey => otherKey in object)) {
 | 
			
		||||
                    throw new MissingDependentKeysError(key, strategy.requires);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // now apply remaining validation strategy
 | 
			
		||||
            try {
 | 
			
		||||
                strategy.validate.call(strategy, object[key]);
 | 
			
		||||
            } catch (ex) {
 | 
			
		||||
                throw new WrapperError(key, ex);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // ensure required keys aren't missing
 | 
			
		||||
        for (const [key] of this[requiredKeys]) {
 | 
			
		||||
            if (!(key in object)) {
 | 
			
		||||
                throw new MissingKeyError(key);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exports.ObjectSchema = ObjectSchema;
 | 
			
		||||
		Reference in New Issue
	
	Block a user