Skip to content

Commit 29d2479

Browse files
Copilotmrlubos
andcommitted
Fix Zod schema union deduplication by including validation constraints in type ID
Co-authored-by: mrlubos <[email protected]>
1 parent e5b3a1e commit 29d2479

File tree

10 files changed

+108
-1
lines changed

10 files changed

+108
-1
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"openapi": "3.1.0",
3+
"info": {
4+
"title": "String Constraints Union Test",
5+
"version": "1.0.0"
6+
},
7+
"components": {
8+
"schemas": {
9+
"LocaleOrLanguage": {
10+
"anyOf": [
11+
{
12+
"type": "string",
13+
"minLength": 5,
14+
"maxLength": 5,
15+
"description": "Combination of ISO 639-1 and ISO 3166-1 alpha-2 separated by a hyphen."
16+
},
17+
{
18+
"type": "string",
19+
"minLength": 2,
20+
"maxLength": 2,
21+
"description": "ISO 639-1 language code."
22+
}
23+
]
24+
}
25+
}
26+
}
27+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import * as z from 'zod/v4-mini';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().check(z.length(5)),
7+
z.string().check(z.length(2))
8+
]);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import { z } from 'zod';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().length(5),
7+
z.string().length(2)
8+
]);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import { z } from 'zod/v4';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().length(5),
7+
z.string().length(2)
8+
]);

packages/openapi-ts-tests/zod/v3/test/3.1.x.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ for (const zodVersion of zodVersions) {
138138
description:
139139
"validator schemas with merged unions (can't use .merge())",
140140
},
141+
{
142+
config: createConfig({
143+
input: 'validators-string-constraints-union.json',
144+
output: 'validators-string-constraints-union',
145+
}),
146+
description: 'validator schemas with string constraints union',
147+
},
141148
];
142149

143150
it.each(scenarios)('$description', async ({ config }) => {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import * as z from 'zod/mini';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().check(z.length(5)),
7+
z.string().check(z.length(2))
8+
]);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import { z } from 'zod/v3';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().length(5),
7+
z.string().length(2)
8+
]);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import { z } from 'zod';
4+
5+
export const zLocaleOrLanguage = z.union([
6+
z.string().length(5),
7+
z.string().length(2)
8+
]);

packages/openapi-ts-tests/zod/v4/test/3.1.x.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ for (const zodVersion of zodVersions) {
138138
description:
139139
"validator schemas with merged unions (can't use .merge())",
140140
},
141+
{
142+
config: createConfig({
143+
input: 'validators-string-constraints-union.json',
144+
output: 'validators-string-constraints-union',
145+
}),
146+
description: 'validator schemas with string constraints union',
147+
},
141148
];
142149

143150
it.each(scenarios)('$description', async ({ config }) => {

packages/openapi-ts/src/ir/schema.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,25 @@ export const deduplicateSchema = <T extends IR.SchemaObject>({
4242
item.format !== undefined && detectFormat
4343
? `format-${item.format}`
4444
: '';
45-
const typeId = `${item.$ref ?? ''}${item.type ?? ''}${constant}${format}`;
45+
46+
// Include validation constraints in the type ID to avoid incorrect deduplication
47+
const constraints = [
48+
item.minLength !== undefined ? `minLength-${item.minLength}` : '',
49+
item.maxLength !== undefined ? `maxLength-${item.maxLength}` : '',
50+
item.minimum !== undefined ? `minimum-${item.minimum}` : '',
51+
item.maximum !== undefined ? `maximum-${item.maximum}` : '',
52+
item.exclusiveMinimum !== undefined
53+
? `exclusiveMinimum-${item.exclusiveMinimum}`
54+
: '',
55+
item.exclusiveMaximum !== undefined
56+
? `exclusiveMaximum-${item.exclusiveMaximum}`
57+
: '',
58+
item.minItems !== undefined ? `minItems-${item.minItems}` : '',
59+
item.maxItems !== undefined ? `maxItems-${item.maxItems}` : '',
60+
item.pattern !== undefined ? `pattern-${item.pattern}` : '',
61+
].join('');
62+
63+
const typeId = `${item.$ref ?? ''}${item.type ?? ''}${constant}${format}${constraints}`;
4664
if (!typeIds.includes(typeId)) {
4765
typeIds.push(typeId);
4866
uniqueItems.push(item);

0 commit comments

Comments
 (0)