Skip to content

Commit

Permalink
Optimise Optional Determining Logic (#352)
Browse files Browse the repository at this point in the history
  • Loading branch information
samchungy authored Oct 30, 2024
1 parent c60ae06 commit 56e11e4
Show file tree
Hide file tree
Showing 13 changed files with 359 additions and 423 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ createDocument({

##### Zod Effects

`.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:
`.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:

_Input_: Request Bodies, Request Parameters, Headers

Expand Down Expand Up @@ -694,6 +694,7 @@ For example in `z.string().nullable()` will be rendered differently
- ZodBoolean
- ZodBranded
- ZodCatch
- Treated as ZodDefault
- ZodDate
- `type` is mapped as `string` by default
- ZodDefault
Expand Down
4 changes: 2 additions & 2 deletions src/create/parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type {
ZodOpenApiParameters,
} from './document';
import { type SchemaState, createSchema } from './schema';
import { isOptionalSchema } from './schema/parsers/optional';

export const createComponentParamRef = (ref: string) =>
`#/components/parameters/${ref}`;
Expand All @@ -30,7 +29,8 @@ export const createBaseParameter = (
documentOptions,
};
const schemaObject = createSchema(schema, state, [...subpath, 'schema']);
const required = !isOptionalSchema(schema, state)?.optional;
const required = !schema.isOptional();

const description =
schema._def.openapi?.description ?? schema._def.description;

Expand Down
5 changes: 3 additions & 2 deletions src/create/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {
ZodOpenApiResponsesObject,
} from './document';
import { type SchemaState, createSchema } from './schema';
import { isOptionalSchema } from './schema/parsers/optional';
import { isISpecificationExtension } from './specificationExtension';

export const createResponseHeaders = (
Expand Down Expand Up @@ -90,7 +89,9 @@ export const createBaseHeader = (
documentOptions,
};
const schemaObject = createSchema(schema, state, ['header']);
const required = !isOptionalSchema(schema, state)?.optional;
const optionalResult = schema.safeParse(undefined);

const required = !optionalResult.success || optionalResult !== undefined;
return {
...rest,
...(schema && { schema: schemaObject }),
Expand Down
1 change: 1 addition & 0 deletions src/create/schema/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ const expectedZodUnion: Schema['schema'] = {
const zodCatch = z.string().catch('bob');
const expectedZodCatch: Schema['schema'] = {
type: 'string',
default: 'bob',
};

const zodPipeline = z
Expand Down
3 changes: 2 additions & 1 deletion src/create/schema/parsers/catch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { createOutputState } from '../../../testing/state';
import { createCatchSchema } from './catch';

describe('createCatchSchema', () => {
it('creates a simple string schema for a string with a catch', () => {
it('creates a default string schema for a string with a catch', () => {
const expected: Schema = {
type: 'schema',
schema: {
type: 'string',
default: 'bob',
},
};
const schema = z.string().catch('bob');
Expand Down
21 changes: 20 additions & 1 deletion src/create/schema/parsers/catch.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
import type { ZodCatch, ZodTypeAny } from 'zod';

import type { oas31 } from '../../../../dist';
import {
type Schema,
type SchemaState,
createSchemaObject,
} from '../../schema';
import { enhanceWithMetadata } from '../metadata';

export const createCatchSchema = <T extends ZodTypeAny>(
zodCatch: ZodCatch<T>,
state: SchemaState,
): Schema => createSchemaObject(zodCatch._def.innerType, state, ['catch']);
): Schema => {
const schemaObject = createSchemaObject(zodCatch._def.innerType, state, [
'default',
]);

const catchResult = zodCatch.safeParse(undefined);

const maybeDefaultValue: Pick<oas31.SchemaObject, 'default'> | undefined =
catchResult.success
? {
default: catchResult.data,
}
: undefined;

return enhanceWithMetadata(schemaObject, {
...maybeDefaultValue,
});
};
42 changes: 24 additions & 18 deletions src/create/schema/parsers/discriminatedUnion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,22 @@ describe('createDiscriminatedUnionSchema', () => {
});

it('handles a discriminated union with a catch type', () => {
const expected: Schema = {
const schema = z.discriminatedUnion('type', [
z
.object({
type: z.literal('a').catch('a'),
})
.openapi({ ref: 'a' }),
z
.object({
type: z.literal('b'),
})
.openapi({ ref: 'b' }),
]);

const result = createDiscriminatedUnionSchema(schema, createOutputState());

expect(result).toEqual<Schema>({
type: 'schema',
schema: {
discriminator: {
Expand All @@ -462,22 +477,13 @@ describe('createDiscriminatedUnionSchema', () => {
},
],
},
};
const schema = z.discriminatedUnion('type', [
z
.object({
type: z.literal('a').catch('a'),
})
.openapi({ ref: 'a' }),
z
.object({
type: z.literal('b'),
})
.openapi({ ref: 'b' }),
]);

const result = createDiscriminatedUnionSchema(schema, createOutputState());

expect(result).toEqual(expected);
effects: [
{
type: 'component',
path: ['discriminated union option 0'],
zodType: schema.options[0],
},
],
});
});
});
Loading

0 comments on commit 56e11e4

Please sign in to comment.