Skip to content

Commit 7a1ad87

Browse files
authored
Merge pull request #3780 from hey-api/copilot/generate-discriminated-union-types
feat(zod,valibot): generate discriminated unions for oneOf/anyOf with discriminator mapping
2 parents 838c39b + 86c0795 commit 7a1ad87

55 files changed

Lines changed: 1554 additions & 259 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/hip-foxes-count.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hey-api/openapi-ts": patch
3+
---
4+
5+
**plugin(zod)**: add support for `.discriminatedUnion()`

.changeset/moody-wings-punch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hey-api/openapi-ts": patch
3+
---
4+
5+
**plugin(valibot)**: add support for `.variant()`
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import * as v from 'valibot';
4+
5+
export const vFoo = v.object({
6+
id: v.string()
7+
});
8+
9+
export const vBar = v.intersect([vFoo, v.object({
10+
bar: v.optional(v.string()),
11+
id: v.literal('Bar')
12+
})]);
13+
14+
export const vBaz = v.intersect([vFoo, v.object({
15+
baz: v.optional(v.string()),
16+
id: v.literal('Baz')
17+
})]);
18+
19+
export const vQux = v.intersect([vFoo, v.object({
20+
qux: v.optional(v.boolean()),
21+
id: v.literal('Qux')
22+
})]);
23+
24+
export const vFooMapped = v.object({
25+
id: v.string()
26+
});
27+
28+
export const vBarMapped = v.intersect([vFooMapped, v.object({
29+
bar: v.optional(v.string()),
30+
id: v.literal('bar')
31+
})]);
32+
33+
export const vBazMapped = v.intersect([vFooMapped, v.object({
34+
baz: v.optional(v.string()),
35+
id: v.literal('baz')
36+
})]);
37+
38+
export const vQuxMapped = v.intersect([vFooMapped, v.object({
39+
qux: v.optional(v.boolean()),
40+
id: v.literal('QuxMapped')
41+
})]);
42+
43+
export const vBarUnion = v.object({
44+
id: v.optional(v.string()),
45+
bar: v.optional(v.string())
46+
});
47+
48+
export const vBazUnion = v.object({
49+
id: v.optional(v.string()),
50+
baz: v.optional(v.string())
51+
});
52+
53+
export const vFooUnion = v.union([v.intersect([v.object({
54+
id: v.literal('bar')
55+
}), vBarUnion]), v.intersect([v.object({
56+
id: v.literal('baz')
57+
}), vBazUnion])]);
58+
59+
export const vQuxExtend = vFooUnion;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import * as v from 'valibot';
4+
5+
export const vQuux = v.picklist(['Bar', 'Baz']);
6+
7+
export const vQux = v.object({
8+
id: v.string(),
9+
type: vQuux
10+
});
11+
12+
export const vBaz = vQux;
13+
14+
export const vBar = vQux;
15+
16+
export const vFoo = v.union([v.intersect([v.object({
17+
type: v.optional(v.literal('Bar'))
18+
}), vBar]), v.intersect([v.object({
19+
type: v.optional(v.literal('Baz'))
20+
}), vBaz])]);
21+
22+
export const vSpæcial = vQux;
23+
24+
export const vQuuz = v.union([
25+
v.intersect([v.object({
26+
type: v.optional(v.literal('bar'))
27+
}), vBar]),
28+
v.intersect([v.object({
29+
type: v.optional(v.literal('baz'))
30+
}), vBaz]),
31+
v.intersect([v.object({
32+
type: v.optional(v.literal('non-ascii'))
33+
}), vSpæcial])
34+
]);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import * as v from 'valibot';
4+
5+
export const vQuux = v.picklist(['Bar', 'Baz']);
6+
7+
export const vQux = v.object({
8+
id: v.string(),
9+
type: vQuux
10+
});
11+
12+
export const vBaz = vQux;
13+
14+
export const vBar = vQux;
15+
16+
export const vFoo = v.union([v.intersect([v.object({
17+
type: v.literal('Bar')
18+
}), vBar]), v.intersect([v.object({
19+
type: v.literal('Baz')
20+
}), vBaz])]);
21+
22+
export const vSpæcial = vQux;
23+
24+
export const vQuuz = v.union([
25+
v.intersect([v.object({
26+
type: v.literal('bar')
27+
}), vBar]),
28+
v.intersect([v.object({
29+
type: v.literal('baz')
30+
}), vBaz]),
31+
v.intersect([v.object({
32+
type: v.literal('non-ascii')
33+
}), vSpæcial])
34+
]);

