import type {KeywordDefinition, KeywordErrorDefinition, KeywordCxt, ErrorObject} from "ajv" import {_, str, nil, Name} from "ajv/dist/compile/codegen" import type {DefinitionOptions} from "./_types" import {metaSchemaRef} from "./_util" export type SelectError = ErrorObject<"select", {failingCase?: string; failingDefault?: true}> const error: KeywordErrorDefinition = { message: ({params: {schemaProp}}) => schemaProp ? str`should match case "${schemaProp}" schema` : str`should match default case schema`, params: ({params: {schemaProp}}) => schemaProp ? _`{failingCase: ${schemaProp}}` : _`{failingDefault: true}`, } export default function getDef(opts?: DefinitionOptions): KeywordDefinition[] { const metaSchema = metaSchemaRef(opts) return [ { keyword: "select", schemaType: ["string", "number", "boolean", "null"], $data: true, error, dependencies: ["selectCases"], code(cxt: KeywordCxt) { const {gen, schemaCode, parentSchema} = cxt cxt.block$data(nil, () => { const valid = gen.let("valid", true) const schValid = gen.name("_valid") const value = gen.const("value", _`${schemaCode} === null ? "null" : ${schemaCode}`) gen.if(false) // optimizer should remove it from generated code for (const schemaProp in parentSchema.selectCases) { cxt.setParams({schemaProp}) gen.elseIf(_`"" + ${value} == ${schemaProp}`) // intentional ==, to match numbers and booleans const schCxt = cxt.subschema({keyword: "selectCases", schemaProp}, schValid) cxt.mergeEvaluated(schCxt, Name) gen.assign(valid, schValid) } gen.else() if (parentSchema.selectDefault !== undefined) { cxt.setParams({schemaProp: undefined}) const schCxt = cxt.subschema({keyword: "selectDefault"}, schValid) cxt.mergeEvaluated(schCxt, Name) gen.assign(valid, schValid) } gen.endIf() cxt.pass(valid) }) }, }, { keyword: "selectCases", dependencies: ["select"], metaSchema: { type: "object", additionalProperties: metaSchema, }, }, { keyword: "selectDefault", dependencies: ["select", "selectCases"], metaSchema, }, ] } module.exports = getDef