source: imaps-frontend/node_modules/ajv/lib/vocabularies/discriminator/index.ts@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 4.2 KB
Line 
1import type {CodeKeywordDefinition, AnySchemaObject, KeywordErrorDefinition} from "../../types"
2import type {KeywordCxt} from "../../compile/validate"
3import {_, getProperty, Name} from "../../compile/codegen"
4import {DiscrError, DiscrErrorObj} from "../discriminator/types"
5import {resolveRef, SchemaEnv} from "../../compile"
6import MissingRefError from "../../compile/ref_error"
7import {schemaHasRulesButRef} from "../../compile/util"
8
9export type DiscriminatorError = DiscrErrorObj<DiscrError.Tag> | DiscrErrorObj<DiscrError.Mapping>
10
11const error: KeywordErrorDefinition = {
12 message: ({params: {discrError, tagName}}) =>
13 discrError === DiscrError.Tag
14 ? `tag "${tagName}" must be string`
15 : `value of tag "${tagName}" must be in oneOf`,
16 params: ({params: {discrError, tag, tagName}}) =>
17 _`{error: ${discrError}, tag: ${tagName}, tagValue: ${tag}}`,
18}
19
20const def: CodeKeywordDefinition = {
21 keyword: "discriminator",
22 type: "object",
23 schemaType: "object",
24 error,
25 code(cxt: KeywordCxt) {
26 const {gen, data, schema, parentSchema, it} = cxt
27 const {oneOf} = parentSchema
28 if (!it.opts.discriminator) {
29 throw new Error("discriminator: requires discriminator option")
30 }
31 const tagName = schema.propertyName
32 if (typeof tagName != "string") throw new Error("discriminator: requires propertyName")
33 if (schema.mapping) throw new Error("discriminator: mapping is not supported")
34 if (!oneOf) throw new Error("discriminator: requires oneOf keyword")
35 const valid = gen.let("valid", false)
36 const tag = gen.const("tag", _`${data}${getProperty(tagName)}`)
37 gen.if(
38 _`typeof ${tag} == "string"`,
39 () => validateMapping(),
40 () => cxt.error(false, {discrError: DiscrError.Tag, tag, tagName})
41 )
42 cxt.ok(valid)
43
44 function validateMapping(): void {
45 const mapping = getMapping()
46 gen.if(false)
47 for (const tagValue in mapping) {
48 gen.elseIf(_`${tag} === ${tagValue}`)
49 gen.assign(valid, applyTagSchema(mapping[tagValue]))
50 }
51 gen.else()
52 cxt.error(false, {discrError: DiscrError.Mapping, tag, tagName})
53 gen.endIf()
54 }
55
56 function applyTagSchema(schemaProp?: number): Name {
57 const _valid = gen.name("valid")
58 const schCxt = cxt.subschema({keyword: "oneOf", schemaProp}, _valid)
59 cxt.mergeEvaluated(schCxt, Name)
60 return _valid
61 }
62
63 function getMapping(): {[T in string]?: number} {
64 const oneOfMapping: {[T in string]?: number} = {}
65 const topRequired = hasRequired(parentSchema)
66 let tagRequired = true
67 for (let i = 0; i < oneOf.length; i++) {
68 let sch = oneOf[i]
69 if (sch?.$ref && !schemaHasRulesButRef(sch, it.self.RULES)) {
70 const ref = sch.$ref
71 sch = resolveRef.call(it.self, it.schemaEnv.root, it.baseId, ref)
72 if (sch instanceof SchemaEnv) sch = sch.schema
73 if (sch === undefined) throw new MissingRefError(it.opts.uriResolver, it.baseId, ref)
74 }
75 const propSch = sch?.properties?.[tagName]
76 if (typeof propSch != "object") {
77 throw new Error(
78 `discriminator: oneOf subschemas (or referenced schemas) must have "properties/${tagName}"`
79 )
80 }
81 tagRequired = tagRequired && (topRequired || hasRequired(sch))
82 addMappings(propSch, i)
83 }
84 if (!tagRequired) throw new Error(`discriminator: "${tagName}" must be required`)
85 return oneOfMapping
86
87 function hasRequired({required}: AnySchemaObject): boolean {
88 return Array.isArray(required) && required.includes(tagName)
89 }
90
91 function addMappings(sch: AnySchemaObject, i: number): void {
92 if (sch.const) {
93 addMapping(sch.const, i)
94 } else if (sch.enum) {
95 for (const tagValue of sch.enum) {
96 addMapping(tagValue, i)
97 }
98 } else {
99 throw new Error(`discriminator: "properties/${tagName}" must have "const" or "enum"`)
100 }
101 }
102
103 function addMapping(tagValue: unknown, i: number): void {
104 if (typeof tagValue != "string" || tagValue in oneOfMapping) {
105 throw new Error(`discriminator: "${tagName}" values must be unique strings`)
106 }
107 oneOfMapping[tagValue] = i
108 }
109 }
110 },
111}
112
113export default def
Note: See TracBrowser for help on using the repository browser.