215 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
Object.defineProperty(exports, "__esModule", {
 | 
						|
  value: true
 | 
						|
});
 | 
						|
Object.defineProperty(exports, "ValidationError", {
 | 
						|
  enumerable: true,
 | 
						|
  get: function () {
 | 
						|
    return _ValidationError.default;
 | 
						|
  }
 | 
						|
});
 | 
						|
exports.disableValidation = disableValidation;
 | 
						|
exports.enableValidation = enableValidation;
 | 
						|
exports.needValidate = needValidate;
 | 
						|
exports.validate = validate;
 | 
						|
var _ValidationError = _interopRequireDefault(require("./ValidationError"));
 | 
						|
var _memorize = _interopRequireDefault(require("./util/memorize"));
 | 
						|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
 | 
						|
const getAjv = (0, _memorize.default)(() => {
 | 
						|
  // Use CommonJS require for ajv libs so TypeScript consumers aren't locked into esModuleInterop (see #110).
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  const Ajv = require("ajv").default;
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  const ajvKeywords = require("ajv-keywords").default;
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  const addFormats = require("ajv-formats").default;
 | 
						|
 | 
						|
  /**
 | 
						|
   * @type {Ajv}
 | 
						|
   */
 | 
						|
  const ajv = new Ajv({
 | 
						|
    strict: false,
 | 
						|
    allErrors: true,
 | 
						|
    verbose: true,
 | 
						|
    $data: true
 | 
						|
  });
 | 
						|
  ajvKeywords(ajv, ["instanceof", "patternRequired"]);
 | 
						|
  // TODO set `{ keywords: true }` for the next major release and remove `keywords/limit.js`
 | 
						|
  addFormats(ajv, {
 | 
						|
    keywords: false
 | 
						|
  });
 | 
						|
 | 
						|
  // Custom keywords
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  const addAbsolutePathKeyword = require("./keywords/absolutePath").default;
 | 
						|
  addAbsolutePathKeyword(ajv);
 | 
						|
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  const addLimitKeyword = require("./keywords/limit").default;
 | 
						|
  addLimitKeyword(ajv);
 | 
						|
  const addUndefinedAsNullKeyword =
 | 
						|
  // eslint-disable-next-line global-require
 | 
						|
  require("./keywords/undefinedAsNull").default;
 | 
						|
  addUndefinedAsNullKeyword(ajv);
 | 
						|
  return ajv;
 | 
						|
});
 | 
						|
 | 
						|
/** @typedef {import("json-schema").JSONSchema4} JSONSchema4 */
 | 
						|
/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
 | 
						|
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
 | 
						|
/** @typedef {import("ajv").ErrorObject} ErrorObject */
 | 
						|
 | 
						|
/**
 | 
						|
 * @typedef {Object} ExtendedSchema
 | 
						|
 * @property {(string | number)=} formatMinimum
 | 
						|
 * @property {(string | number)=} formatMaximum
 | 
						|
 * @property {(string | boolean)=} formatExclusiveMinimum
 | 
						|
 * @property {(string | boolean)=} formatExclusiveMaximum
 | 
						|
 * @property {string=} link
 | 
						|
 * @property {boolean=} undefinedAsNull
 | 
						|
 */
 | 
						|
 | 
						|
// TODO remove me in the next major release
 | 
						|
/** @typedef {ExtendedSchema} Extend */
 | 
						|
 | 
						|
/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7) & ExtendedSchema} Schema */
 | 
						|
 | 
						|
/** @typedef {ErrorObject & { children?: Array<ErrorObject> }} SchemaUtilErrorObject */
 | 
						|
 | 
						|
/**
 | 
						|
 * @callback PostFormatter
 | 
						|
 * @param {string} formattedError
 | 
						|
 * @param {SchemaUtilErrorObject} error
 | 
						|
 * @returns {string}
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @typedef {Object} ValidationErrorConfiguration
 | 
						|
 * @property {string=} name
 | 
						|
 * @property {string=} baseDataPath
 | 
						|
 * @property {PostFormatter=} postFormatter
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {SchemaUtilErrorObject} error
 | 
						|
 * @param {number} idx
 | 
						|
 * @returns {SchemaUtilErrorObject}
 | 
						|
 */
 | 
						|
