@sapphire/shapeshift
Advanced tools
Comparing version 1.1.0-next.dc7ccaf.0 to 1.1.0-next.e6827c5.0
@@ -49,3 +49,14 @@ /// <reference types="node" /> | ||
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>; | ||
@@ -138,3 +149,3 @@ declare function stringLengthLe(length: number): IConstraint<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>; | ||
@@ -150,11 +161,17 @@ parse(value: unknown): 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[]]>; | ||
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, [[]]>; | ||
@@ -314,5 +331,19 @@ declare class BigIntValidator<T extends bigint> extends BaseValidator<T> { | ||
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> { | ||
@@ -337,6 +368,7 @@ 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>[]); | ||
default(value: Exclude<T, undefined> | (() => Exclude<T, undefined>)): DefaultValidator<Exclude<T, undefined>>; | ||
protected handle(value: unknown): Result<T, ValidationError | CombinedError | CombinedPropertyError>; | ||
@@ -362,4 +394,5 @@ protected clone(): this; | ||
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>; | ||
@@ -369,2 +402,4 @@ 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; | ||
@@ -395,2 +430,2 @@ declare class MissingPropertyError extends BaseError { | ||
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, 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, TupleValidator, Type, UnionValidator, UnknownPropertyError, Unwrap, 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 }; |
@@ -350,3 +350,3 @@ var SapphireShapeshift = (() => { | ||
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)); | ||
} | ||
@@ -455,3 +455,3 @@ const errors = []; | ||
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)); | ||
} | ||
@@ -488,3 +488,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 +504,3 @@ }; | ||
function dateLt(value) { | ||
const expected = `expected < ${value}`; | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
@@ -510,3 +510,3 @@ } | ||
function dateLe(value) { | ||
const expected = `expected <= ${value}`; | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
@@ -516,3 +516,3 @@ } | ||
function dateGt(value) { | ||
const expected = `expected > ${value}`; | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
@@ -522,3 +522,3 @@ } | ||
function dateGe(value) { | ||
const expected = `expected >= ${value}`; | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
@@ -528,3 +528,3 @@ } | ||
function dateEq(value) { | ||
const expected = `expected === ${value}`; | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
@@ -534,3 +534,3 @@ } | ||
function dateNe(value) { | ||
const expected = `expected !== ${value}`; | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
@@ -573,3 +573,3 @@ } | ||
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)); | ||
} | ||
@@ -625,3 +625,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)); | ||
} | ||
@@ -641,3 +641,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)); | ||
} | ||
@@ -653,3 +653,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)); | ||
} | ||
@@ -662,3 +662,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)); | ||
} | ||
@@ -802,3 +802,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)); | ||
} | ||
@@ -910,6 +910,6 @@ }; | ||
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)); | ||
} | ||
@@ -992,6 +992,6 @@ return this.handleStrategy(value); | ||
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)); | ||
} | ||
@@ -1051,3 +1051,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)); | ||
} | ||
@@ -1069,2 +1069,36 @@ 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 emailParts = email.split("@"); | ||
if (emailParts.length !== 2) | ||
return false; | ||
const account = emailParts[0]; | ||
if (account.length > 64) | ||
return false; | ||
const domain = emailParts[1]; | ||
if (domain.length > 255) | ||
return false; | ||
const domainParts = domain.split("."); | ||
if (domainParts.length < 2) | ||
return false; | ||
if (domainParts.some((part) => part.length > 63)) | ||
return false; | ||
return accountRegex.test(account) && validateEmailDomain(domain); | ||
} | ||
__name(validateEmail, "validateEmail"); | ||
function validateEmailDomain(domain) { | ||
try { | ||
return new URL(`http://${domain}`).hostname === domain; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
__name(validateEmailDomain, "validateEmailDomain"); | ||
// src/constraints/StringConstraints.ts | ||
function stringLengthComparator(comparator, name, expected, length) { | ||
@@ -1108,2 +1142,57 @@ return { | ||
__name(stringLengthNe, "stringLengthNe"); | ||
function stringEmail() { | ||
return { | ||
run(input) { | ||
return validateEmail(input) ? Result.ok(input) : Result.err(new ConstraintError("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 ConstraintError(type, "Invalid string format", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringRegexValidator, "stringRegexValidator"); | ||
function stringUrl(options) { | ||
return { | ||
run(input) { | ||
try { | ||
const url = new URL(input); | ||
if (options?.allowedProtocols && !options.allowedProtocols.includes(url.protocol)) { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL protocol", input, `expected ${url.protocol} to be one of: ${options.allowedProtocols.join(", ")}`)); | ||
} | ||
if (options?.allowedDomains && !options.allowedDomains.includes(url.hostname)) { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL domain", input, `expected ${url.hostname} to be one of: ${options.allowedDomains.join(", ")}`)); | ||
} | ||
return Result.ok(input); | ||
} catch { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL", input, "expected to match an URL")); | ||
} | ||
} | ||
}; | ||
} | ||
__name(stringUrl, "stringUrl"); | ||
function stringIp(version) { | ||
const ipVersion = version ? `v${version}` : ""; | ||
return { | ||
run(input) { | ||
return (version === 4 ? (0, import_node_net.isIPv4)(input) : version === 6 ? (0, import_node_net.isIPv6)(input) : (0, import_node_net.isIP)(input)) ? Result.ok(input) : Result.err(new ConstraintError(`s.string.ip${ipVersion}`, `Invalid ip${ipVersion} address`, input, `expected to be an ip${ipVersion} address`)); | ||
} | ||
}; | ||
} | ||
__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"); | ||
@@ -1130,4 +1219,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)); | ||
} | ||
@@ -1137,2 +1247,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 | ||
@@ -1214,3 +1355,3 @@ var UnionValidator = class extends BaseValidator { | ||
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)); | ||
} | ||
@@ -1248,2 +1389,7 @@ const errors = []; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
@@ -1313,2 +1459,5 @@ return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -1315,0 +1464,0 @@ return new SetValidator(validator); |
@@ -343,3 +343,3 @@ "use strict"; | ||
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)); | ||
} | ||
@@ -448,3 +448,3 @@ const errors = []; | ||
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)); | ||
} | ||
@@ -481,3 +481,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)); | ||
} | ||
@@ -497,3 +497,3 @@ }; | ||
function dateLt(value) { | ||
const expected = `expected < ${value}`; | ||
const expected = `expected < ${value.toISOString()}`; | ||
return dateComparator(lt, "s.date.lt", expected, value.getTime()); | ||
@@ -503,3 +503,3 @@ } | ||
function dateLe(value) { | ||
const expected = `expected <= ${value}`; | ||
const expected = `expected <= ${value.toISOString()}`; | ||
return dateComparator(le, "s.date.le", expected, value.getTime()); | ||
@@ -509,3 +509,3 @@ } | ||
function dateGt(value) { | ||
const expected = `expected > ${value}`; | ||
const expected = `expected > ${value.toISOString()}`; | ||
return dateComparator(gt, "s.date.gt", expected, value.getTime()); | ||
@@ -515,3 +515,3 @@ } | ||
function dateGe(value) { | ||
const expected = `expected >= ${value}`; | ||
const expected = `expected >= ${value.toISOString()}`; | ||
return dateComparator(ge, "s.date.ge", expected, value.getTime()); | ||
@@ -521,3 +521,3 @@ } | ||
function dateEq(value) { | ||
const expected = `expected === ${value}`; | ||
const expected = `expected === ${value.toISOString()}`; | ||
return dateComparator(eq, "s.date.eq", expected, value.getTime()); | ||
@@ -527,3 +527,3 @@ } | ||
function dateNe(value) { | ||
const expected = `expected !== ${value}`; | ||
const expected = `expected !== ${value.toISOString()}`; | ||
return dateComparator(ne, "s.date.ne", expected, value.getTime()); | ||
@@ -566,3 +566,3 @@ } | ||
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)); | ||
} | ||
@@ -618,3 +618,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)); | ||
} | ||
@@ -634,3 +634,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)); | ||
} | ||
@@ -646,3 +646,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)); | ||
} | ||
@@ -655,3 +655,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)); | ||
} | ||
@@ -795,3 +795,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)); | ||
} | ||
@@ -903,6 +903,6 @@ }; | ||
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)); | ||
} | ||
@@ -985,6 +985,6 @@ return this.handleStrategy(value); | ||
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)); | ||
} | ||
@@ -1044,3 +1044,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)); | ||
} | ||
@@ -1062,2 +1062,36 @@ 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 emailParts = email.split("@"); | ||
if (emailParts.length !== 2) | ||
return false; | ||
const account = emailParts[0]; | ||
if (account.length > 64) | ||
return false; | ||
const domain = emailParts[1]; | ||
if (domain.length > 255) | ||
return false; | ||
const domainParts = domain.split("."); | ||
if (domainParts.length < 2) | ||
return false; | ||
if (domainParts.some((part) => part.length > 63)) | ||
return false; | ||
return accountRegex.test(account) && validateEmailDomain(domain); | ||
} | ||
__name(validateEmail, "validateEmail"); | ||
function validateEmailDomain(domain) { | ||
try { | ||
return new URL(`http://${domain}`).hostname === domain; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
__name(validateEmailDomain, "validateEmailDomain"); | ||
// src/constraints/StringConstraints.ts | ||
function stringLengthComparator(comparator, name, expected, length) { | ||
@@ -1101,2 +1135,57 @@ return { | ||
__name(stringLengthNe, "stringLengthNe"); | ||
function stringEmail() { | ||
return { | ||
run(input) { | ||
return validateEmail(input) ? Result.ok(input) : Result.err(new ConstraintError("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 ConstraintError(type, "Invalid string format", input, expected)); | ||
} | ||
}; | ||
} | ||
__name(stringRegexValidator, "stringRegexValidator"); | ||
function stringUrl(options) { | ||
return { | ||
run(input) { | ||
try { | ||
const url = new URL(input); | ||
if (options?.allowedProtocols && !options.allowedProtocols.includes(url.protocol)) { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL protocol", input, `expected ${url.protocol} to be one of: ${options.allowedProtocols.join(", ")}`)); | ||
} | ||
if (options?.allowedDomains && !options.allowedDomains.includes(url.hostname)) { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL domain", input, `expected ${url.hostname} to be one of: ${options.allowedDomains.join(", ")}`)); | ||
} | ||
return Result.ok(input); | ||
} catch { | ||
return Result.err(new ConstraintError("s.string.url", "Invalid URL", input, "expected to match an URL")); | ||
} | ||
} | ||
}; | ||
} | ||
__name(stringUrl, "stringUrl"); | ||
function stringIp(version) { | ||
const ipVersion = version ? `v${version}` : ""; | ||
return { | ||
run(input) { | ||
return (version === 4 ? (0, import_node_net.isIPv4)(input) : version === 6 ? (0, import_node_net.isIPv6)(input) : (0, import_node_net.isIP)(input)) ? Result.ok(input) : Result.err(new ConstraintError(`s.string.ip${ipVersion}`, `Invalid ip${ipVersion} address`, input, `expected to be an ip${ipVersion} address`)); | ||
} | ||
}; | ||
} | ||
__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"); | ||
@@ -1123,4 +1212,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)); | ||
} | ||
@@ -1130,2 +1240,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 | ||
@@ -1207,3 +1348,3 @@ var UnionValidator = class extends BaseValidator { | ||
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)); | ||
} | ||
@@ -1241,2 +1382,7 @@ const errors = []; | ||
} | ||
default(value) { | ||
const clone = this.clone(); | ||
clone.defaultValue = value; | ||
return clone; | ||
} | ||
handle(value) { | ||
@@ -1306,2 +1452,5 @@ return typeof value === "undefined" ? Result.ok(getValue(this.defaultValue)) : this.validator["handle"](value); | ||
} | ||
tuple(validators) { | ||
return new TupleValidator(validators); | ||
} | ||
set(validator) { | ||
@@ -1308,0 +1457,0 @@ return new SetValidator(validator); |
{ | ||
"name": "@sapphire/shapeshift", | ||
"version": "1.1.0-next.dc7ccaf.0", | ||
"version": "1.1.0-next.e6827c5.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" | ||
}, | ||
@@ -41,8 +42,8 @@ "sideEffects": false, | ||
"@sapphire/ts-config": "^3.3.1", | ||
"@types/jest": "^27.4.0", | ||
"@types/jest": "^27.4.1", | ||
"@types/node": "^17.0.8", | ||
"@typescript-eslint/eslint-plugin": "^5.12.0", | ||
"@typescript-eslint/parser": "^5.12.0", | ||
"@typescript-eslint/eslint-plugin": "^5.12.1", | ||
"@typescript-eslint/parser": "^5.12.1", | ||
"cz-conventional-changelog": "^3.3.0", | ||
"eslint": "^8.9.0", | ||
"eslint": "^8.10.0", | ||
"eslint-config-prettier": "^8.4.0", | ||
@@ -49,0 +50,0 @@ "eslint-plugin-prettier": "^4.0.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; | ||
``` | ||
@@ -212,5 +216,5 @@ | ||
> **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 | ||
@@ -520,2 +524,3 @@ Unlike arrays, tuples have a fixed number of elements and each element can have a different type: | ||
<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> | ||
@@ -522,0 +527,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
494579
4588
535
1