union.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.parseUnionDef = exports.primitiveMappings = void 0;
  4. const parseDef_js_1 = require("../parseDef.js");
  5. exports.primitiveMappings = {
  6. ZodString: "string",
  7. ZodNumber: "number",
  8. ZodBigInt: "integer",
  9. ZodBoolean: "boolean",
  10. ZodNull: "null",
  11. };
  12. function parseUnionDef(def, refs) {
  13. if (refs.target === "openApi3")
  14. return asAnyOf(def, refs);
  15. const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
  16. // This blocks tries to look ahead a bit to produce nicer looking schemas with type array instead of anyOf.
  17. if (options.every((x) => x._def.typeName in exports.primitiveMappings &&
  18. (!x._def.checks || !x._def.checks.length))) {
  19. // all types in union are primitive and lack checks, so might as well squash into {type: [...]}
  20. const types = options.reduce((types, x) => {
  21. const type = exports.primitiveMappings[x._def.typeName]; //Can be safely casted due to row 43
  22. return type && !types.includes(type) ? [...types, type] : types;
  23. }, []);
  24. return {
  25. type: types.length > 1 ? types : types[0],
  26. };
  27. }
  28. else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) {
  29. // all options literals
  30. const types = options.reduce((acc, x) => {
  31. const type = typeof x._def.value;
  32. switch (type) {
  33. case "string":
  34. case "number":
  35. case "boolean":
  36. return [...acc, type];
  37. case "bigint":
  38. return [...acc, "integer"];
  39. case "object":
  40. if (x._def.value === null)
  41. return [...acc, "null"];
  42. case "symbol":
  43. case "undefined":
  44. case "function":
  45. default:
  46. return acc;
  47. }
  48. }, []);
  49. if (types.length === options.length) {
  50. // all the literals are primitive, as far as null can be considered primitive
  51. const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
  52. return {
  53. type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
  54. enum: options.reduce((acc, x) => {
  55. return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
  56. }, []),
  57. };
  58. }
  59. }
  60. else if (options.every((x) => x._def.typeName === "ZodEnum")) {
  61. return {
  62. type: "string",
  63. enum: options.reduce((acc, x) => [
  64. ...acc,
  65. ...x._def.values.filter((x) => !acc.includes(x)),
  66. ], []),
  67. };
  68. }
  69. return asAnyOf(def, refs);
  70. }
  71. exports.parseUnionDef = parseUnionDef;
  72. const asAnyOf = (def, refs) => {
  73. const anyOf = (def.options instanceof Map
  74. ? Array.from(def.options.values())
  75. : def.options)
  76. .map((x, i) => (0, parseDef_js_1.parseDef)(x._def, {
  77. ...refs,
  78. currentPath: [...refs.currentPath, "anyOf", `${i}`],
  79. }))
  80. .filter((x) => !!x &&
  81. (!refs.strictUnions ||
  82. (typeof x === "object" && Object.keys(x).length > 0)));
  83. return anyOf.length ? { anyOf } : undefined;
  84. };