@@ -8,68 +8,28 @@ import type { Chain } from './chain';
88import type { ZodResult } from './types' ;
99
1010/**
11- * Returns the discriminator key if all non-null items in the union follow the
12- * pattern produced by the OpenAPI discriminator parser:
13- * `{ logicalOperator: 'and', items: [discrimObj, ref] }`
14- * where `discrimObj` is an object with exactly one const-valued property.
15- *
16- * Returns `null` when the pattern is not recognised.
17- */
18- function detectDiscriminatorKey ( schemas : ReadonlyArray < IR . SchemaObject > ) : string | null {
19- let key : string | undefined ;
20-
21- for ( const schema of schemas ) {
22- if ( schema . type === 'null' || schema . const === null ) {
23- continue ;
24- }
25-
26- if ( schema . logicalOperator !== 'and' || ! schema . items || schema . items . length !== 2 ) {
27- return null ;
28- }
29-
30- const discrimPart = schema . items [ 0 ] ! ;
31-
32- if ( discrimPart . type !== 'object' || ! discrimPart . properties ) {
33- return null ;
34- }
35-
36- const props = Object . entries ( discrimPart . properties ) ;
37- if ( props . length !== 1 || props [ 0 ] ! [ 1 ] . const === undefined ) {
38- return null ;
39- }
40-
41- const propKey = props [ 0 ] ! [ 0 ] ;
42-
43- if ( key === undefined ) {
44- key = propKey ;
45- } else if ( key !== propKey ) {
46- // All items must share the same discriminator key
47- return null ;
48- }
49- }
50-
51- return key ?? null ;
52- }
53-
54- /**
55- * Attempts to build a `z.discriminatedUnion()` expression when all non-null
56- * union items follow the discriminator intersection pattern
57- * `{ discrimObject, ref }` produced by the OpenAPI discriminator parser.
11+ * Attempts to build a `z.discriminatedUnion()` expression when the parent
12+ * schema carries a `discriminator` set by the IR parser. Each non-null union
13+ * item is expected to follow the pattern
14+ * `{ logicalOperator: 'and', items: [discrimObj, ref] }`
15+ * produced by the OpenAPI discriminator parser.
5816 *
5917 * Returns the expression on success, or `null` to fall back to `z.union()`.
6018 */
6119export function tryBuildDiscriminatedUnion ( {
6220 ctx,
6321 items,
22+ parentSchema,
6423 schemas,
6524 z,
6625} : {
6726 ctx : SchemaVisitorContext < ZodPlugin [ 'Instance' ] > ;
6827 items : ReadonlyArray < ZodResult > ;
28+ parentSchema : IR . SchemaObject ;
6929 schemas : ReadonlyArray < IR . SchemaObject > ;
7030 z : ReturnType < typeof ctx . plugin . external > ;
7131} ) : Chain | null {
72- const discriminatorKey = detectDiscriminatorKey ( schemas ) ;
32+ const discriminatorKey = parentSchema . discriminator ?. propertyName ;
7333 if ( ! discriminatorKey ) {
7434 return null ;
7535 }
@@ -83,8 +43,16 @@ export function tryBuildDiscriminatedUnion({
8343 continue ;
8444 }
8545
86- const refPart = schema . items ! [ 1 ] ! ;
87- const discrimValue = schema . items ! [ 0 ] ! . properties ! [ discriminatorKey ] ! . const ;
46+ if ( schema . logicalOperator !== 'and' || ! schema . items || schema . items . length !== 2 ) {
47+ return null ;
48+ }
49+
50+ const refPart = schema . items [ 1 ] ! ;
51+ const discrimValue = schema . items [ 0 ] ! . properties ?. [ discriminatorKey ] ?. const ;
52+
53+ if ( discrimValue === undefined ) {
54+ return null ;
55+ }
8856
8957 // Lazy references can't be used in a discriminated union directly
9058 if ( items [ i ] ! . meta . hasLazy ) {
0 commit comments