packages/openapi-ts-tests/valibot/v1/test/3.1.x.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,27 @@ describe(`OpenAPI ${version}`, () => {
130130
}),
131131
description: 'anyOf string and binary string',
132132
},
133+
{
134+
config: createConfig({
135+
input: 'discriminator-all-of.yaml',
136+
output: 'discriminator-all-of',
137+
}),
138+
description: 'generates discriminated union for oneOf with discriminator mapping',
139+
},
140+
{
141+
config: createConfig({
142+
input: 'discriminator-any-of.yaml',
143+
output: 'discriminator-any-of',
144+
}),
145+
description: 'generates discriminated union for anyOf with discriminator mapping',
146+
},
147+
{
148+
config: createConfig({
149+
input: 'discriminator-one-of.yaml',
150+
output: 'discriminator-one-of',
151+
}),
152+
description: 'generates discriminated union for oneOf discriminator mapping',
153+
},
133154
{
134155
config: createConfig({
135156
input: 'time-format.yaml',

packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/default/zod.gen.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,9 @@ export const zModelSquare = z.object({
423423
/**
424424
* This is a model with one property with a 'one of' relationship where the options are not $ref
425425
*/
426-
export const zCompositionWithOneOfDiscriminator = z.union([
427-
z.intersection(z.object({
428-
kind: z.literal('circle')
429-
}), zModelCircle),
430-
z.intersection(z.object({
431-
kind: z.literal('square')
432-
}), zModelSquare)
426+
export const zCompositionWithOneOfDiscriminator = z.discriminatedUnion('kind', [
427+
z.extend(zModelCircle, { kind: z.literal('circle') }),
428+
z.extend(zModelSquare, { kind: z.literal('square') })
433429
]);
434430

435431
/**

packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/default/zod.gen.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,9 @@ export const zModelSquare = z.object({
423423
/**
424424
* This is a model with one property with a 'one of' relationship where the options are not $ref
425425
*/
426-
export const zCompositionWithOneOfDiscriminator = z.union([
427-
z.object({
428-
kind: z.literal('circle')
429-
}).and(zModelCircle),
430-
z.object({
431-
kind: z.literal('square')
432-
}).and(zModelSquare)
426+
export const zCompositionWithOneOfDiscriminator = z.discriminatedUnion('kind', [
427+
zModelCircle.extend({ kind: z.literal('circle') }),
428+
zModelSquare.extend({ kind: z.literal('square') })
433429
]);
434430

435431
/**

packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/default/zod.gen.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,9 @@ export const zModelSquare = z.object({
423423
/**
424424
* This is a model with one property with a 'one of' relationship where the options are not $ref
425425
*/
426-
export const zCompositionWithOneOfDiscriminator = z.union([
427-
z.object({
428-
kind: z.literal('circle')
429-
}).and(zModelCircle),
430-
z.object({
431-
kind: z.literal('square')
432-
}).and(zModelSquare)
426+
export const zCompositionWithOneOfDiscriminator = z.discriminatedUnion('kind', [
427+
zModelCircle.extend({ kind: z.literal('circle') }),
428+
zModelSquare.extend({ kind: z.literal('square') })
433429
]);
434430

435431
/**

packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/default/zod.gen.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -423,13 +423,9 @@ export const zModelSquare = z.object({
423423
/**
424424
* This is a model with one property with a 'one of' relationship where the options are not $ref
425425
*/
426-
export const zCompositionWithOneOfDiscriminator = z.union([
427-
z.intersection(z.object({
428-
kind: z.literal('circle')
429-
}), zModelCircle),
430-
z.intersection(z.object({
431-
kind: z.literal('square')
432-
}), zModelSquare)
426+
export const zCompositionWithOneOfDiscriminator = z.discriminatedUnion('kind', [
427+
z.extend(zModelCircle, { kind: z.literal('circle') }),
428+
z.extend(zModelSquare, { kind: z.literal('square') })
433429
]);
434430

435431
/**

0 commit comments

Comments
 (0)