import { ZodType, z } from "zod"; import { zodToJsonSchema } from "zod-to-json-schema"; export type Models = { readonly [K in Key]: ZodType; }; export type BuildJsonSchemasOptions = { readonly $id?: string; readonly target?: `jsonSchema7` | `openApi3`; readonly errorMessages?: boolean; }; export type SchemaKey = M extends Models ? Key & string : never; export type SchemaKeyOrDescription = | SchemaKey | { readonly description: string; readonly key: SchemaKey; }; export type $Ref = (key: SchemaKeyOrDescription) => { readonly $ref: string; readonly description?: string; }; export type JsonSchema = { readonly $id: string; }; export type BuildJsonSchemasResult = { readonly schemas: JsonSchema[]; readonly $ref: $Ref; }; export const buildJsonSchemas = ( models: M, opts: BuildJsonSchemasOptions = {}, ): BuildJsonSchemasResult => { const zodSchema = z.object(models); const zodJsonSchema = zodToJsonSchema(zodSchema, { target: "openApi3", $refStrategy: "none", errorMessages: opts.errorMessages, }); const cleanedSchemas = Object.entries( //@ts-ignore zodJsonSchema.properties as { [key: string]: any }, ).reduce((acc, [key, value]) => { return [...acc, { $id: key, title: key, ...value }]; }, [] as JsonSchema[]); const $ref: $Ref = (key) => { const $ref = `${typeof key === `string` ? key : key.key}#`; return typeof key === `string` ? { $ref, } : { $ref, description: key.description, }; }; return { schemas: cleanedSchemas, $ref, }; };