@gabrielbryk/json-schema-to-zod 2.15.0 → 2.16.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.
- package/CHANGELOG.md +40 -0
- package/dist/parsers/parseAllOf.js +6 -2
- package/dist/parsers/parseObject.js +6 -2
- package/dist/parsers/parseOneOf.js +8 -2
- package/dist/types/Types.d.ts +15 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @gabrielbryk/json-schema-to-zod
|
|
2
2
|
|
|
3
|
+
## 2.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 21d2701: Add `optionalStrategy` option to control whether optional object properties emit `.optional()` or `.exactOptional()`. Defaults to `"exactOptional"` (current behaviour) for full backward compatibility. Use `"optional"` when callers may produce `{ field: undefined }` via optional chaining or object spreads.
|
|
8
|
+
|
|
9
|
+
## 2.15.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 21b550f: Fix recursive oneOf with direct self-references using z.union instead of z.xor
|
|
14
|
+
|
|
15
|
+
When a recursive schema has a oneOf containing a direct self-reference (without z.lazy() wrapper),
|
|
16
|
+
the v2.15.0 fix to use z.union for recursive catchall cases didn't apply because the condition
|
|
17
|
+
`isRecursive && (inCatchall || hasLazyMembers)` didn't cover direct self-references.
|
|
18
|
+
|
|
19
|
+
This patch adds detection for direct self-references in oneOf options, ensuring z.union is used
|
|
20
|
+
instead of z.xor for these patterns. z.xor validation fails during parsing when evaluating
|
|
21
|
+
self-referential branches, so z.union is the correct choice.
|
|
22
|
+
|
|
23
|
+
This fixes validation failures for schemas like EventConsumptionStrategy from the Serverless
|
|
24
|
+
Workflow spec which uses: `oneOf: [simple-cases, allOf: [$ref: self, additional-properties]]`
|
|
25
|
+
|
|
26
|
+
## 2.15.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Fix recursive oneOf with direct self-references using z.union instead of z.xor
|
|
31
|
+
|
|
32
|
+
When a recursive schema has a oneOf containing a direct self-reference (without z.lazy() wrapper),
|
|
33
|
+
the v2.15.0 fix to use z.union for recursive catchall cases didn't apply because the condition
|
|
34
|
+
`isRecursive && (inCatchall || hasLazyMembers)` didn't cover direct self-references.
|
|
35
|
+
|
|
36
|
+
This patch adds detection for direct self-references in oneOf options, ensuring z.union is used
|
|
37
|
+
instead of z.xor for these patterns. z.xor validation fails during parsing when evaluating
|
|
38
|
+
self-referential branches, so z.union is the correct choice.
|
|
39
|
+
|
|
40
|
+
This fixes validation failures for schemas like EventConsumptionStrategy from the Serverless
|
|
41
|
+
Workflow spec which uses: `oneOf: [simple-cases, allOf: [$ref: self, additional-properties]]`
|
|
42
|
+
|
|
3
43
|
## 2.15.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseSchema } from "./parseSchema.js";
|
|
2
2
|
import { half } from "../utils/half.js";
|
|
3
|
-
import { shouldUseGetter, zodExactOptional, zodIntersection, zodLooseObject, zodNever, } from "../utils/schemaRepresentation.js";
|
|
3
|
+
import { shouldUseGetter, zodExactOptional, zodIntersection, zodLooseObject, zodNever, zodOptional, } from "../utils/schemaRepresentation.js";
|
|
4
4
|
const originalIndexKey = "__originalIndex";
|
|
5
5
|
/**
|
|
6
6
|
* Check if a schema defines object properties (inline object shape) without any refs.
|
|
@@ -34,7 +34,11 @@ const parseObjectShape = (schema, refs, pathPrefix) => {
|
|
|
34
34
|
? schema.required.includes(key)
|
|
35
35
|
: typeof propSchema === "object" && propSchema.required === true;
|
|
36
36
|
const optional = !hasDefault && !required;
|
|
37
|
-
const valueRep = optional
|
|
37
|
+
const valueRep = optional
|
|
38
|
+
? refs.optionalStrategy === "optional"
|
|
39
|
+
? zodOptional(parsedProp)
|
|
40
|
+
: zodExactOptional(parsedProp)
|
|
41
|
+
: parsedProp;
|
|
38
42
|
const isGetter = shouldUseGetter(valueRep, refs.currentSchemaName, refs.cycleRefNames, refs.cycleComponentByName);
|
|
39
43
|
shapeEntries.push({ key, rep: valueRep, isGetter });
|
|
40
44
|
}
|
|
@@ -5,7 +5,7 @@ import { expandJsdocs } from "../utils/jsdocs.js";
|
|
|
5
5
|
import { anyOrUnknown } from "../utils/anyOrUnknown.js";
|
|
6
6
|
import { buildIntersectionTree } from "../utils/buildIntersectionTree.js";
|
|
7
7
|
import { collectSchemaProperties } from "../utils/collectSchemaProperties.js";
|
|
8
|
-
import { shouldUseGetter, zodCatchall, zodChain, zodExactOptional, zodLooseObject, zodLooseRecord, zodStrictObject, zodString, zodSuperRefine, } from "../utils/schemaRepresentation.js";
|
|
8
|
+
import { shouldUseGetter, zodCatchall, zodChain, zodExactOptional, zodLooseObject, zodLooseRecord, zodOptional, zodStrictObject, zodString, zodSuperRefine, } from "../utils/schemaRepresentation.js";
|
|
9
9
|
export function parseObject(objectSchema, refs) {
|
|
10
10
|
const collectedProperties = objectSchema.allOf
|
|
11
11
|
? collectSchemaProperties(objectSchema, refs)
|
|
@@ -77,7 +77,11 @@ export function parseObject(objectSchema, refs) {
|
|
|
77
77
|
? true
|
|
78
78
|
: typeof propSchema === "object" && propSchema.required === true;
|
|
79
79
|
const isOptional = !hasDefault && !isRequired;
|
|
80
|
-
const valueRep = isOptional
|
|
80
|
+
const valueRep = isOptional
|
|
81
|
+
? refs.optionalStrategy === "optional"
|
|
82
|
+
? zodOptional(parsedProp)
|
|
83
|
+
: zodExactOptional(parsedProp)
|
|
84
|
+
: parsedProp;
|
|
81
85
|
const jsdoc = refs.withJsdocs &&
|
|
82
86
|
typeof propSchema === "object" &&
|
|
83
87
|
typeof propSchema.description === "string"
|
|
@@ -3,7 +3,7 @@ import { anyOrUnknown } from "../utils/anyOrUnknown.js";
|
|
|
3
3
|
import { resolveRef } from "../utils/resolveRef.js";
|
|
4
4
|
import { collectSchemaProperties } from "../utils/collectSchemaProperties.js";
|
|
5
5
|
import { wrapRecursiveUnion } from "../utils/wrapRecursiveUnion.js";
|
|
6
|
-
import { zodAny, zodDiscriminatedUnion, zodSuperRefine, zodUnion, zodXor, } from "../utils/schemaRepresentation.js";
|
|
6
|
+
import { collectRefNames, zodAny, zodDiscriminatedUnion, zodSuperRefine, zodUnion, zodXor, } from "../utils/schemaRepresentation.js";
|
|
7
7
|
/**
|
|
8
8
|
* Check if a schema is a "required-only" validation constraint.
|
|
9
9
|
* These are schemas that only specify `required` without defining types.
|
|
@@ -302,5 +302,11 @@ const shouldUseUnionForRecursiveOneOf = (refs, parsedSchemas) => {
|
|
|
302
302
|
const isRecursive = current ? (refs.cycleRefNames?.has(current) ?? false) : false;
|
|
303
303
|
const inCatchall = current ? (refs.catchallRefNames?.has(current) ?? false) : false;
|
|
304
304
|
const hasLazyMembers = parsedSchemas.some((rep) => rep.node?.kind === "lazy");
|
|
305
|
-
|
|
305
|
+
// Check if any option contains a direct self-reference (references the current schema).
|
|
306
|
+
// This handles cases where recursive schemas use direct references instead of z.lazy().
|
|
307
|
+
// Without z.lazy(), z.xor() validation fails on these self-referential branches.
|
|
308
|
+
const hasSelfReference = current
|
|
309
|
+
? parsedSchemas.some((rep) => rep.node && collectRefNames(rep.node).has(current))
|
|
310
|
+
: false;
|
|
311
|
+
return Boolean(isRecursive && (inCatchall || hasLazyMembers || hasSelfReference));
|
|
306
312
|
};
|
package/dist/types/Types.d.ts
CHANGED
|
@@ -290,6 +290,21 @@ export type Options = {
|
|
|
290
290
|
* or schema titles.
|
|
291
291
|
*/
|
|
292
292
|
oneOfOverrides?: Record<string, "union" | "xor">;
|
|
293
|
+
/**
|
|
294
|
+
* Controls which Zod modifier is used for optional object properties
|
|
295
|
+
* (those absent from `required` and without a `default`).
|
|
296
|
+
*
|
|
297
|
+
* - `"exactOptional"` (default): emits `.exactOptional()`.
|
|
298
|
+
* The key must be entirely absent at runtime; a present `undefined` fails.
|
|
299
|
+
* - `"optional"`: emits `.optional()`.
|
|
300
|
+
* The key may be present with `undefined` or absent entirely.
|
|
301
|
+
*
|
|
302
|
+
* Use `"optional"` when callers may include keys with `undefined` values,
|
|
303
|
+
* which is common when spreading objects or using optional chaining.
|
|
304
|
+
*
|
|
305
|
+
* @default "exactOptional"
|
|
306
|
+
*/
|
|
307
|
+
optionalStrategy?: "exactOptional" | "optional";
|
|
293
308
|
/**
|
|
294
309
|
* Wrap recursive union schemas in z.lazy() to improve TypeScript inference.
|
|
295
310
|
* This is useful for mutually recursive discriminated unions with optional properties.
|