mirror of
https://github.com/hex248/ob248.com.git
synced 2026-02-08 02:33:02 +00:00
331 lines
8.8 KiB
TypeScript
331 lines
8.8 KiB
TypeScript
import type { Primitive } from "./helpers/typeAliases.js";
|
|
import { util, type ZodParsedType } from "./helpers/util.js";
|
|
import type { TypeOf, ZodType } from "./index.js";
|
|
|
|
type allKeys<T> = T extends any ? keyof T : never;
|
|
|
|
export type inferFlattenedErrors<T extends ZodType<any, any, any>, U = string> = typeToFlattenedError<TypeOf<T>, U>;
|
|
export type typeToFlattenedError<T, U = string> = {
|
|
formErrors: U[];
|
|
fieldErrors: {
|
|
[P in allKeys<T>]?: U[];
|
|
};
|
|
};
|
|
|
|
export const ZodIssueCode = util.arrayToEnum([
|
|
"invalid_type",
|
|
"invalid_literal",
|
|
"custom",
|
|
"invalid_union",
|
|
"invalid_union_discriminator",
|
|
"invalid_enum_value",
|
|
"unrecognized_keys",
|
|
"invalid_arguments",
|
|
"invalid_return_type",
|
|
"invalid_date",
|
|
"invalid_string",
|
|
"too_small",
|
|
"too_big",
|
|
"invalid_intersection_types",
|
|
"not_multiple_of",
|
|
"not_finite",
|
|
]);
|
|
|
|
export type ZodIssueCode = keyof typeof ZodIssueCode;
|
|
|
|
export type ZodIssueBase = {
|
|
path: (string | number)[];
|
|
message?: string | undefined;
|
|
};
|
|
|
|
export interface ZodInvalidTypeIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_type;
|
|
expected: ZodParsedType;
|
|
received: ZodParsedType;
|
|
}
|
|
|
|
export interface ZodInvalidLiteralIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_literal;
|
|
expected: unknown;
|
|
received: unknown;
|
|
}
|
|
|
|
export interface ZodUnrecognizedKeysIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.unrecognized_keys;
|
|
keys: string[];
|
|
}
|
|
|
|
export interface ZodInvalidUnionIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_union;
|
|
unionErrors: ZodError[];
|
|
}
|
|
|
|
export interface ZodInvalidUnionDiscriminatorIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_union_discriminator;
|
|
options: Primitive[];
|
|
}
|
|
|
|
export interface ZodInvalidEnumValueIssue extends ZodIssueBase {
|
|
received: string | number;
|
|
code: typeof ZodIssueCode.invalid_enum_value;
|
|
options: (string | number)[];
|
|
}
|
|
|
|
export interface ZodInvalidArgumentsIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_arguments;
|
|
argumentsError: ZodError;
|
|
}
|
|
|
|
export interface ZodInvalidReturnTypeIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_return_type;
|
|
returnTypeError: ZodError;
|
|
}
|
|
|
|
export interface ZodInvalidDateIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_date;
|
|
}
|
|
|
|
export type StringValidation =
|
|
| "email"
|
|
| "url"
|
|
| "emoji"
|
|
| "uuid"
|
|
| "nanoid"
|
|
| "regex"
|
|
| "cuid"
|
|
| "cuid2"
|
|
| "ulid"
|
|
| "datetime"
|
|
| "date"
|
|
| "time"
|
|
| "duration"
|
|
| "ip"
|
|
| "cidr"
|
|
| "base64"
|
|
| "jwt"
|
|
| "base64url"
|
|
| { includes: string; position?: number | undefined }
|
|
| { startsWith: string }
|
|
| { endsWith: string };
|
|
|
|
export interface ZodInvalidStringIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_string;
|
|
validation: StringValidation;
|
|
}
|
|
|
|
export interface ZodTooSmallIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.too_small;
|
|
minimum: number | bigint;
|
|
inclusive: boolean;
|
|
exact?: boolean;
|
|
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
}
|
|
|
|
export interface ZodTooBigIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.too_big;
|
|
maximum: number | bigint;
|
|
inclusive: boolean;
|
|
exact?: boolean;
|
|
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
}
|
|
|
|
export interface ZodInvalidIntersectionTypesIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.invalid_intersection_types;
|
|
}
|
|
|
|
export interface ZodNotMultipleOfIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.not_multiple_of;
|
|
multipleOf: number | bigint;
|
|
}
|
|
|
|
export interface ZodNotFiniteIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.not_finite;
|
|
}
|
|
|
|
export interface ZodCustomIssue extends ZodIssueBase {
|
|
code: typeof ZodIssueCode.custom;
|
|
params?: { [k: string]: any };
|
|
}
|
|
|
|
export type DenormalizedError = { [k: string]: DenormalizedError | string[] };
|
|
|
|
export type ZodIssueOptionalMessage =
|
|
| ZodInvalidTypeIssue
|
|
| ZodInvalidLiteralIssue
|
|
| ZodUnrecognizedKeysIssue
|
|
| ZodInvalidUnionIssue
|
|
| ZodInvalidUnionDiscriminatorIssue
|
|
| ZodInvalidEnumValueIssue
|
|
| ZodInvalidArgumentsIssue
|
|
| ZodInvalidReturnTypeIssue
|
|
| ZodInvalidDateIssue
|
|
| ZodInvalidStringIssue
|
|
| ZodTooSmallIssue
|
|
| ZodTooBigIssue
|
|
| ZodInvalidIntersectionTypesIssue
|
|
| ZodNotMultipleOfIssue
|
|
| ZodNotFiniteIssue
|
|
| ZodCustomIssue;
|
|
|
|
export type ZodIssue = ZodIssueOptionalMessage & {
|
|
fatal?: boolean | undefined;
|
|
message: string;
|
|
};
|
|
|
|
export const quotelessJson = (obj: any) => {
|
|
const json = JSON.stringify(obj, null, 2);
|
|
return json.replace(/"([^"]+)":/g, "$1:");
|
|
};
|
|
|
|
type recursiveZodFormattedError<T> = T extends [any, ...any[]]
|
|
? { [K in keyof T]?: ZodFormattedError<T[K]> }
|
|
: T extends any[]
|
|
? { [k: number]: ZodFormattedError<T[number]> }
|
|
: T extends object
|
|
? { [K in keyof T]?: ZodFormattedError<T[K]> }
|
|
: unknown;
|
|
|
|
export type ZodFormattedError<T, U = string> = {
|
|
_errors: U[];
|
|
} & recursiveZodFormattedError<NonNullable<T>>;
|
|
|
|
export type inferFormattedError<T extends ZodType<any, any, any>, U = string> = ZodFormattedError<TypeOf<T>, U>;
|
|
|
|
export class ZodError<T = any> extends Error {
|
|
issues: ZodIssue[] = [];
|
|
|
|
get errors() {
|
|
return this.issues;
|
|
}
|
|
|
|
constructor(issues: ZodIssue[]) {
|
|
super();
|
|
|
|
const actualProto = new.target.prototype;
|
|
if (Object.setPrototypeOf) {
|
|
// eslint-disable-next-line ban/ban
|
|
Object.setPrototypeOf(this, actualProto);
|
|
} else {
|
|
(this as any).__proto__ = actualProto;
|
|
}
|
|
this.name = "ZodError";
|
|
this.issues = issues;
|
|
}
|
|
|
|
format(): ZodFormattedError<T>;
|
|
format<U>(mapper: (issue: ZodIssue) => U): ZodFormattedError<T, U>;
|
|
format(_mapper?: any) {
|
|
const mapper: (issue: ZodIssue) => any =
|
|
_mapper ||
|
|
function (issue: ZodIssue) {
|
|
return issue.message;
|
|
};
|
|
const fieldErrors: ZodFormattedError<T> = { _errors: [] } as any;
|
|
const processError = (error: ZodError) => {
|
|
for (const issue of error.issues) {
|
|
if (issue.code === "invalid_union") {
|
|
issue.unionErrors.map(processError);
|
|
} else if (issue.code === "invalid_return_type") {
|
|
processError(issue.returnTypeError);
|
|
} else if (issue.code === "invalid_arguments") {
|
|
processError(issue.argumentsError);
|
|
} else if (issue.path.length === 0) {
|
|
(fieldErrors as any)._errors.push(mapper(issue));
|
|
} else {
|
|
let curr: any = fieldErrors;
|
|
let i = 0;
|
|
while (i < issue.path.length) {
|
|
const el = issue.path[i]!;
|
|
const terminal = i === issue.path.length - 1;
|
|
|
|
if (!terminal) {
|
|
curr[el] = curr[el] || { _errors: [] };
|
|
// if (typeof el === "string") {
|
|
// curr[el] = curr[el] || { _errors: [] };
|
|
// } else if (typeof el === "number") {
|
|
// const errorArray: any = [];
|
|
// errorArray._errors = [];
|
|
// curr[el] = curr[el] || errorArray;
|
|
// }
|
|
} else {
|
|
curr[el] = curr[el] || { _errors: [] };
|
|
curr[el]._errors.push(mapper(issue));
|
|
}
|
|
|
|
curr = curr[el];
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
processError(this);
|
|
return fieldErrors;
|
|
}
|
|
|
|
static create = (issues: ZodIssue[]) => {
|
|
const error = new ZodError(issues);
|
|
return error;
|
|
};
|
|
|
|
static assert(value: unknown): asserts value is ZodError {
|
|
if (!(value instanceof ZodError)) {
|
|
throw new Error(`Not a ZodError: ${value}`);
|
|
}
|
|
}
|
|
|
|
override toString() {
|
|
return this.message;
|
|
}
|
|
override get message() {
|
|
return JSON.stringify(this.issues, util.jsonStringifyReplacer, 2);
|
|
}
|
|
|
|
get isEmpty(): boolean {
|
|
return this.issues.length === 0;
|
|
}
|
|
|
|
addIssue = (sub: ZodIssue) => {
|
|
this.issues = [...this.issues, sub];
|
|
};
|
|
|
|
addIssues = (subs: ZodIssue[] = []) => {
|
|
this.issues = [...this.issues, ...subs];
|
|
};
|
|
|
|
flatten(): typeToFlattenedError<T>;
|
|
flatten<U>(mapper?: (issue: ZodIssue) => U): typeToFlattenedError<T, U>;
|
|
flatten<U = string>(mapper: (issue: ZodIssue) => U = (issue: ZodIssue) => issue.message as any): any {
|
|
const fieldErrors: any = Object.create(null);
|
|
const formErrors: U[] = [];
|
|
for (const sub of this.issues) {
|
|
if (sub.path.length > 0) {
|
|
const firstEl = sub.path[0]!;
|
|
fieldErrors[firstEl] = fieldErrors[firstEl] || [];
|
|
fieldErrors[firstEl].push(mapper(sub));
|
|
} else {
|
|
formErrors.push(mapper(sub));
|
|
}
|
|
}
|
|
return { formErrors, fieldErrors };
|
|
}
|
|
|
|
get formErrors() {
|
|
return this.flatten();
|
|
}
|
|
}
|
|
|
|
type stripPath<T extends object> = T extends any ? util.OmitKeys<T, "path"> : never;
|
|
|
|
export type IssueData = stripPath<ZodIssueOptionalMessage> & {
|
|
path?: (string | number)[];
|
|
fatal?: boolean | undefined;
|
|
};
|
|
|
|
export type ErrorMapCtx = {
|
|
defaultError: string;
|
|
data: any;
|
|
};
|
|
|
|
export type ZodErrorMap = (issue: ZodIssueOptionalMessage, _ctx: ErrorMapCtx) => { message: string };
|