UNPKG

@redocly/ajv

Version:

Another JSON Schema Validator

136 lines 6.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const codegen_1 = require("../../compile/codegen"); const types_1 = require("../discriminator/types"); const compile_1 = require("../../compile"); const util_1 = require("../../compile/util"); const error = { message: ({ params: { discrError, tagName } }) => discrError === types_1.DiscrError.Tag ? `tag "${tagName}" must be string` : `value of tag "${tagName}" must be in oneOf or anyOf`, params: ({ params: { discrError, tag, tagName } }) => (0, codegen_1._) `{error: ${discrError}, tag: ${tagName}, tagValue: ${tag}}`, }; function getDiscriminatorPropertyFromAllOf(sch, tagName) { var _a; if (!sch.allOf || !Array.isArray(sch.allOf)) { return undefined; } for (const subschema of sch.allOf) { if ((_a = subschema === null || subschema === void 0 ? void 0 : subschema.properties) === null || _a === void 0 ? void 0 : _a[tagName]) { return subschema.properties[tagName]; } } return undefined; } const def = { keyword: "discriminator", type: "object", schemaType: "object", error, code(cxt) { const { gen, data, schema, parentSchema, it } = cxt; const keyword = parentSchema.oneOf ? "oneOf" : parentSchema.anyOf ? "anyOf" : undefined; if (!it.opts.discriminator) { throw new Error("discriminator: requires discriminator option"); } const tagName = schema.propertyName; if (typeof tagName != "string") throw new Error("discriminator: requires propertyName"); if (!keyword) throw new Error("discriminator: requires oneOf or anyOf composite keyword"); const parentSchemaVariants = parentSchema[keyword]; const valid = gen.let("valid", false); const tag = gen.const("tag", (0, codegen_1._) `${data}${(0, codegen_1.getProperty)(tagName)}`); gen.if((0, codegen_1._) `typeof ${tag} == "string"`, () => validateMapping(), () => cxt.error(false, { discrError: types_1.DiscrError.Tag, tag, tagName })); cxt.ok(valid); function validateMapping() { const mapping = getMapping(); gen.if(false); for (const tagValue in mapping) { gen.elseIf((0, codegen_1._) `${tag} === ${tagValue}`); gen.assign(valid, applyTagSchema(mapping[tagValue])); } gen.else(); cxt.error(false, { discrError: types_1.DiscrError.Mapping, tag, tagName }); gen.endIf(); } function applyTagSchema(schemaProp) { const _valid = gen.name("valid"); const schCxt = cxt.subschema({ keyword, schemaProp }, _valid); cxt.mergeEvaluated(schCxt, codegen_1.Name); return _valid; } function getMapping() { var _a; const discriminatorMapping = {}; const topRequired = hasRequired(parentSchema); let tagRequired = true; for (let i = 0; i < parentSchemaVariants.length; i++) { let sch = parentSchemaVariants[i]; const schRef = sch === null || sch === void 0 ? void 0 : sch.$ref; if (schRef && schema.mapping) { const { mapping } = schema; const matchedKeys = Object.keys(mapping).filter((key) => mapping[key] === sch.$ref); if (matchedKeys.length) { for (const key of matchedKeys) { addMapping(key, i); } continue; } } if (schRef && !(0, util_1.schemaHasRulesButRef)(sch, it.self.RULES)) { sch = compile_1.resolveRef.call(it.self, it.schemaEnv.root, it.baseId, schRef); if (sch instanceof compile_1.SchemaEnv) sch = sch.schema; } let propSch = (_a = sch === null || sch === void 0 ? void 0 : sch.properties) === null || _a === void 0 ? void 0 : _a[tagName]; if (!propSch && (sch === null || sch === void 0 ? void 0 : sch.allOf)) { propSch = getDiscriminatorPropertyFromAllOf(sch, tagName); } if (typeof propSch != "object") { throw new Error(`discriminator: ${keyword} subschemas (or referenced schemas) must have "properties/${tagName}" or match mapping`); } tagRequired = tagRequired && (topRequired || hasRequired(sch)); addMappings(propSch, i); } if (!tagRequired) throw new Error(`discriminator: "${tagName}" must be required`); return discriminatorMapping; function hasRequired(sch) { if (Array.isArray(sch.required) && sch.required.includes(tagName)) { return true; } if (sch.allOf && Array.isArray(sch.allOf)) { for (const subschema of sch.allOf) { const subSch = subschema; if (Array.isArray(subSch.required) && subSch.required.includes(tagName)) { return true; } } } return false; } function addMappings(sch, i) { if (sch.const) { addMapping(sch.const, i); } else if (sch.enum) { for (const tagValue of sch.enum) { addMapping(tagValue, i); } } else { throw new Error(`discriminator: "properties/${tagName}" must have "const" or "enum"`); } } function addMapping(tagValue, i) { if (typeof tagValue != "string" || tagValue in discriminatorMapping) { throw new Error(`discriminator: "${tagName}" values must be unique strings`); } discriminatorMapping[tagValue] = i; } } }, }; exports.default = def; //# sourceMappingURL=index.js.map