@sapphire/shapeshift
Advanced tools
Comparing version 1.1.0-next.fe6505f.0 to 2.0.0
@@ -1,17 +0,90 @@ | ||
declare class ConstraintError<T = unknown> extends Error { | ||
readonly constraint: string; | ||
readonly given: T; | ||
readonly expected: unknown; | ||
constructor(validator: string, message: string, given: T, expected: unknown); | ||
toJSON(): { | ||
name: string; | ||
constraint: string; | ||
given: T; | ||
expected: unknown; | ||
}; | ||
/// <reference types="node" /> | ||
import { InspectOptionsStylized } from 'node:util'; | ||
declare type ArrayConstraintName = `s.array(T).length${'Lt' | 'Le' | 'Gt' | 'Ge' | 'Eq' | 'Ne' | 'Range' | 'RangeInclusive' | 'RangeExclusive'}`; | ||
declare function arrayLengthLt<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthLe<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthGt<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthGe<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthEq<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthNe<T>(value: number): IConstraint<T[]>; | ||
declare function arrayLengthRange<T>(start: number, endBefore: number): IConstraint<T[]>; | ||
declare function arrayLengthRangeInclusive<T>(start: number, end: number): IConstraint<T[]>; | ||
declare function arrayLengthRangeExclusive<T>(startAfter: number, endBefore: number): IConstraint<T[]>; | ||
declare type BigIntConstraintName = `s.bigint.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'ne' | 'divisibleBy'}`; | ||
declare function bigintLt(value: bigint): IConstraint<bigint>; | ||
declare function bigintLe(value: bigint): IConstraint<bigint>; | ||
declare function bigintGt(value: bigint): IConstraint<bigint>; | ||
declare function bigintGe(value: bigint): IConstraint<bigint>; | ||
declare function bigintEq(value: bigint): IConstraint<bigint>; | ||
declare function bigintNe(value: bigint): IConstraint<bigint>; | ||
declare function bigintDivisibleBy(divider: bigint): IConstraint<bigint>; | ||
declare type BooleanConstraintName = `s.boolean.${boolean}`; | ||
declare const booleanTrue: IConstraint<boolean, true>; | ||
declare const booleanFalse: IConstraint<boolean, false>; | ||
declare type DateConstraintName = `s.date.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'ne' | 'valid' | 'invalid'}`; | ||
declare function dateLt(value: Date): IConstraint<Date>; | ||
declare function dateLe(value: Date): IConstraint<Date>; | ||
declare function dateGt(value: Date): IConstraint<Date>; | ||
declare function dateGe(value: Date): IConstraint<Date>; | ||
declare function dateEq(value: Date): IConstraint<Date>; | ||
declare function dateNe(value: Date): IConstraint<Date>; | ||
declare const dateInvalid: IConstraint<Date>; | ||
declare const dateValid: IConstraint<Date>; | ||
declare type NumberConstraintName = `s.number.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'eq(NaN)' | 'ne' | 'ne(NaN)' | 'int' | 'safeInt' | 'finite' | 'divisibleBy'}`; | ||
declare function numberLt(value: number): IConstraint<number>; | ||
declare function numberLe(value: number): IConstraint<number>; | ||
declare function numberGt(value: number): IConstraint<number>; | ||
declare function numberGe(value: number): IConstraint<number>; | ||
declare function numberEq(value: number): IConstraint<number>; | ||
declare function numberNe(value: number): IConstraint<number>; | ||
declare const numberInt: IConstraint<number>; | ||
declare const numberSafeInt: IConstraint<number>; | ||
declare const numberFinite: IConstraint<number>; | ||
declare const numberNaN: IConstraint<number>; | ||
declare const numberNeNaN: IConstraint<number>; | ||
declare function numberDivisibleBy(divider: number): IConstraint<number>; | ||
declare type StringConstraintName = `s.string.${`length${'Lt' | 'Le' | 'Gt' | 'Ge' | 'Eq' | 'Ne'}` | 'regex' | 'url' | 'uuid' | 'email' | `ip${'v4' | 'v6' | ''}`}`; | ||
declare type StringProtocol = `${string}:`; | ||
declare type StringDomain = `${string}.${string}`; | ||
interface UrlOptions { | ||
allowedProtocols?: StringProtocol[]; | ||
allowedDomains?: StringDomain[]; | ||
} | ||
interface ConstraintErrorMessageBuilder<Given = unknown, Expected = unknown> { | ||
(given: Given, expected: Expected): string; | ||
declare type UUIDVersion = 1 | 3 | 4 | 5; | ||
interface StringUuidOptions { | ||
version?: UUIDVersion | `${UUIDVersion}-${UUIDVersion}` | null; | ||
nullable?: boolean; | ||
} | ||
declare function stringLengthLt(length: number): IConstraint<string>; | ||
declare function stringLengthLe(length: number): IConstraint<string>; | ||
declare function stringLengthGt(length: number): IConstraint<string>; | ||
declare function stringLengthGe(length: number): IConstraint<string>; | ||
declare function stringLengthEq(length: number): IConstraint<string>; | ||
declare function stringLengthNe(length: number): IConstraint<string>; | ||
declare function stringEmail(): IConstraint<string>; | ||
declare function stringUrl(options?: UrlOptions): IConstraint<string>; | ||
declare function stringIp(version?: 4 | 6): IConstraint<string>; | ||
declare function stringRegex(regex: RegExp): IConstraint<string, string>; | ||
declare function stringUuid({ version, nullable }?: StringUuidOptions): IConstraint<string, string>; | ||
declare const customInspectSymbol: unique symbol; | ||
declare const customInspectSymbolStackLess: unique symbol; | ||
declare abstract class BaseError extends Error { | ||
protected [customInspectSymbol](depth: number, options: InspectOptionsStylized): string; | ||
protected abstract [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare type ConstraintErrorNames = ArrayConstraintName | BigIntConstraintName | BooleanConstraintName | DateConstraintName | NumberConstraintName | StringConstraintName; | ||
declare abstract class BaseConstraintError<T = unknown> extends BaseError { | ||
readonly constraint: ConstraintErrorNames; | ||
readonly given: T; | ||
constructor(constraint: ConstraintErrorNames, message: string, given: T); | ||
} | ||
declare class Result<T, E extends Error = Error> { | ||
@@ -36,6 +109,33 @@ readonly success: boolean; | ||
interface IConstraint<Input, Return extends Input = Input> { | ||
run(input: Input): Result<Return, ConstraintError<Input>>; | ||
run(input: Input): Result<Return, BaseConstraintError<Input>>; | ||
} | ||
declare class ValidationError extends Error { | ||
declare class CombinedError extends BaseError { | ||
readonly errors: readonly BaseError[]; | ||
constructor(errors: readonly BaseError[]); | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare class CombinedPropertyError extends BaseError { | ||
readonly errors: [PropertyKey, BaseError][]; | ||
constructor(errors: [PropertyKey, BaseError][]); | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
private static formatProperty; | ||
} | ||
declare class UnknownEnumValueError extends BaseError { | ||
readonly value: string | number; | ||
readonly enumKeys: string[]; | ||
readonly enumMappings: Map<string | number, string | number>; | ||
constructor(value: string | number, keys: string[], enumMappings: Map<string | number, string | number>); | ||
toJSON(): { | ||
name: string; | ||
value: string | number; | ||
enumKeys: string[]; | ||
enumMappings: [string | number, string | number][]; | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare class ValidationError extends BaseError { | ||
readonly validator: string; | ||
@@ -49,2 +149,3 @@ readonly given: unknown; | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
@@ -61,8 +162,12 @@ | ||
or<O>(...predicates: readonly BaseValidator<O>[]): UnionValidator<T | O>; | ||
run(value: unknown): Result<T, Error>; | ||
transform(cb: (value: T) => T): this; | ||
transform<O>(cb: (value: T) => O): BaseValidator<O>; | ||
default(value: Exclude<T, undefined> | (() => Exclude<T, undefined>)): DefaultValidator<Exclude<T, undefined>>; | ||
run(value: unknown): Result<T, BaseError>; | ||
parse(value: unknown): T; | ||
protected clone(): this; | ||
protected abstract handle(value: unknown): Result<T, ValidationError | AggregateError>; | ||
protected abstract handle(value: unknown): Result<T, ValidatorError>; | ||
protected addConstraint(constraint: IConstraint<T>): this; | ||
} | ||
declare type ValidatorError = ValidationError | CombinedError | CombinedPropertyError | UnknownEnumValueError; | ||
@@ -72,5 +177,20 @@ declare class ArrayValidator<T> extends BaseValidator<T[]> { | ||
constructor(validator: BaseValidator<T>, constraints?: readonly IConstraint<T[]>[]); | ||
lengthLt<N extends number>(length: N): BaseValidator<ExpandSmallerTuples<UnshiftTuple<[...Tuple<T, N>]>>>; | ||
lengthLe<N extends number>(length: N): BaseValidator<ExpandSmallerTuples<[...Tuple<T, N>]>>; | ||
lengthGt<N extends number>(length: N): BaseValidator<[...Tuple<T, N>, T, ...T[]]>; | ||
lengthGe<N extends number>(length: N): BaseValidator<[...Tuple<T, N>, ...T[]]>; | ||
lengthEq<N extends number>(length: N): BaseValidator<[...Tuple<T, N>]>; | ||
lengthNe(length: number): BaseValidator<[...T[]]>; | ||
lengthRange<S extends number, E extends number>(start: S, endBefore: E): BaseValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<T, E>]>>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<T, S>]>>>>; | ||
lengthRangeInclusive<S extends number, E extends number>(startAt: S, endAt: E): BaseValidator<Exclude<ExpandSmallerTuples<[...Tuple<T, E>]>, ExpandSmallerTuples<UnshiftTuple<[...Tuple<T, S>]>>>>; | ||
lengthRangeExclusive<S extends number, E extends number>(startAfter: S, endBefore: E): BaseValidator<Exclude<ExpandSmallerTuples<UnshiftTuple<[...Tuple<T, E>]>>, ExpandSmallerTuples<[...Tuple<T, S>]>>>; | ||
protected clone(): this; | ||
protected handle(values: unknown): Result<T[], ValidationError | AggregateError>; | ||
protected handle(values: unknown): Result<T[], ValidationError | CombinedPropertyError>; | ||
} | ||
declare type UnshiftTuple<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? Tail : never; | ||
declare type ExpandSmallerTuples<T extends [...any[]]> = T extends [T[0], ...infer Tail] ? T | ExpandSmallerTuples<Tail> : []; | ||
declare type Shift<A extends Array<any>> = ((...args: A) => void) extends (...args: [A[0], ...infer R]) => void ? R : never; | ||
declare type GrowExpRev<A extends Array<any>, N extends number, P extends Array<Array<any>>> = A['length'] extends N ? A : GrowExpRev<[...A, ...P[0]][N] extends undefined ? [...A, ...P[0]] : A, N, Shift<P>>; | ||
declare type GrowExp<A extends Array<any>, N extends number, P extends Array<Array<any>>> = [...A, ...A][N] extends undefined ? GrowExp<[...A, ...A], N, [A, ...P]> : GrowExpRev<A, N, P>; | ||
declare type Tuple<T, N extends number> = number extends N ? Array<T> : N extends 0 ? [] : N extends 1 ? [T] : GrowExp<[T], N, [[]]>; | ||
@@ -86,2 +206,6 @@ declare class BigIntValidator<T extends bigint> extends BaseValidator<T> { | ||
get negative(): this; | ||
divisibleBy(number: bigint): this; | ||
get abs(): this; | ||
intN(bits: number): this; | ||
uintN(bits: number): this; | ||
protected handle(value: unknown): Result<T, ValidationError>; | ||
@@ -99,8 +223,10 @@ } | ||
declare class DateValidator extends BaseValidator<Date> { | ||
lt(date: Date | number): this; | ||
le(date: Date | number): this; | ||
gt(date: Date | number): this; | ||
ge(date: Date | number): this; | ||
eq(date: Date | number): this; | ||
ne(date: Date | number): this; | ||
lt(date: Date | number | string): this; | ||
le(date: Date | number | string): this; | ||
gt(date: Date | number | string): this; | ||
ge(date: Date | number | string): this; | ||
eq(date: Date | number | string): this; | ||
ne(date: Date | number | string): this; | ||
get valid(): this; | ||
get invalid(): this; | ||
protected handle(value: unknown): Result<Date, ValidationError>; | ||
@@ -118,2 +244,3 @@ } | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
@@ -162,2 +289,10 @@ | ||
get negative(): this; | ||
divisibleBy(divider: number): this; | ||
get abs(): this; | ||
get sign(): this; | ||
get trunc(): this; | ||
get floor(): this; | ||
get fround(): this; | ||
get round(): this; | ||
get ceil(): this; | ||
protected handle(value: unknown): Result<T, ValidationError>; | ||
@@ -176,2 +311,3 @@ } | ||
get ignore(): this; | ||
get passthrough(): this; | ||
get partial(): ObjectValidator<{ | ||
@@ -187,10 +323,12 @@ [Key in keyof T]?: T[Key]; | ||
}>; | ||
protected handle(value: unknown): Result<T, ValidationError | AggregateError>; | ||
protected handle(value: unknown): Result<T, ValidationError | CombinedPropertyError>; | ||
protected clone(): this; | ||
private handleIgnoreStrategy; | ||
private handleStrictStrategy; | ||
private handlePassthroughStrategy; | ||
} | ||
declare const enum ObjectValidatorStrategy { | ||
Ignore = 0, | ||
Strict = 1 | ||
Strict = 1, | ||
Passthrough = 2 | ||
} | ||
@@ -206,3 +344,3 @@ | ||
protected clone(): this; | ||
protected handle(value: unknown): Result<Record<string, T>, ValidationError | AggregateError>; | ||
protected handle(value: unknown): Result<Record<string, T>, ValidationError | CombinedPropertyError>; | ||
} | ||
@@ -214,15 +352,29 @@ | ||
protected clone(): this; | ||
protected handle(values: unknown): Result<Set<T>, ValidationError | AggregateError>; | ||
protected handle(values: unknown): Result<Set<T>, ValidationError | CombinedError>; | ||
} | ||
declare class StringValidator<T extends string> extends BaseValidator<T> { | ||
lengthLt(length: number): this; | ||
lengthLe(length: number): this; | ||
lengthLte(length: number): this; | ||
lengthGt(length: number): this; | ||
lengthGe(length: number): this; | ||
lengthGte(length: number): this; | ||
lengthEq(length: number): this; | ||
lengthNe(length: number): this; | ||
get email(): this; | ||
url(options?: UrlOptions): this; | ||
uuid(options?: StringUuidOptions): this; | ||
regex(regex: RegExp): this; | ||
get ipv4(): this; | ||
get ipv6(): this; | ||
ip(version?: 4 | 6): this; | ||
protected handle(value: unknown): Result<T, ValidationError>; | ||
} | ||
declare class TupleValidator<T extends any[]> extends BaseValidator<[...T]> { | ||
private readonly validators; | ||
constructor(validators: BaseValidator<[...T]>[], constraints?: readonly IConstraint<[...T]>[]); | ||
protected clone(): this; | ||
protected handle(values: unknown): Result<[...T], ValidationError | CombinedPropertyError>; | ||
} | ||
declare class UnionValidator<T> extends BaseValidator<T> { | ||
@@ -236,5 +388,36 @@ private validators; | ||
protected clone(): this; | ||
protected handle(value: unknown): Result<T, ValidationError | AggregateError>; | ||
protected handle(value: unknown): Result<T, ValidationError | CombinedError>; | ||
} | ||
declare class MapValidator<K, V> extends BaseValidator<Map<K, V>> { | ||
private readonly keyValidator; | ||
private readonly valueValidator; | ||
constructor(keyValidator: BaseValidator<K>, valueValidator: BaseValidator<V>, constraints?: readonly IConstraint<Map<K, V>>[]); | ||
protected clone(): this; | ||
protected handle(value: unknown): Result<Map<K, V>, ValidationError | CombinedPropertyError>; | ||
} | ||
declare class DefaultValidator<T> extends BaseValidator<T> { | ||
private readonly validator; | ||
private defaultValue; | ||
constructor(validator: BaseValidator<T>, value: T | (() => T), constraints?: readonly IConstraint<T>[]); | ||
default(value: Exclude<T, undefined> | (() => Exclude<T, undefined>)): DefaultValidator<Exclude<T, undefined>>; | ||
protected handle(value: unknown): Result<T, ValidatorError>; | ||
protected clone(): this; | ||
} | ||
declare class NativeEnumValidator<T extends NativeEnumLike> extends BaseValidator<T[keyof T]> { | ||
readonly enumShape: T; | ||
readonly hasNumericElements: boolean; | ||
private readonly enumKeys; | ||
private readonly enumMapping; | ||
constructor(enumShape: T); | ||
protected handle(value: unknown): Result<T[keyof T], ValidationError | UnknownEnumValueError>; | ||
protected clone(): this; | ||
} | ||
interface NativeEnumLike { | ||
[key: string]: string | number; | ||
[key: number]: string; | ||
} | ||
declare class Shapes { | ||
@@ -254,11 +437,28 @@ get string(): StringValidator<string>; | ||
enum<T>(...values: readonly T[]): UnionValidator<T>; | ||
nativeEnum<T extends NativeEnumLike>(enumShape: T): NativeEnumValidator<T>; | ||
literal<T>(value: T): BaseValidator<T>; | ||
instance<T>(expected: Constructor<T>): InstanceValidator<T>; | ||
union<T>(...validators: readonly BaseValidator<T>[]): UnionValidator<T>; | ||
union<T extends [...BaseValidator<any>[]]>(...validators: [...T]): UnionValidator<Unwrap<T[number]>>; | ||
array<T>(validator: BaseValidator<T>): ArrayValidator<T>; | ||
tuple<T extends [...BaseValidator<any>[]]>(validators: [...T]): TupleValidator<UnwrapTuple<T>>; | ||
set<T>(validator: BaseValidator<T>): SetValidator<T>; | ||
record<T>(validator: BaseValidator<T>): RecordValidator<T>; | ||
map<T, U>(keyValidator: BaseValidator<T>, valueValidator: BaseValidator<U>): MapValidator<T, U>; | ||
} | ||
declare type UnwrapTuple<T extends [...any[]]> = T extends [infer Head, ...infer Tail] ? [Unwrap<Head>, ...UnwrapTuple<Tail>] : []; | ||
declare type Unwrap<T> = T extends BaseValidator<infer V> ? V : never; | ||
declare class MissingPropertyError extends Error { | ||
declare class ExpectedConstraintError<T = unknown> extends BaseConstraintError<T> { | ||
readonly expected: string; | ||
constructor(constraint: ConstraintErrorNames, message: string, given: T, expected: string); | ||
toJSON(): { | ||
name: string; | ||
constraint: ConstraintErrorNames; | ||
given: T; | ||
expected: string; | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare class MissingPropertyError extends BaseError { | ||
readonly property: PropertyKey; | ||
@@ -270,5 +470,18 @@ constructor(property: PropertyKey); | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare class UnknownPropertyError extends Error { | ||
declare class MultiplePossibilitiesConstraintError<T = unknown> extends BaseConstraintError<T> { | ||
readonly expected: readonly string[]; | ||
constructor(constraint: ConstraintErrorNames, message: string, given: T, expected: readonly string[]); | ||
toJSON(): { | ||
name: string; | ||
constraint: ConstraintErrorNames; | ||
given: T; | ||
expected: readonly string[]; | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare class UnknownPropertyError extends BaseError { | ||
readonly property: PropertyKey; | ||
@@ -282,51 +495,7 @@ readonly value: unknown; | ||
}; | ||
protected [customInspectSymbolStackLess](depth: number, options: InspectOptionsStylized): string; | ||
} | ||
declare const arrayLengthLt: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const arrayLengthLe: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const arrayLengthGt: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const arrayLengthGe: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const arrayLengthEq: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const arrayLengthNe: (length: number) => IConstraint<unknown[], unknown[]>; | ||
declare const bigintLt: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const bigintLe: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const bigintGt: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const bigintGe: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const bigintEq: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const bigintNe: (number: bigint) => IConstraint<bigint, bigint>; | ||
declare const booleanTrue: IConstraint<boolean, true>; | ||
declare const booleanFalse: IConstraint<boolean, false>; | ||
declare const dateLt: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateLe: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateGt: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateGe: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateEq: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateNe: (date: Date, number?: number | undefined) => IConstraint<Date, Date>; | ||
declare const dateInvalid: IConstraint<Date>; | ||
declare const dateValid: IConstraint<Date>; | ||
declare const numberLt: (number: number) => IConstraint<number, number>; | ||
declare const numberLe: (number: number) => IConstraint<number, number>; | ||
declare const numberGt: (number: number) => IConstraint<number, number>; | ||
declare const numberGe: (number: number) => IConstraint<number, number>; | ||
declare const numberEq: (number: number) => IConstraint<number, number>; | ||
declare const numberNe: (number: number) => IConstraint<number, number>; | ||
declare const numberInt: IConstraint<number>; | ||
declare const numberSafeInt: IConstraint<number>; | ||
declare const numberFinite: IConstraint<number>; | ||
declare const numberNaN: IConstraint<number>; | ||
declare const numberNeNaN: IConstraint<number>; | ||
declare const stringLengthLt: (length: number) => IConstraint<string, string>; | ||
declare const stringLengthLe: (length: number) => IConstraint<string, string>; | ||
declare const stringLengthGt: (length: number) => IConstraint<string, string>; | ||
declare const stringLengthGe: (length: number) => IConstraint<string, string>; | ||
declare const stringLengthEq: (length: number) => IConstraint<string, string>; | ||
declare const stringLengthNe: (length: number) => IConstraint<string, string>; | ||
declare const s: Shapes; | ||
export { ArrayValidator, BaseValidator, BigIntValidator, BooleanValidator, ConstraintError, ConstraintErrorMessageBuilder, Constructor, DateValidator, ExpectedValidationError, IConstraint, InstanceValidator, LiteralValidator, MappedObjectValidator, MissingPropertyError, NeverValidator, NonNullObject, NullishValidator, NumberValidator, ObjectValidator, ObjectValidatorStrategy, PassthroughValidator, RecordValidator, Result, SetValidator, Shapes, StringValidator, Type, UnionValidator, UnknownPropertyError, ValidationError, arrayLengthEq, arrayLengthGe, arrayLengthGt, arrayLengthLe, arrayLengthLt, arrayLengthNe, bigintEq, bigintGe, bigintGt, bigintLe, bigintLt, bigintNe, booleanFalse, booleanTrue, dateEq, dateGe, dateGt, dateInvalid, dateLe, dateLt, dateNe, dateValid, numberEq, numberFinite, numberGe, numberGt, numberInt, numberLe, numberLt, numberNaN, numberNe, numberNeNaN, numberSafeInt, s, stringLengthEq, stringLengthGe, stringLengthGt, stringLengthLe, stringLengthLt, stringLengthNe }; | ||
export { ArrayConstraintName, ArrayValidator, BaseConstraintError, BaseError, BaseValidator, BigIntConstraintName, BigIntValidator, BooleanConstraintName, BooleanValidator, CombinedError, CombinedPropertyError, ConstraintErrorNames, Constructor, DateConstraintName, DateValidator, DefaultValidator, ExpandSmallerTuples, ExpectedConstraintError, ExpectedValidationError, GrowExp, GrowExpRev, IConstraint, InstanceValidator, LiteralValidator, MapValidator, MappedObjectValidator, MissingPropertyError, MultiplePossibilitiesConstraintError, NativeEnumLike, NativeEnumValidator, NeverValidator, NonNullObject, NullishValidator, NumberConstraintName, NumberValidator, ObjectValidator, ObjectValidatorStrategy, PassthroughValidator, RecordValidator, Result, SetValidator, Shapes, Shift, StringConstraintName, StringDomain, StringProtocol, StringUuidOptions, StringValidator, Tuple, TupleValidator, Type, UUIDVersion, UnionValidator, UnknownEnumValueError, UnknownPropertyError, UnshiftTuple, Unwrap, UnwrapTuple, UrlOptions, ValidationError, ValidatorError, arrayLengthEq, arrayLengthGe, arrayLengthGt, arrayLengthLe, arrayLengthLt, arrayLengthNe, arrayLengthRange, arrayLengthRangeExclusive, arrayLengthRangeInclusive, bigintDivisibleBy, bigintEq, bigintGe, bigintGt, bigintLe, bigintLt, bigintNe, booleanFalse, booleanTrue, customInspectSymbol, customInspectSymbolStackLess, dateEq, dateGe, dateGt, dateInvalid, dateLe, dateLt, dateNe, dateValid, numberDivisibleBy, numberEq, numberFinite, numberGe, numberGt, numberInt, numberLe, numberLt, numberNaN, numberNe, numberNeNaN, numberSafeInt, s, stringEmail, stringIp, stringLengthEq, stringLengthGe, stringLengthGt, stringLengthLe, stringLengthLt, stringLengthNe, stringRegex, stringUrl, stringUuid }; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
var SapphireShapeshift = (() => { | ||
@@ -9,2 +8,9 @@ var __defProp = Object.defineProperty; | ||
var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); | ||
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { | ||
get: (a, b) => (typeof require !== "undefined" ? require : a)[b] | ||
}) : x)(function(x) { | ||
if (typeof require !== "undefined") | ||
return require.apply(this, arguments); | ||
throw new Error('Dynamic require of "' + x + '" is not supported'); | ||
}); | ||
var __export = (target, all) => { | ||
@@ -31,6 +37,10 @@ for (var name in all) | ||
__export(src_exports, { | ||
ConstraintError: () => ConstraintError, | ||
CombinedError: () => CombinedError, | ||
CombinedPropertyError: () => CombinedPropertyError, | ||
ExpectedConstraintError: () => ExpectedConstraintError, | ||
ExpectedValidationError: () => ExpectedValidationError, | ||
MissingPropertyError: () => MissingPropertyError, | ||
MultiplePossibilitiesConstraintError: () => MultiplePossibilitiesConstraintError, | ||
Result: () => Result, | ||
UnknownEnumValueError: () => UnknownEnumValueError, | ||
UnknownPropertyError: () => UnknownPropertyError, | ||
@@ -41,2 +51,32 @@ ValidationError: () => ValidationError, | ||
// src/lib/Result.ts | ||
var Result = class { | ||
constructor(success, value, error) { | ||
this.success = success; | ||
if (success) { | ||
this.value = value; | ||
} else { | ||
this.error = error; | ||
} | ||
} | ||
isOk() { | ||
return this.success; | ||
} | ||
isErr() { | ||
return !this.success; | ||
} | ||
unwrap() { | ||
if (this.isOk()) | ||
return this.value; | ||
throw this.error; | ||
} | ||
static ok(value) { | ||
return new Result(true, value); | ||
} | ||
static err(error) { | ||
return new Result(false, void 0, error); | ||
} | ||
}; | ||
__name(Result, "Result"); | ||
// src/validators/BaseValidator.ts | ||
@@ -66,2 +106,8 @@ var BaseValidator = class { | ||
} | ||
transform(cb) { | ||
return this.addConstraint({ run: (input) => Result.ok(cb(input)) }); | ||
} | ||
default(value) { | ||
return new DefaultValidator(this.clone(), value); | ||
} | ||
run(value) { | ||
@@ -92,48 +138,225 @@ let result = this.handle(value); | ||
// src/lib/errors/ValidationError.ts | ||
var ValidationError = class extends Error { | ||
constructor(validator, message, given) { | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var import_node_util = __require("util"); | ||
// src/lib/errors/BaseError.ts | ||
var customInspectSymbol = Symbol.for("nodejs.util.inspect.custom"); | ||
var customInspectSymbolStackLess = Symbol.for("nodejs.util.inspect.custom.stack-less"); | ||
var BaseError = class extends Error { | ||
[customInspectSymbol](depth, options) { | ||
return `${this[customInspectSymbolStackLess](depth, options)} | ||
${this.stack.slice(this.stack.indexOf("\n"))}`; | ||
} | ||
}; | ||
__name(BaseError, "BaseError"); | ||
// src/lib/errors/BaseConstraintError.ts | ||
var BaseConstraintError = class extends BaseError { | ||
constructor(constraint, message, given) { | ||
super(message); | ||
this.validator = validator; | ||
this.constraint = constraint; | ||
this.given = given; | ||
} | ||
}; | ||
__name(BaseConstraintError, "BaseConstraintError"); | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var ExpectedConstraintError = class extends BaseConstraintError { | ||
constructor(constraint, message, given, expected) { | ||
super(constraint, message, given); | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
validator: this.validator, | ||
given: this.given | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const constraint = options.stylize(this.constraint, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ExpectedConstraintError: ${constraint}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ExpectedConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedBlock = ` | ||
${options.stylize("Expected: ", "string")}${options.stylize(this.expected, "boolean")}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(ValidationError, "ValidationError"); | ||
__name(ExpectedConstraintError, "ExpectedConstraintError"); | ||
// src/lib/Result.ts | ||
var Result = class { | ||
constructor(success, value, error) { | ||
this.success = success; | ||
if (success) { | ||
this.value = value; | ||
} else { | ||
this.error = error; | ||
// src/constraints/util/operators.ts | ||
function lt(a, b) { | ||
return a < b; | ||
} | ||
__name(lt, "lt"); | ||
function le(a, b) { | ||
return a <= b; | ||
} | ||
__name(le, "le"); | ||
function gt(a, b) { | ||
return a > b; | ||
} | ||
__name(gt, "gt"); | ||
function ge(a, b) { | ||
return a >= b; | ||
} | ||
__name(ge, "ge"); | ||
function eq(a, b) { | ||
return a === b; | ||
} | ||
__name(eq, "eq"); | ||
function ne(a, b) { | ||
return a !== b; | ||
} | ||
__name(ne, "ne"); | ||
// src/constraints/ArrayLengthConstraints.ts | ||
function arrayLengthComparator(comparator, name, expected, length) { | ||
return { | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthComparator, "arrayLengthComparator"); | ||
function arrayLengthLt(value) { | ||
const expected = `expected.length < ${value}`; | ||
return arrayLengthComparator(lt, "s.array(T).lengthLt", expected, value); | ||
} | ||
__name(arrayLengthLt, "arrayLengthLt"); | ||
function arrayLengthLe(value) { | ||
const expected = `expected.length <= ${value}`; | ||
return arrayLengthComparator(le, "s.array(T).lengthLe", expected, value); | ||
} | ||
__name(arrayLengthLe, "arrayLengthLe"); | ||
function arrayLengthGt(value) { | ||
const expected = `expected.length > ${value}`; | ||
return arrayLengthComparator(gt, "s.array(T).lengthGt", expected, value); | ||
} | ||
__name(arrayLengthGt, "arrayLengthGt"); | ||
function arrayLengthGe(value) { | ||
const expected = `expected.length >= ${value}`; | ||
return arrayLengthComparator(ge, "s.array(T).lengthGe", expected, value); | ||
} | ||
__name(arrayLengthGe, "arrayLengthGe"); | ||
function arrayLengthEq(value) { | ||
const expected = `expected.length === ${value}`; | ||
return arrayLengthComparator(eq, "s.array(T).lengthEq", expected, value); | ||
} | ||
__name(arrayLengthEq, "arrayLengthEq"); | ||
function arrayLengthNe(value) { | ||
const expected = `expected.length !== ${value}`; | ||
return arrayLengthComparator(ne, "s.array(T).lengthNe", expected, value); | ||
} | ||
__name(arrayLengthNe, "arrayLengthNe"); | ||
function arrayLengthRange(start, endBefore) { | ||
const expected = `expected.length >= ${start} && expected.length < ${endBefore}`; | ||
return { | ||
run(input) { | ||
return input.length >= start && input.length < endBefore ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRange", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRange, "arrayLengthRange"); | ||
function arrayLengthRangeInclusive(start, end) { | ||
const expected = `expected.length >= ${start} && expected.length <= ${end}`; | ||
return { | ||
run(input) { | ||
return input.length >= start && input.length <= end ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRangeInclusive", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRangeInclusive, "arrayLengthRangeInclusive"); | ||
function arrayLengthRangeExclusive(startAfter, endBefore) { | ||
const expected = `expected.length > ${startAfter} && expected.length < ${endBefore}`; | ||
return { | ||
run(input) { | ||
return input.length > startAfter && input.length < endBefore ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRangeExclusive", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRangeExclusive, "arrayLengthRangeExclusive"); | ||
// src/lib/errors/CombinedPropertyError.ts | ||
var CombinedPropertyError = class extends BaseError { | ||
constructor(errors) { | ||
super("Received one or more errors"); | ||
this.errors = errors; | ||
} | ||
isOk() { | ||
return this.success; | ||
[customInspectSymbolStackLess](depth, options) { | ||
if (depth < 0) { | ||
return options.stylize("[CombinedPropertyError]", "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const header = `${options.stylize("CombinedPropertyError", "special")} (${options.stylize(this.errors.length.toString(), "number")})`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const errors = this.errors.map(([key, error]) => { | ||
const property = CombinedPropertyError.formatProperty(key, options); | ||
const body = error[customInspectSymbolStackLess](depth - 1, newOptions).replaceAll("\n", padding); | ||
return ` input${property}${padding}${body}`; | ||
}).join("\n\n"); | ||
return `${header} | ||
${message} | ||
${errors}`; | ||
} | ||
isErr() { | ||
return !this.success; | ||
static formatProperty(key, options) { | ||
if (typeof key === "string") | ||
return options.stylize(`.${key}`, "symbol"); | ||
if (typeof key === "number") | ||
return `[${options.stylize(key.toString(), "number")}]`; | ||
return `[${options.stylize("Symbol", "symbol")}(${key.description})]`; | ||
} | ||
unwrap() { | ||
if (this.isOk()) | ||
return this.value; | ||
throw this.error; | ||
}; | ||
__name(CombinedPropertyError, "CombinedPropertyError"); | ||
// src/lib/errors/ValidationError.ts | ||
var import_node_util2 = __require("util"); | ||
var ValidationError = class extends BaseError { | ||
constructor(validator, message, given) { | ||
super(message); | ||
this.validator = validator; | ||
this.given = given; | ||
} | ||
static ok(value) { | ||
return new Result(true, value); | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
validator: this.validator, | ||
given: this.given | ||
}; | ||
} | ||
static err(error) { | ||
return new Result(false, void 0, error); | ||
[customInspectSymbolStackLess](depth, options) { | ||
const validator = options.stylize(this.validator, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ValidationError: ${validator}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util2.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ValidationError", "special")} > ${validator}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(Result, "Result"); | ||
__name(ValidationError, "ValidationError"); | ||
@@ -146,2 +369,29 @@ // src/validators/ArrayValidator.ts | ||
} | ||
lengthLt(length) { | ||
return this.addConstraint(arrayLengthLt(length)); | ||
} | ||
lengthLe(length) { | ||
return this.addConstraint(arrayLengthLe(length)); | ||
} | ||
lengthGt(length) { | ||
return this.addConstraint(arrayLengthGt(length)); | ||
} | ||
lengthGe(length) { | ||
return this.addConstraint(arrayLengthGe(length)); | ||
} | ||
lengthEq(length) { | ||
return this.addConstraint(arrayLengthEq(length)); | ||
} | ||
lengthNe(length) { | ||
return this.addConstraint(arrayLengthNe(length)); | ||
} | ||
lengthRange(start, endBefore) { | ||
return this.addConstraint(arrayLengthRange(start, endBefore)); | ||
} | ||
lengthRangeInclusive(startAt, endAt) { | ||
return this.addConstraint(arrayLengthRangeInclusive(startAt, endAt)); | ||
} | ||
lengthRangeExclusive(startAfter, endBefore) { | ||
return this.addConstraint(arrayLengthRangeExclusive(startAfter, endBefore)); | ||
} | ||
clone() { | ||
@@ -152,14 +402,14 @@ return Reflect.construct(this.constructor, [this.validator, this.constraints]); | ||
if (!Array.isArray(values)) { | ||
return Result.err(new ValidationError("ArrayValidator", "Expected an array", values)); | ||
return Result.err(new ValidationError("s.array(T)", "Expected an array", values)); | ||
} | ||
const errors = []; | ||
const transformed = []; | ||
for (const value of values) { | ||
const result = this.validator.run(value); | ||
for (let i = 0; i < values.length; i++) { | ||
const result = this.validator.run(values[i]); | ||
if (result.isOk()) | ||
transformed.push(result.value); | ||
else | ||
errors.push(result.error); | ||
errors.push([i, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -169,62 +419,50 @@ }; | ||
// src/lib/errors/ConstraintError.ts | ||
var ConstraintError = class extends Error { | ||
constructor(validator, message, given, expected) { | ||
super(message); | ||
this.constraint = validator; | ||
this.given = given; | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
}; | ||
__name(ConstraintError, "ConstraintError"); | ||
// src/constraints/util/operators.ts | ||
function lt(a, b) { | ||
return a < b; | ||
// src/constraints/BigIntConstraints.ts | ||
function bigintComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid bigint value", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(lt, "lt"); | ||
function le(a, b) { | ||
return a <= b; | ||
__name(bigintComparator, "bigintComparator"); | ||
function bigintLt(value) { | ||
const expected = `expected < ${value}n`; | ||
return bigintComparator(lt, "s.bigint.lt", expected, value); | ||
} | ||
__name(le, "le"); | ||
function gt(a, b) { | ||
return a > b; | ||
__name(bigintLt, "bigintLt"); | ||
function bigintLe(value) { | ||
const expected = `expected <= ${value}n`; | ||
return bigintComparator(le, "s.bigint.le", expected, value); | ||
} | ||
__name(gt, "gt"); | ||
function ge(a, b) { | ||
return a >= b; | ||
__name(bigintLe, "bigintLe"); | ||
function bigintGt(value) { | ||
const expected = `expected > ${value}n`; | ||
return bigintComparator(gt, "s.bigint.gt", expected, value); | ||
} | ||
__name(ge, "ge"); | ||
function eq(a, b) { | ||
return a === b; | ||
__name(bigintGt, "bigintGt"); | ||
function bigintGe(value) { | ||
const expected = `expected >= ${value}n`; | ||
return bigintComparator(ge, "s.bigint.ge", expected, value); | ||
} | ||
__name(eq, "eq"); | ||
function ne(a, b) { | ||
return a !== b; | ||
__name(bigintGe, "bigintGe"); | ||
function bigintEq(value) { | ||
const expected = `expected === ${value}n`; | ||
return bigintComparator(eq, "s.bigint.eq", expected, value); | ||
} | ||
__name(ne, "ne"); | ||
// src/constraints/BigIntConstraints.ts | ||
function bigintComparator(comparator, name, messageBuilder, number) { | ||
__name(bigintEq, "bigintEq"); | ||
function bigintNe(value) { | ||
const expected = `expected !== ${value}n`; | ||
return bigintComparator(ne, "s.bigint.ne", expected, value); | ||
} | ||
__name(bigintNe, "bigintNe"); | ||
function bigintDivisibleBy(divider) { | ||
const expected = `expected % ${divider}n === 0n`; | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, number), input, number)); | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(bigintComparator, "bigintComparator"); | ||
var bigintLt = bigintComparator.bind(null, lt, "bigintLt", (given, expected) => `Expected bigint to be less than ${expected}, but received ${given}`); | ||
var bigintLe = bigintComparator.bind(null, le, "bigintLe", (given, expected) => `Expected bigint to be less or equals than ${expected}, but received ${given}`); | ||
var bigintGt = bigintComparator.bind(null, gt, "bigintGt", (given, expected) => `Expected bigint to be greater than ${expected}, but received ${given}`); | ||
var bigintGe = bigintComparator.bind(null, ge, "bigintGe", (given, expected) => `Expected bigint to be greater or equals than ${expected}, but received ${given}`); | ||
var bigintEq = bigintComparator.bind(null, eq, "bigintEq", (given, expected) => `Expected bigint to be exactly ${expected}, but received ${given}`); | ||
var bigintNe = bigintComparator.bind(null, ne, "bigintNe", (_, expected) => `Expected bigint to not be ${expected}`); | ||
__name(bigintDivisibleBy, "bigintDivisibleBy"); | ||
@@ -257,4 +495,16 @@ // src/validators/BigIntValidator.ts | ||
} | ||
divisibleBy(number) { | ||
return this.addConstraint(bigintDivisibleBy(number)); | ||
} | ||
get abs() { | ||
return this.transform((value) => value < 0 ? -value : value); | ||
} | ||
intN(bits) { | ||
return this.transform((value) => BigInt.asIntN(bits, value)); | ||
} | ||
uintN(bits) { | ||
return this.transform((value) => BigInt.asUintN(bits, value)); | ||
} | ||
handle(value) { | ||
return typeof value === "bigint" ? Result.ok(value) : Result.err(new ValidationError("BigIntValidator", "Expected a bigint primitive", value)); | ||
return typeof value === "bigint" ? Result.ok(value) : Result.err(new ValidationError("s.bigint", "Expected a bigint primitive", value)); | ||
} | ||
@@ -267,3 +517,3 @@ }; | ||
run(input) { | ||
return input ? Result.ok(input) : Result.err(new ConstraintError("booleanTrue", "Expected boolean to be true, but received false", input, true)); | ||
return input ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
} | ||
@@ -273,3 +523,3 @@ }; | ||
run(input) { | ||
return input ? Result.err(new ConstraintError("booleanFalse", "Expected boolean to be false, but received true", input, false)) : Result.ok(input); | ||
return input ? Result.err(new ExpectedConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
} | ||
@@ -293,3 +543,3 @@ }; | ||
handle(value) { | ||
return typeof value === "boolean" ? Result.ok(value) : Result.err(new ValidationError("BooleanValidator", "Expected a boolean primitive", value)); | ||
return typeof value === "boolean" ? Result.ok(value) : Result.err(new ValidationError("s.boolean", "Expected a boolean primitive", value)); | ||
} | ||
@@ -300,6 +550,6 @@ }; | ||
// src/constraints/DateConstraints.ts | ||
function dateComparator(comparator, name, messageBuilder, date, number = date.getTime()) { | ||
function dateComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, date), input, date)); | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Date value", input, expected)); | ||
} | ||
@@ -309,11 +559,35 @@ }; | ||
__name(dateComparator, "dateComparator"); | ||
var dateLt = dateComparator.bind(null, lt, "dateLt", (given, expected) => `Expected date to be earlier than ${expected}, but received ${given}`); | ||
var dateLe = dateComparator.bind(null, le, "dateLe", (given, expected) => `Expected date to be earlier or equals than ${expected}, but received ${given}`); | ||
var dateGt = dateComparator.bind(null, gt, "dateGt", (given, expected) => `Expected date to be later than ${expected}, but received ${given}`); | ||
var dateGe = dateComparator.bind(null, ge, "dateGe", (given, expected) => `Expected date to be later or equals than ${expected}, but received ${given}`); | ||
var dateEq = dateComparator.bind(null, eq, "dateEq", (given, expected) => `Expected date to be exactly ${expected}, but received ${given}`); | ||
var dateNe = dateComparator.bind(null, ne, "dateNe", (_, expected) => `Expected date to not be ${expected}`); | ||
function dateLt(value) { | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
} | ||
__name(dateLt, "dateLt"); | ||
function dateLe(value) { | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
} | ||
__name(dateLe, "dateLe"); | ||
function dateGt(value) { | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
} | ||
__name(dateGt, "dateGt"); | ||
function dateGe(value) { | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
} | ||
__name(dateGe, "dateGe"); | ||
function dateEq(value) { | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
} | ||
__name(dateEq, "dateEq"); | ||
function dateNe(value) { | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
} | ||
__name(dateNe, "dateNe"); | ||
var dateInvalid = { | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ConstraintError("dateInvalid", `Expected Date's time to be a NaN, but received ${input}`, input, "An invalid Date")); | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.date.invalid", "Invalid Date value", input, "expected === NaN")); | ||
} | ||
@@ -323,3 +597,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.err(new ConstraintError("dateValid", `Expected Date's time to not be a NaN, but received ${input}`, input, "A valid Date")) : Result.ok(input); | ||
return Number.isNaN(input.getTime()) ? Result.err(new ExpectedConstraintError("s.date.valid", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
@@ -344,10 +618,16 @@ }; | ||
const resolved = new Date(date); | ||
return Number.isNaN(resolved.getTime()) ? this.addConstraint(dateInvalid) : this.addConstraint(dateEq(resolved)); | ||
return Number.isNaN(resolved.getTime()) ? this.invalid : this.addConstraint(dateEq(resolved)); | ||
} | ||
ne(date) { | ||
const resolved = new Date(date); | ||
return Number.isNaN(resolved.getTime()) ? this.addConstraint(dateValid) : this.addConstraint(dateNe(resolved)); | ||
return Number.isNaN(resolved.getTime()) ? this.valid : this.addConstraint(dateNe(resolved)); | ||
} | ||
get valid() { | ||
return this.addConstraint(dateValid); | ||
} | ||
get invalid() { | ||
return this.addConstraint(dateInvalid); | ||
} | ||
handle(value) { | ||
return value instanceof Date ? Result.ok(value) : Result.err(new ValidationError("DateValidator", "Expected a Date", value)); | ||
return value instanceof Date ? Result.ok(value) : Result.err(new ValidationError("s.date", "Expected a Date", value)); | ||
} | ||
@@ -358,2 +638,3 @@ }; | ||
// src/lib/errors/ExpectedValidationError.ts | ||
var import_node_util3 = __require("util"); | ||
var ExpectedValidationError = class extends ValidationError { | ||
@@ -372,2 +653,23 @@ constructor(validator, message, given, expected) { | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const validator = options.stylize(this.validator, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ExpectedValidationError: ${validator}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const expected = (0, import_node_util3.inspect)(this.expected, newOptions).replaceAll("\n", padding); | ||
const given = (0, import_node_util3.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ExpectedValidationError", "special")} > ${validator}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedBlock = ` | ||
${options.stylize("Expected:", "string")}${padding}${expected}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
@@ -383,3 +685,3 @@ __name(ExpectedValidationError, "ExpectedValidationError"); | ||
handle(value) { | ||
return value instanceof this.expected ? Result.ok(value) : Result.err(new ExpectedValidationError("InstanceValidator", "Expected", value, this.expected)); | ||
return value instanceof this.expected ? Result.ok(value) : Result.err(new ExpectedValidationError("s.instance(V)", "Expected", value, this.expected)); | ||
} | ||
@@ -399,3 +701,3 @@ clone() { | ||
handle(value) { | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("LiteralValidator", "Expected", value, this.expected)); | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("s.literal(V)", "Expected values to be equals", value, this.expected)); | ||
} | ||
@@ -411,3 +713,3 @@ clone() { | ||
handle(value) { | ||
return Result.err(new ValidationError("NeverValidator", "Expected a value to not be passed", value)); | ||
return Result.err(new ValidationError("s.never", "Expected a value to not be passed", value)); | ||
} | ||
@@ -420,3 +722,3 @@ }; | ||
handle(value) { | ||
return value === void 0 || value === null ? Result.ok(value) : Result.err(new ValidationError("NullishValidator", "Expected undefined or null", value)); | ||
return value === void 0 || value === null ? Result.ok(value) : Result.err(new ValidationError("s.nullish", "Expected undefined or null", value)); | ||
} | ||
@@ -427,6 +729,6 @@ }; | ||
// src/constraints/NumberConstraints.ts | ||
function numberComparator(comparator, name, messageBuilder, number) { | ||
function numberComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, number), input, number)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid number value", input, expected)); | ||
} | ||
@@ -436,11 +738,35 @@ }; | ||
__name(numberComparator, "numberComparator"); | ||
var numberLt = numberComparator.bind(null, lt, "numberLt", (given, expected) => `Expected number to be less than ${expected}, but received ${given}`); | ||
var numberLe = numberComparator.bind(null, le, "numberLe", (given, expected) => `Expected number to be less or equals than ${expected}, but received ${given}`); | ||
var numberGt = numberComparator.bind(null, gt, "numberGt", (given, expected) => `Expected number to be greater than ${expected}, but received ${given}`); | ||
var numberGe = numberComparator.bind(null, ge, "numberGe", (given, expected) => `Expected number to be greater or equals than ${expected}, but received ${given}`); | ||
var numberEq = numberComparator.bind(null, eq, "numberEq", (given, expected) => `Expected number to be exactly ${expected}, but received ${given}`); | ||
var numberNe = numberComparator.bind(null, ne, "numberNe", (_, expected) => `Expected number to not be ${expected}`); | ||
function numberLt(value) { | ||
const expected = `expected < ${value}`; | ||
return numberComparator(lt, "s.number.lt", expected, value); | ||
} | ||
__name(numberLt, "numberLt"); | ||
function numberLe(value) { | ||
const expected = `expected <= ${value}`; | ||
return numberComparator(le, "s.number.le", expected, value); | ||
} | ||
__name(numberLe, "numberLe"); | ||
function numberGt(value) { | ||
const expected = `expected > ${value}`; | ||
return numberComparator(gt, "s.number.gt", expected, value); | ||
} | ||
__name(numberGt, "numberGt"); | ||
function numberGe(value) { | ||
const expected = `expected >= ${value}`; | ||
return numberComparator(ge, "s.number.ge", expected, value); | ||
} | ||
__name(numberGe, "numberGe"); | ||
function numberEq(value) { | ||
const expected = `expected === ${value}`; | ||
return numberComparator(eq, "s.number.eq", expected, value); | ||
} | ||
__name(numberEq, "numberEq"); | ||
function numberNe(value) { | ||
const expected = `expected !== ${value}`; | ||
return numberComparator(ne, "s.number.ne", expected, value); | ||
} | ||
__name(numberNe, "numberNe"); | ||
var numberInt = { | ||
run(input) { | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("numberInt", `Expected number to be an integer, but received ${input}`, input, "An integer")); | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.int", "Given value is not an integer", input, "Number.isInteger(expected) to be true")); | ||
} | ||
@@ -450,3 +776,3 @@ }; | ||
run(input) { | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("numberSafeInt", `Expected number to be a safe integer, but received ${input}`, input, "A safe integer")); | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.safeInt", "Given value is not a safe integer", input, "Number.isSafeInteger(expected) to be true")); | ||
} | ||
@@ -456,3 +782,3 @@ }; | ||
run(input) { | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ConstraintError("numberFinite", `Expected number to be a finite number, but received ${input}`, input, "A finite number")); | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.finite", "Given value is not finite", input, "Number.isFinite(expected) to be true")); | ||
} | ||
@@ -462,3 +788,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ConstraintError("numberNaN", `Expected number to be a NaN, but received ${input}`, input, "A NaN")); | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
} | ||
@@ -468,5 +794,14 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.err(new ConstraintError("numberNeNaN", `Expected number to not be a NaN, but received ${input}`, input, "Not NaN")) : Result.ok(input); | ||
return Number.isNaN(input) ? Result.err(new ExpectedConstraintError("s.number.ne(NaN)", "Invalid number value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
}; | ||
function numberDivisibleBy(divider) { | ||
const expected = `expected % ${divider} === 0`; | ||
return { | ||
run(input) { | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(numberDivisibleBy, "numberDivisibleBy"); | ||
@@ -508,4 +843,28 @@ // src/validators/NumberValidator.ts | ||
} | ||
divisibleBy(divider) { | ||
return this.addConstraint(numberDivisibleBy(divider)); | ||
} | ||
get abs() { | ||
return this.transform(Math.abs); | ||
} | ||
get sign() { | ||
return this.transform(Math.sign); | ||
} | ||
get trunc() { | ||
return this.transform(Math.trunc); | ||
} | ||
get floor() { | ||
return this.transform(Math.floor); | ||
} | ||
get fround() { | ||
return this.transform(Math.fround); | ||
} | ||
get round() { | ||
return this.transform(Math.round); | ||
} | ||
get ceil() { | ||
return this.transform(Math.ceil); | ||
} | ||
handle(value) { | ||
return typeof value === "number" ? Result.ok(value) : Result.err(new ValidationError("NumberValidator", "Expected a number primitive", value)); | ||
return typeof value === "number" ? Result.ok(value) : Result.err(new ValidationError("s.number", "Expected a number primitive", value)); | ||
} | ||
@@ -516,5 +875,5 @@ }; | ||
// src/lib/errors/MissingPropertyError.ts | ||
var MissingPropertyError = class extends Error { | ||
var MissingPropertyError = class extends BaseError { | ||
constructor(property) { | ||
super(`Expected property "${String(property)}" is missing`); | ||
super("A required property is missing"); | ||
this.property = property; | ||
@@ -528,2 +887,12 @@ } | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const property = options.stylize(this.property.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[MissingPropertyError: ${property}]`, "special"); | ||
} | ||
const header = `${options.stylize("MissingPropertyError", "special")} > ${property}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
return `${header} | ||
${message}`; | ||
} | ||
}; | ||
@@ -533,5 +902,6 @@ __name(MissingPropertyError, "MissingPropertyError"); | ||
// src/lib/errors/UnknownPropertyError.ts | ||
var UnknownPropertyError = class extends Error { | ||
var import_node_util4 = __require("util"); | ||
var UnknownPropertyError = class extends BaseError { | ||
constructor(property, value) { | ||
super("Unknown property received"); | ||
super("Received unexpected property"); | ||
this.property = property; | ||
@@ -547,2 +917,19 @@ this.value = value; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const property = options.stylize(this.property.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[UnknownPropertyError: ${property}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util4.inspect)(this.value, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("UnknownPropertyError", "special")} > ${property}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${givenBlock}`; | ||
} | ||
}; | ||
@@ -566,2 +953,5 @@ __name(UnknownPropertyError, "UnknownPropertyError"); | ||
} | ||
case ObjectValidatorStrategy.Passthrough: | ||
this.handleStrategy = (value) => this.handlePassthroughStrategy(value); | ||
break; | ||
} | ||
@@ -575,2 +965,5 @@ } | ||
} | ||
get passthrough() { | ||
return Reflect.construct(this.constructor, [this.shape, ObjectValidatorStrategy.Passthrough, this.constraints]); | ||
} | ||
get partial() { | ||
@@ -595,6 +988,6 @@ const shape = Object.fromEntries(this.keys.map((key) => [key, this.shape[key].optional])); | ||
if (typeOfValue !== "object") { | ||
return Result.err(new ValidationError("ObjectValidator", `Expected the value to be an object, but received ${typeOfValue} instead`, value)); | ||
return Result.err(new ValidationError("s.object(T)", `Expected the value to be an object, but received ${typeOfValue} instead`, value)); | ||
} | ||
if (value === null) { | ||
return Result.err(new ValidationError("ObjectValidator", "Expected the value to not be null", value)); | ||
return Result.err(new ValidationError("s.object(T)", "Expected the value to not be null", value)); | ||
} | ||
@@ -617,9 +1010,9 @@ return this.handleStrategy(value); | ||
if (error instanceof ValidationError && error.given === void 0) { | ||
errors.push(new MissingPropertyError(key)); | ||
errors.push([key, new MissingPropertyError(key)]); | ||
} else { | ||
errors.push(error); | ||
errors.push([key, error]); | ||
} | ||
} | ||
} | ||
return errors.length === 0 ? Result.ok(entries) : Result.err(new AggregateError(errors, "Failed to match at least one of the properties")); | ||
return errors.length === 0 ? Result.ok(entries) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -640,5 +1033,5 @@ handleStrictStrategy(value) { | ||
if (error instanceof ValidationError && error.given === void 0) { | ||
errors.push(new MissingPropertyError(key)); | ||
errors.push([key, new MissingPropertyError(key)]); | ||
} else { | ||
errors.push(error); | ||
errors.push([key, error]); | ||
} | ||
@@ -648,6 +1041,10 @@ } | ||
} | ||
errors.push(new UnknownPropertyError(key, value[key])); | ||
errors.push([key, new UnknownPropertyError(key, value[key])]); | ||
} | ||
return errors.length === 0 ? Result.ok(finalResult) : Result.err(new AggregateError(errors, "Failed to match at least one of the properties")); | ||
return errors.length === 0 ? Result.ok(finalResult) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
handlePassthroughStrategy(value) { | ||
const result = this.handleIgnoreStrategy(value); | ||
return result.isErr() ? result : Result.ok({ ...value, ...result.value }); | ||
} | ||
}; | ||
@@ -658,2 +1055,3 @@ __name(ObjectValidator, "ObjectValidator"); | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Strict"] = 1] = "Strict"; | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Passthrough"] = 2] = "Passthrough"; | ||
return ObjectValidatorStrategy2; | ||
@@ -681,6 +1079,6 @@ })(ObjectValidatorStrategy || {}); | ||
if (typeof value !== "object") { | ||
return Result.err(new ValidationError("RecordValidator", "Expected an object", value)); | ||
return Result.err(new ValidationError("s.record(T)", "Expected an object", value)); | ||
} | ||
if (value === null) { | ||
return Result.err(new ValidationError("RecordValidator", "Expected the value to not be null", value)); | ||
return Result.err(new ValidationError("s.record(T)", "Expected the value to not be null", value)); | ||
} | ||
@@ -694,5 +1092,5 @@ const errors = []; | ||
else | ||
errors.push(result.error); | ||
errors.push([key, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -702,2 +1100,30 @@ }; | ||
// src/lib/errors/CombinedError.ts | ||
var CombinedError = class extends BaseError { | ||
constructor(errors) { | ||
super("Received one or more errors"); | ||
this.errors = errors; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
if (depth < 0) { | ||
return options.stylize("[CombinedError]", "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const header = `${options.stylize("CombinedError", "special")} (${options.stylize(this.errors.length.toString(), "number")})`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const errors = this.errors.map((error, i) => { | ||
const index = options.stylize((i + 1).toString(), "number"); | ||
const body = error[customInspectSymbolStackLess](depth - 1, newOptions).replaceAll("\n", padding); | ||
return ` ${index} ${body}`; | ||
}).join("\n\n"); | ||
return `${header} | ||
${message} | ||
${errors}`; | ||
} | ||
}; | ||
__name(CombinedError, "CombinedError"); | ||
// src/validators/SetValidator.ts | ||
@@ -714,3 +1140,3 @@ var SetValidator = class extends BaseValidator { | ||
if (!(values instanceof Set)) { | ||
return Result.err(new ValidationError("SetValidator", "Expected a set", values)); | ||
return Result.err(new ValidationError("s.set(T)", "Expected a set", values)); | ||
} | ||
@@ -726,3 +1152,3 @@ const errors = []; | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedError(errors)); | ||
} | ||
@@ -733,29 +1159,237 @@ }; | ||
// src/constraints/StringConstraints.ts | ||
function stringLength(comparator, name, messageBuilder, length) { | ||
var import_node_net = __require("net"); | ||
// src/constraints/util/emailValidator.ts | ||
var accountRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")$/; | ||
function validateEmail(email) { | ||
if (!email) | ||
return false; | ||
const atIndex = email.indexOf("@"); | ||
if (atIndex === -1) | ||
return false; | ||
if (atIndex > 64) | ||
return false; | ||
const domainIndex = atIndex + 1; | ||
if (email.includes("@", domainIndex)) | ||
return false; | ||
if (email.length - domainIndex > 255) | ||
return false; | ||
let dotIndex = email.indexOf(".", domainIndex); | ||
if (dotIndex === -1) | ||
return false; | ||
let lastDotIndex = domainIndex; | ||
do { | ||
if (dotIndex - lastDotIndex > 63) | ||
return false; | ||
lastDotIndex = dotIndex + 1; | ||
} while ((dotIndex = email.indexOf(".", lastDotIndex)) !== -1); | ||
if (email.length - lastDotIndex > 63) | ||
return false; | ||
return accountRegex.test(email.slice(0, atIndex)) && validateEmailDomain(email.slice(domainIndex)); | ||
} | ||
__name(validateEmail, "validateEmail"); | ||
function validateEmailDomain(domain) { | ||
try { | ||
return new URL(`http://${domain}`).hostname === domain; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
__name(validateEmailDomain, "validateEmailDomain"); | ||
// src/lib/errors/MultiplePossibilitiesConstraintError.ts | ||
var import_node_util5 = __require("util"); | ||
var MultiplePossibilitiesConstraintError = class extends BaseConstraintError { | ||
constructor(constraint, message, given, expected) { | ||
super(constraint, message, given); | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const constraint = options.stylize(this.constraint, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[MultiplePossibilitiesConstraintError: ${constraint}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const verticalLine = options.stylize("|", "undefined"); | ||
const padding = ` | ||
${verticalLine} `; | ||
const given = (0, import_node_util5.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("MultiplePossibilitiesConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedPadding = ` | ||
${verticalLine} - `; | ||
const expectedBlock = ` | ||
${options.stylize("Expected any of the following:", "string")}${expectedPadding}${this.expected.map((possible) => options.stylize(possible, "boolean")).join(expectedPadding)}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(MultiplePossibilitiesConstraintError, "MultiplePossibilitiesConstraintError"); | ||
// src/constraints/util/common/combinedResultFn.ts | ||
function combinedErrorFn(...fns) { | ||
switch (fns.length) { | ||
case 0: | ||
return () => null; | ||
case 1: | ||
return fns[0]; | ||
case 2: { | ||
const [fn0, fn1] = fns; | ||
return (...params) => fn0(...params) || fn1(...params); | ||
} | ||
default: { | ||
return (...params) => { | ||
for (const fn of fns) { | ||
const result = fn(...params); | ||
if (result) | ||
return result; | ||
} | ||
return null; | ||
}; | ||
} | ||
} | ||
} | ||
__name(combinedErrorFn, "combinedErrorFn"); | ||
// src/constraints/util/urlValidators.ts | ||
function createUrlValidators(options) { | ||
const fns = []; | ||
if (options?.allowedProtocols?.length) | ||
fns.push(allowedProtocolsFn(options.allowedProtocols)); | ||
if (options?.allowedDomains?.length) | ||
fns.push(allowedDomainsFn(options.allowedDomains)); | ||
return combinedErrorFn(...fns); | ||
} | ||
__name(createUrlValidators, "createUrlValidators"); | ||
function allowedProtocolsFn(allowedProtocols) { | ||
return (input, url) => allowedProtocols.includes(url.protocol) ? null : new MultiplePossibilitiesConstraintError("s.string.url", "Invalid URL protocol", input, allowedProtocols); | ||
} | ||
__name(allowedProtocolsFn, "allowedProtocolsFn"); | ||
function allowedDomainsFn(allowedDomains) { | ||
return (input, url) => allowedDomains.includes(url.hostname) ? null : new MultiplePossibilitiesConstraintError("s.string.url", "Invalid URL domain", input, allowedDomains); | ||
} | ||
__name(allowedDomainsFn, "allowedDomainsFn"); | ||
// src/constraints/StringConstraints.ts | ||
function stringLengthComparator(comparator, name, expected, length) { | ||
return { | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, length), input, length)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid string length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringLength, "stringLength"); | ||
var stringLengthLt = stringLength.bind(null, lt, "stringLengthLt", (given, expected) => `Expected string to have less than ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthLe = stringLength.bind(null, le, "stringLengthLe", (given, expected) => `Expected string to have maximum ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthGt = stringLength.bind(null, gt, "stringLengthGt", (given, expected) => `Expected string to have more than ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthGe = stringLength.bind(null, ge, "stringLengthGe", (given, expected) => `Expected string to have at least ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthEq = stringLength.bind(null, eq, "stringLengthEq", (given, expected) => `Expected string to have exactly ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthNe = stringLength.bind(null, ne, "stringLengthNe", (given, expected) => `Expected string to not have exactly ${expected} characters, but received one with ${given.length} characters`); | ||
__name(stringLengthComparator, "stringLengthComparator"); | ||
function stringLengthLt(length) { | ||
const expected = `expected.length < ${length}`; | ||
return stringLengthComparator(lt, "s.string.lengthLt", expected, length); | ||
} | ||
__name(stringLengthLt, "stringLengthLt"); | ||
function stringLengthLe(length) { | ||
const expected = `expected.length <= ${length}`; | ||
return stringLengthComparator(le, "s.string.lengthLe", expected, length); | ||
} | ||
__name(stringLengthLe, "stringLengthLe"); | ||
function stringLengthGt(length) { | ||
const expected = `expected.length > ${length}`; | ||
return stringLengthComparator(gt, "s.string.lengthGt", expected, length); | ||
} | ||
__name(stringLengthGt, "stringLengthGt"); | ||
function stringLengthGe(length) { | ||
const expected = `expected.length >= ${length}`; | ||
return stringLengthComparator(ge, "s.string.lengthGe", expected, length); | ||
} | ||
__name(stringLengthGe, "stringLengthGe"); | ||
function stringLengthEq(length) { | ||
const expected = `expected.length === ${length}`; | ||
return stringLengthComparator(eq, "s.string.lengthEq", expected, length); | ||
} | ||
__name(stringLengthEq, "stringLengthEq"); | ||
function stringLengthNe(length) { | ||
const expected = `expected.length !== ${length}`; | ||
return stringLengthComparator(ne, "s.string.lengthNe", expected, length); | ||
} | ||
__name(stringLengthNe, "stringLengthNe"); | ||
function stringEmail() { | ||
return { | ||
run(input) { | ||
return validateEmail(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.string.email", "Invalid email address", input, "expected to be an email address")); | ||
} | ||
}; | ||
} | ||
__name(stringEmail, "stringEmail"); | ||
function stringRegexValidator(type, expected, regex) { | ||
return { | ||
run(input) { | ||
return regex.test(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError(type, "Invalid string format", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringRegexValidator, "stringRegexValidator"); | ||
function stringUrl(options) { | ||
const validatorFn = createUrlValidators(options); | ||
return { | ||
run(input) { | ||
let url; | ||
try { | ||
url = new URL(input); | ||
} catch { | ||
return Result.err(new ExpectedConstraintError("s.string.url", "Invalid URL", input, "expected to match an URL")); | ||
} | ||
const validatorFnResult = validatorFn(input, url); | ||
if (validatorFnResult === null) | ||
return Result.ok(input); | ||
return Result.err(validatorFnResult); | ||
} | ||
}; | ||
} | ||
__name(stringUrl, "stringUrl"); | ||
function stringIp(version) { | ||
const ipVersion = version ? `v${version}` : ""; | ||
const validatorFn = version === 4 ? import_node_net.isIPv4 : version === 6 ? import_node_net.isIPv6 : import_node_net.isIP; | ||
const name = `s.string.ip${ipVersion}`; | ||
const message = `Invalid IP${ipVersion} address`; | ||
const expected = `expected to be an IP${ipVersion} address`; | ||
return { | ||
run(input) { | ||
return validatorFn(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, message, input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringIp, "stringIp"); | ||
function stringRegex(regex) { | ||
return stringRegexValidator("s.string.regex", `expected ${regex}.test(expected) to be true`, regex); | ||
} | ||
__name(stringRegex, "stringRegex"); | ||
function stringUuid({ version = 4, nullable = false } = {}) { | ||
version ??= "1-5"; | ||
const regex = new RegExp(`^(?:[0-9A-F]{8}-[0-9A-F]{4}-[${version}][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}${nullable ? "|00000000-0000-0000-0000-000000000000" : ""})$`, "i"); | ||
const expected = `expected to match UUID${typeof version === "number" ? `v${version}` : ` in range of ${version}`}`; | ||
return stringRegexValidator("s.string.uuid", expected, regex); | ||
} | ||
__name(stringUuid, "stringUuid"); | ||
// src/validators/StringValidator.ts | ||
var StringValidator = class extends BaseValidator { | ||
lengthLe(length) { | ||
lengthLt(length) { | ||
return this.addConstraint(stringLengthLt(length)); | ||
} | ||
lengthLte(length) { | ||
lengthLe(length) { | ||
return this.addConstraint(stringLengthLe(length)); | ||
} | ||
lengthGe(length) { | ||
lengthGt(length) { | ||
return this.addConstraint(stringLengthGt(length)); | ||
} | ||
lengthGte(length) { | ||
lengthGe(length) { | ||
return this.addConstraint(stringLengthGe(length)); | ||
@@ -769,4 +1403,25 @@ } | ||
} | ||
get email() { | ||
return this.addConstraint(stringEmail()); | ||
} | ||
url(options) { | ||
return this.addConstraint(stringUrl(options)); | ||
} | ||
uuid(options) { | ||
return this.addConstraint(stringUuid(options)); | ||
} | ||
regex(regex) { | ||
return this.addConstraint(stringRegex(regex)); | ||
} | ||
get ipv4() { | ||
return this.ip(4); | ||
} | ||
get ipv6() { | ||
return this.ip(6); | ||
} | ||
ip(version) { | ||
return this.addConstraint(stringIp(version)); | ||
} | ||
handle(value) { | ||
return typeof value === "string" ? Result.ok(value) : Result.err(new ValidationError("StringValidator", "Expected a string primitive", value)); | ||
return typeof value === "string" ? Result.ok(value) : Result.err(new ValidationError("s.string", "Expected a string primitive", value)); | ||
} | ||
@@ -776,2 +1431,33 @@ }; | ||
// src/validators/TupleValidator.ts | ||
var TupleValidator = class extends BaseValidator { | ||
constructor(validators, constraints = []) { | ||
super(constraints); | ||
this.validators = []; | ||
this.validators = validators; | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.validators, this.constraints]); | ||
} | ||
handle(values) { | ||
if (!Array.isArray(values)) { | ||
return Result.err(new ValidationError("s.tuple(T)", "Expected an array", values)); | ||
} | ||
if (values.length !== this.validators.length) { | ||
return Result.err(new ValidationError("s.tuple(T)", `Expected an array of length ${this.validators.length}`, values)); | ||
} | ||
const errors = []; | ||
const transformed = []; | ||
for (let i = 0; i < values.length; i++) { | ||
const result = this.validators[i].run(values[i]); | ||
if (result.isOk()) | ||
transformed.push(result.value); | ||
else | ||
errors.push([i, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
}; | ||
__name(TupleValidator, "TupleValidator"); | ||
// src/validators/UnionValidator.ts | ||
@@ -796,3 +1482,3 @@ var UnionValidator = class extends BaseValidator { | ||
} | ||
return new UnionValidator([new LiteralValidator(void 0), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(void 0), ...this.validators]); | ||
} | ||
@@ -812,3 +1498,3 @@ get nullable() { | ||
} | ||
return new UnionValidator([new LiteralValidator(null), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(null), ...this.validators]); | ||
} | ||
@@ -819,6 +1505,10 @@ get nullish() { | ||
const [validator] = this.validators; | ||
if (validator instanceof NullishValidator) { | ||
if (validator instanceof LiteralValidator) { | ||
if (validator.expected === null || validator.expected === void 0) { | ||
return new UnionValidator([new NullishValidator(), ...this.validators.slice(1)], this.constraints); | ||
} | ||
} else if (validator instanceof NullishValidator) { | ||
return this.clone(); | ||
} | ||
return new UnionValidator([new NullishValidator(), this.clone()]); | ||
return new UnionValidator([new NullishValidator(), ...this.validators]); | ||
} | ||
@@ -839,3 +1529,3 @@ or(...predicates) { | ||
} | ||
return Result.err(new AggregateError(errors, "Could not match any of the defined validators")); | ||
return Result.err(new CombinedError(errors)); | ||
} | ||
@@ -845,2 +1535,136 @@ }; | ||
// src/validators/MapValidator.ts | ||
var MapValidator = class extends BaseValidator { | ||
constructor(keyValidator, valueValidator, constraints = []) { | ||
super(constraints); | ||
this.keyValidator = keyValidator; | ||
this.valueValidator = valueValidator; | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.keyValidator, this.valueValidator, this.constraints]); | ||
} | ||
handle(value) { | ||
if (!(value instanceof Map)) { | ||
return Result.err(new ValidationError("s.map(K, V)", "Expected a map", value)); | ||
} | ||
const errors = []; | ||
const transformed = /* @__PURE__ */ new Map(); | ||
for (const [key, val] of value.entries()) { | ||
const keyResult = this.keyValidator.run(key); | ||
const valueResult = this.valueValidator.run(val); | ||
const { length } = errors; | ||
if (keyResult.isErr()) | ||
errors.push([key, keyResult.error]); | ||
if (valueResult.isErr()) | ||
errors.push([key, valueResult.error]); | ||
if (errors.length === length) | ||
transformed.set(keyResult.value, valueResult.value); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
}; | ||
__name(MapValidator, "MapValidator"); | ||
// src/validators/util/getValue.ts | ||
function getValue(valueOrFn) { | ||
return typeof valueOrFn === "function" ? valueOrFn() : valueOrFn; | ||
} | ||
__name(getValue, "getValue"); | ||
// src/validators/DefaultValidator.ts | ||
var DefaultValidator = class extends BaseValidator { | ||
constructor(validator, value, constraints = []) { | ||
super(constraints); | ||
this.validator = validator; | ||
this.defaultValue = value; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.validator, this.defaultValue, this.constraints]); | ||
} | ||
}; | ||
__name(DefaultValidator, "DefaultValidator"); | ||
// src/lib/errors/UnknownEnumValueError.ts | ||
var UnknownEnumValueError = class extends BaseError { | ||
constructor(value, keys, enumMappings) { | ||
super("Expected the value to be one of the following enum values:"); | ||
this.value = value; | ||
this.enumKeys = keys; | ||
this.enumMappings = enumMappings; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
value: this.value, | ||
enumKeys: this.enumKeys, | ||
enumMappings: [...this.enumMappings.entries()] | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const value = options.stylize(this.value.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[UnknownEnumValueError: ${value}]`, "special"); | ||
} | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const pairs = this.enumKeys.map((key) => { | ||
const enumValue = this.enumMappings.get(key); | ||
return `${options.stylize(key, "string")} or ${options.stylize(enumValue.toString(), typeof enumValue === "number" ? "number" : "string")}`; | ||
}).join(padding); | ||
const header = `${options.stylize("UnknownEnumValueError", "special")} > ${value}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const pairsBlock = `${padding}${pairs}`; | ||
return `${header} | ||
${message} | ||
${pairsBlock}`; | ||
} | ||
}; | ||
__name(UnknownEnumValueError, "UnknownEnumValueError"); | ||
// src/validators/NativeEnumValidator.ts | ||
var NativeEnumValidator = class extends BaseValidator { | ||
constructor(enumShape) { | ||
super(); | ||
this.hasNumericElements = false; | ||
this.enumMapping = /* @__PURE__ */ new Map(); | ||
this.enumShape = enumShape; | ||
this.enumKeys = Object.keys(enumShape).filter((key) => { | ||
return typeof enumShape[enumShape[key]] !== "number"; | ||
}); | ||
for (const key of this.enumKeys) { | ||
const enumValue = enumShape[key]; | ||
this.enumMapping.set(key, enumValue); | ||
this.enumMapping.set(enumValue, enumValue); | ||
if (typeof enumValue === "number") { | ||
this.hasNumericElements = true; | ||
this.enumMapping.set(`${enumValue}`, enumValue); | ||
} | ||
} | ||
} | ||
handle(value) { | ||
const typeOfValue = typeof value; | ||
if (typeOfValue === "number" && !this.hasNumericElements) { | ||
return Result.err(new ValidationError("s.nativeEnum(T)", "Expected the value to be a string", value)); | ||
} | ||
if (typeOfValue !== "string" && typeOfValue !== "number") { | ||
return Result.err(new ValidationError("s.nativeEnum(T)", "Expected the value to be a string or number", value)); | ||
} | ||
const casted = value; | ||
const possibleEnumValue = this.enumMapping.get(casted); | ||
return typeof possibleEnumValue === "undefined" ? Result.err(new UnknownEnumValueError(casted, this.enumKeys, this.enumMapping)) : Result.ok(possibleEnumValue); | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.enumShape]); | ||
} | ||
}; | ||
__name(NativeEnumValidator, "NativeEnumValidator"); | ||
// src/lib/Shapes.ts | ||
@@ -887,2 +1711,5 @@ var Shapes = class { | ||
} | ||
nativeEnum(enumShape) { | ||
return new NativeEnumValidator(enumShape); | ||
} | ||
literal(value) { | ||
@@ -902,2 +1729,5 @@ if (value instanceof Date) | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -909,2 +1739,5 @@ return new SetValidator(validator); | ||
} | ||
map(keyValidator, valueValidator) { | ||
return new MapValidator(keyValidator, valueValidator); | ||
} | ||
}; | ||
@@ -911,0 +1744,0 @@ __name(Shapes, "Shapes"); |
1145
dist/index.js
@@ -29,6 +29,10 @@ "use strict"; | ||
__export(src_exports, { | ||
ConstraintError: () => ConstraintError, | ||
CombinedError: () => CombinedError, | ||
CombinedPropertyError: () => CombinedPropertyError, | ||
ExpectedConstraintError: () => ExpectedConstraintError, | ||
ExpectedValidationError: () => ExpectedValidationError, | ||
MissingPropertyError: () => MissingPropertyError, | ||
MultiplePossibilitiesConstraintError: () => MultiplePossibilitiesConstraintError, | ||
Result: () => Result, | ||
UnknownEnumValueError: () => UnknownEnumValueError, | ||
UnknownPropertyError: () => UnknownPropertyError, | ||
@@ -39,2 +43,32 @@ ValidationError: () => ValidationError, | ||
// src/lib/Result.ts | ||
var Result = class { | ||
constructor(success, value, error) { | ||
this.success = success; | ||
if (success) { | ||
this.value = value; | ||
} else { | ||
this.error = error; | ||
} | ||
} | ||
isOk() { | ||
return this.success; | ||
} | ||
isErr() { | ||
return !this.success; | ||
} | ||
unwrap() { | ||
if (this.isOk()) | ||
return this.value; | ||
throw this.error; | ||
} | ||
static ok(value) { | ||
return new Result(true, value); | ||
} | ||
static err(error) { | ||
return new Result(false, void 0, error); | ||
} | ||
}; | ||
__name(Result, "Result"); | ||
// src/validators/BaseValidator.ts | ||
@@ -64,2 +98,8 @@ var BaseValidator = class { | ||
} | ||
transform(cb) { | ||
return this.addConstraint({ run: (input) => Result.ok(cb(input)) }); | ||
} | ||
default(value) { | ||
return new DefaultValidator(this.clone(), value); | ||
} | ||
run(value) { | ||
@@ -90,48 +130,225 @@ let result = this.handle(value); | ||
// src/lib/errors/ValidationError.ts | ||
var ValidationError = class extends Error { | ||
constructor(validator, message, given) { | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var import_node_util = require("util"); | ||
// src/lib/errors/BaseError.ts | ||
var customInspectSymbol = Symbol.for("nodejs.util.inspect.custom"); | ||
var customInspectSymbolStackLess = Symbol.for("nodejs.util.inspect.custom.stack-less"); | ||
var BaseError = class extends Error { | ||
[customInspectSymbol](depth, options) { | ||
return `${this[customInspectSymbolStackLess](depth, options)} | ||
${this.stack.slice(this.stack.indexOf("\n"))}`; | ||
} | ||
}; | ||
__name(BaseError, "BaseError"); | ||
// src/lib/errors/BaseConstraintError.ts | ||
var BaseConstraintError = class extends BaseError { | ||
constructor(constraint, message, given) { | ||
super(message); | ||
this.validator = validator; | ||
this.constraint = constraint; | ||
this.given = given; | ||
} | ||
}; | ||
__name(BaseConstraintError, "BaseConstraintError"); | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var ExpectedConstraintError = class extends BaseConstraintError { | ||
constructor(constraint, message, given, expected) { | ||
super(constraint, message, given); | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
validator: this.validator, | ||
given: this.given | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const constraint = options.stylize(this.constraint, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ExpectedConstraintError: ${constraint}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ExpectedConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedBlock = ` | ||
${options.stylize("Expected: ", "string")}${options.stylize(this.expected, "boolean")}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(ValidationError, "ValidationError"); | ||
__name(ExpectedConstraintError, "ExpectedConstraintError"); | ||
// src/lib/Result.ts | ||
var Result = class { | ||
constructor(success, value, error) { | ||
this.success = success; | ||
if (success) { | ||
this.value = value; | ||
} else { | ||
this.error = error; | ||
// src/constraints/util/operators.ts | ||
function lt(a, b) { | ||
return a < b; | ||
} | ||
__name(lt, "lt"); | ||
function le(a, b) { | ||
return a <= b; | ||
} | ||
__name(le, "le"); | ||
function gt(a, b) { | ||
return a > b; | ||
} | ||
__name(gt, "gt"); | ||
function ge(a, b) { | ||
return a >= b; | ||
} | ||
__name(ge, "ge"); | ||
function eq(a, b) { | ||
return a === b; | ||
} | ||
__name(eq, "eq"); | ||
function ne(a, b) { | ||
return a !== b; | ||
} | ||
__name(ne, "ne"); | ||
// src/constraints/ArrayLengthConstraints.ts | ||
function arrayLengthComparator(comparator, name, expected, length) { | ||
return { | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthComparator, "arrayLengthComparator"); | ||
function arrayLengthLt(value) { | ||
const expected = `expected.length < ${value}`; | ||
return arrayLengthComparator(lt, "s.array(T).lengthLt", expected, value); | ||
} | ||
__name(arrayLengthLt, "arrayLengthLt"); | ||
function arrayLengthLe(value) { | ||
const expected = `expected.length <= ${value}`; | ||
return arrayLengthComparator(le, "s.array(T).lengthLe", expected, value); | ||
} | ||
__name(arrayLengthLe, "arrayLengthLe"); | ||
function arrayLengthGt(value) { | ||
const expected = `expected.length > ${value}`; | ||
return arrayLengthComparator(gt, "s.array(T).lengthGt", expected, value); | ||
} | ||
__name(arrayLengthGt, "arrayLengthGt"); | ||
function arrayLengthGe(value) { | ||
const expected = `expected.length >= ${value}`; | ||
return arrayLengthComparator(ge, "s.array(T).lengthGe", expected, value); | ||
} | ||
__name(arrayLengthGe, "arrayLengthGe"); | ||
function arrayLengthEq(value) { | ||
const expected = `expected.length === ${value}`; | ||
return arrayLengthComparator(eq, "s.array(T).lengthEq", expected, value); | ||
} | ||
__name(arrayLengthEq, "arrayLengthEq"); | ||
function arrayLengthNe(value) { | ||
const expected = `expected.length !== ${value}`; | ||
return arrayLengthComparator(ne, "s.array(T).lengthNe", expected, value); | ||
} | ||
__name(arrayLengthNe, "arrayLengthNe"); | ||
function arrayLengthRange(start, endBefore) { | ||
const expected = `expected.length >= ${start} && expected.length < ${endBefore}`; | ||
return { | ||
run(input) { | ||
return input.length >= start && input.length < endBefore ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRange", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRange, "arrayLengthRange"); | ||
function arrayLengthRangeInclusive(start, end) { | ||
const expected = `expected.length >= ${start} && expected.length <= ${end}`; | ||
return { | ||
run(input) { | ||
return input.length >= start && input.length <= end ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRangeInclusive", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRangeInclusive, "arrayLengthRangeInclusive"); | ||
function arrayLengthRangeExclusive(startAfter, endBefore) { | ||
const expected = `expected.length > ${startAfter} && expected.length < ${endBefore}`; | ||
return { | ||
run(input) { | ||
return input.length > startAfter && input.length < endBefore ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.array(T).lengthRangeExclusive", "Invalid Array length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(arrayLengthRangeExclusive, "arrayLengthRangeExclusive"); | ||
// src/lib/errors/CombinedPropertyError.ts | ||
var CombinedPropertyError = class extends BaseError { | ||
constructor(errors) { | ||
super("Received one or more errors"); | ||
this.errors = errors; | ||
} | ||
isOk() { | ||
return this.success; | ||
[customInspectSymbolStackLess](depth, options) { | ||
if (depth < 0) { | ||
return options.stylize("[CombinedPropertyError]", "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const header = `${options.stylize("CombinedPropertyError", "special")} (${options.stylize(this.errors.length.toString(), "number")})`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const errors = this.errors.map(([key, error]) => { | ||
const property = CombinedPropertyError.formatProperty(key, options); | ||
const body = error[customInspectSymbolStackLess](depth - 1, newOptions).replaceAll("\n", padding); | ||
return ` input${property}${padding}${body}`; | ||
}).join("\n\n"); | ||
return `${header} | ||
${message} | ||
${errors}`; | ||
} | ||
isErr() { | ||
return !this.success; | ||
static formatProperty(key, options) { | ||
if (typeof key === "string") | ||
return options.stylize(`.${key}`, "symbol"); | ||
if (typeof key === "number") | ||
return `[${options.stylize(key.toString(), "number")}]`; | ||
return `[${options.stylize("Symbol", "symbol")}(${key.description})]`; | ||
} | ||
unwrap() { | ||
if (this.isOk()) | ||
return this.value; | ||
throw this.error; | ||
}; | ||
__name(CombinedPropertyError, "CombinedPropertyError"); | ||
// src/lib/errors/ValidationError.ts | ||
var import_node_util2 = require("util"); | ||
var ValidationError = class extends BaseError { | ||
constructor(validator, message, given) { | ||
super(message); | ||
this.validator = validator; | ||
this.given = given; | ||
} | ||
static ok(value) { | ||
return new Result(true, value); | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
validator: this.validator, | ||
given: this.given | ||
}; | ||
} | ||
static err(error) { | ||
return new Result(false, void 0, error); | ||
[customInspectSymbolStackLess](depth, options) { | ||
const validator = options.stylize(this.validator, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ValidationError: ${validator}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util2.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ValidationError", "special")} > ${validator}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(Result, "Result"); | ||
__name(ValidationError, "ValidationError"); | ||
@@ -144,2 +361,29 @@ // src/validators/ArrayValidator.ts | ||
} | ||
lengthLt(length) { | ||
return this.addConstraint(arrayLengthLt(length)); | ||
} | ||
lengthLe(length) { | ||
return this.addConstraint(arrayLengthLe(length)); | ||
} | ||
lengthGt(length) { | ||
return this.addConstraint(arrayLengthGt(length)); | ||
} | ||
lengthGe(length) { | ||
return this.addConstraint(arrayLengthGe(length)); | ||
} | ||
lengthEq(length) { | ||
return this.addConstraint(arrayLengthEq(length)); | ||
} | ||
lengthNe(length) { | ||
return this.addConstraint(arrayLengthNe(length)); | ||
} | ||
lengthRange(start, endBefore) { | ||
return this.addConstraint(arrayLengthRange(start, endBefore)); | ||
} | ||
lengthRangeInclusive(startAt, endAt) { | ||
return this.addConstraint(arrayLengthRangeInclusive(startAt, endAt)); | ||
} | ||
lengthRangeExclusive(startAfter, endBefore) { | ||
return this.addConstraint(arrayLengthRangeExclusive(startAfter, endBefore)); | ||
} | ||
clone() { | ||
@@ -150,14 +394,14 @@ return Reflect.construct(this.constructor, [this.validator, this.constraints]); | ||
if (!Array.isArray(values)) { | ||
return Result.err(new ValidationError("ArrayValidator", "Expected an array", values)); | ||
return Result.err(new ValidationError("s.array(T)", "Expected an array", values)); | ||
} | ||
const errors = []; | ||
const transformed = []; | ||
for (const value of values) { | ||
const result = this.validator.run(value); | ||
for (let i = 0; i < values.length; i++) { | ||
const result = this.validator.run(values[i]); | ||
if (result.isOk()) | ||
transformed.push(result.value); | ||
else | ||
errors.push(result.error); | ||
errors.push([i, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -167,62 +411,50 @@ }; | ||
// src/lib/errors/ConstraintError.ts | ||
var ConstraintError = class extends Error { | ||
constructor(validator, message, given, expected) { | ||
super(message); | ||
this.constraint = validator; | ||
this.given = given; | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
}; | ||
__name(ConstraintError, "ConstraintError"); | ||
// src/constraints/util/operators.ts | ||
function lt(a, b) { | ||
return a < b; | ||
// src/constraints/BigIntConstraints.ts | ||
function bigintComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid bigint value", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(lt, "lt"); | ||
function le(a, b) { | ||
return a <= b; | ||
__name(bigintComparator, "bigintComparator"); | ||
function bigintLt(value) { | ||
const expected = `expected < ${value}n`; | ||
return bigintComparator(lt, "s.bigint.lt", expected, value); | ||
} | ||
__name(le, "le"); | ||
function gt(a, b) { | ||
return a > b; | ||
__name(bigintLt, "bigintLt"); | ||
function bigintLe(value) { | ||
const expected = `expected <= ${value}n`; | ||
return bigintComparator(le, "s.bigint.le", expected, value); | ||
} | ||
__name(gt, "gt"); | ||
function ge(a, b) { | ||
return a >= b; | ||
__name(bigintLe, "bigintLe"); | ||
function bigintGt(value) { | ||
const expected = `expected > ${value}n`; | ||
return bigintComparator(gt, "s.bigint.gt", expected, value); | ||
} | ||
__name(ge, "ge"); | ||
function eq(a, b) { | ||
return a === b; | ||
__name(bigintGt, "bigintGt"); | ||
function bigintGe(value) { | ||
const expected = `expected >= ${value}n`; | ||
return bigintComparator(ge, "s.bigint.ge", expected, value); | ||
} | ||
__name(eq, "eq"); | ||
function ne(a, b) { | ||
return a !== b; | ||
__name(bigintGe, "bigintGe"); | ||
function bigintEq(value) { | ||
const expected = `expected === ${value}n`; | ||
return bigintComparator(eq, "s.bigint.eq", expected, value); | ||
} | ||
__name(ne, "ne"); | ||
// src/constraints/BigIntConstraints.ts | ||
function bigintComparator(comparator, name, messageBuilder, number) { | ||
__name(bigintEq, "bigintEq"); | ||
function bigintNe(value) { | ||
const expected = `expected !== ${value}n`; | ||
return bigintComparator(ne, "s.bigint.ne", expected, value); | ||
} | ||
__name(bigintNe, "bigintNe"); | ||
function bigintDivisibleBy(divider) { | ||
const expected = `expected % ${divider}n === 0n`; | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, number), input, number)); | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(bigintComparator, "bigintComparator"); | ||
var bigintLt = bigintComparator.bind(null, lt, "bigintLt", (given, expected) => `Expected bigint to be less than ${expected}, but received ${given}`); | ||
var bigintLe = bigintComparator.bind(null, le, "bigintLe", (given, expected) => `Expected bigint to be less or equals than ${expected}, but received ${given}`); | ||
var bigintGt = bigintComparator.bind(null, gt, "bigintGt", (given, expected) => `Expected bigint to be greater than ${expected}, but received ${given}`); | ||
var bigintGe = bigintComparator.bind(null, ge, "bigintGe", (given, expected) => `Expected bigint to be greater or equals than ${expected}, but received ${given}`); | ||
var bigintEq = bigintComparator.bind(null, eq, "bigintEq", (given, expected) => `Expected bigint to be exactly ${expected}, but received ${given}`); | ||
var bigintNe = bigintComparator.bind(null, ne, "bigintNe", (_, expected) => `Expected bigint to not be ${expected}`); | ||
__name(bigintDivisibleBy, "bigintDivisibleBy"); | ||
@@ -255,4 +487,16 @@ // src/validators/BigIntValidator.ts | ||
} | ||
divisibleBy(number) { | ||
return this.addConstraint(bigintDivisibleBy(number)); | ||
} | ||
get abs() { | ||
return this.transform((value) => value < 0 ? -value : value); | ||
} | ||
intN(bits) { | ||
return this.transform((value) => BigInt.asIntN(bits, value)); | ||
} | ||
uintN(bits) { | ||
return this.transform((value) => BigInt.asUintN(bits, value)); | ||
} | ||
handle(value) { | ||
return typeof value === "bigint" ? Result.ok(value) : Result.err(new ValidationError("BigIntValidator", "Expected a bigint primitive", value)); | ||
return typeof value === "bigint" ? Result.ok(value) : Result.err(new ValidationError("s.bigint", "Expected a bigint primitive", value)); | ||
} | ||
@@ -265,3 +509,3 @@ }; | ||
run(input) { | ||
return input ? Result.ok(input) : Result.err(new ConstraintError("booleanTrue", "Expected boolean to be true, but received false", input, true)); | ||
return input ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
} | ||
@@ -271,3 +515,3 @@ }; | ||
run(input) { | ||
return input ? Result.err(new ConstraintError("booleanFalse", "Expected boolean to be false, but received true", input, false)) : Result.ok(input); | ||
return input ? Result.err(new ExpectedConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
} | ||
@@ -291,3 +535,3 @@ }; | ||
handle(value) { | ||
return typeof value === "boolean" ? Result.ok(value) : Result.err(new ValidationError("BooleanValidator", "Expected a boolean primitive", value)); | ||
return typeof value === "boolean" ? Result.ok(value) : Result.err(new ValidationError("s.boolean", "Expected a boolean primitive", value)); | ||
} | ||
@@ -298,6 +542,6 @@ }; | ||
// src/constraints/DateConstraints.ts | ||
function dateComparator(comparator, name, messageBuilder, date, number = date.getTime()) { | ||
function dateComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, date), input, date)); | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Date value", input, expected)); | ||
} | ||
@@ -307,11 +551,35 @@ }; | ||
__name(dateComparator, "dateComparator"); | ||
var dateLt = dateComparator.bind(null, lt, "dateLt", (given, expected) => `Expected date to be earlier than ${expected}, but received ${given}`); | ||
var dateLe = dateComparator.bind(null, le, "dateLe", (given, expected) => `Expected date to be earlier or equals than ${expected}, but received ${given}`); | ||
var dateGt = dateComparator.bind(null, gt, "dateGt", (given, expected) => `Expected date to be later than ${expected}, but received ${given}`); | ||
var dateGe = dateComparator.bind(null, ge, "dateGe", (given, expected) => `Expected date to be later or equals than ${expected}, but received ${given}`); | ||
var dateEq = dateComparator.bind(null, eq, "dateEq", (given, expected) => `Expected date to be exactly ${expected}, but received ${given}`); | ||
var dateNe = dateComparator.bind(null, ne, "dateNe", (_, expected) => `Expected date to not be ${expected}`); | ||
function dateLt(value) { | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
} | ||
__name(dateLt, "dateLt"); | ||
function dateLe(value) { | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
} | ||
__name(dateLe, "dateLe"); | ||
function dateGt(value) { | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
} | ||
__name(dateGt, "dateGt"); | ||
function dateGe(value) { | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
} | ||
__name(dateGe, "dateGe"); | ||
function dateEq(value) { | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
} | ||
__name(dateEq, "dateEq"); | ||
function dateNe(value) { | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
} | ||
__name(dateNe, "dateNe"); | ||
var dateInvalid = { | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ConstraintError("dateInvalid", `Expected Date's time to be a NaN, but received ${input}`, input, "An invalid Date")); | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.date.invalid", "Invalid Date value", input, "expected === NaN")); | ||
} | ||
@@ -321,3 +589,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.err(new ConstraintError("dateValid", `Expected Date's time to not be a NaN, but received ${input}`, input, "A valid Date")) : Result.ok(input); | ||
return Number.isNaN(input.getTime()) ? Result.err(new ExpectedConstraintError("s.date.valid", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
@@ -342,10 +610,16 @@ }; | ||
const resolved = new Date(date); | ||
return Number.isNaN(resolved.getTime()) ? this.addConstraint(dateInvalid) : this.addConstraint(dateEq(resolved)); | ||
return Number.isNaN(resolved.getTime()) ? this.invalid : this.addConstraint(dateEq(resolved)); | ||
} | ||
ne(date) { | ||
const resolved = new Date(date); | ||
return Number.isNaN(resolved.getTime()) ? this.addConstraint(dateValid) : this.addConstraint(dateNe(resolved)); | ||
return Number.isNaN(resolved.getTime()) ? this.valid : this.addConstraint(dateNe(resolved)); | ||
} | ||
get valid() { | ||
return this.addConstraint(dateValid); | ||
} | ||
get invalid() { | ||
return this.addConstraint(dateInvalid); | ||
} | ||
handle(value) { | ||
return value instanceof Date ? Result.ok(value) : Result.err(new ValidationError("DateValidator", "Expected a Date", value)); | ||
return value instanceof Date ? Result.ok(value) : Result.err(new ValidationError("s.date", "Expected a Date", value)); | ||
} | ||
@@ -356,2 +630,3 @@ }; | ||
// src/lib/errors/ExpectedValidationError.ts | ||
var import_node_util3 = require("util"); | ||
var ExpectedValidationError = class extends ValidationError { | ||
@@ -370,2 +645,23 @@ constructor(validator, message, given, expected) { | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const validator = options.stylize(this.validator, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[ExpectedValidationError: ${validator}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const expected = (0, import_node_util3.inspect)(this.expected, newOptions).replaceAll("\n", padding); | ||
const given = (0, import_node_util3.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ExpectedValidationError", "special")} > ${validator}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedBlock = ` | ||
${options.stylize("Expected:", "string")}${padding}${expected}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
@@ -381,3 +677,3 @@ __name(ExpectedValidationError, "ExpectedValidationError"); | ||
handle(value) { | ||
return value instanceof this.expected ? Result.ok(value) : Result.err(new ExpectedValidationError("InstanceValidator", "Expected", value, this.expected)); | ||
return value instanceof this.expected ? Result.ok(value) : Result.err(new ExpectedValidationError("s.instance(V)", "Expected", value, this.expected)); | ||
} | ||
@@ -397,3 +693,3 @@ clone() { | ||
handle(value) { | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("LiteralValidator", "Expected", value, this.expected)); | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("s.literal(V)", "Expected values to be equals", value, this.expected)); | ||
} | ||
@@ -409,3 +705,3 @@ clone() { | ||
handle(value) { | ||
return Result.err(new ValidationError("NeverValidator", "Expected a value to not be passed", value)); | ||
return Result.err(new ValidationError("s.never", "Expected a value to not be passed", value)); | ||
} | ||
@@ -418,3 +714,3 @@ }; | ||
handle(value) { | ||
return value === void 0 || value === null ? Result.ok(value) : Result.err(new ValidationError("NullishValidator", "Expected undefined or null", value)); | ||
return value === void 0 || value === null ? Result.ok(value) : Result.err(new ValidationError("s.nullish", "Expected undefined or null", value)); | ||
} | ||
@@ -425,6 +721,6 @@ }; | ||
// src/constraints/NumberConstraints.ts | ||
function numberComparator(comparator, name, messageBuilder, number) { | ||
function numberComparator(comparator, name, expected, number) { | ||
return { | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, number), input, number)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid number value", input, expected)); | ||
} | ||
@@ -434,11 +730,35 @@ }; | ||
__name(numberComparator, "numberComparator"); | ||
var numberLt = numberComparator.bind(null, lt, "numberLt", (given, expected) => `Expected number to be less than ${expected}, but received ${given}`); | ||
var numberLe = numberComparator.bind(null, le, "numberLe", (given, expected) => `Expected number to be less or equals than ${expected}, but received ${given}`); | ||
var numberGt = numberComparator.bind(null, gt, "numberGt", (given, expected) => `Expected number to be greater than ${expected}, but received ${given}`); | ||
var numberGe = numberComparator.bind(null, ge, "numberGe", (given, expected) => `Expected number to be greater or equals than ${expected}, but received ${given}`); | ||
var numberEq = numberComparator.bind(null, eq, "numberEq", (given, expected) => `Expected number to be exactly ${expected}, but received ${given}`); | ||
var numberNe = numberComparator.bind(null, ne, "numberNe", (_, expected) => `Expected number to not be ${expected}`); | ||
function numberLt(value) { | ||
const expected = `expected < ${value}`; | ||
return numberComparator(lt, "s.number.lt", expected, value); | ||
} | ||
__name(numberLt, "numberLt"); | ||
function numberLe(value) { | ||
const expected = `expected <= ${value}`; | ||
return numberComparator(le, "s.number.le", expected, value); | ||
} | ||
__name(numberLe, "numberLe"); | ||
function numberGt(value) { | ||
const expected = `expected > ${value}`; | ||
return numberComparator(gt, "s.number.gt", expected, value); | ||
} | ||
__name(numberGt, "numberGt"); | ||
function numberGe(value) { | ||
const expected = `expected >= ${value}`; | ||
return numberComparator(ge, "s.number.ge", expected, value); | ||
} | ||
__name(numberGe, "numberGe"); | ||
function numberEq(value) { | ||
const expected = `expected === ${value}`; | ||
return numberComparator(eq, "s.number.eq", expected, value); | ||
} | ||
__name(numberEq, "numberEq"); | ||
function numberNe(value) { | ||
const expected = `expected !== ${value}`; | ||
return numberComparator(ne, "s.number.ne", expected, value); | ||
} | ||
__name(numberNe, "numberNe"); | ||
var numberInt = { | ||
run(input) { | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("numberInt", `Expected number to be an integer, but received ${input}`, input, "An integer")); | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.int", "Given value is not an integer", input, "Number.isInteger(expected) to be true")); | ||
} | ||
@@ -448,3 +768,3 @@ }; | ||
run(input) { | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("numberSafeInt", `Expected number to be a safe integer, but received ${input}`, input, "A safe integer")); | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.safeInt", "Given value is not a safe integer", input, "Number.isSafeInteger(expected) to be true")); | ||
} | ||
@@ -454,3 +774,3 @@ }; | ||
run(input) { | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ConstraintError("numberFinite", `Expected number to be a finite number, but received ${input}`, input, "A finite number")); | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.finite", "Given value is not finite", input, "Number.isFinite(expected) to be true")); | ||
} | ||
@@ -460,3 +780,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ConstraintError("numberNaN", `Expected number to be a NaN, but received ${input}`, input, "A NaN")); | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
} | ||
@@ -466,5 +786,14 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.err(new ConstraintError("numberNeNaN", `Expected number to not be a NaN, but received ${input}`, input, "Not NaN")) : Result.ok(input); | ||
return Number.isNaN(input) ? Result.err(new ExpectedConstraintError("s.number.ne(NaN)", "Invalid number value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
}; | ||
function numberDivisibleBy(divider) { | ||
const expected = `expected % ${divider} === 0`; | ||
return { | ||
run(input) { | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(numberDivisibleBy, "numberDivisibleBy"); | ||
@@ -506,4 +835,28 @@ // src/validators/NumberValidator.ts | ||
} | ||
divisibleBy(divider) { | ||
return this.addConstraint(numberDivisibleBy(divider)); | ||
} | ||
get abs() { | ||
return this.transform(Math.abs); | ||
} | ||
get sign() { | ||
return this.transform(Math.sign); | ||
} | ||
get trunc() { | ||
return this.transform(Math.trunc); | ||
} | ||
get floor() { | ||
return this.transform(Math.floor); | ||
} | ||
get fround() { | ||
return this.transform(Math.fround); | ||
} | ||
get round() { | ||
return this.transform(Math.round); | ||
} | ||
get ceil() { | ||
return this.transform(Math.ceil); | ||
} | ||
handle(value) { | ||
return typeof value === "number" ? Result.ok(value) : Result.err(new ValidationError("NumberValidator", "Expected a number primitive", value)); | ||
return typeof value === "number" ? Result.ok(value) : Result.err(new ValidationError("s.number", "Expected a number primitive", value)); | ||
} | ||
@@ -514,5 +867,5 @@ }; | ||
// src/lib/errors/MissingPropertyError.ts | ||
var MissingPropertyError = class extends Error { | ||
var MissingPropertyError = class extends BaseError { | ||
constructor(property) { | ||
super(`Expected property "${String(property)}" is missing`); | ||
super("A required property is missing"); | ||
this.property = property; | ||
@@ -526,2 +879,12 @@ } | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const property = options.stylize(this.property.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[MissingPropertyError: ${property}]`, "special"); | ||
} | ||
const header = `${options.stylize("MissingPropertyError", "special")} > ${property}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
return `${header} | ||
${message}`; | ||
} | ||
}; | ||
@@ -531,5 +894,6 @@ __name(MissingPropertyError, "MissingPropertyError"); | ||
// src/lib/errors/UnknownPropertyError.ts | ||
var UnknownPropertyError = class extends Error { | ||
var import_node_util4 = require("util"); | ||
var UnknownPropertyError = class extends BaseError { | ||
constructor(property, value) { | ||
super("Unknown property received"); | ||
super("Received unexpected property"); | ||
this.property = property; | ||
@@ -545,2 +909,19 @@ this.value = value; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const property = options.stylize(this.property.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[UnknownPropertyError: ${property}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const given = (0, import_node_util4.inspect)(this.value, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("UnknownPropertyError", "special")} > ${property}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${givenBlock}`; | ||
} | ||
}; | ||
@@ -564,2 +945,5 @@ __name(UnknownPropertyError, "UnknownPropertyError"); | ||
} | ||
case ObjectValidatorStrategy.Passthrough: | ||
this.handleStrategy = (value) => this.handlePassthroughStrategy(value); | ||
break; | ||
} | ||
@@ -573,2 +957,5 @@ } | ||
} | ||
get passthrough() { | ||
return Reflect.construct(this.constructor, [this.shape, ObjectValidatorStrategy.Passthrough, this.constraints]); | ||
} | ||
get partial() { | ||
@@ -593,6 +980,6 @@ const shape = Object.fromEntries(this.keys.map((key) => [key, this.shape[key].optional])); | ||
if (typeOfValue !== "object") { | ||
return Result.err(new ValidationError("ObjectValidator", `Expected the value to be an object, but received ${typeOfValue} instead`, value)); | ||
return Result.err(new ValidationError("s.object(T)", `Expected the value to be an object, but received ${typeOfValue} instead`, value)); | ||
} | ||
if (value === null) { | ||
return Result.err(new ValidationError("ObjectValidator", "Expected the value to not be null", value)); | ||
return Result.err(new ValidationError("s.object(T)", "Expected the value to not be null", value)); | ||
} | ||
@@ -615,9 +1002,9 @@ return this.handleStrategy(value); | ||
if (error instanceof ValidationError && error.given === void 0) { | ||
errors.push(new MissingPropertyError(key)); | ||
errors.push([key, new MissingPropertyError(key)]); | ||
} else { | ||
errors.push(error); | ||
errors.push([key, error]); | ||
} | ||
} | ||
} | ||
return errors.length === 0 ? Result.ok(entries) : Result.err(new AggregateError(errors, "Failed to match at least one of the properties")); | ||
return errors.length === 0 ? Result.ok(entries) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -638,5 +1025,5 @@ handleStrictStrategy(value) { | ||
if (error instanceof ValidationError && error.given === void 0) { | ||
errors.push(new MissingPropertyError(key)); | ||
errors.push([key, new MissingPropertyError(key)]); | ||
} else { | ||
errors.push(error); | ||
errors.push([key, error]); | ||
} | ||
@@ -646,6 +1033,10 @@ } | ||
} | ||
errors.push(new UnknownPropertyError(key, value[key])); | ||
errors.push([key, new UnknownPropertyError(key, value[key])]); | ||
} | ||
return errors.length === 0 ? Result.ok(finalResult) : Result.err(new AggregateError(errors, "Failed to match at least one of the properties")); | ||
return errors.length === 0 ? Result.ok(finalResult) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
handlePassthroughStrategy(value) { | ||
const result = this.handleIgnoreStrategy(value); | ||
return result.isErr() ? result : Result.ok({ ...value, ...result.value }); | ||
} | ||
}; | ||
@@ -656,2 +1047,3 @@ __name(ObjectValidator, "ObjectValidator"); | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Strict"] = 1] = "Strict"; | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Passthrough"] = 2] = "Passthrough"; | ||
return ObjectValidatorStrategy2; | ||
@@ -679,6 +1071,6 @@ })(ObjectValidatorStrategy || {}); | ||
if (typeof value !== "object") { | ||
return Result.err(new ValidationError("RecordValidator", "Expected an object", value)); | ||
return Result.err(new ValidationError("s.record(T)", "Expected an object", value)); | ||
} | ||
if (value === null) { | ||
return Result.err(new ValidationError("RecordValidator", "Expected the value to not be null", value)); | ||
return Result.err(new ValidationError("s.record(T)", "Expected the value to not be null", value)); | ||
} | ||
@@ -692,5 +1084,5 @@ const errors = []; | ||
else | ||
errors.push(result.error); | ||
errors.push([key, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
@@ -700,2 +1092,30 @@ }; | ||
// src/lib/errors/CombinedError.ts | ||
var CombinedError = class extends BaseError { | ||
constructor(errors) { | ||
super("Received one or more errors"); | ||
this.errors = errors; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
if (depth < 0) { | ||
return options.stylize("[CombinedError]", "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1, compact: true }; | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const header = `${options.stylize("CombinedError", "special")} (${options.stylize(this.errors.length.toString(), "number")})`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const errors = this.errors.map((error, i) => { | ||
const index = options.stylize((i + 1).toString(), "number"); | ||
const body = error[customInspectSymbolStackLess](depth - 1, newOptions).replaceAll("\n", padding); | ||
return ` ${index} ${body}`; | ||
}).join("\n\n"); | ||
return `${header} | ||
${message} | ||
${errors}`; | ||
} | ||
}; | ||
__name(CombinedError, "CombinedError"); | ||
// src/validators/SetValidator.ts | ||
@@ -712,3 +1132,3 @@ var SetValidator = class extends BaseValidator { | ||
if (!(values instanceof Set)) { | ||
return Result.err(new ValidationError("SetValidator", "Expected a set", values)); | ||
return Result.err(new ValidationError("s.set(T)", "Expected a set", values)); | ||
} | ||
@@ -724,3 +1144,3 @@ const errors = []; | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new AggregateError(errors, "Failed to validate at least one entry")); | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedError(errors)); | ||
} | ||
@@ -731,29 +1151,237 @@ }; | ||
// src/constraints/StringConstraints.ts | ||
function stringLength(comparator, name, messageBuilder, length) { | ||
var import_node_net = require("net"); | ||
// src/constraints/util/emailValidator.ts | ||
var accountRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")$/; | ||
function validateEmail(email) { | ||
if (!email) | ||
return false; | ||
const atIndex = email.indexOf("@"); | ||
if (atIndex === -1) | ||
return false; | ||
if (atIndex > 64) | ||
return false; | ||
const domainIndex = atIndex + 1; | ||
if (email.includes("@", domainIndex)) | ||
return false; | ||
if (email.length - domainIndex > 255) | ||
return false; | ||
let dotIndex = email.indexOf(".", domainIndex); | ||
if (dotIndex === -1) | ||
return false; | ||
let lastDotIndex = domainIndex; | ||
do { | ||
if (dotIndex - lastDotIndex > 63) | ||
return false; | ||
lastDotIndex = dotIndex + 1; | ||
} while ((dotIndex = email.indexOf(".", lastDotIndex)) !== -1); | ||
if (email.length - lastDotIndex > 63) | ||
return false; | ||
return accountRegex.test(email.slice(0, atIndex)) && validateEmailDomain(email.slice(domainIndex)); | ||
} | ||
__name(validateEmail, "validateEmail"); | ||
function validateEmailDomain(domain) { | ||
try { | ||
return new URL(`http://${domain}`).hostname === domain; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
__name(validateEmailDomain, "validateEmailDomain"); | ||
// src/lib/errors/MultiplePossibilitiesConstraintError.ts | ||
var import_node_util5 = require("util"); | ||
var MultiplePossibilitiesConstraintError = class extends BaseConstraintError { | ||
constructor(constraint, message, given, expected) { | ||
super(constraint, message, given); | ||
this.expected = expected; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
constraint: this.constraint, | ||
given: this.given, | ||
expected: this.expected | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const constraint = options.stylize(this.constraint, "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[MultiplePossibilitiesConstraintError: ${constraint}]`, "special"); | ||
} | ||
const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const verticalLine = options.stylize("|", "undefined"); | ||
const padding = ` | ||
${verticalLine} `; | ||
const given = (0, import_node_util5.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("MultiplePossibilitiesConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const expectedPadding = ` | ||
${verticalLine} - `; | ||
const expectedBlock = ` | ||
${options.stylize("Expected any of the following:", "string")}${expectedPadding}${this.expected.map((possible) => options.stylize(possible, "boolean")).join(expectedPadding)}`; | ||
const givenBlock = ` | ||
${options.stylize("Received:", "regexp")}${padding}${given}`; | ||
return `${header} | ||
${message} | ||
${expectedBlock} | ||
${givenBlock}`; | ||
} | ||
}; | ||
__name(MultiplePossibilitiesConstraintError, "MultiplePossibilitiesConstraintError"); | ||
// src/constraints/util/common/combinedResultFn.ts | ||
function combinedErrorFn(...fns) { | ||
switch (fns.length) { | ||
case 0: | ||
return () => null; | ||
case 1: | ||
return fns[0]; | ||
case 2: { | ||
const [fn0, fn1] = fns; | ||
return (...params) => fn0(...params) || fn1(...params); | ||
} | ||
default: { | ||
return (...params) => { | ||
for (const fn of fns) { | ||
const result = fn(...params); | ||
if (result) | ||
return result; | ||
} | ||
return null; | ||
}; | ||
} | ||
} | ||
} | ||
__name(combinedErrorFn, "combinedErrorFn"); | ||
// src/constraints/util/urlValidators.ts | ||
function createUrlValidators(options) { | ||
const fns = []; | ||
if (options?.allowedProtocols?.length) | ||
fns.push(allowedProtocolsFn(options.allowedProtocols)); | ||
if (options?.allowedDomains?.length) | ||
fns.push(allowedDomainsFn(options.allowedDomains)); | ||
return combinedErrorFn(...fns); | ||
} | ||
__name(createUrlValidators, "createUrlValidators"); | ||
function allowedProtocolsFn(allowedProtocols) { | ||
return (input, url) => allowedProtocols.includes(url.protocol) ? null : new MultiplePossibilitiesConstraintError("s.string.url", "Invalid URL protocol", input, allowedProtocols); | ||
} | ||
__name(allowedProtocolsFn, "allowedProtocolsFn"); | ||
function allowedDomainsFn(allowedDomains) { | ||
return (input, url) => allowedDomains.includes(url.hostname) ? null : new MultiplePossibilitiesConstraintError("s.string.url", "Invalid URL domain", input, allowedDomains); | ||
} | ||
__name(allowedDomainsFn, "allowedDomainsFn"); | ||
// src/constraints/StringConstraints.ts | ||
function stringLengthComparator(comparator, name, expected, length) { | ||
return { | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ConstraintError(name, messageBuilder(input, length), input, length)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid string length", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringLength, "stringLength"); | ||
var stringLengthLt = stringLength.bind(null, lt, "stringLengthLt", (given, expected) => `Expected string to have less than ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthLe = stringLength.bind(null, le, "stringLengthLe", (given, expected) => `Expected string to have maximum ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthGt = stringLength.bind(null, gt, "stringLengthGt", (given, expected) => `Expected string to have more than ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthGe = stringLength.bind(null, ge, "stringLengthGe", (given, expected) => `Expected string to have at least ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthEq = stringLength.bind(null, eq, "stringLengthEq", (given, expected) => `Expected string to have exactly ${expected} characters, but received one with ${given.length} characters`); | ||
var stringLengthNe = stringLength.bind(null, ne, "stringLengthNe", (given, expected) => `Expected string to not have exactly ${expected} characters, but received one with ${given.length} characters`); | ||
__name(stringLengthComparator, "stringLengthComparator"); | ||
function stringLengthLt(length) { | ||
const expected = `expected.length < ${length}`; | ||
return stringLengthComparator(lt, "s.string.lengthLt", expected, length); | ||
} | ||
__name(stringLengthLt, "stringLengthLt"); | ||
function stringLengthLe(length) { | ||
const expected = `expected.length <= ${length}`; | ||
return stringLengthComparator(le, "s.string.lengthLe", expected, length); | ||
} | ||
__name(stringLengthLe, "stringLengthLe"); | ||
function stringLengthGt(length) { | ||
const expected = `expected.length > ${length}`; | ||
return stringLengthComparator(gt, "s.string.lengthGt", expected, length); | ||
} | ||
__name(stringLengthGt, "stringLengthGt"); | ||
function stringLengthGe(length) { | ||
const expected = `expected.length >= ${length}`; | ||
return stringLengthComparator(ge, "s.string.lengthGe", expected, length); | ||
} | ||
__name(stringLengthGe, "stringLengthGe"); | ||
function stringLengthEq(length) { | ||
const expected = `expected.length === ${length}`; | ||
return stringLengthComparator(eq, "s.string.lengthEq", expected, length); | ||
} | ||
__name(stringLengthEq, "stringLengthEq"); | ||
function stringLengthNe(length) { | ||
const expected = `expected.length !== ${length}`; | ||
return stringLengthComparator(ne, "s.string.lengthNe", expected, length); | ||
} | ||
__name(stringLengthNe, "stringLengthNe"); | ||
function stringEmail() { | ||
return { | ||
run(input) { | ||
return validateEmail(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.string.email", "Invalid email address", input, "expected to be an email address")); | ||
} | ||
}; | ||
} | ||
__name(stringEmail, "stringEmail"); | ||
function stringRegexValidator(type, expected, regex) { | ||
return { | ||
run(input) { | ||
return regex.test(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError(type, "Invalid string format", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringRegexValidator, "stringRegexValidator"); | ||
function stringUrl(options) { | ||
const validatorFn = createUrlValidators(options); | ||
return { | ||
run(input) { | ||
let url; | ||
try { | ||
url = new URL(input); | ||
} catch { | ||
return Result.err(new ExpectedConstraintError("s.string.url", "Invalid URL", input, "expected to match an URL")); | ||
} | ||
const validatorFnResult = validatorFn(input, url); | ||
if (validatorFnResult === null) | ||
return Result.ok(input); | ||
return Result.err(validatorFnResult); | ||
} | ||
}; | ||
} | ||
__name(stringUrl, "stringUrl"); | ||
function stringIp(version) { | ||
const ipVersion = version ? `v${version}` : ""; | ||
const validatorFn = version === 4 ? import_node_net.isIPv4 : version === 6 ? import_node_net.isIPv6 : import_node_net.isIP; | ||
const name = `s.string.ip${ipVersion}`; | ||
const message = `Invalid IP${ipVersion} address`; | ||
const expected = `expected to be an IP${ipVersion} address`; | ||
return { | ||
run(input) { | ||
return validatorFn(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, message, input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringIp, "stringIp"); | ||
function stringRegex(regex) { | ||
return stringRegexValidator("s.string.regex", `expected ${regex}.test(expected) to be true`, regex); | ||
} | ||
__name(stringRegex, "stringRegex"); | ||
function stringUuid({ version = 4, nullable = false } = {}) { | ||
version ??= "1-5"; | ||
const regex = new RegExp(`^(?:[0-9A-F]{8}-[0-9A-F]{4}-[${version}][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}${nullable ? "|00000000-0000-0000-0000-000000000000" : ""})$`, "i"); | ||
const expected = `expected to match UUID${typeof version === "number" ? `v${version}` : ` in range of ${version}`}`; | ||
return stringRegexValidator("s.string.uuid", expected, regex); | ||
} | ||
__name(stringUuid, "stringUuid"); | ||
// src/validators/StringValidator.ts | ||
var StringValidator = class extends BaseValidator { | ||
lengthLe(length) { | ||
lengthLt(length) { | ||
return this.addConstraint(stringLengthLt(length)); | ||
} | ||
lengthLte(length) { | ||
lengthLe(length) { | ||
return this.addConstraint(stringLengthLe(length)); | ||
} | ||
lengthGe(length) { | ||
lengthGt(length) { | ||
return this.addConstraint(stringLengthGt(length)); | ||
} | ||
lengthGte(length) { | ||
lengthGe(length) { | ||
return this.addConstraint(stringLengthGe(length)); | ||
@@ -767,4 +1395,25 @@ } | ||
} | ||
get email() { | ||
return this.addConstraint(stringEmail()); | ||
} | ||
url(options) { | ||
return this.addConstraint(stringUrl(options)); | ||
} | ||
uuid(options) { | ||
return this.addConstraint(stringUuid(options)); | ||
} | ||
regex(regex) { | ||
return this.addConstraint(stringRegex(regex)); | ||
} | ||
get ipv4() { | ||
return this.ip(4); | ||
} | ||
get ipv6() { | ||
return this.ip(6); | ||
} | ||
ip(version) { | ||
return this.addConstraint(stringIp(version)); | ||
} | ||
handle(value) { | ||
return typeof value === "string" ? Result.ok(value) : Result.err(new ValidationError("StringValidator", "Expected a string primitive", value)); | ||
return typeof value === "string" ? Result.ok(value) : Result.err(new ValidationError("s.string", "Expected a string primitive", value)); | ||
} | ||
@@ -774,2 +1423,33 @@ }; | ||
// src/validators/TupleValidator.ts | ||
var TupleValidator = class extends BaseValidator { | ||
constructor(validators, constraints = []) { | ||
super(constraints); | ||
this.validators = []; | ||
this.validators = validators; | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.validators, this.constraints]); | ||
} | ||
handle(values) { | ||
if (!Array.isArray(values)) { | ||
return Result.err(new ValidationError("s.tuple(T)", "Expected an array", values)); | ||
} | ||
if (values.length !== this.validators.length) { | ||
return Result.err(new ValidationError("s.tuple(T)", `Expected an array of length ${this.validators.length}`, values)); | ||
} | ||
const errors = []; | ||
const transformed = []; | ||
for (let i = 0; i < values.length; i++) { | ||
const result = this.validators[i].run(values[i]); | ||
if (result.isOk()) | ||
transformed.push(result.value); | ||
else | ||
errors.push([i, result.error]); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
}; | ||
__name(TupleValidator, "TupleValidator"); | ||
// src/validators/UnionValidator.ts | ||
@@ -794,3 +1474,3 @@ var UnionValidator = class extends BaseValidator { | ||
} | ||
return new UnionValidator([new LiteralValidator(void 0), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(void 0), ...this.validators]); | ||
} | ||
@@ -810,3 +1490,3 @@ get nullable() { | ||
} | ||
return new UnionValidator([new LiteralValidator(null), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(null), ...this.validators]); | ||
} | ||
@@ -817,6 +1497,10 @@ get nullish() { | ||
const [validator] = this.validators; | ||
if (validator instanceof NullishValidator) { | ||
if (validator instanceof LiteralValidator) { | ||
if (validator.expected === null || validator.expected === void 0) { | ||
return new UnionValidator([new NullishValidator(), ...this.validators.slice(1)], this.constraints); | ||
} | ||
} else if (validator instanceof NullishValidator) { | ||
return this.clone(); | ||
} | ||
return new UnionValidator([new NullishValidator(), this.clone()]); | ||
return new UnionValidator([new NullishValidator(), ...this.validators]); | ||
} | ||
@@ -837,3 +1521,3 @@ or(...predicates) { | ||
} | ||
return Result.err(new AggregateError(errors, "Could not match any of the defined validators")); | ||
return Result.err(new CombinedError(errors)); | ||
} | ||
@@ -843,2 +1527,136 @@ }; | ||
// src/validators/MapValidator.ts | ||
var MapValidator = class extends BaseValidator { | ||
constructor(keyValidator, valueValidator, constraints = []) { | ||
super(constraints); | ||
this.keyValidator = keyValidator; | ||
this.valueValidator = valueValidator; | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.keyValidator, this.valueValidator, this.constraints]); | ||
} | ||
handle(value) { | ||
if (!(value instanceof Map)) { | ||
return Result.err(new ValidationError("s.map(K, V)", "Expected a map", value)); | ||
} | ||
const errors = []; | ||
const transformed = /* @__PURE__ */ new Map(); | ||
for (const [key, val] of value.entries()) { | ||
const keyResult = this.keyValidator.run(key); | ||
const valueResult = this.valueValidator.run(val); | ||
const { length } = errors; | ||
if (keyResult.isErr()) | ||
errors.push([key, keyResult.error]); | ||
if (valueResult.isErr()) | ||
errors.push([key, valueResult.error]); | ||
if (errors.length === length) | ||
transformed.set(keyResult.value, valueResult.value); | ||
} | ||
return errors.length === 0 ? Result.ok(transformed) : Result.err(new CombinedPropertyError(errors)); | ||
} | ||
}; | ||
__name(MapValidator, "MapValidator"); | ||
// src/validators/util/getValue.ts | ||
function getValue(valueOrFn) { | ||
return typeof valueOrFn === "function" ? valueOrFn() : valueOrFn; | ||
} | ||
__name(getValue, "getValue"); | ||
// src/validators/DefaultValidator.ts | ||
var DefaultValidator = class extends BaseValidator { | ||
constructor(validator, value, constraints = []) { | ||
super(constraints); | ||
this.validator = validator; | ||
this.defaultValue = value; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.validator, this.defaultValue, this.constraints]); | ||
} | ||
}; | ||
__name(DefaultValidator, "DefaultValidator"); | ||
// src/lib/errors/UnknownEnumValueError.ts | ||
var UnknownEnumValueError = class extends BaseError { | ||
constructor(value, keys, enumMappings) { | ||
super("Expected the value to be one of the following enum values:"); | ||
this.value = value; | ||
this.enumKeys = keys; | ||
this.enumMappings = enumMappings; | ||
} | ||
toJSON() { | ||
return { | ||
name: this.name, | ||
value: this.value, | ||
enumKeys: this.enumKeys, | ||
enumMappings: [...this.enumMappings.entries()] | ||
}; | ||
} | ||
[customInspectSymbolStackLess](depth, options) { | ||
const value = options.stylize(this.value.toString(), "string"); | ||
if (depth < 0) { | ||
return options.stylize(`[UnknownEnumValueError: ${value}]`, "special"); | ||
} | ||
const padding = ` | ||
${options.stylize("|", "undefined")} `; | ||
const pairs = this.enumKeys.map((key) => { | ||
const enumValue = this.enumMappings.get(key); | ||
return `${options.stylize(key, "string")} or ${options.stylize(enumValue.toString(), typeof enumValue === "number" ? "number" : "string")}`; | ||
}).join(padding); | ||
const header = `${options.stylize("UnknownEnumValueError", "special")} > ${value}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
const pairsBlock = `${padding}${pairs}`; | ||
return `${header} | ||
${message} | ||
${pairsBlock}`; | ||
} | ||
}; | ||
__name(UnknownEnumValueError, "UnknownEnumValueError"); | ||
// src/validators/NativeEnumValidator.ts | ||
var NativeEnumValidator = class extends BaseValidator { | ||
constructor(enumShape) { | ||
super(); | ||
this.hasNumericElements = false; | ||
this.enumMapping = /* @__PURE__ */ new Map(); | ||
this.enumShape = enumShape; | ||
this.enumKeys = Object.keys(enumShape).filter((key) => { | ||
return typeof enumShape[enumShape[key]] !== "number"; | ||
}); | ||
for (const key of this.enumKeys) { | ||
const enumValue = enumShape[key]; | ||
this.enumMapping.set(key, enumValue); | ||
this.enumMapping.set(enumValue, enumValue); | ||
if (typeof enumValue === "number") { | ||
this.hasNumericElements = true; | ||
this.enumMapping.set(`${enumValue}`, enumValue); | ||
} | ||
} | ||
} | ||
handle(value) { | ||
const typeOfValue = typeof value; | ||
if (typeOfValue === "number" && !this.hasNumericElements) { | ||
return Result.err(new ValidationError("s.nativeEnum(T)", "Expected the value to be a string", value)); | ||
} | ||
if (typeOfValue !== "string" && typeOfValue !== "number") { | ||
return Result.err(new ValidationError("s.nativeEnum(T)", "Expected the value to be a string or number", value)); | ||
} | ||
const casted = value; | ||
const possibleEnumValue = this.enumMapping.get(casted); | ||
return typeof possibleEnumValue === "undefined" ? Result.err(new UnknownEnumValueError(casted, this.enumKeys, this.enumMapping)) : Result.ok(possibleEnumValue); | ||
} | ||
clone() { | ||
return Reflect.construct(this.constructor, [this.enumShape]); | ||
} | ||
}; | ||
__name(NativeEnumValidator, "NativeEnumValidator"); | ||
// src/lib/Shapes.ts | ||
@@ -885,2 +1703,5 @@ var Shapes = class { | ||
} | ||
nativeEnum(enumShape) { | ||
return new NativeEnumValidator(enumShape); | ||
} | ||
literal(value) { | ||
@@ -900,2 +1721,5 @@ if (value instanceof Date) | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -907,2 +1731,5 @@ return new SetValidator(validator); | ||
} | ||
map(keyValidator, valueValidator) { | ||
return new MapValidator(keyValidator, valueValidator); | ||
} | ||
}; | ||
@@ -916,6 +1743,10 @@ __name(Shapes, "Shapes"); | ||
0 && (module.exports = { | ||
ConstraintError, | ||
CombinedError, | ||
CombinedPropertyError, | ||
ExpectedConstraintError, | ||
ExpectedValidationError, | ||
MissingPropertyError, | ||
MultiplePossibilitiesConstraintError, | ||
Result, | ||
UnknownEnumValueError, | ||
UnknownPropertyError, | ||
@@ -922,0 +1753,0 @@ ValidationError, |
{ | ||
"name": "@sapphire/shapeshift", | ||
"version": "1.1.0-next.fe6505f.0", | ||
"version": "2.0.0", | ||
"description": "Blazing fast input validation and transformation ⚡", | ||
@@ -14,3 +14,4 @@ "author": "@sapphire", | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js" | ||
"require": "./dist/index.js", | ||
"types": "./dist/index.d.ts" | ||
}, | ||
@@ -30,25 +31,25 @@ "sideEffects": false, | ||
"sversion": "standard-version", | ||
"prepublishOnly": "rollup-type-bundler", | ||
"prepublishOnly": "rollup-type-bundler -e node:util", | ||
"prepare": "husky install .github/husky" | ||
}, | ||
"devDependencies": { | ||
"@commitlint/cli": "^16.1.0", | ||
"@commitlint/config-conventional": "^16.0.0", | ||
"@commitlint/cli": "^16.2.1", | ||
"@commitlint/config-conventional": "^16.2.1", | ||
"@favware/npm-deprecate": "^1.0.4", | ||
"@favware/rollup-type-bundler": "^1.0.7", | ||
"@sapphire/eslint-config": "^4.0.11", | ||
"@sapphire/prettier-config": "^1.2.9", | ||
"@sapphire/ts-config": "^3.1.8", | ||
"@types/jest": "^27.4.0", | ||
"@types/node": "^17.0.8", | ||
"@typescript-eslint/eslint-plugin": "^5.10.0", | ||
"@typescript-eslint/parser": "^5.10.0", | ||
"@sapphire/eslint-config": "^4.3.0", | ||
"@sapphire/prettier-config": "^1.4.0", | ||
"@sapphire/ts-config": "^3.3.2", | ||
"@types/jest": "^27.4.1", | ||
"@types/node": "^17.0.21", | ||
"@typescript-eslint/eslint-plugin": "^5.14.0", | ||
"@typescript-eslint/parser": "^5.14.0", | ||
"cz-conventional-changelog": "^3.3.0", | ||
"eslint": "~8.7.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"eslint": "^8.11.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"husky": "^7.0.4", | ||
"jest": "^27.4.7", | ||
"jest-circus": "^27.4.6", | ||
"lint-staged": "^12.2.2", | ||
"jest": "^27.5.1", | ||
"jest-circus": "^27.5.1", | ||
"lint-staged": "^12.3.5", | ||
"prettier": "^2.5.1", | ||
@@ -58,7 +59,6 @@ "pretty-quick": "^3.1.3", | ||
"ts-jest": "^27.1.3", | ||
"ts-node": "^10.4.0", | ||
"tsup": "^5.11.11", | ||
"typedoc": "^0.22.11", | ||
"typedoc-plugin-mdn-links": "^1.0.4", | ||
"typescript": "^4.5.5" | ||
"tsup": "^5.12.1", | ||
"typedoc": "^0.22.13", | ||
"typedoc-plugin-mdn-links": "^1.0.5", | ||
"typescript": "^4.6.2" | ||
}, | ||
@@ -118,3 +118,3 @@ "repository": { | ||
"prettier": "@sapphire/prettier-config", | ||
"packageManager": "yarn@3.1.1" | ||
"packageManager": "yarn@3.2.0" | ||
} |
@@ -108,5 +108,9 @@ <div align="center"> | ||
s.string.lengthNe(5); | ||
s.string.url; // TODO | ||
s.string.uuid; // TODO | ||
s.string.regex(regex); // TODO | ||
s.string.email; | ||
s.string.url(); | ||
s.string.uuid(); | ||
s.string.regex(regex); | ||
s.string.ip(); | ||
s.string.ipv4; | ||
s.string.ipv6; | ||
``` | ||
@@ -136,3 +140,3 @@ | ||
s.number.divisibleBy(5); // TODO | Divisible by 5 | ||
s.number.divisibleBy(5); // Divisible by 5 | ||
``` | ||
@@ -143,10 +147,10 @@ | ||
```typescript | ||
s.number.abs; // TODO | Transforms the number to an absolute number | ||
s.number.sign; // TODO | Gets the number's sign | ||
s.number.abs; // Transforms the number to an absolute number | ||
s.number.sign; // Gets the number's sign | ||
s.number.trunc; // TODO | Transforms the number to the result of Math.trunc` | ||
s.number.floor; // TODO | Transforms the number to the result of Math.floor` | ||
s.number.fround; // TODO | Transforms the number to the result of Math.fround` | ||
s.number.round; // TODO | Transforms the number to the result of Math.round` | ||
s.number.ceil; // TODO | Transforms the number to the result of Math.ceil` | ||
s.number.trunc; // Transforms the number to the result of `Math.trunc` | ||
s.number.floor; // Transforms the number to the result of `Math.floor` | ||
s.number.fround; // Transforms the number to the result of `Math.fround` | ||
s.number.round; // Transforms the number to the result of `Math.round` | ||
s.number.ceil; // Transforms the number to the result of `Math.ceil` | ||
``` | ||
@@ -169,3 +173,3 @@ | ||
s.bigint.divisibleBy(5n); // TODO | Divisible by 5n | ||
s.bigint.divisibleBy(5n); // Divisible by 5n | ||
``` | ||
@@ -176,6 +180,6 @@ | ||
```typescript | ||
s.bigint.abs; // TODO | Transforms the bigint to an absolute bigint | ||
s.bigint.abs; // Transforms the bigint to an absolute bigint | ||
s.bigint.intN(5); // TODO | Clamps to a bigint to a signed bigint with 5 digits, see BigInt.asIntN | ||
s.bigint.uintN(5); // TODO | Clamps to a bigint to an unsigned bigint with 5 digits, see BigInt.asUintN | ||
s.bigint.intN(5); // Clamps to a bigint to a signed bigint with 5 digits, see BigInt.asIntN | ||
s.bigint.uintN(5); // Clamps to a bigint to an unsigned bigint with 5 digits, see BigInt.asUintN | ||
``` | ||
@@ -205,3 +209,3 @@ | ||
ShapeShift includes a handful of string-specific validations: | ||
ShapeShift includes a handful of array-specific validations: | ||
@@ -215,7 +219,10 @@ ```typescript | ||
s.string.array.lengthNe(5); // Must not have exactly 5 elements | ||
s.string.array.lengthRange(0, 4); // Must have at least 0 elements and less than 4 elements (in math, that is [0, 4)) | ||
s.string.array.lengthRangeInclusive(0, 4); // Must have at least 0 elements and at most 4 elements (in math, that is [0, 4]) | ||
s.string.array.lengthRangeExclusive(0, 4); // Must have more than 0 element and less than 4 elements (in math, that is (0, 4)) | ||
``` | ||
> **Note**: `.lengthGt` and `.lengthGe` are overloaded and change the inferred type from 1 to 10. For example, `s.string.array.lengthGe(2)`'s inferred type is `[string, string, ...string[]]` // TODO | ||
> **Note**: All `.length` methods define tuple types with the given amount of elements. For example, `s.string.array.lengthGe(2)`'s inferred type is `[string, string, ...string[]]` | ||
#### Tuples // TODO | ||
#### Tuples | ||
@@ -338,2 +345,6 @@ Unlike arrays, tuples have a fixed number of elements and each element can have a different type: | ||
##### `.passthrough` | ||
You can use the `.passthrough` getter to make the validator add the unrecognized properties the shape does not have, from the input. | ||
#### Records | ||
@@ -347,3 +358,3 @@ | ||
tags.parse({ foo: 'bar', hello: 'world' }); // => { foo: 'bar', hello: 'world' } | ||
tags.parse({ foo: 42 }); // => throws AggregateError | ||
tags.parse({ foo: 42 }); // => throws CombinedError | ||
tags.parse('Hello'); // => throws ValidateError | ||
@@ -357,7 +368,7 @@ ``` | ||
```typescript | ||
const stringOrNumber = s.union([s.string, s.number]); | ||
const stringOrNumber = s.union(s.string, s.number); | ||
stringOrNumber.parse('Sapphire'); // => 'Sapphire' | ||
stringOrNumber.parse(42); // => 42 | ||
stringOrNumber.parse({}); // => throws AggregateError | ||
stringOrNumber.parse({}); // => throws CombinedError | ||
``` | ||
@@ -374,3 +385,3 @@ | ||
#### Maps // TODO | ||
#### Maps | ||
@@ -433,3 +444,3 @@ ```typescript | ||
const getLength = s.string.transform((value) => value.length); // TODO | ||
const getLength = s.string.transform((value) => value.length); | ||
getLength.parse('Hello There'); // => 11 | ||
@@ -454,3 +465,3 @@ ``` | ||
```typescript | ||
const name = s.string.default('Sapphire'); // TODO | ||
const name = s.string.default('Sapphire'); | ||
name.parse('Hello'); // => 'Hello' | ||
@@ -461,3 +472,3 @@ name.parse(undefined); // => 'Sapphire' | ||
```typescript | ||
const number = s.number.default(Math.random); // TODO | ||
const number = s.number.default(Math.random); | ||
number.parse(12); // => 12 | ||
@@ -531,2 +542,4 @@ number.parse(undefined); // => 0.989911985608602 | ||
<td align="center"><a href="https://renovate.whitesourcesoftware.com/"><img src="https://avatars.githubusercontent.com/u/25180681?v=4?s=100" width="100px;" alt=""/><br /><sub><b>WhiteSource Renovate</b></sub></a><br /><a href="#maintenance-renovate-bot" title="Maintenance">🚧</a></td> | ||
<td align="center"><a href="https://github.com/Khasms"><img src="https://avatars.githubusercontent.com/u/36800359?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John</b></sub></a><br /><a href="https://github.com/sapphiredev/shapeshift/commits?author=Khasms" title="Code">💻</a></td> | ||
<td align="center"><a href="https://github.com/imranbarbhuiya"><img src="https://avatars.githubusercontent.com/u/74945038?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Parbez</b></sub></a><br /><a href="https://github.com/sapphiredev/shapeshift/commits?author=imranbarbhuiya" title="Code">💻</a> <a href="https://github.com/sapphiredev/shapeshift/commits?author=imranbarbhuiya" title="Tests">⚠️</a> <a href="https://github.com/sapphiredev/shapeshift/issues?q=author%3Aimranbarbhuiya" title="Bug reports">🐛</a> <a href="https://github.com/sapphiredev/shapeshift/commits?author=imranbarbhuiya" title="Documentation">📖</a></td> | ||
</tr> | ||
@@ -533,0 +546,0 @@ </table> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
598723
27
5350
0
0
542
3
1