Skip to content

Commit

Permalink
Union ValueError Iterator (#1015)
Browse files Browse the repository at this point in the history
* feat: attach to ValueError the first error of each Union.anyOf visit

* chore: small tweak

* test: add test

* chore: tweak test

* fix: flatten nested union errors

* feat: expose variant errors as ValueErrorIterator[]

* feat: use a single ValueErrorIterator instance

* update tests

* implement requested changes

* update test

* update ErrorFunctionParameter

* small fix
  • Loading branch information
aleclarson authored Oct 11, 2024
1 parent f9134bb commit 0f65387
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 13 deletions.
25 changes: 14 additions & 11 deletions src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { GetErrorFunction } from './function'
import { TypeBoxError } from '../type/error/index'
import { Deref } from '../value/deref/index'
import { Hash } from '../value/hash/index'
import { Check } from '../value/check/index'
import { Kind } from '../type/symbols/index'

import type { TSchema } from '../type/schema/index'
Expand Down Expand Up @@ -167,6 +168,7 @@ export interface ValueError {
path: string
value: unknown
message: string
errors: ValueErrorIterator[]
}
// ------------------------------------------------------------------
// ValueErrors
Expand Down Expand Up @@ -205,8 +207,15 @@ export class ValueErrorIterator {
// --------------------------------------------------------------------------
// Create
// --------------------------------------------------------------------------
function Create(errorType: ValueErrorType, schema: TSchema, path: string, value: unknown): ValueError {
return { type: errorType, schema, path, value, message: GetErrorFunction()({ errorType, path, schema, value }) }
function Create(errorType: ValueErrorType, schema: TSchema, path: string, value: unknown, errors: ValueErrorIterator[] = []): ValueError {
return {
type: errorType,
schema,
path,
value,
message: GetErrorFunction()({ errorType, path, schema, value, errors }),
errors,
}
}
// --------------------------------------------------------------------------
// Types
Expand Down Expand Up @@ -516,15 +525,9 @@ 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<ValueError> {
let count = 0
for (const subschema of schema.anyOf) {
const errors = [...Visit(subschema, references, path, value)]
if (errors.length === 0) return // matched
count += errors.length
}
if (count > 0) {
yield Create(ValueErrorType.Union, schema, path, value)
}
if (Check(schema, references, value)) return
const errors = schema.anyOf.map((variant) => new ValueErrorIterator(Visit(variant, references, path, value)))
yield Create(ValueErrorType.Union, schema, path, value, errors)
}
function* FromUint8Array(schema: TUint8Array, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
if (!IsUint8Array(value)) return yield Create(ValueErrorType.Uint8Array, schema, path, value)
Expand Down
4 changes: 3 additions & 1 deletion src/errors/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ THE SOFTWARE.

import { TSchema } from '../type/schema/index'
import { Kind } from '../type/symbols/index'
import { ValueErrorType } from './errors'
import { ValueErrorIterator, ValueErrorType } from './errors'

/** Creates an error message using en-US as the default locale */
export function DefaultErrorFunction(error: ErrorFunctionParameter) {
Expand Down Expand Up @@ -178,6 +178,8 @@ export type ErrorFunctionParameter = {
schema: TSchema
/** The value associated with the error */
value: unknown
/** Interior errors for this error */
errors: ValueErrorIterator[]
}
export type ErrorFunction = (parameter: ErrorFunctionParameter) => string
/** Manages error message providers */
Expand Down
4 changes: 3 additions & 1 deletion test/runtime/errors/types/union.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Type } from '@sinclair/typebox'
import { ValueErrorType } from '@sinclair/typebox/errors'
import { ValueErrorIterator, ValueErrorType } from '@sinclair/typebox/errors'
import { Resolve } from './resolve'
import { Assert } from '../../assert'

Expand All @@ -17,5 +17,7 @@ describe('errors/type/Union', () => {
const R = Resolve(T, true)
Assert.IsEqual(R.length, 1)
Assert.IsEqual(R[0].type, ValueErrorType.Union)
Assert.IsEqual(R[0].errors[0].First()?.type, ValueErrorType.String)
Assert.IsEqual(R[0].errors[1].First()?.type, ValueErrorType.Number)
})
})

0 comments on commit 0f65387

Please sign in to comment.