zodToJsonSchema.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import { parseDef } from "./parseDef.js";
  2. import { getRefs } from "./Refs.js";
  3. import { parseAnyDef } from "./parsers/any.js";
  4. const zodToJsonSchema = (schema, options) => {
  5. const refs = getRefs(options);
  6. let definitions = typeof options === "object" && options.definitions
  7. ? Object.entries(options.definitions).reduce((acc, [name, schema]) => ({
  8. ...acc,
  9. [name]: parseDef(schema._def, {
  10. ...refs,
  11. currentPath: [...refs.basePath, refs.definitionPath, name],
  12. }, true) ?? parseAnyDef(refs),
  13. }), {})
  14. : undefined;
  15. const name = typeof options === "string"
  16. ? options
  17. : options?.nameStrategy === "title"
  18. ? undefined
  19. : options?.name;
  20. const main = parseDef(schema._def, name === undefined
  21. ? refs
  22. : {
  23. ...refs,
  24. currentPath: [...refs.basePath, refs.definitionPath, name],
  25. }, false) ?? parseAnyDef(refs);
  26. const title = typeof options === "object" &&
  27. options.name !== undefined &&
  28. options.nameStrategy === "title"
  29. ? options.name
  30. : undefined;
  31. if (title !== undefined) {
  32. main.title = title;
  33. }
  34. if (refs.flags.hasReferencedOpenAiAnyType) {
  35. if (!definitions) {
  36. definitions = {};
  37. }
  38. if (!definitions[refs.openAiAnyTypeName]) {
  39. definitions[refs.openAiAnyTypeName] = {
  40. // Skipping "object" as no properties can be defined and additionalProperties must be "false"
  41. type: ["string", "number", "integer", "boolean", "array", "null"],
  42. items: {
  43. $ref: refs.$refStrategy === "relative"
  44. ? "1"
  45. : [
  46. ...refs.basePath,
  47. refs.definitionPath,
  48. refs.openAiAnyTypeName,
  49. ].join("/"),
  50. },
  51. };
  52. }
  53. }
  54. const combined = name === undefined
  55. ? definitions
  56. ? {
  57. ...main,
  58. [refs.definitionPath]: definitions,
  59. }
  60. : main
  61. : {
  62. $ref: [
  63. ...(refs.$refStrategy === "relative" ? [] : refs.basePath),
  64. refs.definitionPath,
  65. name,
  66. ].join("/"),
  67. [refs.definitionPath]: {
  68. ...definitions,
  69. [name]: main,
  70. },
  71. };
  72. if (refs.target === "jsonSchema7") {
  73. combined.$schema = "http://json-schema.org/draft-07/schema#";
  74. }
  75. else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") {
  76. combined.$schema = "https://json-schema.org/draft/2019-09/schema#";
  77. }
  78. if (refs.target === "openAi" &&
  79. ("anyOf" in combined ||
  80. "oneOf" in combined ||
  81. "allOf" in combined ||
  82. ("type" in combined && Array.isArray(combined.type)))) {
  83. console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property.");
  84. }
  85. return combined;
  86. };
  87. export { zodToJsonSchema };