From 84ff329e14d8d07638f3a78af32cdbfbb349c6c7 Mon Sep 17 00:00:00 2001 From: Alec Larson <1925840+aleclarson@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:18:53 -0500 Subject: [PATCH] fix: surface deepest error from failed union validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Expected union value" error message is practically useless, so I think it‘s a better DX to surface the deepest validation error (based on property path). --- src/errors/errors.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/errors/errors.ts b/src/errors/errors.ts index f81de1a6..67bd2274 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -513,14 +513,16 @@ function* FromUndefined(schema: TUndefined, references: TSchema[], path: string, if (!IsUndefined(value)) yield Create(ValueErrorType.Undefined, schema, path, value) } function* FromUnion(schema: TUnion, references: TSchema[], path: string, value: any): IterableIterator { - let count = 0 + let unionErrors: ValueError[] | undefined for (const subschema of schema.anyOf) { const errors = [...Visit(subschema, references, path, value)] if (errors.length === 0) return // matched - count += errors.length + if (unionErrors) {for (const error of errors) unionErrors.push(error)} + else {unionErrors = errors} } - if (count > 0) { - yield Create(ValueErrorType.Union, schema, path, value) + if (unionErrors) { + const pathDepth = (error: ValueError) => error.path.split('/').length + yield unionErrors.reduce((deepestError, error) => (!deepestError || pathDepth(error) > pathDepth(deepestError) ? error : deepestError)) } } function* FromUint8Array(schema: TUint8Array, references: TSchema[], path: string, value: any): IterableIterator {