Skip to content

Commit 56e11e4

Browse files
authored
Optimise Optional Determining Logic (#352)
1 parent c60ae06 commit 56e11e4

13 files changed

+359
-423
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ createDocument({
469469

470470
##### Zod Effects
471471

472-
`.transform()`, `.default()` and `.pipe()` are complicated because they technically comprise of two types (input & output). This means that we need to understand which type you are creating. In particular with transform it is very difficult to infer the output type. This library will automatically select which _type_ to use by checking how the schema is used based on the following rules:
472+
`.transform()`, `.catch()`, `.default()` and `.pipe()` are complicated because they technically comprise of two types (input & output). This means that we need to understand which type you are creating. In particular with transform it is very difficult to infer the output type. This library will automatically select which _type_ to use by checking how the schema is used based on the following rules:
473473

474474
_Input_: Request Bodies, Request Parameters, Headers
475475

@@ -694,6 +694,7 @@ For example in `z.string().nullable()` will be rendered differently
694694
- ZodBoolean
695695
- ZodBranded
696696
- ZodCatch
697+
- Treated as ZodDefault
697698
- ZodDate
698699
- `type` is mapped as `string` by default
699700
- ZodDefault

src/create/parameters.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import type {
1010
ZodOpenApiParameters,
1111
} from './document';
1212
import { type SchemaState, createSchema } from './schema';
13-
import { isOptionalSchema } from './schema/parsers/optional';
1413

1514
export const createComponentParamRef = (ref: string) =>
1615
`#/components/parameters/${ref}`;
@@ -30,7 +29,8 @@ export const createBaseParameter = (
3029
documentOptions,
3130
};
3231
const schemaObject = createSchema(schema, state, [...subpath, 'schema']);
33-
const required = !isOptionalSchema(schema, state)?.optional;
32+
const required = !schema.isOptional();
33+
3434
const description =
3535
schema._def.openapi?.description ?? schema._def.description;
3636

src/create/responses.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {
1414
ZodOpenApiResponsesObject,
1515
} from './document';
1616
import { type SchemaState, createSchema } from './schema';
17-
import { isOptionalSchema } from './schema/parsers/optional';
1817
import { isISpecificationExtension } from './specificationExtension';
1918

2019
export const createResponseHeaders = (
@@ -90,7 +89,9 @@ export const createBaseHeader = (
9089
documentOptions,
9190
};
9291
const schemaObject = createSchema(schema, state, ['header']);
93-
const required = !isOptionalSchema(schema, state)?.optional;
92+
const optionalResult = schema.safeParse(undefined);
93+
94+
const required = !optionalResult.success || optionalResult !== undefined;
9495
return {
9596
...rest,
9697
...(schema && { schema: schemaObject }),

src/create/schema/index.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ const expectedZodUnion: Schema['schema'] = {
191191
const zodCatch = z.string().catch('bob');
192192
const expectedZodCatch: Schema['schema'] = {
193193
type: 'string',
194+
default: 'bob',
194195
};
195196

196197
const zodPipeline = z

src/create/schema/parsers/catch.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import { createOutputState } from '../../../testing/state';
77
import { createCatchSchema } from './catch';
88

99
describe('createCatchSchema', () => {
10-
it('creates a simple string schema for a string with a catch', () => {
10+
it('creates a default string schema for a string with a catch', () => {
1111
const expected: Schema = {
1212
type: 'schema',
1313
schema: {
1414
type: 'string',
15+
default: 'bob',
1516
},
1617
};
1718
const schema = z.string().catch('bob');

src/create/schema/parsers/catch.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
import type { ZodCatch, ZodTypeAny } from 'zod';
22

3+
import type { oas31 } from '../../../../dist';
34
import {
45
type Schema,
56
type SchemaState,
67
createSchemaObject,
78
} from '../../schema';
9+
import { enhanceWithMetadata } from '../metadata';
810

911
export const createCatchSchema = <T extends ZodTypeAny>(
1012
zodCatch: ZodCatch<T>,
1113
state: SchemaState,
12-
): Schema => createSchemaObject(zodCatch._def.innerType, state, ['catch']);
14+
): Schema => {
15+
const schemaObject = createSchemaObject(zodCatch._def.innerType, state, [
16+
'default',
17+
]);
18+
19+
const catchResult = zodCatch.safeParse(undefined);
20+
21+
const maybeDefaultValue: Pick<oas31.SchemaObject, 'default'> | undefined =
22+
catchResult.success
23+
? {
24+
default: catchResult.data,
25+
}
26+
: undefined;
27+
28+
return enhanceWithMetadata(schemaObject, {
29+
...maybeDefaultValue,
30+
});
31+
};

src/create/schema/parsers/discriminatedUnion.test.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,22 @@ describe('createDiscriminatedUnionSchema', () => {
443443
});
444444

445445
it('handles a discriminated union with a catch type', () => {
446-
const expected: Schema = {
446+
const schema = z.discriminatedUnion('type', [
447+
z
448+
.object({
449+
type: z.literal('a').catch('a'),
450+
})
451+
.openapi({ ref: 'a' }),
452+
z
453+
.object({
454+
type: z.literal('b'),
455+
})
456+
.openapi({ ref: 'b' }),
457+
]);
458+
459+
const result = createDiscriminatedUnionSchema(schema, createOutputState());
460+
461+
expect(result).toEqual<Schema>({
447462
type: 'schema',
448463
schema: {
449464
discriminator: {
@@ -462,22 +477,13 @@ describe('createDiscriminatedUnionSchema', () => {
462477
},
463478
],
464479
},
465-
};
466-
const schema = z.discriminatedUnion('type', [
467-
z
468-
.object({
469-
type: z.literal('a').catch('a'),
470-
})
471-
.openapi({ ref: 'a' }),
472-
z
473-
.object({
474-
type: z.literal('b'),
475-
})
476-
.openapi({ ref: 'b' }),
477-
]);
478-
479-
const result = createDiscriminatedUnionSchema(schema, createOutputState());
480-
481-
expect(result).toEqual(expected);
480+
effects: [
481+
{
482+
type: 'component',
483+
path: ['discriminated union option 0'],
484+
zodType: schema.options[0],
485+
},
486+
],
487+
});
482488
});
483489
});

0 commit comments

Comments
 (0)