Skip to content

Commit

Permalink
Support async z.custom
Browse files Browse the repository at this point in the history
  • Loading branch information
colinhacks committed Feb 11, 2025
1 parent b7e173d commit 1dd44a0
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 22 deletions.
13 changes: 13 additions & 0 deletions deno/lib/__tests__/custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@ test("string params", () => {
// @ts-ignore
expect(JSON.stringify(result.error).includes("customerr")).toEqual(true);
});

test("async validations", async () => {
const example1 = z.custom<number>(async (x) => {
return typeof x === "number";
});
const r1 = await example1.safeParseAsync(1234);
expect(r1.success).toEqual(true);
expect(r1.data).toEqual(1234);

const r2 = await example1.safeParseAsync("asdf");
expect(r2.success).toEqual(false);
expect(r2.error!.issues.length).toEqual(1);
});
38 changes: 27 additions & 11 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5235,10 +5235,21 @@ export class ZodReadonly<T extends ZodTypeAny> extends ZodType<
////////// //////////
////////////////////////////////////////
////////////////////////////////////////
function cleanParams(params: unknown, data: unknown) {
const p =
typeof params === "function"
? params(data)
: typeof params === "string"
? { message: params }
: params;

const p2 = typeof p === "string" ? { message: p } : p;
return p2;
}
type CustomParams = CustomErrorParams & { fatal?: boolean };
export function custom<T>(
check?: (data: any) => any,
params: string | CustomParams | ((input: any) => CustomParams) = {},
_params: string | CustomParams | ((input: any) => CustomParams) = {},
/**
* @deprecated
*
Expand All @@ -5253,17 +5264,22 @@ export function custom<T>(
): ZodType<T, ZodTypeDef, T> {
if (check)
return ZodAny.create().superRefine((data, ctx) => {
if (!check(data)) {
const p =
typeof params === "function"
? params(data)
: typeof params === "string"
? { message: params }
: params;
const _fatal = p.fatal ?? fatal ?? true;
const p2 = typeof p === "string" ? { message: p } : p;
ctx.addIssue({ code: "custom", ...p2, fatal: _fatal });
const r = check(data);
if (r instanceof Promise) {
return r.then((r) => {
if (!r) {
const params = cleanParams(_params, data);
const _fatal = params.fatal ?? fatal ?? true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
});
}
if (!r) {
const params = cleanParams(_params, data);
const _fatal = params.fatal ?? fatal ?? true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
return;
});
return ZodAny.create();
}
Expand Down
13 changes: 13 additions & 0 deletions src/__tests__/custom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,16 @@ test("string params", () => {
// @ts-ignore
expect(JSON.stringify(result.error).includes("customerr")).toEqual(true);
});

test("async validations", async () => {
const example1 = z.custom<number>(async (x) => {
return typeof x === "number";
});
const r1 = await example1.safeParseAsync(1234);
expect(r1.success).toEqual(true);
expect(r1.data).toEqual(1234);

const r2 = await example1.safeParseAsync("asdf");
expect(r2.success).toEqual(false);
expect(r2.error!.issues.length).toEqual(1);
});
38 changes: 27 additions & 11 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5235,10 +5235,21 @@ export class ZodReadonly<T extends ZodTypeAny> extends ZodType<
////////// //////////
////////////////////////////////////////
////////////////////////////////////////
function cleanParams(params: unknown, data: unknown) {
const p =
typeof params === "function"
? params(data)
: typeof params === "string"
? { message: params }
: params;

const p2 = typeof p === "string" ? { message: p } : p;
return p2;
}
type CustomParams = CustomErrorParams & { fatal?: boolean };
export function custom<T>(
check?: (data: any) => any,
params: string | CustomParams | ((input: any) => CustomParams) = {},
_params: string | CustomParams | ((input: any) => CustomParams) = {},
/**
* @deprecated
*
Expand All @@ -5253,17 +5264,22 @@ export function custom<T>(
): ZodType<T, ZodTypeDef, T> {
if (check)
return ZodAny.create().superRefine((data, ctx) => {
if (!check(data)) {
const p =
typeof params === "function"
? params(data)
: typeof params === "string"
? { message: params }
: params;
const _fatal = p.fatal ?? fatal ?? true;
const p2 = typeof p === "string" ? { message: p } : p;
ctx.addIssue({ code: "custom", ...p2, fatal: _fatal });
const r = check(data);
if (r instanceof Promise) {
return r.then((r) => {
if (!r) {
const params = cleanParams(_params, data);
const _fatal = params.fatal ?? fatal ?? true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
});
}
if (!r) {
const params = cleanParams(_params, data);
const _fatal = params.fatal ?? fatal ?? true;
ctx.addIssue({ code: "custom", ...params, fatal: _fatal });
}
return;
});
return ZodAny.create();
}
Expand Down

0 comments on commit 1dd44a0

Please sign in to comment.