@gabrielbryk/json-schema-to-zod 2.10.1 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/AGENTS.md +44 -0
  2. package/CHANGELOG.md +38 -0
  3. package/README.md +6 -33
  4. package/check-types-lift.sh +23 -0
  5. package/check-types.sh +20 -0
  6. package/dist/{esm/cli.js → cli.js} +0 -6
  7. package/dist/{esm/core → core}/analyzeSchema.js +4 -5
  8. package/dist/core/emitZod.js +263 -0
  9. package/dist/{esm/generators → generators}/generateBundle.js +26 -13
  10. package/dist/{esm/index.js → index.js} +6 -0
  11. package/dist/jsonSchemaToZod.js +17 -0
  12. package/dist/parsers/parseAllOf.js +125 -0
  13. package/dist/parsers/parseAnyOf.js +28 -0
  14. package/dist/{esm/parsers → parsers}/parseArray.js +27 -11
  15. package/dist/parsers/parseBoolean.js +4 -0
  16. package/dist/parsers/parseConst.js +22 -0
  17. package/dist/parsers/parseEnum.js +35 -0
  18. package/dist/{esm/parsers → parsers}/parseIfThenElse.js +10 -6
  19. package/dist/parsers/parseMultipleType.js +10 -0
  20. package/dist/parsers/parseNot.js +14 -0
  21. package/dist/parsers/parseNull.js +4 -0
  22. package/dist/parsers/parseNullable.js +12 -0
  23. package/dist/{esm/parsers → parsers}/parseNumber.js +4 -1
  24. package/dist/{esm/parsers → parsers}/parseObject.js +200 -37
  25. package/dist/parsers/parseOneOf.js +365 -0
  26. package/dist/{esm/parsers → parsers}/parseSchema.js +55 -117
  27. package/dist/parsers/parseSimpleDiscriminatedOneOf.js +24 -0
  28. package/dist/{esm/parsers → parsers}/parseString.js +29 -18
  29. package/dist/types/Types.d.ts +32 -4
  30. package/dist/types/core/analyzeSchema.d.ts +3 -2
  31. package/dist/types/generators/generateBundle.d.ts +0 -2
  32. package/dist/types/index.d.ts +6 -0
  33. package/dist/types/parsers/parseAllOf.d.ts +2 -2
  34. package/dist/types/parsers/parseAnyOf.d.ts +2 -2
  35. package/dist/types/parsers/parseArray.d.ts +2 -2
  36. package/dist/types/parsers/parseBoolean.d.ts +2 -1
  37. package/dist/types/parsers/parseConst.d.ts +2 -2
  38. package/dist/types/parsers/parseDefault.d.ts +2 -2
  39. package/dist/types/parsers/parseEnum.d.ts +2 -2
  40. package/dist/types/parsers/parseIfThenElse.d.ts +2 -2
  41. package/dist/types/parsers/parseMultipleType.d.ts +2 -2
  42. package/dist/types/parsers/parseNot.d.ts +2 -2
  43. package/dist/types/parsers/parseNull.d.ts +2 -1
  44. package/dist/types/parsers/parseNullable.d.ts +2 -2
  45. package/dist/types/parsers/parseNumber.d.ts +2 -2
  46. package/dist/types/parsers/parseObject.d.ts +2 -2
  47. package/dist/types/parsers/parseOneOf.d.ts +2 -2
  48. package/dist/types/parsers/parseSchema.d.ts +2 -2
  49. package/dist/types/parsers/parseSimpleDiscriminatedOneOf.d.ts +2 -2
  50. package/dist/types/parsers/parseString.d.ts +2 -2
  51. package/dist/types/utils/anyOrUnknown.d.ts +5 -4
  52. package/dist/types/utils/esmEmitter.d.ts +29 -0
  53. package/dist/types/utils/extractInlineObject.d.ts +15 -0
  54. package/dist/types/utils/liftInlineObjects.d.ts +21 -0
  55. package/dist/types/utils/namingService.d.ts +21 -0
  56. package/dist/types/utils/resolveRef.d.ts +7 -0
  57. package/dist/types/utils/schemaRepresentation.d.ts +71 -0
  58. package/dist/utils/anyOrUnknown.js +13 -0
  59. package/dist/{esm/utils → utils}/buildRefRegistry.js +4 -0
  60. package/dist/utils/esmEmitter.js +87 -0
  61. package/dist/utils/extractInlineObject.js +119 -0
  62. package/dist/utils/liftInlineObjects.js +476 -0
  63. package/dist/utils/namingService.js +58 -0
  64. package/dist/utils/resolveRef.js +92 -0
  65. package/dist/utils/schemaRepresentation.js +569 -0
  66. package/docs/IMPROVEMENT-PLAN.md +243 -0
  67. package/docs/ZOD-V4-RECURSIVE-TYPE-LIMITATIONS.md +292 -0
  68. package/docs/proposals/bundle-refactor.md +1 -1
  69. package/docs/proposals/discriminated-union-with-default.md +248 -0
  70. package/docs/proposals/inline-object-lifting.md +77 -0
  71. package/eslint.config.js +4 -2
  72. package/jest.config.mjs +19 -0
  73. package/package.json +17 -20
  74. package/scripts/generateWorkflowSchema.ts +0 -1
  75. package/dist/cjs/Types.js +0 -2
  76. package/dist/cjs/cli.js +0 -70
  77. package/dist/cjs/core/analyzeSchema.js +0 -62
  78. package/dist/cjs/core/emitZod.js +0 -157
  79. package/dist/cjs/generators/generateBundle.js +0 -510
  80. package/dist/cjs/index.js +0 -50
  81. package/dist/cjs/jsonSchemaToZod.js +0 -10
  82. package/dist/cjs/package.json +0 -1
  83. package/dist/cjs/parsers/parseAllOf.js +0 -46
  84. package/dist/cjs/parsers/parseAnyOf.js +0 -18
  85. package/dist/cjs/parsers/parseArray.js +0 -90
  86. package/dist/cjs/parsers/parseBoolean.js +0 -5
  87. package/dist/cjs/parsers/parseConst.js +0 -7
  88. package/dist/cjs/parsers/parseDefault.js +0 -8
  89. package/dist/cjs/parsers/parseEnum.js +0 -21
  90. package/dist/cjs/parsers/parseIfThenElse.js +0 -35
  91. package/dist/cjs/parsers/parseMultipleType.js +0 -10
  92. package/dist/cjs/parsers/parseNot.js +0 -12
  93. package/dist/cjs/parsers/parseNull.js +0 -5
  94. package/dist/cjs/parsers/parseNullable.js +0 -12
  95. package/dist/cjs/parsers/parseNumber.js +0 -116
  96. package/dist/cjs/parsers/parseObject.js +0 -318
  97. package/dist/cjs/parsers/parseOneOf.js +0 -53
  98. package/dist/cjs/parsers/parseSchema.js +0 -419
  99. package/dist/cjs/parsers/parseSimpleDiscriminatedOneOf.js +0 -21
  100. package/dist/cjs/parsers/parseString.js +0 -317
  101. package/dist/cjs/utils/anyOrUnknown.js +0 -14
  102. package/dist/cjs/utils/buildRefRegistry.js +0 -56
  103. package/dist/cjs/utils/cliTools.js +0 -108
  104. package/dist/cjs/utils/cycles.js +0 -113
  105. package/dist/cjs/utils/half.js +0 -7
  106. package/dist/cjs/utils/jsdocs.js +0 -20
  107. package/dist/cjs/utils/omit.js +0 -11
  108. package/dist/cjs/utils/resolveUri.js +0 -16
  109. package/dist/cjs/utils/withMessage.js +0 -21
  110. package/dist/cjs/zodToJsonSchema.js +0 -89
  111. package/dist/esm/core/emitZod.js +0 -153
  112. package/dist/esm/jsonSchemaToZod.js +0 -6
  113. package/dist/esm/package.json +0 -1
  114. package/dist/esm/parsers/parseAllOf.js +0 -43
  115. package/dist/esm/parsers/parseAnyOf.js +0 -14
  116. package/dist/esm/parsers/parseBoolean.js +0 -1
  117. package/dist/esm/parsers/parseConst.js +0 -3
  118. package/dist/esm/parsers/parseEnum.js +0 -17
  119. package/dist/esm/parsers/parseMultipleType.js +0 -6
  120. package/dist/esm/parsers/parseNot.js +0 -8
  121. package/dist/esm/parsers/parseNull.js +0 -1
  122. package/dist/esm/parsers/parseNullable.js +0 -8
  123. package/dist/esm/parsers/parseOneOf.js +0 -49
  124. package/dist/esm/parsers/parseSimpleDiscriminatedOneOf.js +0 -17
  125. package/dist/esm/utils/anyOrUnknown.js +0 -10
  126. package/jest.config.cjs +0 -4
  127. package/postcjs.cjs +0 -1
  128. package/postesm.cjs +0 -1
  129. /package/dist/{esm/Types.js → Types.js} +0 -0
  130. /package/dist/{esm/parsers → parsers}/parseDefault.js +0 -0
  131. /package/dist/{esm/utils → utils}/cliTools.js +0 -0
  132. /package/dist/{esm/utils → utils}/cycles.js +0 -0
  133. /package/dist/{esm/utils → utils}/half.js +0 -0
  134. /package/dist/{esm/utils → utils}/jsdocs.js +0 -0
  135. /package/dist/{esm/utils → utils}/omit.js +0 -0
  136. /package/dist/{esm/utils → utils}/resolveUri.js +0 -0
  137. /package/dist/{esm/utils → utils}/withMessage.js +0 -0
  138. /package/dist/{esm/zodToJsonSchema.js → zodToJsonSchema.js} +0 -0
