|
| 1 | +import { |
| 2 | + apiSpecRequestKeys, |
| 3 | + extractExtraApiSpecProps, |
| 4 | + extractExtraResponseProps, |
| 5 | + JsonSchemaApiEndpoints, |
| 6 | + JsonSchemaApiResponses, |
| 7 | + JsonSchemaApiSpec, |
| 8 | + Method, |
| 9 | + StatusCode, |
| 10 | +} from "../core"; |
| 11 | +import { |
| 12 | + ZodAnyApiResponses, |
| 13 | + ZodApiEndpoint, |
| 14 | + ZodApiEndpoints, |
| 15 | + ZodApiSpec, |
| 16 | +} from "./index"; |
| 17 | +import { createSchema } from "zod-openapi"; |
| 18 | +import { JSONSchema7 } from "json-schema"; |
| 19 | +import { z } from "zod"; |
| 20 | + |
| 21 | +export const toJsonSchemaApiEndpoints = <E extends ZodApiEndpoints>( |
| 22 | + endpoints: E, |
| 23 | +): JsonSchemaApiEndpoints => { |
| 24 | + const ret: JsonSchemaApiEndpoints = {}; |
| 25 | + for (const path of Object.keys(endpoints)) { |
| 26 | + ret[path] = toJsonSchemaEndpoint(endpoints[path]); |
| 27 | + } |
| 28 | + return ret; |
| 29 | +}; |
| 30 | + |
| 31 | +export const toJsonSchemaEndpoint = <Endpoint extends ZodApiEndpoint>( |
| 32 | + endpoint: Endpoint, |
| 33 | +) => { |
| 34 | + const ret: Partial<Record<Method, JsonSchemaApiSpec>> = {}; |
| 35 | + for (const method of Method) { |
| 36 | + const spec = endpoint[method]; |
| 37 | + if (spec) { |
| 38 | + ret[method] = toJsonSchemaApiSpec(spec); |
| 39 | + } |
| 40 | + } |
| 41 | + return ret; |
| 42 | +}; |
| 43 | + |
| 44 | +export const toJsonSchemaApiSpec = <Spec extends ZodApiSpec>( |
| 45 | + spec: Spec, |
| 46 | +): JsonSchemaApiSpec => { |
| 47 | + const extraProps = extractExtraApiSpecProps(spec); |
| 48 | + const ret: JsonSchemaApiSpec = { |
| 49 | + responses: toJsonSchemaResponses(spec.responses), |
| 50 | + }; |
| 51 | + for (const key of apiSpecRequestKeys) { |
| 52 | + if (spec[key]) { |
| 53 | + // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 54 | + ret[key] = toSchema(spec[key]); |
| 55 | + } |
| 56 | + } |
| 57 | + return { ...extraProps, ...ret }; |
| 58 | +}; |
| 59 | + |
| 60 | +const toJsonSchemaResponses = ( |
| 61 | + responses: ZodAnyApiResponses, |
| 62 | +): JsonSchemaApiResponses => { |
| 63 | + const statusCodes = Object.keys(responses).map(Number) as StatusCode[]; |
| 64 | + const ret: JsonSchemaApiResponses = {}; |
| 65 | + for (const statusCode of statusCodes) { |
| 66 | + const r = responses[statusCode]; |
| 67 | + if (!r) { |
| 68 | + continue; |
| 69 | + } |
| 70 | + ret[statusCode] = { |
| 71 | + ...extractExtraResponseProps(r), |
| 72 | + body: toSchema(r.body), |
| 73 | + headers: r.headers ? toSchema(r.headers) : undefined, |
| 74 | + }; |
| 75 | + } |
| 76 | + return ret; |
| 77 | +}; |
| 78 | + |
| 79 | +const toSchema = (s: z.ZodTypeAny) => { |
| 80 | + return createSchema(s).schema as JSONSchema7; |
| 81 | +}; |
0 commit comments