parseDef.mjs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { ZodFirstPartyTypeKind } from 'zod';
  2. import { parseAnyDef } from "./parsers/any.mjs";
  3. import { parseArrayDef } from "./parsers/array.mjs";
  4. import { parseBigintDef } from "./parsers/bigint.mjs";
  5. import { parseBooleanDef } from "./parsers/boolean.mjs";
  6. import { parseBrandedDef } from "./parsers/branded.mjs";
  7. import { parseCatchDef } from "./parsers/catch.mjs";
  8. import { parseDateDef } from "./parsers/date.mjs";
  9. import { parseDefaultDef } from "./parsers/default.mjs";
  10. import { parseEffectsDef } from "./parsers/effects.mjs";
  11. import { parseEnumDef } from "./parsers/enum.mjs";
  12. import { parseIntersectionDef } from "./parsers/intersection.mjs";
  13. import { parseLiteralDef } from "./parsers/literal.mjs";
  14. import { parseMapDef } from "./parsers/map.mjs";
  15. import { parseNativeEnumDef } from "./parsers/nativeEnum.mjs";
  16. import { parseNeverDef } from "./parsers/never.mjs";
  17. import { parseNullDef } from "./parsers/null.mjs";
  18. import { parseNullableDef } from "./parsers/nullable.mjs";
  19. import { parseNumberDef } from "./parsers/number.mjs";
  20. import { parseObjectDef } from "./parsers/object.mjs";
  21. import { parseOptionalDef } from "./parsers/optional.mjs";
  22. import { parsePipelineDef } from "./parsers/pipeline.mjs";
  23. import { parsePromiseDef } from "./parsers/promise.mjs";
  24. import { parseRecordDef } from "./parsers/record.mjs";
  25. import { parseSetDef } from "./parsers/set.mjs";
  26. import { parseStringDef } from "./parsers/string.mjs";
  27. import { parseTupleDef } from "./parsers/tuple.mjs";
  28. import { parseUndefinedDef } from "./parsers/undefined.mjs";
  29. import { parseUnionDef } from "./parsers/union.mjs";
  30. import { parseUnknownDef } from "./parsers/unknown.mjs";
  31. import { parseReadonlyDef } from "./parsers/readonly.mjs";
  32. import { ignoreOverride } from "./Options.mjs";
  33. export function parseDef(def, refs, forceResolution = false) {
  34. const seenItem = refs.seen.get(def);
  35. if (refs.override) {
  36. const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
  37. if (overrideResult !== ignoreOverride) {
  38. return overrideResult;
  39. }
  40. }
  41. if (seenItem && !forceResolution) {
  42. const seenSchema = get$ref(seenItem, refs);
  43. if (seenSchema !== undefined) {
  44. if ('$ref' in seenSchema) {
  45. refs.seenRefs.add(seenSchema.$ref);
  46. }
  47. return seenSchema;
  48. }
  49. }
  50. const newItem = { def, path: refs.currentPath, jsonSchema: undefined };
  51. refs.seen.set(def, newItem);
  52. const jsonSchema = selectParser(def, def.typeName, refs, forceResolution);
  53. if (jsonSchema) {
  54. addMeta(def, refs, jsonSchema);
  55. }
  56. newItem.jsonSchema = jsonSchema;
  57. return jsonSchema;
  58. }
  59. const get$ref = (item, refs) => {
  60. switch (refs.$refStrategy) {
  61. case 'root':
  62. return { $ref: item.path.join('/') };
  63. // this case is needed as OpenAI strict mode doesn't support top-level `$ref`s, i.e.
  64. // the top-level schema *must* be `{"type": "object", "properties": {...}}` but if we ever
  65. // need to define a `$ref`, relative `$ref`s aren't supported, so we need to extract
  66. // the schema to `#/definitions/` and reference that.
  67. //
  68. // e.g. if we need to reference a schema at
  69. // `["#","definitions","contactPerson","properties","person1","properties","name"]`
  70. // then we'll extract it out to `contactPerson_properties_person1_properties_name`
  71. case 'extract-to-root':
  72. const name = item.path.slice(refs.basePath.length + 1).join('_');
  73. // we don't need to extract the root schema in this case, as it's already
  74. // been added to the definitions
  75. if (name !== refs.name && refs.nameStrategy === 'duplicate-ref') {
  76. refs.definitions[name] = item.def;
  77. }
  78. return { $ref: [...refs.basePath, refs.definitionPath, name].join('/') };
  79. case 'relative':
  80. return { $ref: getRelativePath(refs.currentPath, item.path) };
  81. case 'none':
  82. case 'seen': {
  83. if (item.path.length < refs.currentPath.length &&
  84. item.path.every((value, index) => refs.currentPath[index] === value)) {
  85. console.warn(`Recursive reference detected at ${refs.currentPath.join('/')}! Defaulting to any`);
  86. return {};
  87. }
  88. return refs.$refStrategy === 'seen' ? {} : undefined;
  89. }
  90. }
  91. };
  92. const getRelativePath = (pathA, pathB) => {
  93. let i = 0;
  94. for (; i < pathA.length && i < pathB.length; i++) {
  95. if (pathA[i] !== pathB[i])
  96. break;
  97. }
  98. return [(pathA.length - i).toString(), ...pathB.slice(i)].join('/');
  99. };
  100. const selectParser = (def, typeName, refs, forceResolution) => {
  101. switch (typeName) {
  102. case ZodFirstPartyTypeKind.ZodString:
  103. return parseStringDef(def, refs);
  104. case ZodFirstPartyTypeKind.ZodNumber:
  105. return parseNumberDef(def, refs);
  106. case ZodFirstPartyTypeKind.ZodObject:
  107. return parseObjectDef(def, refs);
  108. case ZodFirstPartyTypeKind.ZodBigInt:
  109. return parseBigintDef(def, refs);
  110. case ZodFirstPartyTypeKind.ZodBoolean:
  111. return parseBooleanDef();
  112. case ZodFirstPartyTypeKind.ZodDate:
  113. return parseDateDef(def, refs);
  114. case ZodFirstPartyTypeKind.ZodUndefined:
  115. return parseUndefinedDef();
  116. case ZodFirstPartyTypeKind.ZodNull:
  117. return parseNullDef(refs);
  118. case ZodFirstPartyTypeKind.ZodArray:
  119. return parseArrayDef(def, refs);
  120. case ZodFirstPartyTypeKind.ZodUnion:
  121. case ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
  122. return parseUnionDef(def, refs);
  123. case ZodFirstPartyTypeKind.ZodIntersection:
  124. return parseIntersectionDef(def, refs);
  125. case ZodFirstPartyTypeKind.ZodTuple:
  126. return parseTupleDef(def, refs);
  127. case ZodFirstPartyTypeKind.ZodRecord:
  128. return parseRecordDef(def, refs);
  129. case ZodFirstPartyTypeKind.ZodLiteral:
  130. return parseLiteralDef(def, refs);
  131. case ZodFirstPartyTypeKind.ZodEnum:
  132. return parseEnumDef(def);
  133. case ZodFirstPartyTypeKind.ZodNativeEnum:
  134. return parseNativeEnumDef(def);
  135. case ZodFirstPartyTypeKind.ZodNullable:
  136. return parseNullableDef(def, refs);
  137. case ZodFirstPartyTypeKind.ZodOptional:
  138. return parseOptionalDef(def, refs);
  139. case ZodFirstPartyTypeKind.ZodMap:
  140. return parseMapDef(def, refs);
  141. case ZodFirstPartyTypeKind.ZodSet:
  142. return parseSetDef(def, refs);
  143. case ZodFirstPartyTypeKind.ZodLazy:
  144. return parseDef(def.getter()._def, refs);
  145. case ZodFirstPartyTypeKind.ZodPromise:
  146. return parsePromiseDef(def, refs);
  147. case ZodFirstPartyTypeKind.ZodNaN:
  148. case ZodFirstPartyTypeKind.ZodNever:
  149. return parseNeverDef();
  150. case ZodFirstPartyTypeKind.ZodEffects:
  151. return parseEffectsDef(def, refs, forceResolution);
  152. case ZodFirstPartyTypeKind.ZodAny:
  153. return parseAnyDef();
  154. case ZodFirstPartyTypeKind.ZodUnknown:
  155. return parseUnknownDef();
  156. case ZodFirstPartyTypeKind.ZodDefault:
  157. return parseDefaultDef(def, refs);
  158. case ZodFirstPartyTypeKind.ZodBranded:
  159. return parseBrandedDef(def, refs);
  160. case ZodFirstPartyTypeKind.ZodReadonly:
  161. return parseReadonlyDef(def, refs);
  162. case ZodFirstPartyTypeKind.ZodCatch:
  163. return parseCatchDef(def, refs);
  164. case ZodFirstPartyTypeKind.ZodPipeline:
  165. return parsePipelineDef(def, refs);
  166. case ZodFirstPartyTypeKind.ZodFunction:
  167. case ZodFirstPartyTypeKind.ZodVoid:
  168. case ZodFirstPartyTypeKind.ZodSymbol:
  169. return undefined;
  170. default:
  171. return ((_) => undefined)(typeName);
  172. }
  173. };
  174. const addMeta = (def, refs, jsonSchema) => {
  175. if (def.description) {
  176. jsonSchema.description = def.description;
  177. if (refs.markdownDescription) {
  178. jsonSchema.markdownDescription = def.description;
  179. }
  180. }
  181. return jsonSchema;
  182. };
  183. //# sourceMappingURL=parseDef.mjs.map