Repository: colinhacks/zod
Pull request #4117 (2025-04-12 03:38:04)

fix(docs): enum typo

coderabbitai[bot]: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=colinhacks/zod&utm_content=4117):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Patch:
diff --git a/packages/core/src/doc.ts b/packages/core/src/doc.ts
index ced22d4d..ffb7bd72 100644
--- a/packages/core/src/doc.ts
+++ b/packages/core/src/doc.ts
@@ -34,7 +34,9 @@ export class Doc {
   }
 
   compile() {
-    const lines = [...this.content.map((x) => `  ${x}`)];
-    return new Function(...this.args, lines.join("\n"));
+    const args = this?.args;
+    const content = this?.content ?? [``];
+    const lines = [...content.map((x) => `  ${x}`)];
+    return new Function(...args, lines.join("\n"));
   }
 }
diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts
index 7c3ca641..397c017e 100644
--- a/packages/core/src/errors.ts
+++ b/packages/core/src/errors.ts
@@ -169,12 +169,17 @@ export interface $ZodErrorMap<T extends $ZodIssueBase = $ZodIssue> {
 ////////////////////////    ERROR CLASS   ////////////////////////
 
 const ZOD_ERROR: symbol = Symbol.for("{{zod.error}}");
+export interface $ZodError<T = unknown> extends Error {
+  _zod: { type: T };
+  stack?: string;
+  name: string;
+}
 export class $ZodError<T = unknown> implements Error {
   /** @deprecated Virtual property, do not access. */
-  _zod!: { type: T };
+
   public issues: $ZodIssue[];
-  name!: string;
-  stack?: string;
+
+  // stack?: string;
 
   get message(): string {
     return JSON.stringify(this.issues, jsonStringifyReplacer, 2);
diff --git a/packages/core/src/locales/en.ts b/packages/core/src/locales/en.ts
index 5de51ee6..55ecf50e 100644
--- a/packages/core/src/locales/en.ts
+++ b/packages/core/src/locales/en.ts
@@ -27,7 +27,8 @@ export const parsedType = (data: any): string => {
       if (data === null) {
         return "null";
       }
-      if (Object.getPrototypeOf(data) !== Object.prototype) {
+
+      if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) {
         return data.constructor.name;
       }
     }
diff --git a/packages/core/src/schemas.ts b/packages/core/src/schemas.ts
index e3807edf..96cb935b 100644
--- a/packages/core/src/schemas.ts
+++ b/packages/core/src/schemas.ts
@@ -199,8 +199,7 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
           throw new core.$ZodAsyncError();
         }
         if (asyncResult || _ instanceof Promise) {
-          asyncResult = asyncResult ?? Promise.resolve();
-          asyncResult.then(async () => {
+          asyncResult = (asyncResult ?? Promise.resolve()).then(async () => {
             await _;
             const nextLen = payload.issues.length;
             if (nextLen === currLen) return;
@@ -239,11 +238,11 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
       if (result instanceof Promise) {
         return result.then(({ issues, value }) => {
           if (issues.length === 0) return { value } as any;
-          return { issues };
+          return { issues: issues.map((iss) => util.finalizeIssue(iss, {}, core.config())) };
         });
       }
       if (result.issues.length === 0) return { value: result.value } as any;
-      return { issues: result.issues };
+      return { issues: result.issues.map((iss) => util.finalizeIssue(iss, {}, core.config())) };
     },
     vendor: "zod",
     version: 1 as const,
@@ -1684,7 +1683,7 @@ export const $ZodObjectLike: core.$constructor<$ZodObjectLike> = /*@__PURE__*/ c
 
     let fastpass!: ReturnType<typeof generateFastpass>;
     const fastEnabled = util.allowsEval.value; // && !def.catchall;
-    const isObject = util.isObject;
+    const isObject = util.isPlainObject;
     const { catchall } = def;
 
     let value!: typeof _normalized.value;
diff --git a/packages/core/src/to-json-schema.ts b/packages/core/src/to-json-schema.ts
index b17d50f5..b3d7969e 100644
--- a/packages/core/src/to-json-schema.ts
+++ b/packages/core/src/to-json-schema.ts
@@ -168,7 +168,8 @@ export class JSONSchemaGenerator {
         // custom pattern overrides format
         if (format) {
           json.format = formatMap[format] ?? format;
-        } else if (pattern) {
+        }
+        if (pattern) {
           json.pattern = pattern.source;
         }
         if (contentEncoding) json.contentEncoding = contentEncoding;
diff --git a/packages/core/src/versions.ts b/packages/core/src/versions.ts
index 7d2699b2..d8be5fb3 100644
--- a/packages/core/src/versions.ts
+++ b/packages/core/src/versions.ts
@@ -1,5 +1,5 @@
 export const version = {
   major: 0,
   minor: 4,
-  patch: 1 as number,
+  patch: 6 as number,
 } as const;
diff --git a/packages/docs/content/api.mdx b/packages/docs/content/api.mdx
index cfe059d3..20f3ac51 100644
--- a/packages/docs/content/api.mdx
+++ b/packages/docs/content/api.mdx
@@ -221,7 +221,7 @@ z.ulid();
 z.ipv4();
 z.ipv6();
 z.cidrv4();        // ipv4 CIDR block
-z.cidrv4();        // ipv6 CIDR block
+z.cidrv6();        // ipv6 CIDR block
 z.iso.date();
 z.iso.time();
 z.iso.datetime();
@@ -621,7 +621,7 @@ To create a new enum schema, excluding certain values:
 <Tab value="zod">
 ```ts
 const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
-const SalmonAndTroutOnly = FishEnum.extract(["Salmon", "Trout"]);
+const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);
 ```
 </Tab>
 <Tab value="@zod/mini">
@@ -640,7 +640,7 @@ To create a new enum schema, extracting certain values:
 <Tab value="zod">
 ```ts
 const FishEnum = z.enum(["Salmon", "Tuna", "Trout"]);
-const TunaOnly = FishEnum.exclude(["Salmon", "Trout"]);
+const SalmonAndTroutOnly = FishEnum.extract(["Salmon", "Trout"]);
 ```
 </Tab>
 <Tab value="@zod/mini">
diff --git a/packages/zod/src/schemas.ts b/packages/zod/src/schemas.ts
index b9b4c585..09153dd0 100644
--- a/packages/zod/src/schemas.ts
+++ b/packages/zod/src/schemas.ts
@@ -323,7 +323,7 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
   inst.duration = (params) => inst.check(iso.duration(params as any));
 
   // validations
-  inst.regex = (params) => inst.check(checks.regex(params));
+  inst.regex = (...args) => inst.check(checks.regex(...args));
   inst.includes = (...args) => inst.check(checks.includes(...args));
   inst.startsWith = (params) => inst.check(checks.startsWith(params));
   inst.endsWith = (params) => inst.check(checks.endsWith(params));
diff --git a/play.ts b/play.ts
index 49082dbb..a6f32fb0 100644
--- a/play.ts
+++ b/play.ts
@@ -1,27 +1,3 @@
 import * as z from "zod";
 
-const a = z.object({
-  type: z.object({ key: z.literal("A") }),
-  name: z.string(),
-});
-
-const b = z.object({
-  type: z.object({ key: z.literal("B") }),
-  age: z.number(),
-});
-
-const c = z.discriminatedUnion([a, b]);
-
-console.log(
-  c.safeParse({
-    type: { key: "A" },
-    name: "hello",
-  })
-);
-
-console.log(
-  c.safeParse({
-    type: { key: "B" },
-    age: 12,
-  })
-);
+console.log(z.object({}).parse([]));


Test patch:
diff --git a/packages/core/tests/locales/en.test.ts b/packages/core/tests/locales/en.test.ts
new file mode 100644
index 00000000..b06aaddd
--- /dev/null
+++ b/packages/core/tests/locales/en.test.ts
@@ -0,0 +1,22 @@
+import { expect, test } from "vitest";
+import { parsedType } from "../../src/locales/en.js";
+
+test("parsedType", () => {
+  expect(parsedType("string")).toBe("string");
+  expect(parsedType(1)).toBe("number");
+  expect(parsedType(true)).toBe("boolean");
+  expect(parsedType(null)).toBe("null");
+  expect(parsedType(undefined)).toBe("undefined");
+  expect(parsedType([])).toBe("array");
+  expect(parsedType({})).toBe("object");
+  expect(parsedType(new Date())).toBe("Date");
+  expect(parsedType(new Map())).toBe("Map");
+  expect(parsedType(new Set())).toBe("Set");
+  expect(parsedType(new Error())).toBe("Error");
+
+  const nullPrototype = Object.create(null);
+  expect(parsedType(nullPrototype)).toBe("object");
+
+  const doubleNullPrototype = Object.create(Object.create(null));
+  expect(parsedType(doubleNullPrototype)).toBe("object");
+});
diff --git a/packages/mini/tests/object.test.ts b/packages/mini/tests/object.test.ts
index 3db8f214..d40735da 100644
--- a/packages/mini/tests/object.test.ts
+++ b/packages/mini/tests/object.test.ts
@@ -28,6 +28,12 @@ test("z.object", () => {
   // "test?" is required in ZodObject
   expect(() => z.parse(a, { name: "john", age: "30" })).toThrow();
   expect(() => z.parse(a, "hello")).toThrow();
+
+  // null prototype
+  const schema = z.object({ a: z.string() });
+  const obj = Object.create(null);
+  obj.a = "foo";
+  expect(schema.parse(obj)).toEqual({ a: "foo" });
 });
 
 test("z.strictObject", () => {
diff --git a/packages/zod/tests/async-parsing.test.ts b/packages/zod/tests/async-parsing.test.ts
index f45f1345..a2d2c213 100644
--- a/packages/zod/tests/async-parsing.test.ts
+++ b/packages/zod/tests/async-parsing.test.ts
@@ -331,7 +331,14 @@ test("async validation multiple errors 2", async () => {
     z.object({
       hello: z.string(),
       foo: z.object({
-        bar: z.number().refine(is_async ? async () => false : () => false),
+        bar: z.number().refine(
+          is_async
+            ? async () =>
+                new Promise((resolve) => {
+                  setTimeout(() => resolve(false), 500);
+                })
+            : () => false
+        ),
       }),
     });
 
diff --git a/packages/zod/tests/json-schema.test.ts b/packages/zod/tests/json-schema.test.ts
index 0269ecb9..b30aba3d 100644
--- a/packages/zod/tests/json-schema.test.ts
+++ b/packages/zod/tests/json-schema.test.ts
@@ -39,54 +39,63 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.email())).toMatchInlineSnapshot(`
       {
         "format": "email",
+        "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.datetime())).toMatchInlineSnapshot(`
       {
         "format": "date-time",
+        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z)$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.date())).toMatchInlineSnapshot(`
       {
         "format": "date",
+        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.time())).toMatchInlineSnapshot(`
       {
         "format": "time",
+        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.duration())).toMatchInlineSnapshot(`
       {
         "format": "duration",
+        "pattern": "^P(?:(\\d+W)|(?!.*W)(?=\\d|T\\d)(\\d+Y)?(\\d+M)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+([.,]\\d+)?S)?)?)$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.ipv4())).toMatchInlineSnapshot(`
       {
         "format": "ipv4",
+        "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.ipv6())).toMatchInlineSnapshot(`
       {
         "format": "ipv6",
+        "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.uuid())).toMatchInlineSnapshot(`
       {
         "format": "uuid",
+        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.guid())).toMatchInlineSnapshot(`
       {
         "format": "uuid",
+        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
         "type": "string",
       }
     `);
@@ -100,12 +109,14 @@ describe("toJSONSchema", () => {
       {
         "contentEncoding": "base64",
         "format": "base64",
+        "pattern": "^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.cuid())).toMatchInlineSnapshot(`
       {
         "format": "cuid",
+        "pattern": "^[cC][^\\s-]{8,}$",
         "type": "string",
       }
     `);
@@ -113,24 +124,28 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.emoji())).toMatchInlineSnapshot(`
       {
         "format": "emoji",
+        "pattern": "^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.nanoid())).toMatchInlineSnapshot(`
       {
         "format": "nanoid",
+        "pattern": "^[a-zA-Z0-9_-]{21}$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.cuid2())).toMatchInlineSnapshot(`
       {
         "format": "cuid2",
+        "pattern": "^[0-9a-z]+$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.ulid())).toMatchInlineSnapshot(`
       {
         "format": "ulid",
+        "pattern": "^[0-9A-HJKMNP-TV-Z]{26}$",
         "type": "string",
       }
     `);
@@ -219,18 +234,21 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.string().email())).toMatchInlineSnapshot(`
       {
         "format": "email",
+        "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.string().uuid())).toMatchInlineSnapshot(`
       {
         "format": "uuid",
+        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.datetime())).toMatchInlineSnapshot(`
       {
         "format": "date-time",
+        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?(Z)$",
         "type": "string",
       }
     `);
@@ -238,18 +256,21 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.iso.date())).toMatchInlineSnapshot(`
       {
         "format": "date",
+        "pattern": "^((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.time())).toMatchInlineSnapshot(`
       {
         "format": "time",
+        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(\\.\\d+)?$",
         "type": "string",
       }
     `);
     expect(toJSONSchema(z.iso.duration())).toMatchInlineSnapshot(`
       {
         "format": "duration",
+        "pattern": "^P(?:(\\d+W)|(?!.*W)(?=\\d|T\\d)(\\d+Y)?(\\d+M)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+([.,]\\d+)?S)?)?)$",
         "type": "string",
       }
     `);
@@ -262,6 +283,7 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.ipv4())).toMatchInlineSnapshot(`
       {
         "format": "ipv4",
+        "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$",
         "type": "string",
       }
     `);
@@ -269,6 +291,7 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.ipv6())).toMatchInlineSnapshot(`
       {
         "format": "ipv6",
+        "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})$",
         "type": "string",
       }
     `);
@@ -277,6 +300,7 @@ describe("toJSONSchema", () => {
       {
         "contentEncoding": "base64",
         "format": "base64",
+        "pattern": "^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$",
         "type": "string",
       }
     `);
@@ -289,6 +313,14 @@ describe("toJSONSchema", () => {
     expect(toJSONSchema(z.guid())).toMatchInlineSnapshot(`
       {
         "format": "uuid",
+        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$",
+        "type": "string",
+      }
+    `);
+    expect(toJSONSchema(z.string().regex(/asdf/))).toMatchInlineSnapshot(`
+      {
+        "format": "regex",
+        "pattern": "asdf",
         "type": "string",
       }
     `);
diff --git a/packages/zod/tests/object.test.ts b/packages/zod/tests/object.test.ts
index 18344196..46283b7a 100644
--- a/packages/zod/tests/object.test.ts
+++ b/packages/zod/tests/object.test.ts
@@ -440,3 +440,10 @@ test("assignability", () => {
   z.interface({ "a?": z.string() }) satisfies z.ZodInterface;
   z.interface({ "?a": z.string() }) satisfies z.ZodInterface;
 });
+
+test("null prototype", () => {
+  const schema = z.object({ a: z.string() });
+  const obj = Object.create(null);
+  obj.a = "foo";
+  expect(schema.parse(obj)).toEqual({ a: "foo" });
+});
diff --git a/packages/zod/tests/standard-schema.test.ts b/packages/zod/tests/standard-schema.test.ts
new file mode 100644
index 00000000..87b37580
--- /dev/null
+++ b/packages/zod/tests/standard-schema.test.ts
@@ -0,0 +1,57 @@
+import { expect, test } from "vitest";
+
+import * as z from "zod";
+
+test("length checks", async () => {
+  const schema = z.string();
+  const result = await schema["~standard"].validate(12);
+  expect(result).toMatchInlineSnapshot(`
+    {
+      "issues": [
+        {
+          "code": "invalid_type",
+          "expected": "string",
+          "message": "Invalid input: expected string, received number",
+          "path": [],
+        },
+      ],
+    }
+  `);
+});
+
+test("length checks", async () => {
+  const schema = z.string();
+  const result = await schema["~standard"].validate("asdf");
+  expect(result).toMatchInlineSnapshot(`
+    {
+      "value": "asdf",
+    }
+  `);
+});
+
+test("length checks", async () => {
+  const schema = z.string().refine(async (val) => val.length > 5);
+  const result = await schema["~standard"].validate(12);
+  expect(result).toMatchInlineSnapshot(`
+    {
+      "issues": [
+        {
+          "code": "invalid_type",
+          "expected": "string",
+          "message": "Invalid input: expected string, received number",
+          "path": [],
+        },
+      ],
+    }
+  `);
+});
+
+test("length checks", async () => {
+  const schema = z.string().refine(async (val) => val.length > 5);
+  const result = await schema["~standard"].validate("234134134");
+  expect(result).toMatchInlineSnapshot(`
+    {
+      "value": "234134134",
+    }
+  `);
+});
diff --git a/packages/zod/tests/string.test.ts b/packages/zod/tests/string.test.ts
index 2295182b..b7388f42 100644
--- a/packages/zod/tests/string.test.ts
+++ b/packages/zod/tests/string.test.ts
@@ -581,6 +581,27 @@ test("regexp error message", () => {
   expect(() => z.string().uuid().parse("purr")).toThrow();
 });
 
+test("regexp error custom message", () => {
+  const result = z
+    .string()
+    .regex(/^moo+$/, { message: "Custom error message" })
+    .safeParse("boooo");
+  expect(result.error!.issues).toMatchInlineSnapshot(`
+    [
+      {
+        "code": "invalid_format",
+        "format": "regex",
+        "message": "Custom error message",
+        "origin": "string",
+        "path": [],
+        "pattern": "/^moo+$/",
+      },
+    ]
+  `);
+
+  expect(() => z.string().uuid().parse("purr")).toThrow();
+});
+
 test("regex lastIndex reset", () => {
   const schema = z.string().regex(/^\d+$/g);
   expect(schema.safeParse("123").success).toEqual(true);