function applyPrefix(error, idx) {
 | 
						|
  // eslint-disable-next-line no-param-reassign
 | 
						|
  error.instancePath = `[${idx}]${error.instancePath}`;
 | 
						|
  if (error.children) {
 | 
						|
    error.children.forEach(err => applyPrefix(err, idx));
 | 
						|
  }
 | 
						|
  return error;
 | 
						|
}
 | 
						|
let skipValidation = false;
 | 
						|
 | 
						|
// We use `process.env.SKIP_VALIDATION` because you can have multiple `schema-utils` with different version,
 | 
						|
// so we want to disable it globally, `process.env` doesn't supported by browsers, so we have the local `skipValidation` variables
 | 
						|
 | 
						|
// Enable validation
 | 
						|
function enableValidation() {
 | 
						|
  skipValidation = false;
 | 
						|
 | 
						|
  // Disable validation for any versions
 | 
						|
  if (process && process.env) {
 | 
						|
    process.env.SKIP_VALIDATION = "n";
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Disable validation
 | 
						|
function disableValidation() {
 | 
						|
  skipValidation = true;
 | 
						|
  if (process && process.env) {
 | 
						|
    process.env.SKIP_VALIDATION = "y";
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Check if we need to confirm
 | 
						|
function needValidate() {
 | 
						|
  if (skipValidation) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  if (process && process.env && process.env.SKIP_VALIDATION) {
 | 
						|
    const value = process.env.SKIP_VALIDATION.trim();
 | 
						|
    if (/^(?:y|yes|true|1|on)$/i.test(value)) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
    if (/^(?:n|no|false|0|off)$/i.test(value)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {Schema} schema
 | 
						|
 * @param {Array<object> | object} options
 | 
						|
 * @param {ValidationErrorConfiguration=} configuration
 | 
						|
 * @returns {void}
 | 
						|
 */
 | 
						|
function validate(schema, options, configuration) {
 | 
						|
  if (!needValidate()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  let errors = [];
 | 
						|
  if (Array.isArray(options)) {
 | 
						|
    for (let i = 0; i <= options.length - 1; i++) {
 | 
						|
      errors.push(...validateObject(schema, options[i]).map(err => applyPrefix(err, i)));
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    errors = validateObject(schema, options);
 | 
						|
  }
 | 
						|
  if (errors.length > 0) {
 | 
						|
    throw new _ValidationError.default(errors, schema, configuration);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {Schema} schema
 | 
						|
 * @param {Array<object> | object} options
 | 
						|
 * @returns {Array<SchemaUtilErrorObject>}
 | 
						|
 */
 | 
						|
function validateObject(schema, options) {
 | 
						|
  // Not need to cache, because `ajv@8` has built-in cache
 | 
						|
  const compiledSchema = getAjv().compile(schema);
 | 
						|
  const valid = compiledSchema(options);
 | 
						|
  if (valid) return [];
 | 
						|
  return compiledSchema.errors ? filterErrors(compiledSchema.errors) : [];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {Array<ErrorObject>} errors
 | 
						|
 * @returns {Array<SchemaUtilErrorObject>}
 | 
						|
 */
 | 
						|
function filterErrors(errors) {
 | 
						|
  /** @type {Array<SchemaUtilErrorObject>} */
 | 
						|
  let newErrors = [];
 | 
						|
  for (const error of (/** @type {Array<SchemaUtilErrorObject>} */errors)) {
 | 
						|
    const {
 | 
						|
      instancePath
 | 
						|
    } = error;
 | 
						|
    /** @type {Array<SchemaUtilErrorObject>} */
 | 
						|
    let children = [];
 | 
						|
    newErrors = newErrors.filter(oldError => {
 | 
						|
      if (oldError.instancePath.includes(instancePath)) {
 | 
						|
        if (oldError.children) {
 | 
						|
          children = children.concat(oldError.children.slice(0));
 | 
						|
        }
 | 
						|
 | 
						|
        // eslint-disable-next-line no-undefined, no-param-reassign
 | 
						|
        oldError.children = undefined;
 | 
						|
        children.push(oldError);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      return true;
 | 
						|
    });
 | 
						|
    if (children.length) {
 | 
						|
      error.children = children;
 | 
						|
    }
 | 
						|
    newErrors.push(error);
 | 
						|
  }
 | 
						|
  return newErrors;
 | 
						|
} |