@gabrielbryk/json-schema-to-zod 2.10.0 → 2.11.0

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 +35 -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 +225 -67
  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 +11 -7
  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 +168 -29
  25. package/dist/parsers/parseOneOf.js +365 -0
  26. package/dist/{esm/parsers → parsers}/parseSchema.js +56 -110
  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 -141
  79. package/dist/cjs/generators/generateBundle.js +0 -365
  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 -315
  97. package/dist/cjs/parsers/parseOneOf.js +0 -53
  98. package/dist/cjs/parsers/parseSchema.js +0 -411
  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 -137
  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
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withMessage = withMessage;
4
- function withMessage(schema, key, get) {
5
- const value = schema[key];
6
- let r = "";
7
- if (value !== undefined) {
8
- const got = get({ value, json: JSON.stringify(value) });
9
- if (got) {
10
- const { opener, closer, messagePrefix = "", messageCloser } = got;
11
- r += opener;
12
- if (schema.errorMessage?.[key] !== undefined) {
13
- r += messagePrefix + JSON.stringify(schema.errorMessage[key]);
14
- r += messageCloser ?? closer;
15
- return r;
16
- }
17
- r += closer;
18
- }
19
- }
20
- return r;
21
- }
@@ -1,89 +0,0 @@
1
- "use strict";
2
- /**
3
- * Post-processor for Zod's z.toJSONSchema() output.
4
- *
5
- * When `preserveJsonSchemaForRoundTrip` was used during JSON Schema → Zod conversion,
6
- * this function reconstructs the original JSON Schema features from the stored __jsonSchema meta.
7
- *
8
- * Usage:
9
- * 1. Convert JSON Schema to Zod code with `preserveJsonSchemaForRoundTrip: true`
10
- * 2. Evaluate the Zod code to get a schema instance
11
- * 3. Call Zod's `z.toJSONSchema(schema)` to get JSON Schema output
12
- * 4. Pass that output to `reconstructJsonSchema()` to restore preserved features
13
- *
14
- * Handles:
15
- * - patternProperties (stored in __jsonSchema.patternProperties)
16
- * - if/then/else conditionals (stored in __jsonSchema.conditional)
17
- */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.reconstructJsonSchema = reconstructJsonSchema;
20
- /**
21
- * Recursively process a JSON Schema to reconstruct original features from __jsonSchema meta.
22
- *
23
- * Handles special cases:
24
- * - allOf[object, {__jsonSchema: {conditional: ...}}] -> object with if/then/else at top level
25
- * - patternProperties meta -> patternProperties at current level
26
- */
27
- function reconstructJsonSchema(schema) {
28
- if (typeof schema !== "object" || schema === null) {
29
- return schema;
30
- }
31
- const result = { ...schema };
32
- // Handle allOf structures created by .and() with conditionals
33
- // Pattern: allOf: [mainSchema, {__jsonSchema: {conditional: ...}, anyOf: [...]}]
34
- if (Array.isArray(result.allOf) &&
35
- result.allOf.length === 2 &&
36
- typeof result.allOf[1] === "object" &&
37
- result.allOf[1] !== null) {
38
- const secondElement = result.allOf[1];
39
- // Check if second element has conditional meta
40
- if (secondElement.__jsonSchema &&
41
- typeof secondElement.__jsonSchema === "object" &&
42
- secondElement.__jsonSchema.conditional) {
43
- // Extract the main schema and conditional
44
- const mainSchema = reconstructJsonSchema(result.allOf[0]);
45
- const conditionalMeta = secondElement.__jsonSchema
46
- .conditional;
47
- // Merge: main schema + if/then/else at top level
48
- const merged = {
49
- ...mainSchema,
50
- if: conditionalMeta.if,
51
- then: conditionalMeta.then,
52
- else: conditionalMeta.else,
53
- };
54
- // Recursively process the merged result
55
- return reconstructJsonSchema(merged);
56
- }
57
- }
58
- // Check for __jsonSchema meta at this level
59
- if (result.__jsonSchema && typeof result.__jsonSchema === "object") {
60
- const preserved = result.__jsonSchema;
61
- // Reconstruct patternProperties
62
- if (preserved.patternProperties) {
63
- result.patternProperties = preserved.patternProperties;
64
- }
65
- // Reconstruct if/then/else conditional (for non-allOf cases)
66
- if (preserved.conditional) {
67
- const conditional = preserved.conditional;
68
- result.if = conditional.if;
69
- result.then = conditional.then;
70
- result.else = conditional.else;
71
- }
72
- // Remove the __jsonSchema meta from the output
73
- delete result.__jsonSchema;
74
- }
75
- // Recursively process nested schemas
76
- for (const [key, value] of Object.entries(result)) {
77
- if (typeof value === "object" && value !== null) {
78
- if (Array.isArray(value)) {
79
- result[key] = value.map((item) => typeof item === "object" && item !== null
80
- ? reconstructJsonSchema(item)
81
- : item);
82
- }
83
- else {
84
- result[key] = reconstructJsonSchema(value);
85
- }
86
- }
87
- }
88
- return result;
89
- }
@@ -1,137 +0,0 @@
1
- import { parseSchema } from "../parsers/parseSchema.js";
2
- import { expandJsdocs } from "../utils/jsdocs.js";
3
- const orderDeclarations = (entries, dependencies) => {
4
- const valueByName = new Map(entries);
5
- const depGraph = new Map();
6
- for (const [from, set] of dependencies.entries()) {
7
- const onlyKnown = new Set();
8
- for (const dep of set) {
9
- if (valueByName.has(dep) && dep !== from) {
10
- onlyKnown.add(dep);
11
- }
12
- }
13
- if (onlyKnown.size)
14
- depGraph.set(from, onlyKnown);
15
- }
16
- const names = Array.from(valueByName.keys());
17
- for (const [name, value] of entries) {
18
- const deps = depGraph.get(name) ?? new Set();
19
- for (const candidate of names) {
20
- if (candidate === name)
21
- continue;
22
- const matcher = new RegExp(`\\b${candidate}\\b`);
23
- if (matcher.test(value)) {
24
- deps.add(candidate);
25
- }
26
- }
27
- if (deps.size)
28
- depGraph.set(name, deps);
29
- }
30
- const ordered = [];
31
- const perm = new Set();
32
- const temp = new Set();
33
- const visit = (name) => {
34
- if (perm.has(name))
35
- return;
36
- if (temp.has(name)) {
37
- temp.delete(name);
38
- perm.add(name);
39
- ordered.push(name);
40
- return;
41
- }
42
- temp.add(name);
43
- const deps = depGraph.get(name);
44
- if (deps) {
45
- for (const dep of deps) {
46
- if (valueByName.has(dep)) {
47
- visit(dep);
48
- }
49
- }
50
- }
51
- temp.delete(name);
52
- perm.add(name);
53
- ordered.push(name);
54
- };
55
- for (const name of valueByName.keys()) {
56
- visit(name);
57
- }
58
- const unique = [];
59
- const seen = new Set();
60
- for (const name of ordered) {
61
- if (!seen.has(name)) {
62
- seen.add(name);
63
- unique.push(name);
64
- }
65
- }
66
- return unique.map((name) => [name, valueByName.get(name)]);
67
- };
68
- export const emitZod = (analysis) => {
69
- const { schema, options, refNameByPointer, usedNames, cycleRefNames, cycleComponentByName, } = analysis;
70
- const { module, name, type, noImport, exportRefs, withMeta, ...rest } = options;
71
- const declarations = new Map();
72
- const dependencies = new Map();
73
- const parsedSchema = parseSchema(schema, {
74
- module,
75
- name,
76
- path: [],
77
- seen: new Map(),
78
- declarations,
79
- dependencies,
80
- inProgress: new Set(),
81
- refNameByPointer,
82
- usedNames,
83
- root: schema,
84
- currentSchemaName: name,
85
- cycleRefNames,
86
- cycleComponentByName,
87
- refRegistry: analysis.refRegistry,
88
- rootBaseUri: analysis.rootBaseUri,
89
- ...rest,
90
- withMeta,
91
- });
92
- const declarationBlock = declarations.size
93
- ? orderDeclarations(Array.from(declarations.entries()), dependencies)
94
- .map(([refName, value]) => {
95
- const shouldExport = exportRefs && module === "esm";
96
- const decl = `${shouldExport ? "export " : ""}const ${refName} = ${value}`;
97
- return decl;
98
- })
99
- .join("\n")
100
- : "";
101
- const jsdocs = rest.withJsdocs && typeof schema === "object" && schema !== null && "description" in schema
102
- ? expandJsdocs(String(schema.description ?? ""))
103
- : "";
104
- const lines = [];
105
- if (module === "cjs" && !noImport) {
106
- lines.push(`const { z } = require("zod")`);
107
- }
108
- if (module === "esm" && !noImport) {
109
- lines.push(`import { z } from "zod"`);
110
- }
111
- if (declarationBlock) {
112
- lines.push(declarationBlock);
113
- }
114
- if (module === "cjs") {
115
- const payload = name ? `{ ${JSON.stringify(name)}: ${parsedSchema} }` : parsedSchema;
116
- lines.push(`${jsdocs}module.exports = ${payload}`);
117
- }
118
- else if (module === "esm") {
119
- const exportLine = `${jsdocs}export ${name ? `const ${name} =` : `default`} ${parsedSchema}`;
120
- lines.push(exportLine);
121
- }
122
- else if (name) {
123
- lines.push(`${jsdocs}const ${name} = ${parsedSchema}`);
124
- }
125
- else {
126
- lines.push(`${jsdocs}${parsedSchema}`);
127
- }
128
- let typeLine;
129
- if (type && name) {
130
- const typeName = typeof type === "string" ? type : `${name[0].toUpperCase()}${name.substring(1)}`;
131
- typeLine = `export type ${typeName} = z.infer<typeof ${name}>`;
132
- }
133
- const joined = lines.filter(Boolean).join("\n\n");
134
- const combined = typeLine ? `${joined}\n${typeLine}` : joined;
135
- const shouldEndWithNewline = module === "esm" || module === "cjs";
136
- return `${combined}${shouldEndWithNewline ? "\n" : ""}`;
137
- };
@@ -1,6 +0,0 @@
1
- import { analyzeSchema } from "./core/analyzeSchema.js";
2
- import { emitZod } from "./core/emitZod.js";
3
- export const jsonSchemaToZod = (schema, options = {}) => {
4
- const analysis = analyzeSchema(schema, options);
5
- return emitZod(analysis);
6
- };
@@ -1 +0,0 @@
1
- {"type":"module"}
@@ -1,43 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- import { half } from "../utils/half.js";
3
- const originalIndexKey = "__originalIndex";
4
- const ensureOriginalIndex = (arr) => {
5
- const newArr = [];
6
- for (let i = 0; i < arr.length; i++) {
7
- const item = arr[i];
8
- if (typeof item === "boolean") {
9
- newArr.push(item ? { [originalIndexKey]: i } : { [originalIndexKey]: i, not: {} });
10
- }
11
- else if (typeof item === "object" &&
12
- item !== null &&
13
- originalIndexKey in item) {
14
- return arr;
15
- }
16
- else {
17
- newArr.push({ ...item, [originalIndexKey]: i });
18
- }
19
- }
20
- return newArr;
21
- };
22
- export function parseAllOf(schema, refs) {
23
- if (schema.allOf.length === 0) {
24
- return "z.never()";
25
- }
26
- else if (schema.allOf.length === 1) {
27
- const item = schema.allOf[0];
28
- return parseSchema(item, {
29
- ...refs,
30
- path: [
31
- ...refs.path,
32
- "allOf",
33
- item[originalIndexKey] ?? 0,
34
- ],
35
- });
36
- }
37
- else {
38
- const [left, right] = half(ensureOriginalIndex(schema.allOf));
39
- return `z.intersection(${parseAllOf({ allOf: left }, refs)}, ${parseAllOf({
40
- allOf: right,
41
- }, refs)})`;
42
- }
43
- }
@@ -1,14 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
- export const parseAnyOf = (schema, refs) => {
4
- return schema.anyOf.length
5
- ? schema.anyOf.length === 1
6
- ? parseSchema(schema.anyOf[0], {
7
- ...refs,
8
- path: [...refs.path, "anyOf", 0],
9
- })
10
- : `z.union([${schema.anyOf
11
- .map((schema, i) => parseSchema(schema, { ...refs, path: [...refs.path, "anyOf", i] }))
12
- .join(", ")}])`
13
- : anyOrUnknown(refs);
14
- };
@@ -1 +0,0 @@
1
- export const parseBoolean = () => "z.boolean()";
@@ -1,3 +0,0 @@
1
- export const parseConst = (schema) => {
2
- return `z.literal(${JSON.stringify(schema.const)})`;
3
- };
@@ -1,17 +0,0 @@
1
- export const parseEnum = (schema) => {
2
- if (schema.enum.length === 0) {
3
- return "z.never()";
4
- }
5
- else if (schema.enum.length === 1) {
6
- // union does not work when there is only one element
7
- return `z.literal(${JSON.stringify(schema.enum[0])})`;
8
- }
9
- else if (schema.enum.every((x) => typeof x === "string")) {
10
- return `z.enum([${schema.enum.map((x) => JSON.stringify(x))}])`;
11
- }
12
- else {
13
- return `z.union([${schema.enum
14
- .map((x) => `z.literal(${JSON.stringify(x)})`)
15
- .join(", ")}])`;
16
- }
17
- };
@@ -1,6 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- export const parseMultipleType = (schema, refs) => {
3
- return `z.union([${schema.type
4
- .map((type) => parseSchema({ ...schema, type }, { ...refs, withoutDefaults: true }))
5
- .join(", ")}])`;
6
- };
@@ -1,8 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
- export const parseNot = (schema, refs) => {
4
- return `${anyOrUnknown(refs)}.refine((value) => !${parseSchema(schema.not, {
5
- ...refs,
6
- path: [...refs.path, "not"],
7
- })}.safeParse(value).success, "Invalid input: Should NOT be valid against schema")`;
8
- };
@@ -1 +0,0 @@
1
- export const parseNull = () => "z.null()";
@@ -1,8 +0,0 @@
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
- return `${parseSchema(omit(schema, "nullable"), refs, true)}.nullable()`;
8
- };
@@ -1,49 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
- export const parseOneOf = (schema, refs) => {
4
- if (!schema.oneOf.length) {
5
- return anyOrUnknown(refs);
6
- }
7
- if (schema.oneOf.length === 1) {
8
- return parseSchema(schema.oneOf[0], {
9
- ...refs,
10
- path: [...refs.path, "oneOf", 0],
11
- });
12
- }
13
- // Generate parsed schemas for each oneOf option
14
- const parsedSchemas = schema.oneOf.map((s, i) => parseSchema(s, {
15
- ...refs,
16
- path: [...refs.path, "oneOf", i],
17
- }));
18
- // JSON Schema oneOf = exactly one must match (exclusive OR)
19
- // Zod union = at least one must match (inclusive OR)
20
- //
21
- // By default, use simple z.union() which provides "at least one must match".
22
- // This is more practical for most use cases, as strict oneOf enforcement
23
- // often fails when schemas have overlapping base types.
24
- //
25
- // If strictOneOf is enabled, add superRefine to enforce "exactly one" constraint.
26
- if (refs.strictOneOf) {
27
- return `z.union([${parsedSchemas.join(", ")}]).superRefine((x, ctx) => {
28
- const schemas = [${parsedSchemas.join(", ")}];
29
- const errors = schemas.reduce<z.ZodError[]>(
30
- (errors, schema) =>
31
- ((result) =>
32
- result.error ? [...errors, result.error] : errors)(
33
- schema.safeParse(x),
34
- ),
35
- [],
36
- );
37
- if (schemas.length - errors.length !== 1) {
38
- ctx.addIssue({
39
- path: [],
40
- code: "invalid_union",
41
- errors: errors.map(e => e.issues),
42
- message: "Invalid input: Should pass single schema",
43
- });
44
- }
45
- })`;
46
- }
47
- // Default: use simple z.union() (at least one must match)
48
- return `z.union([${parsedSchemas.join(", ")}])`;
49
- };
@@ -1,17 +0,0 @@
1
- import { parseSchema } from "./parseSchema.js";
2
- import { anyOrUnknown } from "../utils/anyOrUnknown.js";
3
- export const parseSimpleDiscriminatedOneOf = (schema, refs) => {
4
- const discriminator = schema.discriminator.propertyName;
5
- const options = schema.oneOf.map((option, i) => parseSchema(option, {
6
- ...refs,
7
- path: [...refs.path, "oneOf", i],
8
- }));
9
- return schema.oneOf.length
10
- ? schema.oneOf.length === 1
11
- ? parseSchema(schema.oneOf[0], {
12
- ...refs,
13
- path: [...refs.path, "oneOf", 0],
14
- })
15
- : `z.discriminatedUnion("${discriminator}", [${options.join(", ")}])`
16
- : anyOrUnknown(refs);
17
- };
@@ -1,10 +0,0 @@
1
- /**
2
- * Returns "z.unknown()" if the useUnknown option is enabled, otherwise "z.any()".
3
- * This helper is used throughout the library for fallback cases.
4
- *
5
- * @param refs - The refs object containing options
6
- * @returns The appropriate Zod schema string
7
- */
8
- export const anyOrUnknown = (refs) => {
9
- return refs?.useUnknown ? "z.unknown()" : "z.any()";
10
- };
package/jest.config.cjs DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- preset: "ts-jest",
3
- testEnvironment: "node",
4
- };
package/postcjs.cjs DELETED
@@ -1 +0,0 @@
1
- require("fs").writeFileSync("./dist/cjs/package.json", '{"type":"commonjs"}', "utf-8")
package/postesm.cjs DELETED
@@ -1 +0,0 @@
1
- require("fs").writeFileSync("./dist/esm/package.json", '{"type":"module"}', "utf-8")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes