diff options
Diffstat (limited to 'node_modules/schema-utils/dist/ValidationError.js')
| -rw-r--r-- | node_modules/schema-utils/dist/ValidationError.js | 1277 |
1 files changed, 1277 insertions, 0 deletions
diff --git a/node_modules/schema-utils/dist/ValidationError.js b/node_modules/schema-utils/dist/ValidationError.js new file mode 100644 index 00000000..bd4086fc --- /dev/null +++ b/node_modules/schema-utils/dist/ValidationError.js @@ -0,0 +1,1277 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +const { + stringHints, + numberHints +} = require("./util/hints"); +/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */ + +/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */ + +/** @typedef {import("./validate").Schema} Schema */ + +/** @typedef {import("./validate").ValidationErrorConfiguration} ValidationErrorConfiguration */ + +/** @typedef {import("./validate").PostFormatter} PostFormatter */ + +/** @typedef {import("./validate").SchemaUtilErrorObject} SchemaUtilErrorObject */ + +/** @enum {number} */ + + +const SPECIFICITY = { + type: 1, + not: 1, + oneOf: 1, + anyOf: 1, + if: 1, + enum: 1, + const: 1, + instanceof: 1, + required: 2, + pattern: 2, + patternRequired: 2, + format: 2, + formatMinimum: 2, + formatMaximum: 2, + minimum: 2, + exclusiveMinimum: 2, + maximum: 2, + exclusiveMaximum: 2, + multipleOf: 2, + uniqueItems: 2, + contains: 2, + minLength: 2, + maxLength: 2, + minItems: 2, + maxItems: 2, + minProperties: 2, + maxProperties: 2, + dependencies: 2, + propertyNames: 2, + additionalItems: 2, + additionalProperties: 2, + absolutePath: 2 +}; +/** + * + * @param {Array<SchemaUtilErrorObject>} array + * @param {(item: SchemaUtilErrorObject) => number} fn + * @returns {Array<SchemaUtilErrorObject>} + */ + +function filterMax(array, fn) { + const evaluatedMax = array.reduce((max, item) => Math.max(max, fn(item)), 0); + return array.filter(item => fn(item) === evaluatedMax); +} +/** + * + * @param {Array<SchemaUtilErrorObject>} children + * @returns {Array<SchemaUtilErrorObject>} + */ + + +function filterChildren(children) { + let newChildren = children; + newChildren = filterMax(newChildren, + /** + * + * @param {SchemaUtilErrorObject} error + * @returns {number} + */ + error => error.dataPath ? error.dataPath.length : 0); + newChildren = filterMax(newChildren, + /** + * @param {SchemaUtilErrorObject} error + * @returns {number} + */ + error => SPECIFICITY[ + /** @type {keyof typeof SPECIFICITY} */ + error.keyword] || 2); + return newChildren; +} +/** + * Find all children errors + * @param {Array<SchemaUtilErrorObject>} children + * @param {Array<string>} schemaPaths + * @return {number} returns index of first child + */ + + +function findAllChildren(children, schemaPaths) { + let i = children.length - 1; + + const predicate = + /** + * @param {string} schemaPath + * @returns {boolean} + */ + schemaPath => children[i].schemaPath.indexOf(schemaPath) !== 0; + + while (i > -1 && !schemaPaths.every(predicate)) { + if (children[i].keyword === "anyOf" || children[i].keyword === "oneOf") { + const refs = extractRefs(children[i]); + const childrenStart = findAllChildren(children.slice(0, i), refs.concat(children[i].schemaPath)); + i = childrenStart - 1; + } else { + i -= 1; + } + } + + return i + 1; +} +/** + * Extracts all refs from schema + * @param {SchemaUtilErrorObject} error + * @return {Array<string>} + */ + + +function extractRefs(error) { + const { + schema + } = error; + + if (!Array.isArray(schema)) { + return []; + } + + return schema.map(({ + $ref + }) => $ref).filter(s => s); +} +/** + * Groups children by their first level parent (assuming that error is root) + * @param {Array<SchemaUtilErrorObject>} children + * @return {Array<SchemaUtilErrorObject>} + */ + + +function groupChildrenByFirstChild(children) { + const result = []; + let i = children.length - 1; + + while (i > 0) { + const child = children[i]; + + if (child.keyword === "anyOf" || child.keyword === "oneOf") { + const refs = extractRefs(child); + const childrenStart = findAllChildren(children.slice(0, i), refs.concat(child.schemaPath)); + + if (childrenStart !== i) { + result.push(Object.assign({}, child, { + children: children.slice(childrenStart, i) + })); + i = childrenStart; + } else { + result.push(child); + } + } else { + result.push(child); + } + + i -= 1; + } + + if (i === 0) { + result.push(children[i]); + } + + return result.reverse(); +} +/** + * @param {string} str + * @param {string} prefix + * @returns {string} + */ + + +function indent(str, prefix) { + return str.replace(/\n(?!$)/g, `\n${prefix}`); +} +/** + * @param {Schema} schema + * @returns {schema is (Schema & {not: Schema})} + */ + + +function hasNotInSchema(schema) { + return !!schema.not; +} +/** + * @param {Schema} schema + * @return {Schema} + */ + + +function findFirstTypedSchema(schema) { + if (hasNotInSchema(schema)) { + return findFirstTypedSchema(schema.not); + } + + return schema; +} +/** + * @param {Schema} schema + * @return {boolean} + */ + + +function canApplyNot(schema) { + const typedSchema = findFirstTypedSchema(schema); + return likeNumber(typedSchema) || likeInteger(typedSchema) || likeString(typedSchema) || likeNull(typedSchema) || likeBoolean(typedSchema); +} +/** + * @param {any} maybeObj + * @returns {boolean} + */ + + +function isObject(maybeObj) { + return typeof maybeObj === "object" && maybeObj !== null; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeNumber(schema) { + return schema.type === "number" || typeof schema.minimum !== "undefined" || typeof schema.exclusiveMinimum !== "undefined" || typeof schema.maximum !== "undefined" || typeof schema.exclusiveMaximum !== "undefined" || typeof schema.multipleOf !== "undefined"; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeInteger(schema) { + return schema.type === "integer" || typeof schema.minimum !== "undefined" || typeof schema.exclusiveMinimum !== "undefined" || typeof schema.maximum !== "undefined" || typeof schema.exclusiveMaximum !== "undefined" || typeof schema.multipleOf !== "undefined"; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeString(schema) { + return schema.type === "string" || typeof schema.minLength !== "undefined" || typeof schema.maxLength !== "undefined" || typeof schema.pattern !== "undefined" || typeof schema.format !== "undefined" || typeof schema.formatMinimum !== "undefined" || typeof schema.formatMaximum !== "undefined"; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeBoolean(schema) { + return schema.type === "boolean"; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeArray(schema) { + return schema.type === "array" || typeof schema.minItems === "number" || typeof schema.maxItems === "number" || typeof schema.uniqueItems !== "undefined" || typeof schema.items !== "undefined" || typeof schema.additionalItems !== "undefined" || typeof schema.contains !== "undefined"; +} +/** + * @param {Schema & {patternRequired?: Array<string>}} schema + * @returns {boolean} + */ + + +function likeObject(schema) { + return schema.type === "object" || typeof schema.minProperties !== "undefined" || typeof schema.maxProperties !== "undefined" || typeof schema.required !== "undefined" || typeof schema.properties !== "undefined" || typeof schema.patternProperties !== "undefined" || typeof schema.additionalProperties !== "undefined" || typeof schema.dependencies !== "undefined" || typeof schema.propertyNames !== "undefined" || typeof schema.patternRequired !== "undefined"; +} +/** + * @param {Schema} schema + * @returns {boolean} + */ + + +function likeNull(schema) { + return schema.type === "null"; +} +/** + * @param {string} type + * @returns {string} + */ + + +function getArticle(type) { + if (/^[aeiou]/i.test(type)) { + return "an"; + } + + return "a"; +} +/** + * @param {Schema=} schema + * @returns {string} + */ + + +function getSchemaNonTypes(schema) { + if (!schema) { + return ""; + } + + if (!schema.type) { + if (likeNumber(schema) || likeInteger(schema)) { + return " | should be any non-number"; + } + + if (likeString(schema)) { + return " | should be any non-string"; + } + + if (likeArray(schema)) { + return " | should be any non-array"; + } + + if (likeObject(schema)) { + return " | should be any non-object"; + } + } + + return ""; +} +/** + * @param {Array<string>} hints + * @returns {string} + */ + + +function formatHints(hints) { + return hints.length > 0 ? `(${hints.join(", ")})` : ""; +} +/** + * @param {Schema} schema + * @param {boolean} logic + * @returns {string[]} + */ + + +function getHints(schema, logic) { + if (likeNumber(schema) || likeInteger(schema)) { + return numberHints(schema, logic); + } else if (likeString(schema)) { + return stringHints(schema, logic); + } + + return []; +} + +class ValidationError extends Error { + /** + * @param {Array<SchemaUtilErrorObject>} errors + * @param {Schema} schema + * @param {ValidationErrorConfiguration} configuration + */ + constructor(errors, schema, configuration = {}) { + super(); + /** @type {string} */ + + this.name = "ValidationError"; + /** @type {Array<SchemaUtilErrorObject>} */ + + this.errors = errors; + /** @type {Schema} */ + + this.schema = schema; + let headerNameFromSchema; + let baseDataPathFromSchema; + + if (schema.title && (!configuration.name || !configuration.baseDataPath)) { + const splittedTitleFromSchema = schema.title.match(/^(.+) (.+)$/); + + if (splittedTitleFromSchema) { + if (!configuration.name) { + [, headerNameFromSchema] = splittedTitleFromSchema; + } + + if (!configuration.baseDataPath) { + [,, baseDataPathFromSchema] = splittedTitleFromSchema; + } + } + } + /** @type {string} */ + + + this.headerName = configuration.name || headerNameFromSchema || "Object"; + /** @type {string} */ + + this.baseDataPath = configuration.baseDataPath || baseDataPathFromSchema || "configuration"; + /** @type {PostFormatter | null} */ + + this.postFormatter = configuration.postFormatter || null; + const header = `Invalid ${this.baseDataPath} object. ${this.headerName} has been initialized using ${getArticle(this.baseDataPath)} ${this.baseDataPath} object that does not match the API schema.\n`; + /** @type {string} */ + + this.message = `${header}${this.formatValidationErrors(errors)}`; + Error.captureStackTrace(this, this.constructor); + } + /** + * @param {string} path + * @returns {Schema} + */ + + + getSchemaPart(path) { + const newPath = path.split("/"); + let schemaPart = this.schema; + + for (let i = 1; i < newPath.length; i++) { + const inner = schemaPart[ + /** @type {keyof Schema} */ + newPath[i]]; + + if (!inner) { + break; + } + + schemaPart = inner; + } + + return schemaPart; + } + /** + * @param {Schema} schema + * @param {boolean} logic + * @param {Array<Object>} prevSchemas + * @returns {string} + */ + + + formatSchema(schema, logic = true, prevSchemas = []) { + let newLogic = logic; + + const formatInnerSchema = + /** + * + * @param {Object} innerSchema + * @param {boolean=} addSelf + * @returns {string} + */ + (innerSchema, addSelf) => { + if (!addSelf) { + return this.formatSchema(innerSchema, newLogic, prevSchemas); + } + + if (prevSchemas.includes(innerSchema)) { + return "(recursive)"; + } + + return this.formatSchema(innerSchema, newLogic, prevSchemas.concat(schema)); + }; + + if (hasNotInSchema(schema) && !likeObject(schema)) { + if (canApplyNot(schema.not)) { + newLogic = !logic; + return formatInnerSchema(schema.not); + } + + const needApplyLogicHere = !schema.not.not; + const prefix = logic ? "" : "non "; + newLogic = !logic; + return needApplyLogicHere ? prefix + formatInnerSchema(schema.not) : formatInnerSchema(schema.not); + } + + if ( + /** @type {Schema & {instanceof: string | Array<string>}} */ + schema.instanceof) { + const { + instanceof: value + } = + /** @type {Schema & {instanceof: string | Array<string>}} */ + schema; + const values = !Array.isArray(value) ? [value] : value; + return values.map( + /** + * @param {string} item + * @returns {string} + */ + item => item === "Function" ? "function" : item).join(" | "); + } + + if (schema.enum) { + const enumValues = + /** @type {Array<any>} */ + schema.enum.map(item => { + if (item === null && schema.undefinedAsNull) { + return `${JSON.stringify(item)} | undefined`; + } + + return JSON.stringify(item); + }).join(" | "); + return `${enumValues}`; + } + + if (typeof schema.const !== "undefined") { + return JSON.stringify(schema.const); + } + + if (schema.oneOf) { + return ( + /** @type {Array<Schema>} */ + schema.oneOf.map(item => formatInnerSchema(item, true)).join(" | ") + ); + } + + if (schema.anyOf) { + return ( + /** @type {Array<Schema>} */ + schema.anyOf.map(item => formatInnerSchema(item, true)).join(" | ") + ); + } + + if (schema.allOf) { + return ( + /** @type {Array<Schema>} */ + schema.allOf.map(item => formatInnerSchema(item, true)).join(" & ") + ); + } + + if ( + /** @type {JSONSchema7} */ + schema.if) { + const { + if: ifValue, + then: thenValue, + else: elseValue + } = + /** @type {JSONSchema7} */ + schema; + return `${ifValue ? `if ${formatInnerSchema(ifValue)}` : ""}${thenValue ? ` then ${formatInnerSchema(thenValue)}` : ""}${elseValue ? ` else ${formatInnerSchema(elseValue)}` : ""}`; + } + + if (schema.$ref) { + return formatInnerSchema(this.getSchemaPart(schema.$ref), true); + } + + if (likeNumber(schema) || likeInteger(schema)) { + const [type, ...hints] = getHints(schema, logic); + const str = `${type}${hints.length > 0 ? ` ${formatHints(hints)}` : ""}`; + return logic ? str : hints.length > 0 ? `non-${type} | ${str}` : `non-${type}`; + } + + if (likeString(schema)) { + const [type, ...hints] = getHints(schema, logic); + const str = `${type}${hints.length > 0 ? ` ${formatHints(hints)}` : ""}`; + return logic ? str : str === "string" ? "non-string" : `non-string | ${str}`; + } + + if (likeBoolean(schema)) { + return `${logic ? "" : "non-"}boolean`; + } + + if (likeArray(schema)) { + // not logic already applied in formatValidationError + newLogic = true; + const hints = []; + + if (typeof schema.minItems === "number") { + hints.push(`should not have fewer than ${schema.minItems} item${schema.minItems > 1 ? "s" : ""}`); + } + + if (typeof schema.maxItems === "number") { + hints.push(`should not have more than ${schema.maxItems} item${schema.maxItems > 1 ? "s" : ""}`); + } + + if (schema.uniqueItems) { + hints.push("should not have duplicate items"); + } + + const hasAdditionalItems = typeof schema.additionalItems === "undefined" || Boolean(schema.additionalItems); + let items = ""; + + if (schema.items) { + if (Array.isArray(schema.items) && schema.items.length > 0) { + items = `${ + /** @type {Array<Schema>} */ + schema.items.map(item => formatInnerSchema(item)).join(", ")}`; + + if (hasAdditionalItems) { + if (schema.additionalItems && isObject(schema.additionalItems) && Object.keys(schema.additionalItems).length > 0) { + hints.push(`additional items should be ${formatInnerSchema(schema.additionalItems)}`); + } + } + } else if (schema.items && Object.keys(schema.items).length > 0) { + // "additionalItems" is ignored + items = `${formatInnerSchema(schema.items)}`; + } else { + // Fallback for empty `items` value + items = "any"; + } + } else { + // "additionalItems" is ignored + items = "any"; + } + + if (schema.contains && Object.keys(schema.contains).length > 0) { + hints.push(`should contains at least one ${this.formatSchema(schema.contains)} item`); + } + + return `[${items}${hasAdditionalItems ? ", ..." : ""}]${hints.length > 0 ? ` (${hints.join(", ")})` : ""}`; + } + + if (likeObject(schema)) { + // not logic already applied in formatValidationError + newLogic = true; + const hints = []; + + if (typeof schema.minProperties === "number") { + hints.push(`should not have fewer than ${schema.minProperties} ${schema.minProperties > 1 ? "properties" : "property"}`); + } + + if (typeof schema.maxProperties === "number") { + hints.push(`should not have more than ${schema.maxProperties} ${schema.minProperties && schema.minProperties > 1 ? "properties" : "property"}`); + } + + if (schema.patternProperties && Object.keys(schema.patternProperties).length > 0) { + const patternProperties = Object.keys(schema.patternProperties); + hints.push(`additional property names should match pattern${patternProperties.length > 1 ? "s" : ""} ${patternProperties.map(pattern => JSON.stringify(pattern)).join(" | ")}`); + } + + const properties = schema.properties ? Object.keys(schema.properties) : []; + const required = schema.required ? schema.required : []; + const allProperties = [...new Set( + /** @type {Array<string>} */ + [].concat(required).concat(properties))]; + const objectStructure = allProperties.map(property => { + const isRequired = required.includes(property); // Some properties need quotes, maybe we should add check + // Maybe we should output type of property (`foo: string`), but it is looks very unreadable + + return `${property}${isRequired ? "" : "?"}`; + }).concat(typeof schema.additionalProperties === "undefined" || Boolean(schema.additionalProperties) ? schema.additionalProperties && isObject(schema.additionalProperties) ? [`<key>: ${formatInnerSchema(schema.additionalProperties)}`] : ["…"] : []).join(", "); + const { + dependencies, + propertyNames, + patternRequired + } = + /** @type {Schema & {patternRequired?: Array<string>;}} */ + schema; + + if (dependencies) { + Object.keys(dependencies).forEach(dependencyName => { + const dependency = dependencies[dependencyName]; + + if (Array.isArray(dependency)) { + hints.push(`should have ${dependency.length > 1 ? "properties" : "property"} ${dependency.map(dep => `'${dep}'`).join(", ")} when property '${dependencyName}' is present`); + } else { + hints.push(`should be valid according to the schema ${formatInnerSchema(dependency)} when property '${dependencyName}' is present`); + } + }); + } + + if (propertyNames && Object.keys(propertyNames).length > 0) { + hints.push(`each property name should match format ${JSON.stringify(schema.propertyNames.format)}`); + } + + if (patternRequired && patternRequired.length > 0) { + hints.push(`should have property matching pattern ${patternRequired.map( + /** + * @param {string} item + * @returns {string} + */ + item => JSON.stringify(item))}`); + } + + return `object {${objectStructure ? ` ${objectStructure} ` : ""}}${hints.length > 0 ? ` (${hints.join(", ")})` : ""}`; + } + + if (likeNull(schema)) { + return `${logic ? "" : "non-"}null`; + } + + if (Array.isArray(schema.type)) { + // not logic already applied in formatValidationError + return `${schema.type.join(" | ")}`; + } // Fallback for unknown keywords + // not logic already applied in formatValidationError + + /* istanbul ignore next */ + + + return JSON.stringify(schema, null, 2); + } + /** + * @param {Schema=} schemaPart + * @param {(boolean | Array<string>)=} additionalPath + * @param {boolean=} needDot + * @param {boolean=} logic + * @returns {string} + */ + + + getSchemaPartText(schemaPart, additionalPath, needDot = false, logic = true) { + if (!schemaPart) { + return ""; + } + + if (Array.isArray(additionalPath)) { + for (let i = 0; i < additionalPath.length; i++) { + /** @type {Schema | undefined} */ + const inner = schemaPart[ + /** @type {keyof Schema} */ + additionalPath[i]]; + + if (inner) { + // eslint-disable-next-line no-param-reassign + schemaPart = inner; + } else { + break; + } + } + } + + while (schemaPart.$ref) { + // eslint-disable-next-line no-param-reassign + schemaPart = this.getSchemaPart(schemaPart.$ref); + } + + let schemaText = `${this.formatSchema(schemaPart, logic)}${needDot ? "." : ""}`; + + if (schemaPart.description) { + schemaText += `\n-> ${schemaPart.description}`; + } + + if (schemaPart.link) { + schemaText += `\n-> Read more at ${schemaPart.link}`; + } + + return schemaText; + } + /** + * @param {Schema=} schemaPart + * @returns {string} + */ + + + getSchemaPartDescription(schemaPart) { + if (!schemaPart) { + return ""; + } + + while (schemaPart.$ref) { + // eslint-disable-next-line no-param-reassign + schemaPart = this.getSchemaPart(schemaPart.$ref); + } + + let schemaText = ""; + + if (schemaPart.description) { + schemaText += `\n-> ${schemaPart.description}`; + } + + if (schemaPart.link) { + schemaText += `\n-> Read more at ${schemaPart.link}`; + } + + return schemaText; + } + /** + * @param {SchemaUtilErrorObject} error + * @returns {string} + */ + + + formatValidationError(error) { + const { + keyword, + dataPath: errorDataPath + } = error; + const dataPath = `${this.baseDataPath}${errorDataPath}`; + + switch (keyword) { + case "type": + { + const { + parentSchema, + params + } = error; // eslint-disable-next-line default-case + + switch ( + /** @type {import("ajv").TypeParams} */ + params.type) { + case "number": + return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`; + + case "integer": + return `${dataPath} should be an ${this.getSchemaPartText(parentSchema, false, true)}`; + + case "string": + return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`; + + case "boolean": + return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`; + + case "array": + return `${dataPath} should be an array:\n${this.getSchemaPartText(parentSchema)}`; + + case "object": + return `${dataPath} should be an object:\n${this.getSchemaPartText(parentSchema)}`; + + case "null": + return `${dataPath} should be a ${this.getSchemaPartText(parentSchema, false, true)}`; + + default: + return `${dataPath} should be:\n${this.getSchemaPartText(parentSchema)}`; + } + } + + case "instanceof": + { + const { + parentSchema + } = error; + return `${dataPath} should be an instance of ${this.getSchemaPartText(parentSchema, false, true)}`; + } + + case "pattern": + { + const { + params, + parentSchema + } = error; + const { + pattern + } = + /** @type {import("ajv").PatternParams} */ + params; + return `${dataPath} should match pattern ${JSON.stringify(pattern)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "format": + { + const { + params, + parentSchema + } = error; + const { + format + } = + /** @type {import("ajv").FormatParams} */ + params; + return `${dataPath} should match format ${JSON.stringify(format)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "formatMinimum": + case "formatMaximum": + { + const { + params, + parentSchema + } = error; + const { + comparison, + limit + } = + /** @type {import("ajv").ComparisonParams} */ + params; + return `${dataPath} should be ${comparison} ${JSON.stringify(limit)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "minimum": + case "maximum": + case "exclusiveMinimum": + case "exclusiveMaximum": + { + const { + parentSchema, + params + } = error; + const { + comparison, + limit + } = + /** @type {import("ajv").ComparisonParams} */ + params; + const [, ...hints] = getHints( + /** @type {Schema} */ + parentSchema, true); + + if (hints.length === 0) { + hints.push(`should be ${comparison} ${limit}`); + } + + return `${dataPath} ${hints.join(" ")}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "multipleOf": + { + const { + params, + parentSchema + } = error; + const { + multipleOf + } = + /** @type {import("ajv").MultipleOfParams} */ + params; + return `${dataPath} should be multiple of ${multipleOf}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "patternRequired": + { + const { + params, + parentSchema + } = error; + const { + missingPattern + } = + /** @type {import("ajv").PatternRequiredParams} */ + params; + return `${dataPath} should have property matching pattern ${JSON.stringify(missingPattern)}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "minLength": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + + if (limit === 1) { + return `${dataPath} should be a non-empty string${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + const length = limit - 1; + return `${dataPath} should be longer than ${length} character${length > 1 ? "s" : ""}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "minItems": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + + if (limit === 1) { + return `${dataPath} should be a non-empty array${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + return `${dataPath} should not have fewer than ${limit} items${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "minProperties": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + + if (limit === 1) { + return `${dataPath} should be a non-empty object${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + return `${dataPath} should not have fewer than ${limit} properties${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "maxLength": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + const max = limit + 1; + return `${dataPath} should be shorter than ${max} character${max > 1 ? "s" : ""}${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "maxItems": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + return `${dataPath} should not have more than ${limit} items${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "maxProperties": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + return `${dataPath} should not have more than ${limit} properties${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "uniqueItems": + { + const { + params, + parentSchema + } = error; + const { + i + } = + /** @type {import("ajv").UniqueItemsParams} */ + params; + return `${dataPath} should not contain the item '${error.data[i]}' twice${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "additionalItems": + { + const { + params, + parentSchema + } = error; + const { + limit + } = + /** @type {import("ajv").LimitParams} */ + params; + return `${dataPath} should not have more than ${limit} items${getSchemaNonTypes(parentSchema)}. These items are valid:\n${this.getSchemaPartText(parentSchema)}`; + } + + case "contains": + { + const { + parentSchema + } = error; + return `${dataPath} should contains at least one ${this.getSchemaPartText(parentSchema, ["contains"])} item${getSchemaNonTypes(parentSchema)}.`; + } + + case "required": + { + const { + parentSchema, + params + } = error; + const missingProperty = + /** @type {import("ajv").DependenciesParams} */ + params.missingProperty.replace(/^\./, ""); + const hasProperty = parentSchema && Boolean( + /** @type {Schema} */ + parentSchema.properties && + /** @type {Schema} */ + parentSchema.properties[missingProperty]); + return `${dataPath} misses the property '${missingProperty}'${getSchemaNonTypes(parentSchema)}.${hasProperty ? ` Should be:\n${this.getSchemaPartText(parentSchema, ["properties", missingProperty])}` : this.getSchemaPartDescription(parentSchema)}`; + } + + case "additionalProperties": + { + const { + params, + parentSchema + } = error; + const { + additionalProperty + } = + /** @type {import("ajv").AdditionalPropertiesParams} */ + params; + return `${dataPath} has an unknown property '${additionalProperty}'${getSchemaNonTypes(parentSchema)}. These properties are valid:\n${this.getSchemaPartText(parentSchema)}`; + } + + case "dependencies": + { + const { + params, + parentSchema + } = error; + const { + property, + deps + } = + /** @type {import("ajv").DependenciesParams} */ + params; + const dependencies = deps.split(",").map( + /** + * @param {string} dep + * @returns {string} + */ + dep => `'${dep.trim()}'`).join(", "); + return `${dataPath} should have properties ${dependencies} when property '${property}' is present${getSchemaNonTypes(parentSchema)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "propertyNames": + { + const { + params, + parentSchema, + schema + } = error; + const { + propertyName + } = + /** @type {import("ajv").PropertyNamesParams} */ + params; + return `${dataPath} property name '${propertyName}' is invalid${getSchemaNonTypes(parentSchema)}. Property names should be match format ${JSON.stringify(schema.format)}.${this.getSchemaPartDescription(parentSchema)}`; + } + + case "enum": + { + const { + parentSchema + } = error; + + if (parentSchema && + /** @type {Schema} */ + parentSchema.enum && + /** @type {Schema} */ + parentSchema.enum.length === 1) { + return `${dataPath} should be ${this.getSchemaPartText(parentSchema, false, true)}`; + } + + return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}`; + } + + case "const": + { + const { + parentSchema + } = error; + return `${dataPath} should be equal to constant ${this.getSchemaPartText(parentSchema, false, true)}`; + } + + case "not": + { + const postfix = likeObject( + /** @type {Schema} */ + error.parentSchema) ? `\n${this.getSchemaPartText(error.parentSchema)}` : ""; + const schemaOutput = this.getSchemaPartText(error.schema, false, false, false); + + if (canApplyNot(error.schema)) { + return `${dataPath} should be any ${schemaOutput}${postfix}.`; + } + + const { + schema, + parentSchema + } = error; + return `${dataPath} should not be ${this.getSchemaPartText(schema, false, true)}${parentSchema && likeObject(parentSchema) ? `\n${this.getSchemaPartText(parentSchema)}` : ""}`; + } + + case "oneOf": + case "anyOf": + { + const { + parentSchema, + children + } = error; + + if (children && children.length > 0) { + if (error.schema.length === 1) { + const lastChild = children[children.length - 1]; + const remainingChildren = children.slice(0, children.length - 1); + return this.formatValidationError(Object.assign({}, lastChild, { + children: remainingChildren, + parentSchema: Object.assign({}, parentSchema, lastChild.parentSchema) + })); + } + + let filteredChildren = filterChildren(children); + + if (filteredChildren.length === 1) { + return this.formatValidationError(filteredChildren[0]); + } + + filteredChildren = groupChildrenByFirstChild(filteredChildren); + return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}\nDetails:\n${filteredChildren.map( + /** + * @param {SchemaUtilErrorObject} nestedError + * @returns {string} + */ + nestedError => ` * ${indent(this.formatValidationError(nestedError), " ")}`).join("\n")}`; + } + + return `${dataPath} should be one of these:\n${this.getSchemaPartText(parentSchema)}`; + } + + case "if": + { + const { + params, + parentSchema + } = error; + const { + failingKeyword + } = + /** @type {import("ajv").IfParams} */ + params; + return `${dataPath} should match "${failingKeyword}" schema:\n${this.getSchemaPartText(parentSchema, [failingKeyword])}`; + } + + case "absolutePath": + { + const { + message, + parentSchema + } = error; + return `${dataPath}: ${message}${this.getSchemaPartDescription(parentSchema)}`; + } + + /* istanbul ignore next */ + + default: + { + const { + message, + parentSchema + } = error; + const ErrorInJSON = JSON.stringify(error, null, 2); // For `custom`, `false schema`, `$ref` keywords + // Fallback for unknown keywords + + return `${dataPath} ${message} (${ErrorInJSON}).\n${this.getSchemaPartText(parentSchema, false)}`; + } + } + } + /** + * @param {Array<SchemaUtilErrorObject>} errors + * @returns {string} + */ + + + formatValidationErrors(errors) { + return errors.map(error => { + let formattedError = this.formatValidationError(error); + + if (this.postFormatter) { + formattedError = this.postFormatter(formattedError, error); + } + + return ` - ${indent(formattedError, " ")}`; + }).join("\n"); + } + +} + +var _default = ValidationError; +exports.default = _default;
\ No newline at end of file |
