@sapphire/shapeshift
Advanced tools
Comparing version 1.1.0-next.dc7ccaf.0 to 1.1.0-next.deff6a7.0
/// <reference types="node" /> | ||
import { InspectOptionsStylized } from 'node:util'; | ||
declare type ArrayConstraintName = `s.array(T).length${'Lt' | 'Le' | 'Gt' | 'Ge' | 'Eq' | 'Ne'}`; | ||
declare type ArrayConstraintName = `s.array(T).length${'Lt' | 'Le' | 'Gt' | 'Ge' | 'Eq' | 'Ne' | 'Range' | 'RangeInclusive' | 'RangeExclusive'}`; | ||
declare function arrayLengthLt<T>(value: number): IConstraint<T[]>; | ||
@@ -11,2 +11,5 @@ declare function arrayLengthLe<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[]>; | ||
@@ -26,3 +29,3 @@ declare type BigIntConstraintName = `s.bigint.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'ne' | 'divisibleBy'}`; | ||
declare type DateConstraintName = `s.date.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'eq(NaN)' | 'ne' | 'ne(NaN)'}`; | ||
declare type DateConstraintName = `s.date.${'lt' | 'le' | 'gt' | 'ge' | 'eq' | 'ne' | 'valid' | 'invalid'}`; | ||
declare function dateLt(value: Date): IConstraint<Date>; | ||
@@ -51,3 +54,14 @@ declare function dateLe(value: Date): IConstraint<Date>; | ||
declare type StringConstraintName = `s.string.length${'Lt' | 'Le' | 'Gt' | 'Ge' | 'Eq' | 'Ne'}`; | ||
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[]; | ||
} | ||
declare type UUIDVersion = 1 | 3 | 4 | 5; | ||
interface StringUuidOptions { | ||
version?: UUIDVersion | `${UUIDVersion}-${UUIDVersion}` | null; | ||
nullable?: boolean; | ||
} | ||
declare function stringLengthLt(length: number): IConstraint<string>; | ||
@@ -59,2 +73,7 @@ declare function stringLengthLe(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>; | ||
@@ -69,14 +88,6 @@ declare const customInspectSymbol: unique symbol; | ||
declare type ConstraintErrorNames = ArrayConstraintName | BigIntConstraintName | BooleanConstraintName | DateConstraintName | NumberConstraintName | StringConstraintName; | ||
declare class ConstraintError<T = unknown> extends BaseError { | ||
declare abstract class BaseConstraintError<T = unknown> extends BaseError { | ||
readonly constraint: ConstraintErrorNames; | ||
readonly given: 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; | ||
constructor(constraint: ConstraintErrorNames, message: string, given: T); | ||
} | ||
@@ -103,3 +114,3 @@ | ||
interface IConstraint<Input, Return extends Input = Input> { | ||
run(input: Input): Result<Return, ConstraintError<Input>>; | ||
run(input: Input): Result<Return, BaseConstraintError<Input>>; | ||
} | ||
@@ -120,2 +131,16 @@ | ||
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 { | ||
@@ -144,9 +169,10 @@ readonly validator: string; | ||
transform<O>(cb: (value: T) => O): BaseValidator<O>; | ||
default(value: T | (() => T)): DefaultValidator<T>; | ||
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 | CombinedError | CombinedPropertyError>; | ||
protected abstract handle(value: unknown): Result<T, ValidatorError>; | ||
protected addConstraint(constraint: IConstraint<T>): this; | ||
} | ||
declare type ValidatorError = ValidationError | CombinedError | CombinedPropertyError | UnknownEnumValueError; | ||
@@ -156,11 +182,20 @@ declare class ArrayValidator<T> extends BaseValidator<T[]> { | ||
constructor(validator: BaseValidator<T>, constraints?: readonly IConstraint<T[]>[]); | ||
lengthLt(length: number): this; | ||
lengthLe(length: number): this; | ||
lengthGt(length: number): this; | ||
lengthGe(length: number): this; | ||
lengthEq(length: number): this; | ||
lengthNe(length: number): this; | ||
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 | 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, [[]]>; | ||
@@ -192,8 +227,10 @@ declare class BigIntValidator<T extends bigint> extends BaseValidator<T> { | ||
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>; | ||
@@ -276,2 +313,3 @@ } | ||
get ignore(): this; | ||
get passthrough(): this; | ||
get partial(): ObjectValidator<{ | ||
@@ -291,6 +329,8 @@ [Key in keyof T]?: T[Key]; | ||
private handleStrictStrategy; | ||
private handlePassthroughStrategy; | ||
} | ||
declare const enum ObjectValidatorStrategy { | ||
Ignore = 0, | ||
Strict = 1 | ||
Strict = 1, | ||
Passthrough = 2 | ||
} | ||
@@ -323,5 +363,19 @@ | ||
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> { | ||
@@ -346,10 +400,25 @@ private validators; | ||
declare class DefaultValidator<T> extends BaseValidator<T | undefined> { | ||
declare class DefaultValidator<T> extends BaseValidator<T> { | ||
private readonly validator; | ||
private readonly defaultValue; | ||
private defaultValue; | ||
constructor(validator: BaseValidator<T>, value: T | (() => T), constraints?: readonly IConstraint<T>[]); | ||
protected handle(value: unknown): Result<T, ValidationError | CombinedError | CombinedPropertyError>; | ||
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 { | ||
@@ -369,6 +438,8 @@ 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 extends [...BaseValidator<any>[]]>(...validators: [...T]): UnionValidator<T[number] extends BaseValidator<infer U> ? U : never>; | ||
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>; | ||
@@ -378,3 +449,17 @@ record<T>(validator: BaseValidator<T>): RecordValidator<T>; | ||
} | ||
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 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 { | ||
@@ -390,2 +475,14 @@ readonly property: PropertyKey; | ||
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 { | ||
@@ -405,2 +502,2 @@ readonly property: PropertyKey; | ||
export { ArrayConstraintName, ArrayValidator, BaseError, BaseValidator, BigIntConstraintName, BigIntValidator, BooleanConstraintName, BooleanValidator, CombinedError, CombinedPropertyError, ConstraintError, ConstraintErrorNames, Constructor, DateConstraintName, DateValidator, DefaultValidator, ExpectedValidationError, IConstraint, InstanceValidator, LiteralValidator, MapValidator, MappedObjectValidator, MissingPropertyError, NeverValidator, NonNullObject, NullishValidator, NumberConstraintName, NumberValidator, ObjectValidator, ObjectValidatorStrategy, PassthroughValidator, RecordValidator, Result, SetValidator, Shapes, StringConstraintName, StringValidator, Type, UnionValidator, UnknownPropertyError, ValidationError, arrayLengthEq, arrayLengthGe, arrayLengthGt, arrayLengthLe, arrayLengthLt, arrayLengthNe, bigintDivisibleBy, bigintEq, bigintGe, bigintGt, bigintLe, bigintLt, bigintNe, booleanFalse, booleanTrue, dateEq, dateGe, dateGt, dateInvalid, dateLe, dateLt, dateNe, dateValid, numberDivisibleBy, 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 }; |
@@ -38,6 +38,8 @@ var SapphireShapeshift = (() => { | ||
CombinedPropertyError: () => CombinedPropertyError, | ||
ConstraintError: () => ConstraintError, | ||
ExpectedConstraintError: () => ExpectedConstraintError, | ||
ExpectedValidationError: () => ExpectedValidationError, | ||
MissingPropertyError: () => MissingPropertyError, | ||
MultiplePossibilitiesConstraintError: () => MultiplePossibilitiesConstraintError, | ||
Result: () => Result, | ||
UnknownEnumValueError: () => UnknownEnumValueError, | ||
UnknownPropertyError: () => UnknownPropertyError, | ||
@@ -133,3 +135,3 @@ ValidationError: () => ValidationError, | ||
// src/lib/errors/ConstraintError.ts | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var import_node_util = __require("util"); | ||
@@ -148,8 +150,16 @@ | ||
// src/lib/errors/ConstraintError.ts | ||
var ConstraintError = class extends BaseError { | ||
constructor(constraint, message, given, expected) { | ||
// src/lib/errors/BaseConstraintError.ts | ||
var BaseConstraintError = class extends BaseError { | ||
constructor(constraint, message, given) { | ||
super(message); | ||
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; | ||
@@ -168,3 +178,3 @@ } | ||
if (depth < 0) { | ||
return options.stylize(`[ConstraintError: ${constraint}]`, "special"); | ||
return options.stylize(`[ExpectedConstraintError: ${constraint}]`, "special"); | ||
} | ||
@@ -175,3 +185,3 @@ const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const given = (0, import_node_util.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ConstraintError", "special")} > ${constraint}`; | ||
const header = `${options.stylize("ExpectedConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
@@ -188,3 +198,3 @@ const expectedBlock = ` | ||
}; | ||
__name(ConstraintError, "ConstraintError"); | ||
__name(ExpectedConstraintError, "ExpectedConstraintError"); | ||
@@ -221,3 +231,3 @@ // src/constraints/util/operators.ts | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid Array length", input, expected)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Array length", input, expected)); | ||
} | ||
@@ -257,2 +267,29 @@ }; | ||
__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"); | ||
@@ -353,2 +390,11 @@ // src/lib/errors/CombinedPropertyError.ts | ||
} | ||
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() { | ||
@@ -359,3 +405,3 @@ 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)); | ||
} | ||
@@ -380,3 +426,3 @@ const errors = []; | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid bigint value", input, expected)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid bigint value", input, expected)); | ||
} | ||
@@ -420,3 +466,3 @@ }; | ||
run(input) { | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
} | ||
@@ -466,3 +512,3 @@ }; | ||
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)); | ||
} | ||
@@ -475,3 +521,3 @@ }; | ||
run(input) { | ||
return input ? Result.ok(input) : Result.err(new ConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
return input ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
} | ||
@@ -481,3 +527,3 @@ }; | ||
run(input) { | ||
return input ? Result.err(new ConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
return input ? Result.err(new ExpectedConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
} | ||
@@ -501,3 +547,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)); | ||
} | ||
@@ -511,3 +557,3 @@ }; | ||
run(input) { | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid Date value", input, expected)); | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Date value", input, expected)); | ||
} | ||
@@ -518,3 +564,3 @@ }; | ||
function dateLt(value) { | ||
const expected = `expected < ${value}`; | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
@@ -524,3 +570,3 @@ } | ||
function dateLe(value) { | ||
const expected = `expected <= ${value}`; | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
@@ -530,3 +576,3 @@ } | ||
function dateGt(value) { | ||
const expected = `expected > ${value}`; | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
@@ -536,3 +582,3 @@ } | ||
function dateGe(value) { | ||
const expected = `expected >= ${value}`; | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
@@ -542,3 +588,3 @@ } | ||
function dateEq(value) { | ||
const expected = `expected === ${value}`; | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
@@ -548,3 +594,3 @@ } | ||
function dateNe(value) { | ||
const expected = `expected !== ${value}`; | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
@@ -555,3 +601,3 @@ } | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ConstraintError("s.date.eq(NaN)", "Invalid Date value", input, "expected === NaN")); | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.date.invalid", "Invalid Date value", input, "expected === NaN")); | ||
} | ||
@@ -561,3 +607,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.err(new ConstraintError("s.date.ne(NaN)", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
return Number.isNaN(input.getTime()) ? Result.err(new ExpectedConstraintError("s.date.valid", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
@@ -582,10 +628,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)); | ||
} | ||
@@ -641,3 +693,3 @@ }; | ||
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)); | ||
} | ||
@@ -657,3 +709,3 @@ clone() { | ||
handle(value) { | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("LiteralValidator", "Expected values to be equals", 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)); | ||
} | ||
@@ -669,3 +721,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)); | ||
} | ||
@@ -678,3 +730,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)); | ||
} | ||
@@ -688,3 +740,3 @@ }; | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid number value", input, expected)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid number value", input, expected)); | ||
} | ||
@@ -726,3 +778,3 @@ }; | ||
run(input) { | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.int", "Given value is not an integer", input, "Number.isInteger(expected) to be true")); | ||
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")); | ||
} | ||
@@ -732,3 +784,3 @@ }; | ||
run(input) { | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.safeInt", "Given value is not a safe integer", input, "Number.isSafeInteger(expected) to be true")); | ||
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")); | ||
} | ||
@@ -738,3 +790,3 @@ }; | ||
run(input) { | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.finite", "Given value is not finite", input, "Number.isFinite(expected) to be true")); | ||
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")); | ||
} | ||
@@ -744,3 +796,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
} | ||
@@ -750,3 +802,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.err(new ConstraintError("s.number.ne(NaN)", "Invalid number value", input, "expected !== 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); | ||
} | ||
@@ -758,3 +810,3 @@ }; | ||
run(input) { | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
} | ||
@@ -825,3 +877,3 @@ }; | ||
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)); | ||
} | ||
@@ -906,2 +958,5 @@ }; | ||
} | ||
case ObjectValidatorStrategy.Passthrough: | ||
this.handleStrategy = (value) => this.handlePassthroughStrategy(value); | ||
break; | ||
} | ||
@@ -915,2 +970,5 @@ } | ||
} | ||
get passthrough() { | ||
return Reflect.construct(this.constructor, [this.shape, ObjectValidatorStrategy.Passthrough, this.constraints]); | ||
} | ||
get partial() { | ||
@@ -935,6 +993,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)); | ||
} | ||
@@ -990,2 +1048,6 @@ return this.handleStrategy(value); | ||
} | ||
handlePassthroughStrategy(value) { | ||
const result = this.handleIgnoreStrategy(value); | ||
return result.isErr() ? result : Result.ok({ ...value, ...result.value }); | ||
} | ||
}; | ||
@@ -996,2 +1058,3 @@ __name(ObjectValidator, "ObjectValidator"); | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Strict"] = 1] = "Strict"; | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Passthrough"] = 2] = "Passthrough"; | ||
return ObjectValidatorStrategy2; | ||
@@ -1019,6 +1082,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)); | ||
} | ||
@@ -1078,3 +1141,3 @@ const errors = []; | ||
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)); | ||
} | ||
@@ -1096,6 +1159,132 @@ const errors = []; | ||
// src/constraints/StringConstraints.ts | ||
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, "Invalid string length", input, expected)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid string length", input, expected)); | ||
} | ||
@@ -1135,2 +1324,60 @@ }; | ||
__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"); | ||
@@ -1157,4 +1404,25 @@ // src/validators/StringValidator.ts | ||
} | ||
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)); | ||
} | ||
@@ -1164,2 +1432,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 | ||
@@ -1184,3 +1483,3 @@ var UnionValidator = class extends BaseValidator { | ||
} | ||
return new UnionValidator([new LiteralValidator(void 0), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(void 0), ...this.validators]); | ||
} | ||
@@ -1200,3 +1499,3 @@ get nullable() { | ||
} | ||
return new UnionValidator([new LiteralValidator(null), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(null), ...this.validators]); | ||
} | ||
@@ -1207,6 +1506,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]); | ||
} | ||
@@ -1244,3 +1547,3 @@ or(...predicates) { | ||
if (!(value instanceof Map)) { | ||
return Result.err(new ValidationError("MapValidator", "Expected a map", value)); | ||
return Result.err(new ValidationError("s.map(K, V)", "Expected a map", value)); | ||
} | ||
@@ -1278,2 +1581,7 @@ const errors = []; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
@@ -1288,2 +1596,77 @@ return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
// 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 | ||
@@ -1330,2 +1713,5 @@ var Shapes = class { | ||
} | ||
nativeEnum(enumShape) { | ||
return new NativeEnumValidator(enumShape); | ||
} | ||
literal(value) { | ||
@@ -1345,2 +1731,5 @@ if (value instanceof Date) | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -1347,0 +1736,0 @@ return new SetValidator(validator); |
@@ -31,6 +31,8 @@ "use strict"; | ||
CombinedPropertyError: () => CombinedPropertyError, | ||
ConstraintError: () => ConstraintError, | ||
ExpectedConstraintError: () => ExpectedConstraintError, | ||
ExpectedValidationError: () => ExpectedValidationError, | ||
MissingPropertyError: () => MissingPropertyError, | ||
MultiplePossibilitiesConstraintError: () => MultiplePossibilitiesConstraintError, | ||
Result: () => Result, | ||
UnknownEnumValueError: () => UnknownEnumValueError, | ||
UnknownPropertyError: () => UnknownPropertyError, | ||
@@ -126,3 +128,3 @@ ValidationError: () => ValidationError, | ||
// src/lib/errors/ConstraintError.ts | ||
// src/lib/errors/ExpectedConstraintError.ts | ||
var import_node_util = require("util"); | ||
@@ -141,8 +143,16 @@ | ||
// src/lib/errors/ConstraintError.ts | ||
var ConstraintError = class extends BaseError { | ||
constructor(constraint, message, given, expected) { | ||
// src/lib/errors/BaseConstraintError.ts | ||
var BaseConstraintError = class extends BaseError { | ||
constructor(constraint, message, given) { | ||
super(message); | ||
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; | ||
@@ -161,3 +171,3 @@ } | ||
if (depth < 0) { | ||
return options.stylize(`[ConstraintError: ${constraint}]`, "special"); | ||
return options.stylize(`[ExpectedConstraintError: ${constraint}]`, "special"); | ||
} | ||
@@ -168,3 +178,3 @@ const newOptions = { ...options, depth: options.depth === null ? null : options.depth - 1 }; | ||
const given = (0, import_node_util.inspect)(this.given, newOptions).replaceAll("\n", padding); | ||
const header = `${options.stylize("ConstraintError", "special")} > ${constraint}`; | ||
const header = `${options.stylize("ExpectedConstraintError", "special")} > ${constraint}`; | ||
const message = options.stylize(this.message, "regexp"); | ||
@@ -181,3 +191,3 @@ const expectedBlock = ` | ||
}; | ||
__name(ConstraintError, "ConstraintError"); | ||
__name(ExpectedConstraintError, "ExpectedConstraintError"); | ||
@@ -214,3 +224,3 @@ // src/constraints/util/operators.ts | ||
run(input) { | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid Array length", input, expected)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Array length", input, expected)); | ||
} | ||
@@ -250,2 +260,29 @@ }; | ||
__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"); | ||
@@ -346,2 +383,11 @@ // src/lib/errors/CombinedPropertyError.ts | ||
} | ||
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() { | ||
@@ -352,3 +398,3 @@ 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)); | ||
} | ||
@@ -373,3 +419,3 @@ const errors = []; | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid bigint value", input, expected)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid bigint value", input, expected)); | ||
} | ||
@@ -413,3 +459,3 @@ }; | ||
run(input) { | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
return input % divider === 0n ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.bigint.divisibleBy", "BigInt is not divisible", input, expected)); | ||
} | ||
@@ -459,3 +505,3 @@ }; | ||
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)); | ||
} | ||
@@ -468,3 +514,3 @@ }; | ||
run(input) { | ||
return input ? Result.ok(input) : Result.err(new ConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
return input ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.boolean.true", "Invalid boolean value", input, "true")); | ||
} | ||
@@ -474,3 +520,3 @@ }; | ||
run(input) { | ||
return input ? Result.err(new ConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
return input ? Result.err(new ExpectedConstraintError("s.boolean.false", "Invalid boolean value", input, "false")) : Result.ok(input); | ||
} | ||
@@ -494,3 +540,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)); | ||
} | ||
@@ -504,3 +550,3 @@ }; | ||
run(input) { | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid Date value", input, expected)); | ||
return comparator(input.getTime(), number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid Date value", input, expected)); | ||
} | ||
@@ -511,3 +557,3 @@ }; | ||
function dateLt(value) { | ||
const expected = `expected < ${value}`; | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
@@ -517,3 +563,3 @@ } | ||
function dateLe(value) { | ||
const expected = `expected <= ${value}`; | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
@@ -523,3 +569,3 @@ } | ||
function dateGt(value) { | ||
const expected = `expected > ${value}`; | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
@@ -529,3 +575,3 @@ } | ||
function dateGe(value) { | ||
const expected = `expected >= ${value}`; | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
@@ -535,3 +581,3 @@ } | ||
function dateEq(value) { | ||
const expected = `expected === ${value}`; | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
@@ -541,3 +587,3 @@ } | ||
function dateNe(value) { | ||
const expected = `expected !== ${value}`; | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
@@ -548,3 +594,3 @@ } | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ConstraintError("s.date.eq(NaN)", "Invalid Date value", input, "expected === NaN")); | ||
return Number.isNaN(input.getTime()) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.date.invalid", "Invalid Date value", input, "expected === NaN")); | ||
} | ||
@@ -554,3 +600,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input.getTime()) ? Result.err(new ConstraintError("s.date.ne(NaN)", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
return Number.isNaN(input.getTime()) ? Result.err(new ExpectedConstraintError("s.date.valid", "Invalid Date value", input, "expected !== NaN")) : Result.ok(input); | ||
} | ||
@@ -575,10 +621,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)); | ||
} | ||
@@ -634,3 +686,3 @@ }; | ||
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)); | ||
} | ||
@@ -650,3 +702,3 @@ clone() { | ||
handle(value) { | ||
return Object.is(value, this.expected) ? Result.ok(value) : Result.err(new ExpectedValidationError("LiteralValidator", "Expected values to be equals", 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)); | ||
} | ||
@@ -662,3 +714,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)); | ||
} | ||
@@ -671,3 +723,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)); | ||
} | ||
@@ -681,3 +733,3 @@ }; | ||
run(input) { | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ConstraintError(name, "Invalid number value", input, expected)); | ||
return comparator(input, number) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid number value", input, expected)); | ||
} | ||
@@ -719,3 +771,3 @@ }; | ||
run(input) { | ||
return Number.isInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.int", "Given value is not an integer", input, "Number.isInteger(expected) to be true")); | ||
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")); | ||
} | ||
@@ -725,3 +777,3 @@ }; | ||
run(input) { | ||
return Number.isSafeInteger(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.safeInt", "Given value is not a safe integer", input, "Number.isSafeInteger(expected) to be true")); | ||
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")); | ||
} | ||
@@ -731,3 +783,3 @@ }; | ||
run(input) { | ||
return Number.isFinite(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.finite", "Given value is not finite", input, "Number.isFinite(expected) to be true")); | ||
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")); | ||
} | ||
@@ -737,3 +789,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
return Number.isNaN(input) ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.eq(NaN)", "Invalid number value", input, "expected === NaN")); | ||
} | ||
@@ -743,3 +795,3 @@ }; | ||
run(input) { | ||
return Number.isNaN(input) ? Result.err(new ConstraintError("s.number.ne(NaN)", "Invalid number value", input, "expected !== 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); | ||
} | ||
@@ -751,3 +803,3 @@ }; | ||
run(input) { | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
return input % divider === 0 ? Result.ok(input) : Result.err(new ExpectedConstraintError("s.number.divisibleBy", "Number is not divisible", input, expected)); | ||
} | ||
@@ -818,3 +870,3 @@ }; | ||
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)); | ||
} | ||
@@ -899,2 +951,5 @@ }; | ||
} | ||
case ObjectValidatorStrategy.Passthrough: | ||
this.handleStrategy = (value) => this.handlePassthroughStrategy(value); | ||
break; | ||
} | ||
@@ -908,2 +963,5 @@ } | ||
} | ||
get passthrough() { | ||
return Reflect.construct(this.constructor, [this.shape, ObjectValidatorStrategy.Passthrough, this.constraints]); | ||
} | ||
get partial() { | ||
@@ -928,6 +986,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)); | ||
} | ||
@@ -983,2 +1041,6 @@ return this.handleStrategy(value); | ||
} | ||
handlePassthroughStrategy(value) { | ||
const result = this.handleIgnoreStrategy(value); | ||
return result.isErr() ? result : Result.ok({ ...value, ...result.value }); | ||
} | ||
}; | ||
@@ -989,2 +1051,3 @@ __name(ObjectValidator, "ObjectValidator"); | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Strict"] = 1] = "Strict"; | ||
ObjectValidatorStrategy2[ObjectValidatorStrategy2["Passthrough"] = 2] = "Passthrough"; | ||
return ObjectValidatorStrategy2; | ||
@@ -1012,6 +1075,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)); | ||
} | ||
@@ -1071,3 +1134,3 @@ const errors = []; | ||
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)); | ||
} | ||
@@ -1089,6 +1152,132 @@ const errors = []; | ||
// src/constraints/StringConstraints.ts | ||
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, "Invalid string length", input, expected)); | ||
return comparator(input.length, length) ? Result.ok(input) : Result.err(new ExpectedConstraintError(name, "Invalid string length", input, expected)); | ||
} | ||
@@ -1128,2 +1317,60 @@ }; | ||
__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"); | ||
@@ -1150,4 +1397,25 @@ // src/validators/StringValidator.ts | ||
} | ||
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)); | ||
} | ||
@@ -1157,2 +1425,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 | ||
@@ -1177,3 +1476,3 @@ var UnionValidator = class extends BaseValidator { | ||
} | ||
return new UnionValidator([new LiteralValidator(void 0), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(void 0), ...this.validators]); | ||
} | ||
@@ -1193,3 +1492,3 @@ get nullable() { | ||
} | ||
return new UnionValidator([new LiteralValidator(null), this.clone()]); | ||
return new UnionValidator([new LiteralValidator(null), ...this.validators]); | ||
} | ||
@@ -1200,6 +1499,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]); | ||
} | ||
@@ -1237,3 +1540,3 @@ or(...predicates) { | ||
if (!(value instanceof Map)) { | ||
return Result.err(new ValidationError("MapValidator", "Expected a map", value)); | ||
return Result.err(new ValidationError("s.map(K, V)", "Expected a map", value)); | ||
} | ||
@@ -1271,2 +1574,7 @@ const errors = []; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
@@ -1281,2 +1589,77 @@ return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
// 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 | ||
@@ -1323,2 +1706,5 @@ var Shapes = class { | ||
} | ||
nativeEnum(enumShape) { | ||
return new NativeEnumValidator(enumShape); | ||
} | ||
literal(value) { | ||
@@ -1338,2 +1724,5 @@ if (value instanceof Date) | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -1358,6 +1747,8 @@ return new SetValidator(validator); | ||
CombinedPropertyError, | ||
ConstraintError, | ||
ExpectedConstraintError, | ||
ExpectedValidationError, | ||
MissingPropertyError, | ||
MultiplePossibilitiesConstraintError, | ||
Result, | ||
UnknownEnumValueError, | ||
UnknownPropertyError, | ||
@@ -1364,0 +1755,0 @@ ValidationError, |
{ | ||
"name": "@sapphire/shapeshift", | ||
"version": "1.1.0-next.dc7ccaf.0", | ||
"version": "1.1.0-next.deff6a7.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,3 +31,3 @@ "sideEffects": false, | ||
"sversion": "standard-version", | ||
"prepublishOnly": "rollup-type-bundler", | ||
"prepublishOnly": "rollup-type-bundler -e node:util", | ||
"prepare": "husky install .github/husky" | ||
@@ -39,12 +40,12 @@ }, | ||
"@favware/rollup-type-bundler": "^1.0.7", | ||
"@sapphire/eslint-config": "^4.2.1", | ||
"@sapphire/prettier-config": "^1.3.0", | ||
"@sapphire/ts-config": "^3.3.1", | ||
"@types/jest": "^27.4.0", | ||
"@types/node": "^17.0.8", | ||
"@typescript-eslint/eslint-plugin": "^5.12.0", | ||
"@typescript-eslint/parser": "^5.12.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.9.0", | ||
"eslint-config-prettier": "^8.4.0", | ||
"eslint": "^8.11.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
@@ -54,3 +55,3 @@ "husky": "^7.0.4", | ||
"jest-circus": "^27.5.1", | ||
"lint-staged": "^12.3.4", | ||
"lint-staged": "^12.3.5", | ||
"prettier": "^2.5.1", | ||
@@ -60,7 +61,6 @@ "pretty-quick": "^3.1.3", | ||
"ts-jest": "^27.1.3", | ||
"ts-node": "^10.5.0", | ||
"tsup": "^5.11.13", | ||
"typedoc": "^0.22.12", | ||
"tsup": "^5.12.1", | ||
"typedoc": "^0.22.13", | ||
"typedoc-plugin-mdn-links": "^1.0.5", | ||
"typescript": "^4.5.5" | ||
"typescript": "^4.6.2" | ||
}, | ||
@@ -67,0 +67,0 @@ "repository": { |
@@ -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; | ||
``` | ||
@@ -201,3 +205,3 @@ | ||
ShapeShift includes a handful of string-specific validations: | ||
ShapeShift includes a handful of array-specific validations: | ||
@@ -211,7 +215,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 | ||
@@ -334,2 +341,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 | ||
@@ -522,2 +533,3 @@ | ||
<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> | ||
@@ -524,0 +536,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
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
598738
27
5350
542
1