Skip to content

Commit f3011ab

Browse files
committed
feat: perform const comparisons first in static anyOf
That way, they won't interfere with non-const branches in case of 'removeAdditional' option, and we can relax the uncertain check a bit more to exclude static anyOf branches.
1 parent 82876fc commit f3011ab

1 file changed

Lines changed: 11 additions & 2 deletions

File tree

src/compile.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,9 +918,9 @@ const compileSchema = (schema, root, opts, scope, basePathRoot = '') => {
918918
enforce(anyOf.length > 0, 'anyOf cannot be empty')
919919
if (anyOf.length === 1) return performAllOf(anyOf)
920920
if (handleDiscriminator) return handleDiscriminator(anyOf, 'anyOf')
921-
uncertainBranchTypes('anyOf', anyOf)
922921
const suberr = suberror()
923922
if (!canSkipDynamic()) {
923+
uncertainBranchTypes('anyOf', anyOf) // const sorting for removeAdditional is not supported in dynamic mode
924924
// In this case, all have to be checked to gather evaluated properties
925925
const entries = Object.entries(anyOf).map(([key, sch]) =>
926926
subrule(suberr, current, sch, subPath('anyOf', key), dyn)
@@ -931,9 +931,18 @@ const compileSchema = (schema, root, opts, scope, basePathRoot = '') => {
931931
for (const { delta, sub } of entries) fun.if(sub, () => evaluateDeltaDynamic(delta))
932932
return null
933933
}
934+
// We sort the variants to perform const comparisons first, then primitives/array/object/unknown
935+
// This way, we can be sure that array/object + removeAdditional do not affect const evaluation
936+
// Note that this _might_ e.g. remove all elements of an array in a 2nd branch _and_ fail with `const: []` in the 1st, but that's expected behavior
937+
// This can be done because we can stop on the first match in anyOf if we don't need dynamic evaluation
938+
const constBlocks = anyOf.filter((x) => functions.hasOwn(x, 'const'))
939+
const otherBlocks = anyOf.filter((x) => !functions.hasOwn(x, 'const'))
940+
uncertainBranchTypes('anyOf', otherBlocks)
941+
const blocks = [...constBlocks, ...otherBlocks]
942+
934943
let delta
935944
let body = () => error({ path: ['anyOf'], suberr })
936-
for (const [key, sch] of Object.entries(anyOf).reverse()) {
945+
for (const [key, sch] of Object.entries(blocks).reverse()) {
937946
const oldBody = body
938947
body = () => {
939948
const { sub, delta: deltaVar } = subrule(suberr, current, sch, subPath('anyOf', key))

0 commit comments

Comments
 (0)