diff --git a/deno/lib/__tests__/discriminatedUnions.test.ts b/deno/lib/__tests__/discriminatedUnions.test.ts index cc0f3bd28..4e472c8a8 100644 --- a/deno/lib/__tests__/discriminatedUnions.test.ts +++ b/deno/lib/__tests__/discriminatedUnions.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; const test = Deno.test; diff --git a/deno/lib/__tests__/firstparty.test.ts b/deno/lib/__tests__/firstparty.test.ts index 4e49d1397..66ed29bdb 100644 --- a/deno/lib/__tests__/firstparty.test.ts +++ b/deno/lib/__tests__/firstparty.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; const test = Deno.test; diff --git a/deno/lib/__tests__/partials.test.ts b/deno/lib/__tests__/partials.test.ts index bb6eb355f..67fb82050 100644 --- a/deno/lib/__tests__/partials.test.ts +++ b/deno/lib/__tests__/partials.test.ts @@ -185,8 +185,13 @@ test("required with mask", () => { expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional); }); - test("required with mask containing a nonexistent key", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string().optional(), + }); object.required({ age: true, // @ts-expect-error should not accept unexpected keys. @@ -201,17 +206,15 @@ test("required with mask -- ignore falsy values", () => { field: z.string().optional().default("asdf"), country: z.string().optional(), }); - + // @ts-expect-error const requiredObject = object.required({ age: true, country: false }); expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString); expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber); expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault); expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional); - }); - test("partial with mask", async () => { const object = z.object({ name: z.string(), diff --git a/deno/lib/__tests__/string.test.ts b/deno/lib/__tests__/string.test.ts index a03a864c7..8cac57112 100644 --- a/deno/lib/__tests__/string.test.ts +++ b/deno/lib/__tests__/string.test.ts @@ -42,22 +42,62 @@ test("email validations", () => { expect(() => email.parse("asdf@-asdf.com")).toThrow(); expect(() => email.parse("asdf@-a(sdf.com")).toThrow(); expect(() => email.parse("asdf@-asdf.com(")).toThrow(); + expect(() => + email.parse("pawan.anand@%9y83&#$%R&#$%R&%#$R%%^^%5rw3ewe.d.d.aaaa.wef.co") + ).toThrow(); }); test("more email validations", () => { - const data = [ - `"josé.arrañoça"@domain.com`, - `"сайт"@domain.com`, - `"💩"@domain.com`, - `"🍺🕺🎉"@domain.com`, - `poop@💩.la`, - `"🌮"@i❤️tacos.ws`, - "sss--asd@i❤️tacos.ws", + const validEmails = [ + `very.common@example.com`, + `disposable.style.email.with+symbol@example.com`, + `other.email-with-hyphen@example.com`, + `fully-qualified-domain@example.com`, + `user.name+tag+sorting@example.com`, + `x@example.com`, + `example-indeed@strange-example.com`, + `test/test@test.com`, + `example@s.example`, + `" "@example.org`, + `"john..doe"@example.org`, + `mailhost!username@example.org`, + `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`, + `user%example.com@example.org`, + `user-@example.org`, + `postmaster@[123.123.123.123]`, + `user@my-example.com`, + `a@b.cd`, + `work+user@mail.com`, + `user@[68.185.127.196]`, + `ipv4@[85.129.96.247]`, + `valid@[79.208.229.53]`, ]; - const email = z.string().email(); - for (const datum of data) { - email.parse(datum); - } + const invalidEmails = [ + `Abc.example.com`, + `A@b@c@example.com`, + `a"b(c)d,e:f;gi[j\k]l@example.com`, + `just"not"right@example.com`, + `this is"not\allowed@example.com`, + `this\ still\"not\\allowed@example.com`, + `i_like_underscore@but_its_not_allowed_in_this_part.example.com`, + `QA[icon]CHOCOLATE[icon]@test.com`, + `invalid@-start.com`, + `invalid@end.com-`, + `a.b@c.d`, + `invalid@[1.1.1.-1]`, + `invalid@[68.185.127.196.55]`, + `temp@[192.168.1]`, + `temp@[9.18.122.]`, + ]; + const emailSchema = z.string().email(); + expect( + validEmails.every((email) => emailSchema.safeParse(email).success) + ).toBe(true); + expect( + invalidEmails.every( + (email) => emailSchema.safeParse(email).success === false + ) + ).toBe(true); }); test("url validations", () => { diff --git a/deno/lib/__tests__/unions.test.ts b/deno/lib/__tests__/unions.test.ts index 83475e171..3a73d975f 100644 --- a/deno/lib/__tests__/unions.test.ts +++ b/deno/lib/__tests__/unions.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect } from "https://deno.land/x/expect@v0.2.6/mod.ts"; const test = Deno.test; diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 6711aa9eb..9029edf8d 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -519,9 +519,12 @@ const uuidRegex = // from https://stackoverflow.com/a/46181/1550155 // old version: too slow, didn't support unicode // const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +//old email regex +// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; // eslint-disable-next-line -export const emailRegex = - /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; + +const emailRegex = + /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|([^-]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}))$/; // interface IsDateStringOptions extends StringDateOptions { /** @@ -4470,7 +4473,10 @@ export const coerce = { number: ((arg) => ZodNumber.create({ ...arg, coerce: true })) as typeof ZodNumber["create"], boolean: ((arg) => - ZodBoolean.create({ ...arg, coerce: true })) as typeof ZodBoolean["create"], + ZodBoolean.create({ + ...arg, + coerce: true, + })) as typeof ZodBoolean["create"], bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })) as typeof ZodBigInt["create"], date: ((arg) => diff --git a/src/__tests__/discriminatedUnions.test.ts b/src/__tests__/discriminatedUnions.test.ts index dbce353e9..68a3f8fb9 100644 --- a/src/__tests__/discriminatedUnions.test.ts +++ b/src/__tests__/discriminatedUnions.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect, test } from "@jest/globals"; import * as z from "../index"; diff --git a/src/__tests__/firstparty.test.ts b/src/__tests__/firstparty.test.ts index b8b51dec3..bd5f6986d 100644 --- a/src/__tests__/firstparty.test.ts +++ b/src/__tests__/firstparty.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { test } from "@jest/globals"; import { util } from "../helpers/util"; diff --git a/src/__tests__/object-in-es5-env.test.ts b/src/__tests__/object-in-es5-env.test.ts index bfd3ad9c3..6d17a0964 100644 --- a/src/__tests__/object-in-es5-env.test.ts +++ b/src/__tests__/object-in-es5-env.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect, test } from "@jest/globals"; import * as z from "../index"; diff --git a/src/__tests__/partials.test.ts b/src/__tests__/partials.test.ts index 448bdb22c..f6d7fcf7d 100644 --- a/src/__tests__/partials.test.ts +++ b/src/__tests__/partials.test.ts @@ -185,6 +185,12 @@ test("required with mask", () => { }); test("required with mask containing a nonexistent key", () => { + const object = z.object({ + name: z.string(), + age: z.number().optional(), + field: z.string().optional().default("asdf"), + country: z.string().optional(), + }); object.required({ age: true, // @ts-expect-error should not accept unexpected keys. @@ -193,7 +199,6 @@ test("required with mask containing a nonexistent key", () => { }); test("required with mask -- ignore falsy values", () => { - const object = z.object({ name: z.string(), age: z.number().optional(), @@ -201,7 +206,6 @@ test("required with mask -- ignore falsy values", () => { country: z.string().optional(), }); - // @ts-expect-error const requiredObject = object.required({ age: true, country: false }); expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString); diff --git a/src/__tests__/string.test.ts b/src/__tests__/string.test.ts index 9e5a8893e..cb075cf75 100644 --- a/src/__tests__/string.test.ts +++ b/src/__tests__/string.test.ts @@ -41,22 +41,62 @@ test("email validations", () => { expect(() => email.parse("asdf@-asdf.com")).toThrow(); expect(() => email.parse("asdf@-a(sdf.com")).toThrow(); expect(() => email.parse("asdf@-asdf.com(")).toThrow(); + expect(() => + email.parse("pawan.anand@%9y83&#$%R&#$%R&%#$R%%^^%5rw3ewe.d.d.aaaa.wef.co") + ).toThrow(); }); test("more email validations", () => { - const data = [ - `"josé.arrañoça"@domain.com`, - `"сайт"@domain.com`, - `"💩"@domain.com`, - `"🍺🕺🎉"@domain.com`, - `poop@💩.la`, - `"🌮"@i❤️tacos.ws`, - "sss--asd@i❤️tacos.ws", + const validEmails = [ + `very.common@example.com`, + `disposable.style.email.with+symbol@example.com`, + `other.email-with-hyphen@example.com`, + `fully-qualified-domain@example.com`, + `user.name+tag+sorting@example.com`, + `x@example.com`, + `example-indeed@strange-example.com`, + `test/test@test.com`, + `example@s.example`, + `" "@example.org`, + `"john..doe"@example.org`, + `mailhost!username@example.org`, + `"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com`, + `user%example.com@example.org`, + `user-@example.org`, + `postmaster@[123.123.123.123]`, + `user@my-example.com`, + `a@b.cd`, + `work+user@mail.com`, + `user@[68.185.127.196]`, + `ipv4@[85.129.96.247]`, + `valid@[79.208.229.53]`, ]; - const email = z.string().email(); - for (const datum of data) { - email.parse(datum); - } + const invalidEmails = [ + `Abc.example.com`, + `A@b@c@example.com`, + `a"b(c)d,e:f;gi[j\k]l@example.com`, + `just"not"right@example.com`, + `this is"not\allowed@example.com`, + `this\ still\"not\\allowed@example.com`, + `i_like_underscore@but_its_not_allowed_in_this_part.example.com`, + `QA[icon]CHOCOLATE[icon]@test.com`, + `invalid@-start.com`, + `invalid@end.com-`, + `a.b@c.d`, + `invalid@[1.1.1.-1]`, + `invalid@[68.185.127.196.55]`, + `temp@[192.168.1]`, + `temp@[9.18.122.]`, + ]; + const emailSchema = z.string().email(); + expect( + validEmails.every((email) => emailSchema.safeParse(email).success) + ).toBe(true); + expect( + invalidEmails.every( + (email) => emailSchema.safeParse(email).success === false + ) + ).toBe(true); }); test("url validations", () => { diff --git a/src/__tests__/unions.test.ts b/src/__tests__/unions.test.ts index fcae2459a..e7b30bcef 100644 --- a/src/__tests__/unions.test.ts +++ b/src/__tests__/unions.test.ts @@ -1,3 +1,4 @@ +// @ts-ignore TS6133 import { expect, test } from "@jest/globals"; import * as z from "../index"; diff --git a/src/types.ts b/src/types.ts index 88805285a..17d7c3fbb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -519,9 +519,12 @@ const uuidRegex = // from https://stackoverflow.com/a/46181/1550155 // old version: too slow, didn't support unicode // const emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +//old email regex +// const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; // eslint-disable-next-line -export const emailRegex = - /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((?!-)([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{1,})[^-<>()[\].,;:\s@"]$/i; + +const emailRegex = + /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|([^-]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}))$/; // interface IsDateStringOptions extends StringDateOptions { /** @@ -4470,7 +4473,10 @@ export const coerce = { number: ((arg) => ZodNumber.create({ ...arg, coerce: true })) as typeof ZodNumber["create"], boolean: ((arg) => - ZodBoolean.create({ ...arg, coerce: true })) as typeof ZodBoolean["create"], + ZodBoolean.create({ + ...arg, + coerce: true, + })) as typeof ZodBoolean["create"], bigint: ((arg) => ZodBigInt.create({ ...arg, coerce: true })) as typeof ZodBigInt["create"], date: ((arg) =>