UNPKG

eslint-plugin-json-schema-validator

Version:
210 lines (209 loc) 7.05 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.compile = void 0; const url_1 = require("url"); const ajv_1 = __importDefault(require("./ajv")); const limit_number_1 = require("./ajv-custom/limit-number"); const schema_1 = require("./schema"); const ajv = new ajv_1.default({ allErrors: true, verbose: true, validateSchema: false, logger: false, strict: false, }); ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json")); ajv.removeKeyword("id"); limit_number_1.applyLimitNumberKeywords(ajv); function unescapeFragment(str) { return unescapeJsonPointer(decodeURIComponent(str)); } function unescapeJsonPointer(str) { return str.replace(/~1/g, "/").replace(/~0/g, "~"); } function compile(schema, schemaPath, context) { return schemaToValidator(schema, schemaPath, context); } exports.compile = compile; function schemaToValidator(schema, schemaPath, context) { let validateSchema; while (true) { try { validateSchema = ajv.compile(schema); } catch (e) { if (resolveError(e, schemaPath, schema, context)) { continue; } throw e; } break; } return (data) => { if (validateSchema(data)) { return []; } return validateSchema.errors.map(errorToValidateError); }; } function resolveError(error, baseSchemaPath, baseSchema, context) { if (error.missingRef) { let schemaPath = ""; let schemaId = ""; if (error.missingRef.startsWith("http://") || error.missingRef.startsWith("https://")) { const uri = new url_1.URL(error.missingRef); uri.hash = ""; schemaPath = uri.toString(); schemaId = schemaPath; } else { const ref = error.missingRef; const baseUri = new url_1.URL(baseSchema.$id || baseSchemaPath); baseUri.hash = ""; const slashIndex = baseUri.pathname.lastIndexOf("/"); if (slashIndex >= 0) { baseUri.pathname = baseUri.pathname.slice(0, slashIndex + 1); } const uri = new url_1.URL(`${baseUri.toString()}${ref}`); uri.hash = ""; schemaPath = uri.toString(); schemaId = ref.split("#")[0]; } if (schemaPath) { const refSchema = schema_1.loadSchema(schemaPath, context); if (refSchema) { while (true) { try { ajv.addSchema(refSchema, schemaId); } catch (e) { if (resolveError(e, schemaPath, refSchema, context)) { continue; } throw e; } break; } return true; } } } return false; } function errorToValidateError(errorObject) { const error = errorObject; const dataPath = error.dataPath.startsWith("/") ? error.dataPath.slice(1) : error.dataPath; const path = dataPath ? dataPath.split("/").map(unescapeFragment) : []; if (error.keyword === "additionalProperties") { path.push(error.params.additionalProperty); return { message: `Unexpected property ${joinPath(path)}`, path, }; } if (error.keyword === "propertyNames") { return { message: `${joinPath(path)} property name ${JSON.stringify(error.params.propertyName)} is invalid.`, path: [...path, error.params.propertyName], }; } if (error.keyword === "uniqueItems") { const baseMessage = `should NOT have duplicate items (items ## ${error.params.j} and ${error.params.i} are identical)`; return { message: `${joinPath(path)} ${baseMessage}.`, path: [...path, String(error.params.i)], }; } let baseMessage; if (error.keyword === "enum") { baseMessage = `should be equal to ${joinEnums(error.params.allowedValues)}`; } else if (error.keyword === "const") { baseMessage = `should be equal to ${JSON.stringify(error.params.allowedValue)}`; } else if (error.keyword === "not") { const schema = error.schema; const schemaKeys = Object.keys(schema); if (schemaKeys.length === 1 && schemaKeys[0] === "type") { baseMessage = `should NOT be ${schema.type}`; } else if (schemaKeys.length === 1 && schemaKeys[0] === "enum") { baseMessage = `should NOT be equal to ${joinEnums(schema.enum)}`; } else { baseMessage = `should NOT be valid of define schema`; } } else if (error.keyword === "type" || error.keyword === "oneOf" || error.keyword === "anyOf" || error.keyword === "minItems" || error.keyword === "maxItems" || error.keyword === "additionalItems" || error.keyword === "contains" || error.keyword === "required" || error.keyword === "maxProperties" || error.keyword === "minProperties" || error.keyword === "dependencies" || error.keyword === "pattern" || error.keyword === "maxLength" || error.keyword === "minLength" || error.keyword === "format" || error.keyword === "maximum" || error.keyword === "minimum" || error.keyword === "exclusiveMaximum" || error.keyword === "exclusiveMinimum" || error.keyword === "multipleOf" || error.keyword === "if") { baseMessage = error.message; } else { baseMessage = error.message; } if (error.propertyName) { return { message: `${joinPath(path)} property name ${JSON.stringify(error.propertyName)} ${baseMessage}.`, path: [...path, error.propertyName], }; } return { message: `${joinPath(path)} ${baseMessage}.`, path, }; function joinEnums(enums) { const list = enums.map((v) => JSON.stringify(v)); const last = list.pop(); if (list.length) { return `${list.join(", ")} or ${last}`; } return last; } function joinPath(paths) { if (!paths.length) { return "Root"; } let result = ""; for (const p of paths) { if (/^[a-z_$][\w$]*$/iu.test(p)) { if (result) { result += `.${p}`; } else { result = p; } } else { result += `[${/^\d+$/iu.test(p) ? p : JSON.stringify(p)}]`; } } return `"${result}"`; } }