Skip to content

Commit

Permalink
Merge Master | Work on Errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Apr 29, 2024
1 parent 70c2946 commit ac6a5fc
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 19 deletions.
13 changes: 5 additions & 8 deletions example/index.ts
Expand Up @@ -7,9 +7,9 @@ const UnsafeByte = Type.Unsafe<number>({ type: 'byte' })

const Byte = Type.Refine(UnsafeByte)
.Check((value) => typeof value === 'number')
.Check((value) => !isNaN(value))
.Check((value) => value >= 0)
.Check((value) => value < 256)
.Check((value) => !isNaN(value), { message: 'Must not be NaN', x: 100 })
.Check((value) => value >= 0, { message: 'Must be greater than 0' })
.Check((value) => value < 256, { message: 'Must be something' })
.Done()

const A = Type.Object({
Expand All @@ -18,12 +18,9 @@ const A = Type.Object({
z: Byte,
})

console.log(Byte)
console.dir(A, { depth: 100 })
console.log(TypeCompiler.Code(A))
console.log(Value.Check(A, { x: 0, y: 0, z: 0 }))
console.log(Value.Check(Byte, 255))
console.log(Value.Check(Byte, -1))
console.log(Value.Check(Byte, NaN))
console.log(Value.Errors(Byte, 'asdsa').Take(10))

// Todo: Error Tests
// Todo: Investigate Error Propogation for Refinements
8 changes: 5 additions & 3 deletions src/errors/errors.ts
Expand Up @@ -132,7 +132,7 @@ export enum ValueErrorType {
Object,
Promise,
RegExp,
Refine,
Refinement,
StringFormatNotFound,
StringFormat,
StringMaxLength,
Expand Down Expand Up @@ -199,7 +199,7 @@ export class ValueErrorIterator {
// Create
// --------------------------------------------------------------------------
function CreateRefinementError(schema: TSchema, refinement: Refinement, path: string, value: unknown): ValueError {
return { type: ValueErrorType.Refine, schema, path, value, message: refinement.message }
return { type: ValueErrorType.Refinement, schema, path, value, message: refinement.message || '' }
}
function CreateError(errorType: ValueErrorType, schema: TSchema, path: string, value: unknown): ValueError {
return { type: errorType, schema, path, value, message: GetErrorFunction()({ errorType, path, schema, value }) }
Expand Down Expand Up @@ -541,7 +541,9 @@ function* FromKind(schema: TSchema, references: TSchema[], path: string, value:
}
function* FromRefine(schema: TSchema & Record<PropertyKey, unknown> & { [RefineKind]: Refinement[] }, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
for (const refinement of schema[RefineKind]) {
if (!refinement.check(value)) yield CreateRefinementError(schema, refinement, path, value)
if (refinement.check(value)) continue
// only generate one refinement error per type
return yield CreateRefinementError(schema, refinement, path, value)
}
}
function* Visit<T extends TSchema>(schema: T, references: TSchema[], path: string, value: any): IterableIterator<ValueError> {
Expand Down
4 changes: 2 additions & 2 deletions src/errors/function.ts
Expand Up @@ -32,7 +32,7 @@ import { IsRefinement } from '../type/guard/type'
import { ValueErrorType } from './errors'

/** Creates an error message using en-US as the default locale */
export function DefaultErrorFunction(error: ErrorFunctionParameter) {
export function DefaultErrorFunction(error: ErrorFunctionParameter): string {
switch (error.errorType) {
case ValueErrorType.ArrayContains:
return 'Expected array to contain at least one matching value'
Expand Down Expand Up @@ -128,7 +128,7 @@ export function DefaultErrorFunction(error: ErrorFunctionParameter) {
return 'Required property'
case ValueErrorType.Promise:
return 'Expected Promise'
case ValueErrorType.Refine:
case ValueErrorType.Refinement:
return IsRefinement(error.schema) ? error.schema.message : 'Refinement Error'
case ValueErrorType.RegExp:
return 'Expected string to match regular expression'
Expand Down
17 changes: 11 additions & 6 deletions src/type/refine/refine.ts
Expand Up @@ -32,20 +32,25 @@ import { Static } from '../static/index'
import { CloneType } from '../clone/type'
import { IsRefine } from '../guard/type'

export interface Refinement {
check: RefineCheckFunction
export interface RefinementCheckOptions {
[key: string]: any
message: string
}

export interface Refinement extends RefinementCheckOptions {
check: RefineCheckFunction
}
export type RefineCheckFunction<T extends TSchema = TSchema, S = Static<T>> = (value: S) => boolean

function DefaultRefinementCheckOptions(): RefinementCheckOptions {
return { message: 'Invalid' }
}
export class RefineBuilder<T extends TSchema> {
constructor(private readonly schema: T, private readonly refinements: Refinement[]) {}
/** Adds a refinement check to this type */
public Check(check: RefineCheckFunction<T>, message: string = ''): RefineBuilder<T> {
return new RefineBuilder(this.schema, [...this.refinements, { check, message }])
public Check(check: RefineCheckFunction<T>, options: RefinementCheckOptions = DefaultRefinementCheckOptions()): RefineBuilder<T> {
return new RefineBuilder(this.schema, [...this.refinements, { check, ...options }])
}
/** Applies refinement checks and returns the type */
/** Completes the refinement and returns the type. */
public Done(): T {
return CloneType(this.schema, { [RefineKind]: [...this.refinements] })
}
Expand Down

0 comments on commit ac6a5fc

Please sign in to comment.