diff --git a/CHANGELOG.md b/CHANGELOG.md index 816493284..ddaa191b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,9 @@ ### v24.2.1 -- Removed overrides for depicting enums in the generated `Documentation`: - - The better implementation provided by [Zod v3.25.45](https://github.com/colinhacks/zod/releases/tag/v3.25.45); -- Removed overrides for depicting literals in the generated `Documentation`: - - Fixed in [Zod v3.25.49](https://github.com/colinhacks/zod/releases/tag/v3.25.49). +- Prioritizing Zod native depiction for `z.enum()` and `z.literal()` by the `Documentation` generator: + - Enum `type` implemented in [Zod v3.25.45](https://github.com/colinhacks/zod/releases/tag/v3.25.45); + - Literal `type` implemented in [Zod v3.25.49](https://github.com/colinhacks/zod/releases/tag/v3.25.49). ### v24.2.0 diff --git a/express-zod-api/src/documentation-helpers.ts b/express-zod-api/src/documentation-helpers.ts index 1b4290b50..0f28b33f7 100644 --- a/express-zod-api/src/documentation-helpers.ts +++ b/express-zod-api/src/documentation-helpers.ts @@ -143,6 +143,24 @@ export const depictNullable: Depicter = ({ jsonSchema }) => { const isSupportedType = (subject: string): subject is SchemaObjectType => subject in samples; +/** + * @todo remove in v25 + * @since zod 3.25.45 + */ +export const depictEnum: Depicter = ({ jsonSchema }) => { + jsonSchema.type ??= typeof jsonSchema.enum?.[0]; + return jsonSchema; +}; + +/** + * @todo remove in v25 + * @since zod 3.25.49 + * */ +export const depictLiteral: Depicter = ({ jsonSchema }) => { + jsonSchema.type ??= typeof (jsonSchema.const || jsonSchema.enum?.[0]); + return jsonSchema; +}; + const ensureCompliance = ({ $ref, type, @@ -377,6 +395,8 @@ const depicters: Partial> = intersection: depictIntersection, tuple: depictTuple, pipe: depictPipeline, + literal: depictLiteral, + enum: depictEnum, [ezDateInBrand]: depictDateIn, [ezDateOutBrand]: depictDateOut, [ezUploadBrand]: depictUpload, diff --git a/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap b/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap index 621ca0865..c4f8a17da 100644 --- a/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap @@ -106,6 +106,16 @@ DocumentationError({ }) `; +exports[`Documentation helpers > depictEnum() > should set type 1`] = ` +{ + "enum": [ + "test", + "jest", + ], + "type": "string", +} +`; + exports[`Documentation helpers > depictIntersection() > should NOT flatten object schemas having conflicting props 1`] = ` { "allOf": [ @@ -190,6 +200,23 @@ exports[`Documentation helpers > depictIntersection() > should merge examples de } `; +exports[`Documentation helpers > depictLiteral() > should set type from either const or enum prop 0 1`] = ` +{ + "const": "test", + "type": "string", +} +`; + +exports[`Documentation helpers > depictLiteral() > should set type from either const or enum prop 1 1`] = ` +{ + "enum": [ + "test", + "jest", + ], + "type": "string", +} +`; + exports[`Documentation helpers > depictNullable() > should add null type to the first of anyOf 0 1`] = ` { "type": [ diff --git a/express-zod-api/tests/documentation-helpers.spec.ts b/express-zod-api/tests/documentation-helpers.spec.ts index 3d29080ff..b9ca95689 100644 --- a/express-zod-api/tests/documentation-helpers.spec.ts +++ b/express-zod-api/tests/documentation-helpers.spec.ts @@ -25,6 +25,8 @@ import { depictDateIn, depictDateOut, depictBody, + depictEnum, + depictLiteral, depictRequest, } from "../src/documentation-helpers"; @@ -301,6 +303,28 @@ describe("Documentation helpers", () => { }); }); + describe("depictEnum()", () => { + test("should set type", () => { + expect( + depictEnum( + { zodSchema: z.never(), jsonSchema: { enum: ["test", "jest"] } }, + requestCtx, + ), + ).toMatchSnapshot(); + }); + }); + + describe("depictLiteral()", () => { + test.each([{ const: "test" }, { enum: ["test", "jest"] }])( + "should set type from either const or enum prop %#", + (jsonSchema) => { + expect( + depictLiteral({ zodSchema: z.never(), jsonSchema }, requestCtx), + ).toMatchSnapshot(); + }, + ); + }); + describe("depictBigInt()", () => { test("should set type:string and format:bigint", () => { expect(