Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: colinhacks/zod
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.22.0
Choose a base ref
...
head repository: colinhacks/zod
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.22.1
Choose a head ref
  • 2 commits
  • 5 files changed
  • 2 contributors

Commits on Aug 15, 2023

  1. Initial prototype fix for issue #2651 (#2652)

    * Initial prototype fix
    
    * Add implementation/test for async
    
    * Fix formatting
    ddurschlag authored Aug 15, 2023
    Copy the full SHA
    932cc47 View commit details
  2. 3.22.1

    colinhacks committed Aug 15, 2023
    Copy the full SHA
    0a055e7 View commit details
Showing with 85 additions and 17 deletions.
  1. +26 −0 deno/lib/__tests__/function.test.ts
  2. +16 −8 deno/lib/types.ts
  3. +1 −1 package.json
  4. +26 −0 src/__tests__/function.test.ts
  5. +16 −8 src/types.ts
26 changes: 26 additions & 0 deletions deno/lib/__tests__/function.test.ts
Original file line number Diff line number Diff line change
@@ -29,6 +29,32 @@ test("function inference 1", () => {
util.assertEqual<func1, (k: string) => number>(true);
});

test("method parsing", () => {
const methodObject = z.object({
property: z.number(),
method: z.function().args(z.string()).returns(z.number())
});
const methodInstance = {
property: 3,
method: function(s: string) { return s.length + this.property; }
};
const parsed = methodObject.parse(methodInstance);
expect(parsed.method('length=8')).toBe(11); // 8 length + 3 property
});

test("async method parsing", async () => {
const methodObject = z.object({
property: z.number(),
method: z.function().args(z.string()).returns(z.promise(z.number()))
});
const methodInstance = {
property: 3,
method: async function(s: string) { return s.length + this.property; }
};
const parsed = methodObject.parse(methodInstance);
expect(await parsed.method('length=8')).toBe(11); // 8 length + 3 property
});

test("args method", () => {
const t1 = z.function();
type t1 = z.infer<typeof t1>;
24 changes: 16 additions & 8 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
@@ -3736,17 +3736,21 @@ export class ZodFunction<
const fn = ctx.data;

if (this._def.returns instanceof ZodPromise) {
return OK(async (...args: any[]) => {
// Would love a way to avoid disabling this rule, but we need
// an alias (using an arrow function was what caused 2651).
// eslint-disable-next-line @typescript-eslint/no-this-alias
const me = this;
return OK(async function (this: any, ...args: any[]) {
const error = new ZodError([]);
const parsedArgs = await this._def.args
const parsedArgs = await me._def.args
.parseAsync(args, params)
.catch((e) => {
error.addIssue(makeArgsIssue(args, e));
throw error;
});
const result = await fn(...(parsedArgs as any));
const result = await Reflect.apply(fn, this, parsedArgs as any);
const parsedReturns = await (
this._def.returns as unknown as ZodPromise<ZodTypeAny>
me._def.returns as unknown as ZodPromise<ZodTypeAny>
)._def.type
.parseAsync(result, params)
.catch((e) => {
@@ -3756,13 +3760,17 @@ export class ZodFunction<
return parsedReturns;
});
} else {
return OK((...args: any[]) => {
const parsedArgs = this._def.args.safeParse(args, params);
// Would love a way to avoid disabling this rule, but we need
// an alias (using an arrow function was what caused 2651).
// eslint-disable-next-line @typescript-eslint/no-this-alias
const me = this;
return OK(function (this: any, ...args: any[]) {
const parsedArgs = me._def.args.safeParse(args, params);
if (!parsedArgs.success) {
throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
}
const result = fn(...(parsedArgs.data as any));
const parsedReturns = this._def.returns.safeParse(result, params);
const result = Reflect.apply(fn, this, parsedArgs.data);
const parsedReturns = me._def.returns.safeParse(result, params);
if (!parsedReturns.success) {
throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zod",
"version": "3.22.0",
"version": "3.22.1",
"author": "Colin McDonnell <colin@colinhacks.com>",
"repository": {
"type": "git",
26 changes: 26 additions & 0 deletions src/__tests__/function.test.ts
Original file line number Diff line number Diff line change
@@ -28,6 +28,32 @@ test("function inference 1", () => {
util.assertEqual<func1, (k: string) => number>(true);
});

test("method parsing", () => {
const methodObject = z.object({
property: z.number(),
method: z.function().args(z.string()).returns(z.number())
});
const methodInstance = {
property: 3,
method: function(s: string) { return s.length + this.property; }
};
const parsed = methodObject.parse(methodInstance);
expect(parsed.method('length=8')).toBe(11); // 8 length + 3 property
});

test("async method parsing", async () => {
const methodObject = z.object({
property: z.number(),
method: z.function().args(z.string()).returns(z.promise(z.number()))
});
const methodInstance = {
property: 3,
method: async function(s: string) { return s.length + this.property; }
};
const parsed = methodObject.parse(methodInstance);
expect(await parsed.method('length=8')).toBe(11); // 8 length + 3 property
});

test("args method", () => {
const t1 = z.function();
type t1 = z.infer<typeof t1>;
24 changes: 16 additions & 8 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -3736,17 +3736,21 @@ export class ZodFunction<
const fn = ctx.data;

if (this._def.returns instanceof ZodPromise) {
return OK(async (...args: any[]) => {
// Would love a way to avoid disabling this rule, but we need
// an alias (using an arrow function was what caused 2651).
// eslint-disable-next-line @typescript-eslint/no-this-alias
const me = this;
return OK(async function (this: any, ...args: any[]) {
const error = new ZodError([]);
const parsedArgs = await this._def.args
const parsedArgs = await me._def.args
.parseAsync(args, params)
.catch((e) => {
error.addIssue(makeArgsIssue(args, e));
throw error;
});
const result = await fn(...(parsedArgs as any));
const result = await Reflect.apply(fn, this, parsedArgs as any);
const parsedReturns = await (
this._def.returns as unknown as ZodPromise<ZodTypeAny>
me._def.returns as unknown as ZodPromise<ZodTypeAny>
)._def.type
.parseAsync(result, params)
.catch((e) => {
@@ -3756,13 +3760,17 @@ export class ZodFunction<
return parsedReturns;
});
} else {
return OK((...args: any[]) => {
const parsedArgs = this._def.args.safeParse(args, params);
// Would love a way to avoid disabling this rule, but we need
// an alias (using an arrow function was what caused 2651).
// eslint-disable-next-line @typescript-eslint/no-this-alias
const me = this;
return OK(function (this: any, ...args: any[]) {
const parsedArgs = me._def.args.safeParse(args, params);
if (!parsedArgs.success) {
throw new ZodError([makeArgsIssue(args, parsedArgs.error)]);
}
const result = fn(...(parsedArgs.data as any));
const parsedReturns = this._def.returns.safeParse(result, params);
const result = Reflect.apply(fn, this, parsedArgs.data);
const parsedReturns = me._def.returns.safeParse(result, params);
if (!parsedReturns.success) {
throw new ZodError([makeReturnsIssue(result, parsedReturns.error)]);
}