From c5c195bd47503bc55ccd011c36b3de81867fe3a1 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Tue, 3 Jan 2023 13:46:42 +0000 Subject: [PATCH] fix JTD discriminator with more than 8 properties, fixes #1971 (#2194) * fix JTD discriminator with more than 8 properties, fixes #1971 * prettier --- lib/vocabularies/jtd/properties.ts | 19 ++++--- spec/issues/1971_jtd_discriminator.spec.ts | 61 ++++++++++++++++++++++ 2 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 spec/issues/1971_jtd_discriminator.spec.ts diff --git a/lib/vocabularies/jtd/properties.ts b/lib/vocabularies/jtd/properties.ts index 728c0b92c..9dd24c5cd 100644 --- a/lib/vocabularies/jtd/properties.ts +++ b/lib/vocabularies/jtd/properties.ts @@ -138,9 +138,7 @@ export function validateProperties(cxt: KeywordCxt): void { function validateAdditional(): void { gen.forIn("key", data, (key: Name) => { - const _allProps = - it.jtdDiscriminator === undefined ? allProps : [it.jtdDiscriminator].concat(allProps) - const addProp = isAdditional(key, _allProps, "properties") + const addProp = isAdditional(key, allProps, "properties", it.jtdDiscriminator) const addOptProp = isAdditional(key, allOptProps, "optionalProperties") const extra = addProp === true ? addOptProp : addOptProp === true ? addProp : and(addProp, addOptProp) @@ -159,14 +157,23 @@ export function validateProperties(cxt: KeywordCxt): void { }) } - function isAdditional(key: Name, props: string[], keyword: string): Code | true { + function isAdditional( + key: Name, + props: string[], + keyword: string, + jtdDiscriminator?: string + ): Code | true { let additional: Code | boolean if (props.length > 8) { // TODO maybe an option instead of hard-coded 8? const propsSchema = schemaRefOrVal(it, parentSchema[keyword], keyword) additional = not(isOwnProperty(gen, propsSchema as Code, key)) - } else if (props.length) { - additional = and(...props.map((p) => _`${key} !== ${p}`)) + if (jtdDiscriminator !== undefined) { + additional = and(additional, _`${key} !== ${jtdDiscriminator}`) + } + } else if (props.length || jtdDiscriminator !== undefined) { + const ps = jtdDiscriminator === undefined ? props : [jtdDiscriminator].concat(props) + additional = and(...ps.map((p) => _`${key} !== ${p}`)) } else { additional = true } diff --git a/spec/issues/1971_jtd_discriminator.spec.ts b/spec/issues/1971_jtd_discriminator.spec.ts new file mode 100644 index 000000000..80ff57f13 --- /dev/null +++ b/spec/issues/1971_jtd_discriminator.spec.ts @@ -0,0 +1,61 @@ +import _Ajv from "../ajv_jtd" +import * as assert from "assert" + +describe("JTD discriminator with more than 8 (hardcoded in properties.ts) properties (issue #1971)", () => { + const ajv = new _Ajv() + + it("should correctly validate empty values form", () => { + const schema = { + discriminator: "tag", + mapping: { + manual: { + properties: { + first: {type: "uint16"}, + second: {type: "uint16"}, + third: {type: "uint16"}, + fourth: {type: "uint16"}, + fifth: {type: "uint16"}, + sixth: {type: "uint16"}, + additionalOne: {type: "uint16"}, + additionalTwo: {type: "uint16"}, + }, + }, + auto: { + properties: { + first: {type: "uint16"}, + second: {type: "uint16"}, + third: {type: "uint16"}, + fourth: {type: "uint16"}, + fifth: {type: "uint16"}, + sixth: {type: "uint16"}, + additionalThree: {type: "uint16"}, + }, + }, + }, + } + const data1 = { + tag: "manual", + first: 1, + second: 1, + third: 1, + fourth: 1, + fifth: 1, + sixth: 1, + additionalOne: 1, + additionalTwo: 1, + } + const data2 = { + tag: "auto", + first: 1, + second: 1, + third: 1, + fourth: 1, + fifth: 1, + sixth: 1, + additionalThree: 1, + } + const validate = ajv.compile(schema) + assert.strictEqual(validate(data1), true) + assert.strictEqual(validate(data2), true) + }) +})