@@ -0,0 +1,125 @@
1
+ import { parseSchema } from "./parseSchema.js";
2
+ import { half } from "../utils/half.js";
3
+ const originalIndexKey = "__originalIndex";
4
+ /**
5
+ * Check if a schema defines object properties (inline object shape) without any refs.
6
+ */
7
+ const isInlineObjectOnly = (schema) => {
8
+ if (typeof schema !== "object" || schema === null)
9
+ return false;
10
+ const obj = schema;
11
+ // Must have properties
12
+ if (!obj.properties || Object.keys(obj.properties).length === 0)
13
+ return false;
14
+ // Must NOT have $ref or $dynamicRef (can't use spread with refs)
15
+ if (obj.$ref || obj.$dynamicRef)
16
+ return false;
17
+ return true;
18
+ };
19
+ /**
20
+ * Parse just the shape entries from an object schema (without z.object wrapper).
21
+ * Returns array of "key: expression" strings for spreading.
22
+ */
23
+ const parseObjectShape = (schema, refs, pathPrefix) => {
24
+ const shapeEntries = [];
25
+ const shapeTypes = [];
26
+ for (const key of Object.keys(schema.properties)) {
27
+ const propSchema = schema.properties[key];
28
+ const parsedProp = parseSchema(propSchema, {
29
+ ...refs,
30
+ path: [...pathPrefix, "properties", key],
31
+ });
32
+ const hasDefault = typeof propSchema === "object" && propSchema.default !== undefined;
33
+ const required = Array.isArray(schema.required)
34
+ ? schema.required.includes(key)
35
+ : typeof propSchema === "object" && propSchema.required === true;
36
+ const optional = !hasDefault && !required;
37
+ const valueExpr = optional
38
+ ? `${parsedProp.expression}.optional()`
39
+ : parsedProp.expression;
40
+ const valueType = optional
41
+ ? `z.ZodOptional<${parsedProp.type}>`
42
+ : parsedProp.type;
43
+ shapeEntries.push(`${JSON.stringify(key)}: ${valueExpr}`);
44
+ shapeTypes.push(`${JSON.stringify(key)}: ${valueType}`);
45
+ }
46
+ return { shapeEntries, shapeTypes };
47
+ };
48
+ /**
49
+ * Check if all allOf members can be combined using spread syntax.
50
+ * Only works when ALL members are inline objects (no $refs).
51
+ * Returns the merged object if possible, undefined otherwise.
52
+ */
53
+ const trySpreadPattern = (allOfMembers, refs) => {
54
+ const shapeEntries = [];
55
+ const shapeTypes = [];
56
+ for (let i = 0; i < allOfMembers.length; i++) {
57
+ const member = allOfMembers[i];
58
+ const idx = member[originalIndexKey] ?? i;
59
+ // Only handle pure inline objects - no refs allowed
60
+ if (!isInlineObjectOnly(member)) {
61
+ return undefined;
62
+ }
63
+ // Extract shape entries from inline object
64
+ const { shapeEntries: entries, shapeTypes: types } = parseObjectShape(member, refs, [...refs.path, "allOf", idx]);
65
+ shapeEntries.push(...entries);
66
+ shapeTypes.push(...types);
67
+ }
68
+ if (shapeEntries.length === 0)
69
+ return undefined;
70
+ return {
71
+ expression: `z.object({ ${shapeEntries.join(", ")} })`,
72
+ type: `z.ZodObject<{ ${shapeTypes.join(", ")} }>`,
73
+ };
74
+ };
75
+ const ensureOriginalIndex = (arr) => {
76
+ const newArr = [];
77
+ for (let i = 0; i < arr.length; i++) {
78
+ const item = arr[i];
79
+ if (typeof item === "boolean") {
80
+ newArr.push(item ? { [originalIndexKey]: i } : { [originalIndexKey]: i, not: {} });
81
+ }
82
+ else if (typeof item === "object" &&
83
+ item !== null &&
84
+ originalIndexKey in item) {
85
+ return arr;
86
+ }
87
+ else {
88
+ newArr.push({ ...item, [originalIndexKey]: i });
89
+ }
90
+ }
91
+ return newArr;
92
+ };
93
+ export function parseAllOf(schema, refs) {
94
+ if (schema.allOf.length === 0) {
95
+ return { expression: "z.never()", type: "z.ZodNever" };
96
+ }
97
+ else if (schema.allOf.length === 1) {
98
+ const item = schema.allOf[0];
99
+ return parseSchema(item, {
100
+ ...refs,
101
+ path: [
102
+ ...refs.path,
103
+ "allOf",
104
+ item[originalIndexKey] ?? 0,
105
+ ],
106
+ });
107
+ }
108
+ else {
109
+ // Try spread pattern first (more efficient than intersection)
110
+ // This works when all members are either $refs to object schemas or inline objects
111
+ const indexed = ensureOriginalIndex(schema.allOf);
112
+ const spreadResult = trySpreadPattern(indexed, refs);
113
+ if (spreadResult) {
114
+ return spreadResult;
115
+ }
116
+ // Fallback to intersection-based approach
117
+ const [left, right] = half(indexed);
118
+ const leftResult = parseAllOf({ allOf: left }, refs);
119
+ const rightResult = parseAllOf({ allOf: right }, refs);
120
+ return {
121
+ expression: `z.intersection(${leftResult.expression}, ${rightResult.expression})`,
122
+ type: `z.ZodIntersection<${leftResult.type}, ${rightResult.type}>`,
123
+ };
124
+ }
125
+ }
@@ -0,0 +1,28 @@
1
+ import { parseSchema } from "./parseSchema.js";
2
+ import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
+ import { extractInlineObject } from "../utils/extractInlineObject.js";
4
+ export const parseAnyOf = (schema, refs) => {
5
+ if (!schema.anyOf.length) {
6
+ return anyOrUnknown(refs);
7
+ }
8
+ if (schema.anyOf.length === 1) {
9
+ return parseSchema(schema.anyOf[0], {
10
+ ...refs,
11
+ path: [...refs.path, "anyOf", 0],
12
+ });
13
+ }
14
+ // Rule 1: Extract inline objects to top-level declarations
15
+ const members = schema.anyOf.map((memberSchema, i) => {
16
+ const extracted = extractInlineObject(memberSchema, refs, [...refs.path, "anyOf", i]);
17
+ if (extracted) {
18
+ return { expression: extracted, type: `typeof ${extracted}` };
19
+ }
20
+ return parseSchema(memberSchema, { ...refs, path: [...refs.path, "anyOf", i] });
21
+ });
22
+ const expressions = members.map(m => m.expression).join(", ");
23
+ const types = members.map(m => m.type).join(", ");
24
+ const expression = `z.union([${expressions}])`;
25
+ // Use readonly tuple for union type annotations (required for recursive type inference)
26
+ const type = `z.ZodUnion<readonly [${types}]>`;
27
+ return { expression, type };
28
+ };
@@ -3,16 +3,20 @@ import { parseSchema } from "./parseSchema.js";
3
3
  import { anyOrUnknown } from "../utils/anyOrUnknown.js";
