forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			587 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			587 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 | 
						|
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
/* This file implements a not-quite standard JSON schema validator. It differs
 | 
						|
 * from the spec in a few ways:
 | 
						|
 *
 | 
						|
 *  - the spec doesn't allow custom types to be defined, but this validator
 | 
						|
 *    defines "URL", "URLorEmpty", "origin" etc.
 | 
						|
 * - Strings are automatically converted to `URL` objects for the appropriate
 | 
						|
 *   types.
 | 
						|
 * - It doesn't support "pattern" when matching strings.
 | 
						|
 * - The boolean type accepts (and casts) 0 and 1 as valid values.
 | 
						|
 */
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
ChromeUtils.defineLazyGetter(lazy, "log", () => {
 | 
						|
  let { ConsoleAPI } = ChromeUtils.importESModule(
 | 
						|
    "resource://gre/modules/Console.sys.mjs"
 | 
						|
  );
 | 
						|
  return new ConsoleAPI({
 | 
						|
    prefix: "JsonSchemaValidator.jsm",
 | 
						|
    // tip: set maxLogLevel to "debug" and use log.debug() to create detailed
 | 
						|
    // messages during development. See LOG_LEVELS in Console.sys.mjs for details.
 | 
						|
    maxLogLevel: "error",
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * To validate a single value, use the static `JsonSchemaValidator.validate`
 | 
						|
 * method.  If you need to validate multiple values, you instead might want to
 | 
						|
 * make a JsonSchemaValidator instance with the options you need and then call
 | 
						|
 * the `validate` instance method.
 | 
						|
 */
 | 
						|
export class JsonSchemaValidator {
 | 
						|
  /**
 | 
						|
   * Validates a value against a schema.
 | 
						|
   *
 | 
						|
   * @param {*} value
 | 
						|
   *   The value to validate.
 | 
						|
   * @param {object} schema
 | 
						|
   *   The schema to validate against.
 | 
						|
   * @param {boolean} allowArrayNonMatchingItems
 | 
						|
   *   When true:
 | 
						|
   *     Invalid items in arrays will be ignored, and they won't be included in
 | 
						|
   *     result.parsedValue.
 | 
						|
   *   When false:
 | 
						|
   *     Invalid items in arrays will cause validation to fail.
 | 
						|
   * @param {boolean} allowExplicitUndefinedProperties
 | 
						|
   *   When true:
 | 
						|
   *     `someProperty: undefined` will be allowed for non-required properties.
 | 
						|
   *   When false:
 | 
						|
   *     `someProperty: undefined` will cause validation to fail even for
 | 
						|
   *     properties that are not required.
 | 
						|
   * @param {boolean} allowNullAsUndefinedProperties
 | 
						|
   *   When true:
 | 
						|
   *     `someProperty: null` will be allowed for non-required properties whose
 | 
						|
   *     expected types are non-null.
 | 
						|
   *   When false:
 | 
						|
   *     `someProperty: null` will cause validation to fail for non-required
 | 
						|
   *     properties, except for properties whose expected types are null.
 | 
						|
   * @param {boolean} allowAdditionalProperties
 | 
						|
   *   When true:
 | 
						|
   *     Properties that are not defined in the schema will be ignored, and they
 | 
						|
   *     won't be included in result.parsedValue.
 | 
						|
   *   When false:
 | 
						|
   *     Properties that are not defined in the schema will cause validation to
 | 
						|
   *     fail.
 | 
						|
   *   Note: Schema objects of type "object" can also contain a boolean property
 | 
						|
   *     called `additionalProperties` that functions as a local version of this
 | 
						|
   *     param. When true, extra properties will be allowed in the corresponding
 | 
						|
   *     input objects regardless of `allowAdditionalProperties`, and as with
 | 
						|
   *     `allowAdditionalProperties`, extra properties won't be included in
 | 
						|
   *     `result.parsedValue`. (The inverse is not true: If a schema object
 | 
						|
   *     defines `additionalProperties: false` but `allowAdditionalProperties`
 | 
						|
   *     is true, extra properties will be allowed.)
 | 
						|
   * @return {object}
 | 
						|
   *   The result of the validation, an object that looks like this:
 | 
						|
   *
 | 
						|
   *   {
 | 
						|
   *     valid,
 | 
						|
   *     parsedValue,
 | 
						|
   *     error: {
 | 
						|
   *       message,
 | 
						|
   *       rootValue,
 | 
						|
   *       rootSchema,
 | 
						|
   *       invalidValue,
 | 
						|
   *       invalidPropertyNameComponents,
 | 
						|
   *     }
 | 
						|
   *   }
 | 
						|
   *
 | 
						|
   *   {boolean} valid
 | 
						|
   *     True if validation is successful, false if not.
 | 
						|
   *   {*} parsedValue
 | 
						|
   *     If validation is successful, this is the validated value.  It can
 | 
						|
   *     differ from the passed-in value in the following ways:
 | 
						|
   *       * If a type in the schema is "URL" or "URLorEmpty", the passed-in
 | 
						|
   *         value can use a string instead and it will be converted into a
 | 
						|
   *         `URL` object in parsedValue.
 | 
						|
   *       * Some of the `allow*` parameters control the properties that appear.
 | 
						|
   *         See above.
 | 
						|
   *   {Error} error
 | 
						|
   *     If validation fails, `error` will be present.  It contains a number of
 | 
						|
   *     properties useful for understanding the validation failure.
 | 
						|
   *   {string} error.message
 | 
						|
   *     The validation failure message.
 | 
						|
   *   {*} error.rootValue
 | 
						|
   *     The passed-in value.
 | 
						|
   *   {object} error.rootSchema
 | 
						|
   *     The passed-in schema.
 | 
						|
   *   {*} invalidValue
 | 
						|
   *     The value that caused validation to fail.  If the passed-in value is a
 | 
						|
   *     scalar type, this will be the value itself.  If the value is an object
 | 
						|
   *     or array, it will be the specific nested value in the object or array
 | 
						|
   *     that caused validation to fail.
 | 
						|
   *   {array} invalidPropertyNameComponents
 | 
						|
   *     If the passed-in value is an object or array, this will contain the
 | 
						|
   *     names of the object properties or array indexes where invalidValue can
 | 
						|
   *     be found.  For example, assume the passed-in value is:
 | 
						|
   *       { foo: { bar: { baz: 123 }}}
 | 
						|
   *     And assume `baz` should be a string instead of a number.  Then
 | 
						|
   *     invalidValue will be 123, and invalidPropertyNameComponents will be
 | 
						|
   *     ["foo", "bar", "baz"], indicating that the erroneous property in the
 | 
						|
   *     passed-in object is `foo.bar.baz`.
 | 
						|
   */
 | 
						|
  static validate(
 | 
						|
    value,
 | 
						|
    schema,
 | 
						|
    {
 | 
						|
      allowArrayNonMatchingItems = false,
 | 
						|
      allowExplicitUndefinedProperties = false,
 | 
						|
      allowNullAsUndefinedProperties = false,
 | 
						|
      allowAdditionalProperties = false,
 | 
						|
    } = {}
 | 
						|
  ) {
 | 
						|
    let validator = new JsonSchemaValidator({
 | 
						|
      allowArrayNonMatchingItems,
 | 
						|
      allowExplicitUndefinedProperties,
 | 
						|
      allowNullAsUndefinedProperties,
 | 
						|
      allowAdditionalProperties,
 | 
						|
    });
 | 
						|
    return validator.validate(value, schema);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Constructor.
 | 
						|
   *
 | 
						|
   * @param {boolean} allowArrayNonMatchingItems
 | 
						|
   *   See the static `validate` method above.
 | 
						|
   * @param {boolean} allowExplicitUndefinedProperties
 | 
						|
   *   See the static `validate` method above.
 | 
						|
   * @param {boolean} allowNullAsUndefinedProperties
 | 
						|
   *   See the static `validate` method above.
 | 
						|
   * @param {boolean} allowAdditionalProperties
 | 
						|
   *   See the static `validate` method above.
 | 
						|
   */
 | 
						|
  constructor({
 | 
						|
    allowArrayNonMatchingItems = false,
 | 
						|
    allowExplicitUndefinedProperties = false,
 | 
						|
    allowNullAsUndefinedProperties = false,
 | 
						|
    allowAdditionalProperties = false,
 | 
						|
  } = {}) {
 | 
						|
    this.allowArrayNonMatchingItems = allowArrayNonMatchingItems;
 | 
						|
    this.allowExplicitUndefinedProperties = allowExplicitUndefinedProperties;
 | 
						|
    this.allowNullAsUndefinedProperties = allowNullAsUndefinedProperties;
 | 
						|
    this.allowAdditionalProperties = allowAdditionalProperties;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Validates a value against a schema.
 | 
						|
   *
 | 
						|
   * @param {*} value
 | 
						|
   *   The value to validate.
 | 
						|
   * @param {object} schema
 | 
						|
   *   The schema to validate against.
 | 
						|
   * @return {object}
 | 
						|
   *   The result object.  See the static `validate` method above.
 | 
						|
   */
 | 
						|
  validate(value, schema) {
 | 
						|
    return this._validateRecursive(value, schema, [], {
 | 
						|
      rootValue: value,
 | 
						|
      rootSchema: schema,
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  // eslint-disable-next-line complexity
 | 
						|
  _validateRecursive(param, properties, keyPath, state) {
 | 
						|
    lazy.log.debug(`checking @${param}@ for type ${properties.type}`);
 | 
						|
 | 
						|
    if (Array.isArray(properties.type)) {
 | 
						|
      lazy.log.debug("type is an array");
 | 
						|
      // For an array of types, the value is valid if it matches any of the
 | 
						|
      // listed types. To check this, make versions of the object definition
 | 
						|
      // that include only one type at a time, and check the value against each
 | 
						|
      // one.
 | 
						|
      for (const type of properties.type) {
 | 
						|
        let typeProperties = Object.assign({}, properties, { type });
 | 
						|
        lazy.log.debug(`checking subtype ${type}`);
 | 
						|
        let result = this._validateRecursive(
 | 
						|
          param,
 | 
						|
          typeProperties,
 | 
						|
          keyPath,
 | 
						|
          state
 | 
						|
        );
 | 
						|
        if (result.valid) {
 | 
						|
          return result;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      // None of the types matched
 | 
						|
      return {
 | 
						|
        valid: false,
 | 
						|
        error: new JsonSchemaValidatorError({
 | 
						|
          message:
 | 
						|
            `The value '${valueToString(param)}' does not match any type in ` +
 | 
						|
            valueToString(properties.type),
 | 
						|
          value: param,
 | 
						|
          keyPath,
 | 
						|
          state,
 | 
						|
        }),
 | 
						|
      };
 | 
						|
    }
 | 
						|
 | 
						|
    switch (properties.type) {
 | 
						|
      case "boolean":
 | 
						|
      case "number":
 | 
						|
      case "integer":
 | 
						|
      case "string":
 | 
						|
      case "URL":
 | 
						|
      case "URLorEmpty":
 | 
						|
      case "origin":
 | 
						|
      case "null": {
 | 
						|
        let result = this._validateSimpleParam(
 | 
						|
          param,
 | 
						|
          properties.type,
 | 
						|
          keyPath,
 | 
						|
          state
 | 
						|
        );
 | 
						|
        if (!result.valid) {
 | 
						|
          return result;
 | 
						|
        }
 | 
						|
        if (properties.enum && typeof result.parsedValue !== "boolean") {
 | 
						|
          if (!properties.enum.includes(param)) {
 | 
						|
            return {
 | 
						|
              valid: false,
 | 
						|
              error: new JsonSchemaValidatorError({
 | 
						|
                message:
 | 
						|
                  `The value '${valueToString(param)}' is not one of the ` +
 | 
						|
                  `enumerated values ${valueToString(properties.enum)}`,
 | 
						|
                value: param,
 | 
						|
                keyPath,
 | 
						|
                state,
 | 
						|
              }),
 | 
						|
            };
 | 
						|
          }
 | 
						|
        }
 | 
						|
        return result;
 | 
						|
      }
 | 
						|
 | 
						|
      case "array":
 | 
						|
        if (!Array.isArray(param)) {
 | 
						|
          return {
 | 
						|
            valid: false,
 | 
						|
            error: new JsonSchemaValidatorError({
 | 
						|
              message:
 | 
						|
                `The value '${valueToString(param)}' does not match the ` +
 | 
						|
                `expected type 'array'`,
 | 
						|
              value: param,
 | 
						|
              keyPath,
 | 
						|
              state,
 | 
						|
            }),
 | 
						|
          };
 | 
						|
        }
 | 
						|
 | 
						|
        let parsedArray = [];
 | 
						|
        for (let i = 0; i < param.length; i++) {
 | 
						|
          let item = param[i];
 | 
						|
          lazy.log.debug(
 | 
						|
            `in array, checking @${item}@ for type ${properties.items.type}`
 | 
						|
          );
 | 
						|
          let result = this._validateRecursive(
 | 
						|
            item,
 | 
						|
            properties.items,
 | 
						|
            keyPath.concat(i),
 | 
						|
            state
 | 
						|
          );
 | 
						|
          if (!result.valid) {
 | 
						|
            if (
 | 
						|
              ("strict" in properties && properties.strict) ||
 | 
						|
              (!("strict" in properties) && !this.allowArrayNonMatchingItems)
 | 
						|
            ) {
 | 
						|
              return result;
 | 
						|
            }
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          parsedArray.push(result.parsedValue);
 | 
						|
        }
 | 
						|
 | 
						|
        return { valid: true, parsedValue: parsedArray };
 | 
						|
 | 
						|
      case "object": {
 | 
						|
        if (typeof param != "object" || !param) {
 | 
						|
          return {
 | 
						|
            valid: false,
 | 
						|
            error: new JsonSchemaValidatorError({
 | 
						|
              message:
 | 
						|
                `The value '${valueToString(param)}' does not match the ` +
 | 
						|
                `expected type 'object'`,
 | 
						|
              value: param,
 | 
						|
              keyPath,
 | 
						|
              state,
 | 
						|
            }),
 | 
						|
          };
 | 
						|
        }
 | 
						|
 | 
						|
        let parsedObj = {};
 | 
						|
        let patternProperties = [];
 | 
						|
        if ("patternProperties" in properties) {
 | 
						|
          for (let prop of Object.keys(properties.patternProperties || {})) {
 | 
						|
            let pattern;
 | 
						|
            try {
 | 
						|
              pattern = new RegExp(prop);
 | 
						|
            } catch (e) {
 | 
						|
              throw new Error(
 | 
						|
                `Internal error: Invalid property pattern ${prop}`
 | 
						|
              );
 | 
						|
            }
 | 
						|
            patternProperties.push({
 | 
						|
              pattern,
 | 
						|
              schema: properties.patternProperties[prop],
 | 
						|
            });
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (properties.required) {
 | 
						|
          for (let required of properties.required) {
 | 
						|
            if (!(required in param)) {
 | 
						|
              lazy.log.error(`Object is missing required property ${required}`);
 | 
						|
              return {
 | 
						|
                valid: false,
 | 
						|
                error: new JsonSchemaValidatorError({
 | 
						|
                  message: `Object is missing required property '${required}'`,
 | 
						|
                  value: param,
 | 
						|
                  keyPath,
 | 
						|
                  state,
 | 
						|
                }),
 | 
						|
              };
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        for (let item of Object.keys(param)) {
 | 
						|
          let schema;
 | 
						|
          if (
 | 
						|
            "properties" in properties &&
 | 
						|
            properties.properties.hasOwnProperty(item)
 | 
						|
          ) {
 | 
						|
            schema = properties.properties[item];
 | 
						|
          } else if (patternProperties.length) {
 | 
						|
            for (let patternProperty of patternProperties) {
 | 
						|
              if (patternProperty.pattern.test(item)) {
 | 
						|
                schema = patternProperty.schema;
 | 
						|
                break;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
          if (!schema) {
 | 
						|
            let allowAdditionalProperties =
 | 
						|
              properties.additionalProperties ||
 | 
						|
              (!properties.strict && this.allowAdditionalProperties);
 | 
						|
            if (allowAdditionalProperties) {
 | 
						|
              continue;
 | 
						|
            }
 | 
						|
            return {
 | 
						|
              valid: false,
 | 
						|
              error: new JsonSchemaValidatorError({
 | 
						|
                message: `Object has unexpected property '${item}'`,
 | 
						|
                value: param,
 | 
						|
                keyPath,
 | 
						|
                state,
 | 
						|
              }),
 | 
						|
            };
 | 
						|
          }
 | 
						|
          let allowExplicitUndefinedProperties =
 | 
						|
            !properties.strict && this.allowExplicitUndefinedProperties;
 | 
						|
          let allowNullAsUndefinedProperties =
 | 
						|
            !properties.strict && this.allowNullAsUndefinedProperties;
 | 
						|
          let isUndefined =
 | 
						|
            (!allowExplicitUndefinedProperties && !(item in param)) ||
 | 
						|
            (allowExplicitUndefinedProperties && param[item] === undefined) ||
 | 
						|
            (allowNullAsUndefinedProperties && param[item] === null);
 | 
						|
          if (isUndefined) {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          let result = this._validateRecursive(
 | 
						|
            param[item],
 | 
						|
            schema,
 | 
						|
            keyPath.concat(item),
 | 
						|
            state
 | 
						|
          );
 | 
						|
          if (!result.valid) {
 | 
						|
            return result;
 | 
						|
          }
 | 
						|
          parsedObj[item] = result.parsedValue;
 | 
						|
        }
 | 
						|
        return { valid: true, parsedValue: parsedObj };
 | 
						|
      }
 | 
						|
 | 
						|
      case "JSON":
 | 
						|
        if (typeof param == "object") {
 | 
						|
          return { valid: true, parsedValue: param };
 | 
						|
        }
 | 
						|
        try {
 | 
						|
          let json = JSON.parse(param);
 | 
						|
          if (typeof json != "object") {
 | 
						|
            return {
 | 
						|
              valid: false,
 | 
						|
              error: new JsonSchemaValidatorError({
 | 
						|
                message: `JSON was not an object: ${valueToString(param)}`,
 | 
						|
                value: param,
 | 
						|
                keyPath,
 | 
						|
                state,
 | 
						|
              }),
 | 
						|
            };
 | 
						|
          }
 | 
						|
          return { valid: true, parsedValue: json };
 | 
						|
        } catch (e) {
 | 
						|
          lazy.log.error("JSON string couldn't be parsed");
 | 
						|
          return {
 | 
						|
            valid: false,
 | 
						|
            error: new JsonSchemaValidatorError({
 | 
						|
              message: `JSON string could not be parsed: ${valueToString(
 | 
						|
                param
 | 
						|
              )}`,
 | 
						|
              value: param,
 | 
						|
              keyPath,
 | 
						|
              state,
 | 
						|
            }),
 | 
						|
          };
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return {
 | 
						|
      valid: false,
 | 
						|
      error: new JsonSchemaValidatorError({
 | 
						|
        message: `Invalid schema property type: ${valueToString(
 | 
						|
          properties.type
 | 
						|
        )}`,
 | 
						|
        value: param,
 | 
						|
        keyPath,
 | 
						|
        state,
 | 
						|
      }),
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  _validateSimpleParam(param, type, keyPath, state) {
 | 
						|
    let valid = false;
 | 
						|
    let parsedParam = param;
 | 
						|
    let error = undefined;
 | 
						|
 | 
						|
    switch (type) {
 | 
						|
      case "boolean":
 | 
						|
        if (typeof param == "boolean") {
 | 
						|
          valid = true;
 | 
						|
        } else if (typeof param == "number" && (param == 0 || param == 1)) {
 | 
						|
          valid = true;
 | 
						|
          parsedParam = !!param;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case "number":
 | 
						|
      case "string":
 | 
						|
        valid = typeof param == type;
 | 
						|
        break;
 | 
						|
 | 
						|
      // integer is an alias to "number" that some JSON schema tools use
 | 
						|
      case "integer":
 | 
						|
        valid = typeof param == "number";
 | 
						|
        break;
 | 
						|
 | 
						|
      case "null":
 | 
						|
        valid = param === null;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "origin":
 | 
						|
        if (typeof param != "string") {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
          parsedParam = new URL(param);
 | 
						|
 | 
						|
          if (parsedParam.protocol == "file:") {
 | 
						|
            // Treat the entire file URL as an origin.
 | 
						|
            // Note this is stricter than the current Firefox policy,
 | 
						|
            // but consistent with Chrome.
 | 
						|
            // See https://bugzilla.mozilla.org/show_bug.cgi?id=803143
 | 
						|
            valid = true;
 | 
						|
          } else {
 | 
						|
            let pathQueryRef = parsedParam.pathname + parsedParam.hash;
 | 
						|
            // Make sure that "origin" types won't accept full URLs.
 | 
						|
            if (pathQueryRef != "/" && pathQueryRef != "") {
 | 
						|
              lazy.log.error(
 | 
						|
                `Ignoring parameter "${param}" - origin was expected but received full URL.`
 | 
						|
              );
 | 
						|
              valid = false;
 | 
						|
            } else {
 | 
						|
              valid = true;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        } catch (ex) {
 | 
						|
          lazy.log.error(`Ignoring parameter "${param}" - not a valid origin.`);
 | 
						|
          valid = false;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case "URL":
 | 
						|
      case "URLorEmpty":
 | 
						|
        if (typeof param != "string") {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (type == "URLorEmpty" && param === "") {
 | 
						|
          valid = true;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
          parsedParam = new URL(param);
 | 
						|
          valid = true;
 | 
						|
        } catch (ex) {
 | 
						|
          if (!param.startsWith("http")) {
 | 
						|
            lazy.log.error(
 | 
						|
              `Ignoring parameter "${param}" - scheme (http or https) must be specified.`
 | 
						|
            );
 | 
						|
          }
 | 
						|
          valid = false;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!valid && !error) {
 | 
						|
      error = new JsonSchemaValidatorError({
 | 
						|
        message:
 | 
						|
          `The value '${valueToString(param)}' does not match the expected ` +
 | 
						|
          `type '${type}'`,
 | 
						|
        value: param,
 | 
						|
        keyPath,
 | 
						|
        state,
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    let result = {
 | 
						|
      valid,
 | 
						|
      parsedValue: parsedParam,
 | 
						|
    };
 | 
						|
    if (error) {
 | 
						|
      result.error = error;
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
class JsonSchemaValidatorError extends Error {
 | 
						|
  constructor({ message, value, keyPath, state } = {}, ...args) {
 | 
						|
    if (keyPath.length) {
 | 
						|
      message +=
 | 
						|
        ". " +
 | 
						|
        `The invalid value is property '${keyPath.join(".")}' in ` +
 | 
						|
        JSON.stringify(state.rootValue);
 | 
						|
    }
 | 
						|
    super(message, ...args);
 | 
						|
    this.name = "JsonSchemaValidatorError";
 | 
						|
    this.rootValue = state.rootValue;
 | 
						|
    this.rootSchema = state.rootSchema;
 | 
						|
    this.invalidPropertyNameComponents = keyPath;
 | 
						|
    this.invalidValue = value;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function valueToString(value) {
 | 
						|
  try {
 | 
						|
    return JSON.stringify(value);
 | 
						|
  } catch (ex) {}
 | 
						|
  return String(value);
 | 
						|
}
 |