From f584c792e5240e89c12c4a4ed7507a18b0dec4dd Mon Sep 17 00:00:00 2001 From: Andreas Jim Date: Wed, 2 Nov 2022 10:45:51 +0100 Subject: [PATCH 1/2] feat: Type Errors as NonEmptyArray (#670) --- docs/modules/index.ts.md | 2 +- src/index.ts | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index 33f37940..acb51e28 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -399,7 +399,7 @@ Added in v1.0.0 **Signature** ```ts -export interface Errors extends Array {} +export interface Errors extends NonEmptyArray {} ``` Added in v1.0.0 diff --git a/src/index.ts b/src/index.ts index 2434a683..46d1bd93 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,7 +42,7 @@ export interface ValidationError { * @category Decode error * @since 1.0.0 */ -export interface Errors extends Array {} +export interface Errors extends NonEmptyArray {} /** * @category Decode error @@ -340,7 +340,7 @@ function enumerableRecord( } const o = e.right const a: { [key: string]: any } = {} - const errors: Errors = [] + const errors: ValidationError[] = [] let changed = false for (let i = 0; i < len; i++) { const k = keys[i] @@ -354,7 +354,7 @@ function enumerableRecord( a[k] = vok } } - return errors.length > 0 ? failures(errors) : success((changed || Object.keys(o).length !== len ? a : o) as any) + return isNonEmpty(errors) ? failures(errors) : success((changed || Object.keys(o).length !== len ? a : o) as any) }, codomain.encode === identity ? identity @@ -405,7 +405,7 @@ function nonEnumerableRecord( (u, c) => { if (UnknownRecord.is(u)) { const a: { [key: string]: any } = {} - const errors: Errors = [] + const errors: ValidationError[] = [] const keys = Object.keys(u) const len = keys.length let changed = false @@ -429,7 +429,7 @@ function nonEnumerableRecord( } } } - return errors.length > 0 ? failures(errors) : success((changed ? a : u) as any) + return isNonEmpty(errors) ? failures(errors) : success((changed ? a : u) as any) } if (isAnyC(codomain) && Array.isArray(u)) { return success(u) @@ -1278,7 +1278,7 @@ export function array(item: C, name = `Array<${item.name}>`): A const us = e.right const len = us.length let as: Array> = us - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < len; i++) { const ui = us[i] const result = item.validate(ui, appendContext(c, String(i), item, ui)) @@ -1294,7 +1294,7 @@ export function array(item: C, name = `Array<${item.name}>`): A } } } - return errors.length > 0 ? failures(errors) : success(as) + return isNonEmpty(errors) ? failures(errors) : success(as) }, item.encode === identity ? identity : (a) => a.map(item.encode), item @@ -1356,7 +1356,7 @@ export function type

(props: P, name: string = getInterfaceTypeN } const o = e.right let a = o - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < len; i++) { const k = keys[i] const ak = a[k] @@ -1375,7 +1375,7 @@ export function type

(props: P, name: string = getInterfaceTypeN } } } - return errors.length > 0 ? failures(errors) : success(a as any) + return isNonEmpty(errors) ? failures(errors) : success(a as any) }, useIdentity(types) ? identity @@ -1452,7 +1452,7 @@ export function partial

( } const o = e.right let a = o - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < len; i++) { const k = keys[i] const ak = a[k] @@ -1473,7 +1473,7 @@ export function partial

( } } } - return errors.length > 0 ? failures(errors) : success(a as any) + return isNonEmpty(errors) ? failures(errors) : success(a as any) }, useIdentity(types) ? identity @@ -1616,7 +1616,7 @@ export function union]>( name, (u): u is TypeOf => codecs.some((type) => type.is(u)), (u, c) => { - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < codecs.length; i++) { const codec = codecs[i] const result = codec.validate(u, appendContext(c, String(i), codec, u)) @@ -1626,7 +1626,7 @@ export function union]>( return success(result.right) } } - return failures(errors) + return failures(errors as Errors) }, useIdentity(codecs) ? identity @@ -1719,7 +1719,7 @@ export function intersection]>( ? success : (u, c) => { const us: Array = [] - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < len; i++) { const codec = codecs[i] const result = codec.validate(u, appendContext(c, String(i), codec, u)) @@ -1729,7 +1729,7 @@ export function intersection]>( us.push(result.right) } } - return errors.length > 0 ? failures(errors) : success(mergeAll(u, us)) + return isNonEmpty(errors) ? failures(errors) : success(mergeAll(u, us)) }, codecs.length === 0 ? identity @@ -1825,7 +1825,7 @@ export function tuple]>( } const us = e.right let as: Array = us.length > len ? us.slice(0, len) : us // strip additional components - const errors: Errors = [] + const errors: ValidationError[] = [] for (let i = 0; i < len; i++) { const a = us[i] const type = codecs[i] @@ -1843,7 +1843,7 @@ export function tuple]>( } } } - return errors.length > 0 ? failures(errors) : success(as) + return isNonEmpty(errors) ? failures(errors) : success(as) }, useIdentity(codecs) ? identity : (a) => codecs.map((type, i) => type.encode(a[i])), codecs From 5c4eed19100673cba499d06902378db19107798d Mon Sep 17 00:00:00 2001 From: Andreas Jim Date: Wed, 2 Nov 2022 11:08:12 +0100 Subject: [PATCH 2/2] feat: Type Context as NonEmptyArray (#670) --- docs/modules/index.ts.md | 4 ++-- src/index.ts | 15 +++++---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index acb51e28..a627325f 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -374,7 +374,7 @@ Added in v1.0.0 **Signature** ```ts -export interface Context extends ReadonlyArray {} +export interface Context extends ReadonlyNonEmptyArray {} ``` Added in v1.0.0 @@ -2123,7 +2123,7 @@ Added in v1.0.0 **Signature** ```ts -export declare function appendContext(c: Context, key: string, decoder: Decoder, actual?: unknown): Context +export declare const appendContext: (c: Context, key: string, decoder: Decoder, actual?: unknown) => Context ``` Added in v1.0.0 diff --git a/src/index.ts b/src/index.ts index 46d1bd93..f91b0e28 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,8 @@ */ import { Either, isLeft, left, right } from 'fp-ts/lib/Either' import { Predicate, Refinement } from 'fp-ts/lib/function' +import { ReadonlyNonEmptyArray } from 'fp-ts/lib/ReadonlyNonEmptyArray' +import { readonlyNonEmptyArray } from 'fp-ts' // ------------------------------------------------------------------------------------- // Decode error @@ -23,7 +25,7 @@ export interface ContextEntry { * @category Decode error * @since 1.0.0 */ -export interface Context extends ReadonlyArray {} +export interface Context extends ReadonlyNonEmptyArray {} /** * @category Decode error @@ -237,15 +239,8 @@ export function getContextEntry(key: string, decoder: Decoder): Contex /** * @since 1.0.0 */ -export function appendContext(c: Context, key: string, decoder: Decoder, actual?: unknown): Context { - const len = c.length - const r = Array(len + 1) - for (let i = 0; i < len; i++) { - r[i] = c[i] - } - r[len] = { key, type: decoder, actual } - return r -} +export const appendContext = (c: Context, key: string, decoder: Decoder, actual?: unknown): Context => + readonlyNonEmptyArray.snoc(c, { key, type: decoder, actual }) function pushAll(xs: Array, ys: Array): void { const l = ys.length