Repository: RobinTail/express-zod-api
Pull request #850 (2023-03-04 12:54:28)

Detaching `ez` namespace for proprietary schemas
This may help with #584 and #822 

RobinTail: I think I'd better use a fork of zod with
- my custom schemas
- `.example()`

Patch:
diff --git a/example/endpoints/update-user.ts b/example/endpoints/update-user.ts
index ea524928..e9d647e7 100644
--- a/example/endpoints/update-user.ts
+++ b/example/endpoints/update-user.ts
@@ -1,4 +1,4 @@
-import { createHttpError, withMeta, z } from "../../src";
+import { createHttpError, ez, withMeta, z } from "../../src";
 import { keyAndTokenAuthenticatedEndpointsFactory } from "../factories";
 
 export const updateUserEndpoint =
@@ -17,7 +17,7 @@ export const updateUserEndpoint =
             "should be greater than or equal to 0"
           ),
         name: z.string().min(1),
-        birthday: z.dateIn(),
+        birthday: ez.dateIn(),
       })
     ).example({
       id: "12",
@@ -27,7 +27,7 @@ export const updateUserEndpoint =
     output: withMeta(
       z.object({
         name: z.string(),
-        createdAt: z.dateOut(),
+        createdAt: ez.dateOut(),
       })
     ).example({
       name: "John Doe",
diff --git a/example/endpoints/upload-avatar.ts b/example/endpoints/upload-avatar.ts
index 3c3c083d..73740a1b 100644
--- a/example/endpoints/upload-avatar.ts
+++ b/example/endpoints/upload-avatar.ts
@@ -1,4 +1,4 @@
-import { z } from "../../src";
+import { ez, z } from "../../src";
 import crypto from "crypto";
 import { taggedEndpointsFactory } from "../factories";
 
@@ -8,7 +8,7 @@ export const uploadAvatarEndpoint = taggedEndpointsFactory.build({
   description: "Handles a file upload.",
   input: z
     .object({
-      avatar: z
+      avatar: ez
         .upload()
         .refine(
           (file) => file.mimetype.match(/image\/.+/),
diff --git a/example/factories.ts b/example/factories.ts
index 01ff6156..65cc9afe 100644
--- a/example/factories.ts
+++ b/example/factories.ts
@@ -3,6 +3,7 @@ import {
   EndpointsFactory,
   createResultHandler,
   defaultResultHandler,
+  ez,
   z,
 } from "../src";
 import { config } from "./config";
@@ -46,7 +47,7 @@ export const fileStreamingEndpointsFactory = new EndpointsFactory({
   config,
   resultHandler: createResultHandler({
     getPositiveResponse: () => ({
-      schema: z.file().binary(),
+      schema: ez.file().binary(),
       mimeType: "image/*",
     }),
     getNegativeResponse: () => ({
diff --git a/src/extend-zod.ts b/src/extend-zod.ts
deleted file mode 100644
index 67bf78ac..00000000
--- a/src/extend-zod.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { ZodDate } from "zod";
-import { ZodDateIn } from "./date-in-schema";
-import { ZodDateOut } from "./date-out-schema";
-import { ZodFile } from "./file-schema";
-import { ZodUpload } from "./upload-schema";
-
-export * from "zod";
-export const file = ZodFile.create;
-export const upload = ZodUpload.create;
-export const dateIn = ZodDateIn.create;
-export const dateOut = ZodDateOut.create;
-
-/**
- * @description z.date() represents the Date, it should not be used within IO schemas
- * @deprecated Please use z.dateIn() or z.dateOut() within IO schemas
- * */
-export const date = ZodDate.create;
diff --git a/src/ez-namespace.ts b/src/ez-namespace.ts
new file mode 100644
index 00000000..7bb9e9b9
--- /dev/null
+++ b/src/ez-namespace.ts
@@ -0,0 +1,11 @@
+import { ZodDateIn } from "./date-in-schema";
+import { ZodDateOut } from "./date-out-schema";
+import { ZodFile } from "./file-schema";
+import { ZodUpload } from "./upload-schema";
+
+export namespace ez {
+  export const file = ZodFile.create;
+  export const upload = ZodUpload.create;
+  export const dateIn = ZodDateIn.create;
+  export const dateOut = ZodDateOut.create;
+}
diff --git a/src/index.ts b/src/index.ts
index ba0bd4bf..47eed1dd 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -27,7 +27,8 @@ export { withMeta } from "./metadata";
 export { testEndpoint } from "./mock";
 export { Client } from "./client";
 
-import * as z from "./extend-zod";
-import createHttpError from "http-errors";
+export { z } from "zod";
+export { ez } from "./ez-namespace";
 
-export { createHttpError, z };
+import createHttpError from "http-errors";
+export { createHttpError };


Test patch:
diff --git a/tests/unit/common-helpers.spec.ts b/tests/unit/common-helpers.spec.ts
index 0ce7f9d2..5c2c5bc1 100644
--- a/tests/unit/common-helpers.spec.ts
+++ b/tests/unit/common-helpers.spec.ts
@@ -15,7 +15,13 @@ import {
   isValidDate,
   makeErrorFromAnything,
 } from "../../src/common-helpers";
-import { InputValidationError, createHttpError, withMeta, z } from "../../src";
+import {
+  InputValidationError,
+  createHttpError,
+  ez,
+  withMeta,
+  z,
+} from "../../src";
 import { Request } from "express";
 
 describe("Common Helpers", () => {
@@ -441,29 +447,29 @@ describe("Common Helpers", () => {
 
   describe("hasUpload()", () => {
     test("should return true for z.upload()", () => {
-      expect(hasUpload(z.upload())).toBeTruthy();
+      expect(hasUpload(ez.upload())).toBeTruthy();
     });
-    test("should return true for wrapped z.upload()", () => {
-      expect(hasUpload(z.object({ test: z.upload() }))).toBeTruthy();
-      expect(hasUpload(z.upload().or(z.boolean()))).toBeTruthy();
-      expect(
-        hasUpload(
-          z.object({ test: z.boolean() }).and(z.object({ test2: z.upload() }))
-        )
-      ).toBeTruthy();
-      expect(hasUpload(z.optional(z.upload()))).toBeTruthy();
-      expect(hasUpload(z.upload().nullable())).toBeTruthy();
-      expect(hasUpload(z.upload().default({} as UploadedFile))).toBeTruthy();
-      expect(hasUpload(z.record(z.upload()))).toBeTruthy();
-      expect(hasUpload(z.upload().refine(() => true))).toBeTruthy();
-      expect(hasUpload(z.array(z.upload()))).toBeTruthy();
-    });
-    test("should return false in other cases", () => {
-      expect(hasUpload(z.object({}))).toBeFalsy();
-      expect(hasUpload(z.any())).toBeFalsy();
-      expect(hasUpload(z.literal("test"))).toBeFalsy();
-      expect(hasUpload(z.boolean().and(z.literal(true)))).toBeFalsy();
-      expect(hasUpload(z.number().or(z.string()))).toBeFalsy();
+    test.each([
+      z.object({ test: ez.upload() }),
+      ez.upload().or(z.boolean()),
+      z.object({ test: z.boolean() }).and(z.object({ test2: ez.upload() })),
+      z.optional(ez.upload()),
+      ez.upload().nullable(),
+      ez.upload().default({} as UploadedFile),
+      z.record(ez.upload()),
+      ez.upload().refine(() => true),
+      z.array(ez.upload()),
+    ])("should return true for wrapped z.upload() %#", (subject) => {
+      expect(hasUpload(subject)).toBeTruthy();
+    });
+    test.each([
+      z.object({}),
+      z.any(),
+      z.literal("test"),
+      z.boolean().and(z.literal(true)),
+      z.number().or(z.string()),
+    ])("should return false in other cases %#", (subject) => {
+      expect(hasUpload(subject)).toBeFalsy();
     });
   });
 
diff --git a/tests/unit/endpoint.spec.ts b/tests/unit/endpoint.spec.ts
index 6d61c6d6..e59a0acf 100644
--- a/tests/unit/endpoint.spec.ts
+++ b/tests/unit/endpoint.spec.ts
@@ -4,6 +4,7 @@ import {
   createResultHandler,
   defaultEndpointsFactory,
   defaultResultHandler,
+  ez,
   testEndpoint,
   z,
 } from "../../src";
@@ -755,7 +756,7 @@ describe("Endpoint", () => {
     test("should avoid double parsing, should not mutate input", async () => {
       const dateInputMiddleware = createMiddleware({
         input: z.object({
-          middleware_date_input: z.dateIn().optional(),
+          middleware_date_input: ez.dateIn().optional(),
         }),
         middleware: async ({ input: { middleware_date_input }, logger }) => {
           logger.debug("date in mw handler", typeof middleware_date_input);
diff --git a/tests/unit/open-api-helpers.spec.ts b/tests/unit/open-api-helpers.spec.ts
index 29050142..fd55bcdf 100644
--- a/tests/unit/open-api-helpers.spec.ts
+++ b/tests/unit/open-api-helpers.spec.ts
@@ -3,6 +3,7 @@ import { IOSchemaError } from "../../src/errors";
 import {
   OpenAPIError,
   defaultEndpointsFactory,
+  ez,
   withMeta,
   z,
 } from "../../src/index";
@@ -218,7 +219,7 @@ describe("Open API helpers", () => {
     test("should set format:binary and type:string", () => {
       expect(
         depictUpload({
-          schema: z.upload(),
+          schema: ez.upload(),
           ...requestContext,
           next: makeNext(requestContext),
         })
@@ -227,7 +228,7 @@ describe("Open API helpers", () => {
     test("should throw when using in response", () => {
       try {
         depictUpload({
-          schema: z.upload(),
+          schema: ez.upload(),
           ...responseContext,
           next: makeNext(responseContext),
         });
@@ -240,7 +241,7 @@ describe("Open API helpers", () => {
   });
 
   describe("depictFile()", () => {
-    test.each([z.file(), z.file().binary(), z.file().base64()])(
+    test.each([ez.file(), ez.file().binary(), ez.file().base64()])(
       "should set type:string and format accordingly %#",
       (schema) => {
         expect(
@@ -255,7 +256,7 @@ describe("Open API helpers", () => {
     test("should throw when using in input", () => {
       try {
         depictFile({
-          schema: z.file().binary(),
+          schema: ez.file().binary(),
           ...requestContext,
           next: makeNext(requestContext),
         });
@@ -768,7 +769,7 @@ describe("Open API helpers", () => {
     test("should set type:string, pattern and format", () => {
       expect(
         depictDateIn({
-          schema: z.dateIn(),
+          schema: ez.dateIn(),
           ...requestContext,
           next: makeNext(requestContext),
         })
@@ -777,7 +778,7 @@ describe("Open API helpers", () => {
     test("should throw when ZodDateIn in response", () => {
       try {
         depictDateIn({
-          schema: z.dateIn(),
+          schema: ez.dateIn(),
           ...responseContext,
           next: makeNext(responseContext),
         });
@@ -793,7 +794,7 @@ describe("Open API helpers", () => {
     test("should set type:string, description and format", () => {
       expect(
         depictDateOut({
-          schema: z.dateOut(),
+          schema: ez.dateOut(),
           ...responseContext,
           next: makeNext(responseContext),
         })
@@ -802,7 +803,7 @@ describe("Open API helpers", () => {
     test("should throw when ZodDateOut in request", () => {
       try {
         depictDateOut({
-          schema: z.dateOut(),
+          schema: ez.dateOut(),
           ...requestContext,
           next: makeNext(requestContext),
         });
diff --git a/tests/unit/open-api.spec.ts b/tests/unit/open-api.spec.ts
index 3ec7c31b..68bb2966 100644
--- a/tests/unit/open-api.spec.ts
+++ b/tests/unit/open-api.spec.ts
@@ -7,6 +7,7 @@ import {
   createMiddleware,
   createResultHandler,
   defaultEndpointsFactory,
+  ez,
   withMeta,
   z,
 } from "../../src";
@@ -266,11 +267,11 @@ describe("Open API generator", () => {
               input: z.object({
                 bigint: z.bigint(),
                 boolean: z.boolean(),
-                dateIn: z.dateIn(),
+                dateIn: ez.dateIn(),
               }),
               output: z.object({
                 null: z.null(),
-                dateOut: z.dateOut(),
+                dateOut: ez.dateOut(),
               }),
               handler: async () => ({
                 null: null,