UNPKG

openai

Version:

The official TypeScript library for the OpenAI API

121 lines (106 loc) 3.52 kB
import { ZodSchema } from 'zod'; import { Options, Targets } from './Options'; import { JsonSchema7Type, parseDef } from './parseDef'; import { getRefs } from './Refs'; import { zodDef, isEmptyObj } from './util'; const zodToJsonSchema = <Target extends Targets = 'jsonSchema7'>( schema: ZodSchema<any>, options?: Partial<Options<Target>> | string, ): (Target extends 'jsonSchema7' ? JsonSchema7Type : object) & { $schema?: string; definitions?: { [key: string]: Target extends 'jsonSchema7' ? JsonSchema7Type : Target extends 'jsonSchema2019-09' ? JsonSchema7Type : object; }; } => { const refs = getRefs(options); const name = typeof options === 'string' ? options : options?.nameStrategy === 'title' ? undefined : options?.name; const main = parseDef( schema._def, name === undefined ? refs : ( { ...refs, currentPath: [...refs.basePath, refs.definitionPath, name], } ), false, ) ?? {}; const title = typeof options === 'object' && options.name !== undefined && options.nameStrategy === 'title' ? options.name : undefined; if (title !== undefined) { main.title = title; } const definitions = (() => { if (isEmptyObj(refs.definitions)) { return undefined; } const definitions: Record<string, any> = {}; const processedDefinitions = new Set(); // the call to `parseDef()` here might itself add more entries to `.definitions` // so we need to continually evaluate definitions until we've resolved all of them // // we have a generous iteration limit here to avoid blowing up the stack if there // are any bugs that would otherwise result in us iterating indefinitely for (let i = 0; i < 500; i++) { const newDefinitions = Object.entries(refs.definitions).filter( ([key]) => !processedDefinitions.has(key), ); if (newDefinitions.length === 0) break; for (const [key, schema] of newDefinitions) { definitions[key] = parseDef( zodDef(schema), { ...refs, currentPath: [...refs.basePath, refs.definitionPath, key] }, true, ) ?? {}; processedDefinitions.add(key); } } return definitions; })(); const combined: ReturnType<typeof zodToJsonSchema<Target>> = name === undefined ? definitions ? { ...main, [refs.definitionPath]: definitions, } : main : refs.nameStrategy === 'duplicate-ref' ? { ...main, ...(definitions || refs.seenRefs.size ? { [refs.definitionPath]: { ...definitions, // only actually duplicate the schema definition if it was ever referenced // otherwise the duplication is completely pointless ...(refs.seenRefs.size ? { [name]: main } : undefined), }, } : undefined), } : { $ref: [...(refs.$refStrategy === 'relative' ? [] : refs.basePath), refs.definitionPath, name].join( '/', ), [refs.definitionPath]: { ...definitions, [name]: main, }, }; if (refs.target === 'jsonSchema7') { combined.$schema = 'http://json-schema.org/draft-07/schema#'; } else if (refs.target === 'jsonSchema2019-09') { combined.$schema = 'https://json-schema.org/draft/2019-09/schema#'; } return combined; }; export { zodToJsonSchema };