4
4
  export const parseArray = (schema, refs) => {
5
5
  if (Array.isArray(schema.items)) {
6
- let tuple = `z.tuple([${schema.items.map((v, i) => parseSchema(v, { ...refs, path: [...refs.path, "items", i] }))}])`;
6
+ // Tuple case
7
+ const itemResults = schema.items.map((v, i) => parseSchema(v, { ...refs, path: [...refs.path, "items", i] }));
8
+ let tuple = `z.tuple([${itemResults.map(r => r.expression).join(", ")}])`;
9
+ const tupleTypes = itemResults.map(r => r.type).join(", ");
10
+ let tupleType = `z.ZodTuple<[${tupleTypes}]>`;
7
11
  if (schema.contains) {
8
- const containsSchema = parseSchema(schema.contains, {
12
+ const containsResult = parseSchema(schema.contains, {
9
13
  ...refs,
10
14
  path: [...refs.path, "contains"],
11
15
  });
12
16
  const minContains = schema.minContains ?? (schema.contains ? 1 : undefined);
13
17
  const maxContains = schema.maxContains;
14
18
  tuple += `.superRefine((arr, ctx) => {
15
- const matches = arr.filter((item) => ${containsSchema}.safeParse(item).success).length;
19
+ const matches = arr.filter((item) => ${containsResult.expression}.safeParse(item).success).length;
16
20
  if (${minContains ?? 0} && matches < ${minContains ?? 0}) {
17
21
  ctx.addIssue({ code: "custom", message: "Array contains too few matching items" });
18
22
  }
@@ -20,15 +24,23 @@ export const parseArray = (schema, refs) => {
20
24
  ctx.addIssue({ code: "custom", message: "Array contains too many matching items" });
21
25
  }
22
26
  })`;
27
+ // In Zod v4, .superRefine() doesn't change the type
23
28
  }
24
- return tuple;
29
+ return {
30
+ expression: tuple,
31
+ type: tupleType,
32
+ };
25
33
  }
26
- let r = !schema.items
27
- ? `z.array(${anyOrUnknown(refs)})`
28
- : `z.array(${parseSchema(schema.items, {
34
+ // Array case
35
+ const anyOrUnknownResult = anyOrUnknown(refs);
36
+ const itemResult = !schema.items
37
+ ? anyOrUnknownResult
38
+ : parseSchema(schema.items, {
29
39
  ...refs,
30
40
  path: [...refs.path, "items"],
31
- })})`;
41
+ });
42
+ let r = `z.array(${itemResult.expression})`;
43
+ let arrayType = `z.ZodArray<${itemResult.type}>`;
32
44
  r += withMessage(schema, "minItems", ({ json }) => ({
33
45
  opener: `.min(${json}`,
34
46
  closer: ")",
@@ -66,14 +78,14 @@ export const parseArray = (schema, refs) => {
66
78
  })`;
67
79
  }
68
80
  if (schema.contains) {
69
- const containsSchema = parseSchema(schema.contains, {
81
+ const containsResult = parseSchema(schema.contains, {
70
82
  ...refs,
71
83
  path: [...refs.path, "contains"],
72
84
  });
73
85
  const minContains = schema.minContains ?? (schema.contains ? 1 : undefined);
74
86
  const maxContains = schema.maxContains;
75
87
  r += `.superRefine((arr, ctx) => {
76
- const matches = arr.filter((item) => ${containsSchema}.safeParse(item).success).length;
88
+ const matches = arr.filter((item) => ${containsResult.expression}.safeParse(item).success).length;
77
89
  if (${minContains ?? 0} && matches < ${minContains ?? 0}) {
78
90
  ctx.addIssue({ code: "custom", message: "Array contains too few matching items" });
79
91
  }
@@ -82,5 +94,9 @@ export const parseArray = (schema, refs) => {
82
94
  }
83
95
  })`;
84
96
  }
85
- return r;
97
+ // In Zod v4, .superRefine() doesn't change the type, so no wrapping needed
98
+ return {
99
+ expression: r,
100
+ type: arrayType,
101
+ };
86
102
  };
@@ -0,0 +1,4 @@
1
+ export const parseBoolean = () => ({
2
+ expression: "z.boolean()",
3
+ type: "z.ZodBoolean",
4
+ });
@@ -0,0 +1,22 @@
1
+ export const parseConst = (schema) => {
2
+ const value = schema.const;
3
+ const expression = `z.literal(${JSON.stringify(value)})`;
4
+ // Determine the literal type based on the value type
5
+ let type;
6
+ if (typeof value === "string") {
7
+ type = `z.ZodLiteral<${JSON.stringify(value)}>`;
8
+ }
9
+ else if (typeof value === "number") {
10
+ type = `z.ZodLiteral<${value}>`;
11
+ }
12
+ else if (typeof value === "boolean") {
13
+ type = `z.ZodLiteral<${value}>`;
14
+ }
15
+ else if (value === null) {
16
+ type = "z.ZodLiteral<null>";
17
+ }
18
+ else {
19
+ type = "z.ZodLiteral<unknown>";
20
+ }
21
+ return { expression, type };
22
+ };
@@ -0,0 +1,35 @@
1
+ export const parseEnum = (schema) => {
2
+ if (schema.enum.length === 0) {
3
+ return {
4
+ expression: "z.never()",
5
+ type: "z.ZodNever",
6
+ };
7
+ }
8
+ else if (schema.enum.length === 1) {
9
+ // union does not work when there is only one element
10
+ const value = schema.enum[0];
11
+ return {
12
+ expression: `z.literal(${JSON.stringify(value)})`,
13
+ type: `z.ZodLiteral<${typeof value === "string" ? JSON.stringify(value) : value}>`,
14
+ };
15
+ }
16
+ else if (schema.enum.every((x) => typeof x === "string")) {
17
+ const values = schema.enum;
18
+ // Zod v4 ZodEnum uses object format: { key: "key"; ... }
19
+ const enumObject = values.map((x) => `${JSON.stringify(x)}: ${JSON.stringify(x)}`).join("; ");
20
+ return {
21
+ expression: `z.enum([${values.map((x) => JSON.stringify(x))}])`,
22
+ type: `z.ZodEnum<{ ${enumObject} }>`,
23
+ };
24
+ }
25
+ else {
26
+ // Mixed types: create union of literals
27
+ const literalTypes = schema.enum.map((x) => typeof x === "string" ? JSON.stringify(x) : x === null ? "null" : String(x));
28
+ return {
29
+ expression: `z.union([${schema.enum
30
+ .map((x) => `z.literal(${JSON.stringify(x)})`)
31
+ .join(", ")}])`,
32
+ type: `z.ZodUnion<[${literalTypes.map((t) => `z.ZodLiteral<${t}>`).join(", ")}]>`,
33
+ };
34
+ }
35
+ };
@@ -9,10 +9,10 @@ export const parseIfThenElse = (schema, refs) => {
9
9
  ...refs,
10
10
  path: [...refs.path, "else"],
11
11
  });
12
- let result = `z.union([${$then}, ${$else}]).superRefine((value,ctx) => {
13
- const result = ${$if}.safeParse(value).success
14
- ? ${$then}.safeParse(value)
15
- : ${$else}.safeParse(value);
12
+ let expression = `z.union([${$then.expression}, ${$else.expression}]).superRefine((value,ctx) => {
13
+ const result = ${$if.expression}.safeParse(value).success
14
+ ? ${$then.expression}.safeParse(value)
15
+ : ${$else.expression}.safeParse(value);
16
16
  if (!result.success) {
17
17
  const issues = result.error.issues;
18
18
  issues.forEach((issue) => ctx.addIssue({ ...issue }))
@@ -25,7 +25,11 @@ export const parseIfThenElse = (schema, refs) => {
25
25
  then: schema.then,
26
26
  else: schema.else,
27
27
  });
28
- result += `.meta({ __jsonSchema: { conditional: ${conditionalMeta} } })`;
28
+ expression += `.meta({ __jsonSchema: { conditional: ${conditionalMeta} } })`;
29
29
  }
30
- return result;
30
+ return {
31
+ expression,
32
+ // In Zod v4, .superRefine() doesn't change the type
33
+ type: `z.ZodUnion<[${$then.type}, ${$else.type}]>`,
34
+ };
31
35
  };
@@ -0,0 +1,10 @@
1
+ import { parseSchema } from "./parseSchema.js";
2
+ export const parseMultipleType = (schema, refs) => {
3
+ const schemas = schema.type.map((type) => parseSchema({ ...schema, type }, { ...refs, withoutDefaults: true }));
4
+ const expressions = schemas.map(s => s.expression).join(", ");
5
+ const types = schemas.map(s => s.type).join(", ");
6
+ return {
7
+ expression: `z.union([${expressions}])`,
8
+ type: `z.ZodUnion<[${types}]>`,
9
+ };
10
+ };
@@ -0,0 +1,14 @@
1
+ import { parseSchema } from "./parseSchema.js";
2
+ import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
+ export const parseNot = (schema, refs) => {
4
+ const baseSchema = anyOrUnknown(refs);
5
+ const notSchema = parseSchema(schema.not, {
6
+ ...refs,
7
+ path: [...refs.path, "not"],
8
+ });
9
+ return {
10
+ expression: `${baseSchema.expression}.refine((value) => !${notSchema.expression}.safeParse(value).success, "Invalid input: Should NOT be valid against schema")`,
11
+ // In Zod v4, .refine() doesn't change the type
12
+ type: baseSchema.type,
13
+ };
14
+ };
@@ -0,0 +1,4 @@
1
+ export const parseNull = () => ({
2
+ expression: "z.null()",
3
+ type: "z.ZodNull",
4
+ });
@@ -0,0 +1,12 @@
1
+ import { omit } from "../utils/omit.js";
2
+ import { parseSchema } from "./parseSchema.js";
3
+ /**
4
+ * For compatibility with open api 3.0 nullable
5
+ */
6
+ export const parseNullable = (schema, refs) => {
7
+ const innerSchema = parseSchema(omit(schema, "nullable"), refs, true);
8
+ return {
9
+ expression: `${innerSchema.expression}.nullable()`,
10
+ type: `z.ZodNullable<${innerSchema.type}>`,
11
+ };
12
+ };
@@ -108,5 +108,8 @@ export const parseNumber = (schema) => {
108
108
  messageCloser: " })",
109
109
  }));
110
110
  }
111
- return r;
111
+ return {
112
+ expression: r,
113
+ type: "z.ZodNumber",
114
+ };
112
115
  };