UNPKG

@redocly/openapi-core

Version:

See https://github.com/Redocly/redocly-cli

106 lines 4.07 kB
import Ajv2020 from '@redocly/ajv/dist/2020.js'; import AjvDraft4 from '@redocly/ajv/dist/draft4.js'; import addFormats from 'ajv-formats'; import { escapePointerFragment } from '../ref-utils.js'; const ajvInstances = {}; export function releaseAjvInstance() { ajvInstances['2020'] = undefined; ajvInstances['draft4'] = undefined; } function getSchemaIdKey(dialect) { return dialect === 'draft4' ? 'id' : '$id'; } function getDialectBySpecVersion(specVersion) { if (specVersion === 'oas2' || specVersion === 'oas3_0') return 'draft4'; return '2020'; } function getAjv(resolve, dialect) { if (!ajvInstances[dialect]) { const schemaIdKey = getSchemaIdKey(dialect); const options = { schemaId: schemaIdKey, meta: true, allErrors: true, strictSchema: false, inlineRefs: false, validateSchema: false, discriminator: true, allowUnionTypes: true, validateFormats: true, passContext: true, loadSchemaSync(base, $ref, $id) { const decodedBase = decodeURI(base.split('#')[0]); const resolvedRef = resolve({ $ref }, decodedBase); if (!resolvedRef || !resolvedRef.location) return false; return { [schemaIdKey]: encodeURI(resolvedRef.location.source.absoluteRef) + '#' + $id, ...resolvedRef.node, }; }, logger: false, }; ajvInstances[dialect] = dialect === '2020' ? new Ajv2020(options) : new AjvDraft4(options); addFormats(ajvInstances[dialect]); } return ajvInstances[dialect]; } function getAjvValidator(schema, loc, resolve, allowAdditionalProperties, dialect) { const ajv = getAjv(resolve, dialect); const $id = encodeURI(loc.absolutePointer); const schemaIdKey = getSchemaIdKey(dialect); if (!ajv.getSchema($id)) { ajv.setDefaultUnevaluatedProperties(allowAdditionalProperties); ajv.addSchema({ [schemaIdKey]: $id, ...schema, }, $id); } return ajv.getSchema($id); } export function validateJsonSchema(data, schema, options) { const { schemaLoc, instancePath, resolve, allowAdditionalProperties, ajvContext, specVersion } = options; const dialect = getDialectBySpecVersion(specVersion); const validate = getAjvValidator(schema, schemaLoc, resolve, allowAdditionalProperties, dialect); if (!validate) return { valid: true, errors: [] }; // unresolved refs are reported const dataCxt = { instancePath, parentData: { fake: {} }, parentDataProperty: 'fake', rootData: {}, dynamicAnchors: {}, }; const valid = validate.call(ajvContext ?? {}, data, dataCxt); return { valid: !!valid, errors: (validate.errors || []).map(beatifyErrorMessage), }; function beatifyErrorMessage(error) { let message = error.message; const suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined; if (suggest) { message += ` ${suggest.map((e) => `"${e}"`).join(', ')}`; } if (error.keyword === 'type') { message = `type ${message}`; } const relativePath = error.instancePath.substring(instancePath.length + 1); const propName = relativePath.substring(relativePath.lastIndexOf('/') + 1); if (propName) { message = `\`${propName}\` property ${message}`; } if (error.keyword === 'additionalProperties' || error.keyword === 'unevaluatedProperties') { const property = error.params.additionalProperty || error.params.unevaluatedProperty; message = `${message} \`${property}\``; error.instancePath += '/' + escapePointerFragment(property); } return { ...error, message, suggest, }; } } //# sourceMappingURL=ajv.js.map