diff --git a/example/example.documentation.yaml b/example/example.documentation.yaml index 612d9e264..d43165b6b 100644 --- a/example/example.documentation.yaml +++ b/example/example.documentation.yaml @@ -29,6 +29,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -57,6 +58,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -174,6 +176,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -211,6 +214,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -255,6 +259,7 @@ paths: type: object properties: status: + type: string const: created data: type: object @@ -275,6 +280,7 @@ paths: type: object properties: status: + type: string const: created data: type: object @@ -295,6 +301,7 @@ paths: type: object properties: status: + type: string const: error reason: type: string @@ -309,6 +316,7 @@ paths: type: object properties: status: + type: string const: exists id: type: integer @@ -325,6 +333,7 @@ paths: type: object properties: status: + type: string const: error reason: type: string @@ -455,6 +464,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -490,6 +500,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -529,6 +540,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -549,6 +561,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -593,6 +606,7 @@ paths: type: integer exclusiveMaximum: 9007199254740991 event: + type: string const: time id: type: string @@ -644,6 +658,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -664,6 +679,7 @@ paths: type: object properties: status: + type: string const: error error: type: object diff --git a/express-zod-api/src/documentation-helpers.ts b/express-zod-api/src/documentation-helpers.ts index 78b3b4b81..ccee20d85 100644 --- a/express-zod-api/src/documentation-helpers.ts +++ b/express-zod-api/src/documentation-helpers.ts @@ -199,6 +199,16 @@ export const depictNullable: Depicter = ({ jsonSchema }) => { const isSupportedType = (subject: string): subject is SchemaObjectType => subject in samples; +export const depictEnum: Depicter = ({ jsonSchema }) => ({ + type: typeof jsonSchema.enum?.[0], + ...jsonSchema, +}); + +export const depictLiteral: Depicter = ({ jsonSchema }) => ({ + type: typeof (jsonSchema.const || jsonSchema.enum?.[0]), + ...jsonSchema, +}); + const ensureCompliance = ({ $ref, type, @@ -450,6 +460,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 018c591b3..91089c014 100644 --- a/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/documentation-helpers.spec.ts.snap @@ -52,6 +52,16 @@ exports[`Documentation helpers > depictDefault() > Feature #1706: should overrid } `; +exports[`Documentation helpers > depictEnum() > should set type 1`] = ` +{ + "enum": [ + "test", + "jest", + ], + "type": "string", +} +`; + exports[`Documentation helpers > depictExamples() > should 'pass' examples in case of 'request' 1`] = ` { "example1": { @@ -202,6 +212,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/__snapshots__/documentation.spec.ts.snap b/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap index 266f83dcf..c3d08b78d 100644 --- a/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap @@ -20,6 +20,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -36,6 +37,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -89,6 +91,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -105,6 +108,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -143,6 +147,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -159,6 +164,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -212,6 +218,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -228,6 +235,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -259,6 +267,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -275,6 +284,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -342,6 +352,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -361,6 +372,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -402,6 +414,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -418,6 +431,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -457,6 +471,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -473,6 +488,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -543,6 +559,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -562,6 +579,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -639,11 +657,13 @@ paths: type: object properties: status: + type: string const: success data: type: object properties: literal: + type: string const: something transformation: type: number @@ -661,6 +681,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -714,6 +735,7 @@ paths: - type: object properties: type: + type: string const: a a: type: string @@ -723,6 +745,7 @@ paths: - type: object properties: type: + type: string const: b b: type: string @@ -739,12 +762,14 @@ paths: type: object properties: status: + type: string const: success data: anyOf: - type: object properties: status: + type: string const: success data: {} required: @@ -753,6 +778,7 @@ paths: - type: object properties: status: + type: string const: error error: type: object @@ -777,6 +803,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -848,6 +875,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -876,6 +904,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -959,6 +988,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -967,8 +997,29 @@ paths: type: - string - "null" + literal: + type: + - string + - "null" + const: test + multiliteral: + type: + - string + - "null" + enum: + - one + - two + enum: + type: + - string + - "null" + enum: + - test required: - nullable + - literal + - multiliteral + - enum required: - status - data @@ -980,6 +1031,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1063,6 +1115,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1085,6 +1138,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1162,6 +1216,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1188,6 +1243,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1245,6 +1301,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1264,6 +1321,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1339,6 +1397,7 @@ paths: type: object properties: status: + type: string const: OK result: type: object @@ -1356,6 +1415,7 @@ paths: type: object properties: status: + type: string const: NOT OK required: - status @@ -1436,6 +1496,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1457,6 +1518,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1584,6 +1646,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1604,6 +1667,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1654,6 +1718,7 @@ paths: type: object properties: regularEnum: + type: string enum: - ABC - DEF @@ -1669,11 +1734,13 @@ paths: type: object properties: status: + type: string const: success data: type: object properties: nativeEnum: + type: number enum: - 1 - 2 @@ -1690,6 +1757,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1749,6 +1817,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1780,6 +1849,7 @@ paths: literal: type: object propertyNames: + type: string const: only additionalProperties: type: boolean @@ -1787,13 +1857,16 @@ paths: type: object propertyNames: anyOf: - - const: option1 - - const: option2 + - type: string + const: option1 + - type: string + const: option2 additionalProperties: type: boolean enum: type: object propertyNames: + type: string enum: - option1 - option2 @@ -1817,6 +1890,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1884,6 +1958,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -1903,6 +1978,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -1990,6 +2066,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2012,6 +2089,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2069,6 +2147,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2087,6 +2166,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2152,6 +2232,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2171,6 +2252,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2234,6 +2316,7 @@ paths: type: object properties: status: + type: string const: ok data: type: object @@ -2253,6 +2336,7 @@ paths: type: object properties: status: + type: string const: kinda data: type: object @@ -2269,12 +2353,14 @@ paths: content: application/json: schema: + type: string const: error "500": description: POST /v1/mtpl Negative response 500 content: application/json: schema: + type: string const: failure components: schemas: {} @@ -2329,6 +2415,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2348,6 +2435,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2417,6 +2505,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2436,6 +2525,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2494,6 +2584,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2513,6 +2604,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2577,6 +2669,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2593,6 +2686,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2665,6 +2759,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2681,6 +2776,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2751,6 +2847,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2767,6 +2864,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2828,6 +2926,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2850,6 +2949,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2893,6 +2993,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -2915,6 +3016,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -2991,6 +3093,7 @@ paths: type: object properties: status: + type: string const: success data: anyOf: @@ -3023,6 +3126,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3084,6 +3188,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3100,6 +3205,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3167,6 +3273,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3207,6 +3314,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3286,6 +3394,7 @@ components: type: object properties: status: + type: string const: success data: type: object @@ -3298,6 +3407,7 @@ components: type: object properties: status: + type: string const: error error: type: object @@ -3356,6 +3466,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3383,6 +3494,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3444,6 +3556,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3471,6 +3584,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3538,6 +3652,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3565,6 +3680,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3628,6 +3744,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3655,6 +3772,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3714,6 +3832,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3735,6 +3854,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3784,8 +3904,10 @@ paths: description: parameter of post /v1/:name schema: anyOf: - - const: John - - const: Jane + - type: string + const: John + - type: string + const: Jane requestBody: description: the body of request content: @@ -3807,6 +3929,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -3823,6 +3946,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -3902,12 +4026,15 @@ components: schemas: ParameterOfPostV1NameName: anyOf: - - const: John - - const: Jane + - type: string + const: John + - type: string + const: Jane SuperPositiveResponseOfV1Name: type: object properties: status: + type: string const: success data: type: object @@ -3920,6 +4047,7 @@ components: type: object properties: status: + type: string const: error error: type: object @@ -3968,8 +4096,10 @@ paths: description: GET /v1/:name Parameter schema: anyOf: - - const: John - - const: Jane + - type: string + const: John + - type: string + const: Jane - name: other in: query required: true @@ -3985,6 +4115,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -4001,6 +4132,7 @@ paths: type: object properties: status: + type: string const: error error: type: object @@ -4050,8 +4182,10 @@ paths: description: POST /v1/:name Parameter schema: anyOf: - - const: John - - const: Jane + - type: string + const: John + - type: string + const: Jane requestBody: description: POST /v1/:name Request body content: @@ -4073,6 +4207,7 @@ paths: type: object properties: status: + type: string const: success data: type: object @@ -4089,6 +4224,7 @@ paths: type: object properties: status: + type: string const: error error: type: object diff --git a/express-zod-api/tests/documentation-helpers.spec.ts b/express-zod-api/tests/documentation-helpers.spec.ts index 4be1a7cf3..6f05998b9 100644 --- a/express-zod-api/tests/documentation-helpers.spec.ts +++ b/express-zod-api/tests/documentation-helpers.spec.ts @@ -29,6 +29,8 @@ import { depictDateIn, depictDateOut, depictBody, + depictEnum, + depictLiteral, } from "../src/documentation-helpers"; describe("Documentation helpers", () => { @@ -310,6 +312,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( diff --git a/express-zod-api/tests/documentation.spec.ts b/express-zod-api/tests/documentation.spec.ts index c7a096a37..cd5d33658 100644 --- a/express-zod-api/tests/documentation.spec.ts +++ b/express-zod-api/tests/documentation.spec.ts @@ -90,9 +90,15 @@ describe("Documentation", () => { }), output: z.object({ nullable: z.string().nullable(), + literal: z.literal("test").nullable(), + multiliteral: z.literal(["one", "two"]).nullable(), + enum: z.enum(["test"]).nullable(), }), handler: async () => ({ nullable: null, + literal: "test" as const, + multiliteral: "one" as const, + enum: "test" as const, }), }), },