diff --git a/.changeset/brown-ideas-matter.md b/.changeset/brown-ideas-matter.md new file mode 100644 index 000000000..5cb3ddfc1 --- /dev/null +++ b/.changeset/brown-ideas-matter.md @@ -0,0 +1,5 @@ +--- +"@hey-api/shared": patch +--- + +**internal**: export schema walker interfaces diff --git a/.changeset/clean-singers-stand.md b/.changeset/clean-singers-stand.md new file mode 100644 index 000000000..be7d11535 --- /dev/null +++ b/.changeset/clean-singers-stand.md @@ -0,0 +1,9 @@ +--- +"@hey-api/openapi-ts": minor +--- + +**plugin(valibot)**: remove `enum.nodes.nullable` resolver node + +### Removed resolver node + +Valibot plugin no longer exposes the `enum.nodes.nullable` node. It was refactored so that nullable values are handled outside of resolvers. diff --git a/.changeset/stale-falcons-raise.md b/.changeset/stale-falcons-raise.md new file mode 100644 index 000000000..69cbcf167 --- /dev/null +++ b/.changeset/stale-falcons-raise.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**plugin(valibot)**: use `.nullable()` and `.nullish()` methods diff --git a/docs/openapi-ts/migrating.md b/docs/openapi-ts/migrating.md index e12c4cfe4..e4483af66 100644 --- a/docs/openapi-ts/migrating.md +++ b/docs/openapi-ts/migrating.md @@ -7,6 +7,12 @@ description: Migrating to @hey-api/openapi-ts. While we try to avoid breaking changes, sometimes it's unavoidable in order to offer you the latest features. This page lists changes that require updates to your code. If you run into a problem with migration, please [open an issue](https://github.com/hey-api/openapi-ts/issues). +## v0.93.0 + +### Removed resolver node + +Valibot and Zod plugins no longer expose the `enum.nodes.nullable` node. Both plugins were refactored so that nullable values are handled outside of resolvers. + ## v0.92.0 ### Updated Symbol interface diff --git a/packages/openapi-python/src/plugins/pydantic/shared/export.ts b/packages/openapi-python/src/plugins/pydantic/shared/export.ts index 1271ef854..a565fcb58 100644 --- a/packages/openapi-python/src/plugins/pydantic/shared/export.ts +++ b/packages/openapi-python/src/plugins/pydantic/shared/export.ts @@ -1,25 +1,36 @@ -import type { Symbol } from '@hey-api/codegen-core'; -import type { IR } from '@hey-api/shared'; +import { applyNaming, pathToName } from '@hey-api/shared'; // import { createSchemaComment } from '../../../plugins/shared/utils/schema'; import { $ } from '../../../py-dsl'; +import type { ProcessorContext } from './processor'; // import { identifiers } from '../v2/constants'; // import { pipesToNode } from './pipes'; import type { Ast, IrSchemaToAstOptions } from './types'; export function exportAst({ - // ast, + meta, + naming, + namingAnchor, + path, plugin, - // schema, - // state, - symbol, -}: IrSchemaToAstOptions & { - ast: Ast; - schema: IR.SchemaObject; - symbol: Symbol; -}): void { - // const v = plugin.external('valibot.v'); - const classDef = $.class(symbol); + tags, +}: Pick & + ProcessorContext & { + ast: Ast; + }): void { + const name = pathToName(path, { anchor: namingAnchor }); + const symbol = plugin.symbol(applyNaming(name, naming), { + meta: { + category: 'schema', + path, + tags, + tool: 'pydantic', + ...meta, + }, + }); + + const baseModel = plugin.external('pydantic.BaseModel'); + const classDef = $.class(symbol).extends(baseModel); // .export() // .$if(plugin.config.comments && createSchemaComment(schema), (c, v) => c.doc(v)) // .$if(state.hasLazyExpression['~ref'], (c) => diff --git a/packages/openapi-python/src/plugins/pydantic/shared/processor.ts b/packages/openapi-python/src/plugins/pydantic/shared/processor.ts new file mode 100644 index 000000000..c1eba30cc --- /dev/null +++ b/packages/openapi-python/src/plugins/pydantic/shared/processor.ts @@ -0,0 +1,16 @@ +import type { + IR, + NamingConfig, + SchemaProcessorContext, + SchemaProcessorResult, +} from '@hey-api/shared'; + +import type { IrSchemaToAstOptions } from './types'; + +export type ProcessorContext = Pick & + SchemaProcessorContext & { + naming: NamingConfig; + schema: IR.SchemaObject; + }; + +export type ProcessorResult = SchemaProcessorResult; diff --git a/packages/openapi-python/src/plugins/pydantic/shared/types.ts b/packages/openapi-python/src/plugins/pydantic/shared/types.ts index 76afbb1be..e02bde635 100644 --- a/packages/openapi-python/src/plugins/pydantic/shared/types.ts +++ b/packages/openapi-python/src/plugins/pydantic/shared/types.ts @@ -3,6 +3,7 @@ import type { IR, SchemaExtractor } from '@hey-api/shared'; import type { $ } from '../../../py-dsl'; import type { PydanticPlugin } from '../types'; +import type { ProcessorContext } from './processor'; export type Ast = { /** @@ -32,7 +33,7 @@ export type IrSchemaToAstOptions = { /** The plugin instance. */ plugin: PydanticPlugin['Instance']; /** Optional schema extractor function. */ - schemaExtractor?: SchemaExtractor; + schemaExtractor?: SchemaExtractor; /** The plugin state references. */ state: Refs; }; diff --git a/packages/openapi-python/src/plugins/pydantic/v2/plugin.ts b/packages/openapi-python/src/plugins/pydantic/v2/plugin.ts index 617a2829c..4521d1332 100644 --- a/packages/openapi-python/src/plugins/pydantic/v2/plugin.ts +++ b/packages/openapi-python/src/plugins/pydantic/v2/plugin.ts @@ -1,12 +1,12 @@ import type { SymbolMeta } from '@hey-api/codegen-core'; -import { fromRef, ref, refs } from '@hey-api/codegen-core'; +import { fromRef, ref } from '@hey-api/codegen-core'; import type { IR, SchemaWithType } from '@hey-api/shared'; -import { applyNaming, deduplicateSchema, pathToJsonPointer, refToName } from '@hey-api/shared'; +import { deduplicateSchema, pathToJsonPointer } from '@hey-api/shared'; // import { $ } from '../../../py-dsl'; -import { exportAst } from '../shared/export'; -import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types'; +import type { Ast, IrSchemaToAstOptions } from '../shared/types'; import type { PydanticPlugin } from '../types'; +import { createProcessor } from './processor'; import { irSchemaWithTypeToAst } from './toAst'; export function irSchemaToAst({ @@ -25,7 +25,9 @@ export function irSchemaToAst({ resource: 'definition', resourceId: pathToJsonPointer(fromRef(state.path)), }, + naming: plugin.config.definitions, path: fromRef(state.path), + plugin, schema, }); if (extracted !== schema) schema = extracted; @@ -119,39 +121,6 @@ export function irSchemaToAst({ }; } -function handleComponent({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: IR.SchemaObject; -}): void { - const $ref = pathToJsonPointer(fromRef(state.path)); - const baseName = refToName($ref); - const symbol = plugin.symbol(applyNaming(baseName, plugin.config.definitions), { - meta: { - category: 'schema', - path: fromRef(state.path), - resource: 'definition', - resourceId: $ref, - tags: fromRef(state.tags), - tool: 'pydantic', - }, - }); - const ast = irSchemaToAst({ - plugin, - schema, - state, - }); - exportAst({ - ast, - plugin, - schema, - state, - symbol, - }); -} - export const handlerV2: PydanticPlugin['Handler'] = ({ plugin }) => { plugin.symbol('Any', { external: 'typing', @@ -202,36 +171,47 @@ export const handlerV2: PydanticPlugin['Handler'] = ({ plugin }) => { }, }); - plugin.forEach('operation', 'parameter', 'requestBody', 'schema', 'webhook', (event) => { - const state = refs({ - hasLazyExpression: false, - path: event._path, - tags: event.tags, - }); + const processor = createProcessor(plugin); + plugin.forEach('operation', 'parameter', 'requestBody', 'schema', 'webhook', (event) => { switch (event.type) { case 'parameter': - handleComponent({ - // baseName: event.name, + processor.process({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(event._path), + }, + naming: plugin.config.definitions, + path: event._path, plugin, schema: event.parameter.schema, - state, + tags: event.tags, }); break; case 'requestBody': - handleComponent({ - // baseName: event.name, + processor.process({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(event._path), + }, + naming: plugin.config.definitions, + path: event._path, plugin, schema: event.requestBody.schema, - state, + tags: event.tags, }); break; case 'schema': - handleComponent({ - // baseName: event.name, + processor.process({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(event._path), + }, + naming: plugin.config.definitions, + path: event._path, plugin, schema: event.schema, - state, + tags: event.tags, }); break; } diff --git a/packages/openapi-python/src/plugins/pydantic/v2/processor.ts b/packages/openapi-python/src/plugins/pydantic/v2/processor.ts new file mode 100644 index 000000000..17c795819 --- /dev/null +++ b/packages/openapi-python/src/plugins/pydantic/v2/processor.ts @@ -0,0 +1,58 @@ +import { refs } from '@hey-api/codegen-core'; +import type { IR } from '@hey-api/shared'; +import { createSchemaProcessor, pathToJsonPointer } from '@hey-api/shared'; + +import { exportAst } from '../shared/export'; +import type { ProcessorContext, ProcessorResult } from '../shared/processor'; +import type { PluginState } from '../shared/types'; +import type { PydanticPlugin } from '../types'; +import { irSchemaToAst } from './plugin'; + +export function createProcessor(plugin: PydanticPlugin['Instance']): ProcessorResult { + const processor = createSchemaProcessor(); + + const hooks = [plugin.config['~hooks']?.schemas, plugin.context.config.parser.hooks.schemas]; + + function extractor(ctx: ProcessorContext): IR.SchemaObject { + if (processor.hasEmitted(ctx.path)) { + return ctx.schema; + } + + for (const hook of hooks) { + const result = hook?.shouldExtract?.(ctx); + if (result) { + process({ + namingAnchor: processor.context.anchor, + tags: processor.context.tags, + ...ctx, + }); + return { $ref: pathToJsonPointer(ctx.path) }; + } + } + + return ctx.schema; + } + + function process(ctx: ProcessorContext): void { + if (!processor.markEmitted(ctx.path)) return; + + processor.withContext({ anchor: ctx.namingAnchor, tags: ctx.tags }, () => { + const state = refs({ + hasLazyExpression: false, + path: ctx.path, + tags: ctx.tags, + }); + + const ast = irSchemaToAst({ + plugin, + schema: ctx.schema, + schemaExtractor: extractor, + state, + }); + + exportAst({ ...ctx, ast, plugin, state }); + }); + } + + return { process }; +} diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/valibot/default/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/valibot/default/valibot.gen.ts index 167326e71..ec15aab7a 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/valibot/default/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/valibot/default/valibot.gen.ts @@ -197,8 +197,8 @@ export const vModelWithStringError = v.object({ * This is a model with one string property */ export const vModelWithNullableString = v.object({ - nullableProp: v.optional(v.union([v.string(), v.null()])), - nullableRequiredProp: v.union([v.string(), v.null()]) + nullableProp: v.nullish(v.string()), + nullableRequiredProp: v.nullable(v.string()) }); /** @@ -581,8 +581,8 @@ export const vCallToTestOrderOfParamsData = v.object({ parameterStringWithDefault: v.optional(v.string(), 'Hello World!'), parameterStringWithEmptyDefault: v.optional(v.string(), ''), parameterStringWithNoDefault: v.string(), - parameterStringNullableWithNoDefault: v.optional(v.union([v.string(), v.null()])), - parameterStringNullableWithDefault: v.optional(v.union([v.string(), v.null()]), null) + parameterStringNullableWithNoDefault: v.nullish(v.string()), + parameterStringNullableWithDefault: v.nullish(v.string(), null) }) }); diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/valibot/default/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/valibot/default/valibot.gen.ts index d1a8d2901..ab74b0696 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/valibot/default/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/valibot/default/valibot.gen.ts @@ -81,7 +81,7 @@ export const vSimpleFile = v.string(); /** * This is a simple string */ -export const vSimpleStringWithPattern = v.union([v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.null()]); +export const vSimpleStringWithPattern = v.nullable(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -243,10 +243,10 @@ export const vModelFromZendesk = v.string(); * This is a model with one string property */ export const vModelWithNullableString = v.object({ - nullableProp1: v.optional(v.union([v.string(), v.null()])), - nullableRequiredProp1: v.union([v.string(), v.null()]), - nullableProp2: v.optional(v.union([v.string(), v.null()])), - nullableRequiredProp2: v.union([v.string(), v.null()]), + nullableProp1: v.nullish(v.string()), + nullableRequiredProp1: v.nullable(v.string()), + nullableProp2: v.nullish(v.string()), + nullableRequiredProp2: v.nullable(v.string()), 'foo_bar-enum': v.optional(v.picklist([ 'Success', 'Warning', @@ -425,7 +425,7 @@ export const vCompositionWithAnyOfAnonymous = v.object({ * This is a model with nested 'any of' property with a type null */ export const vCompositionWithNestedAnyAndTypeNull = v.object({ - propA: v.optional(v.union([v.array(v.union([vModelWithDictionary, v.null()])), v.array(v.union([vModelWithArray, v.null()]))])) + propA: v.optional(v.union([v.array(v.nullable(vModelWithDictionary)), v.array(v.nullable(vModelWithArray))])) }); export const v3eNum1Период = v.picklist(['Bird', 'Dog']); @@ -436,21 +436,20 @@ export const vConstValue = v.picklist(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const vCompositionWithNestedAnyOfAndNull = v.object({ - propA: v.optional(v.union([v.array(v.unknown()), v.null()])) + propA: v.nullish(v.array(v.unknown())) }); /** * This is a model with one property with a 'one of' relationship */ export const vCompositionWithOneOfAndNullable = v.object({ - propA: v.optional(v.union([ + propA: v.nullish(v.union([ v.object({ boolean: v.optional(v.boolean()) }), vModelWithEnum, vModelWithArray, - vModelWithDictionary, - v.null() + vModelWithDictionary ])) }); @@ -479,28 +478,27 @@ export const vCompositionWithOneOfAndComplexArrayDictionary = v.object({ * This is a model with one property with a 'all of' relationship */ export const vCompositionWithAllOfAndNullable = v.object({ - propA: v.optional(v.union([v.intersect([ - v.object({ - boolean: v.optional(v.boolean()) - }), - vModelWithEnum, - vModelWithArray, - vModelWithDictionary - ]), v.null()])) + propA: v.nullish(v.intersect([ + v.object({ + boolean: v.optional(v.boolean()) + }), + vModelWithEnum, + vModelWithArray, + vModelWithDictionary + ])) }); /** * This is a model with one property with a 'any of' relationship */ export const vCompositionWithAnyOfAndNullable = v.object({ - propA: v.optional(v.union([ + propA: v.nullish(v.union([ v.object({ boolean: v.optional(v.boolean()) }), vModelWithEnum, vModelWithArray, - vModelWithDictionary, - v.null() + vModelWithDictionary ])) }); @@ -527,7 +525,7 @@ export const vCompositionExtendedModel = v.intersect([vCompositionBaseModel, v.o export const vModelWithProperties = v.object({ required: v.string(), requiredAndReadOnly: v.pipe(v.string(), v.readonly()), - requiredAndNullable: v.union([v.string(), v.null()]), + requiredAndNullable: v.nullable(v.string()), string: v.optional(v.string()), number: v.optional(v.number()), boolean: v.optional(v.boolean()), @@ -550,11 +548,11 @@ export const vModelWithReference = v.object({ * This is a model with one nested property */ export const vModelWithNestedProperties = v.object({ - first: v.pipe(v.union([v.pipe(v.object({ - second: v.pipe(v.union([v.pipe(v.object({ - third: v.pipe(v.union([v.pipe(v.string(), v.readonly()), v.null()]), v.readonly()) - }), v.readonly()), v.null()]), v.readonly()) - }), v.readonly()), v.null()]), v.readonly()) + first: v.nullable(v.pipe(v.object({ + second: v.nullable(v.pipe(v.object({ + third: v.nullable(v.pipe(v.string(), v.readonly())) + }), v.readonly())) + }), v.readonly())) }); /** @@ -665,15 +663,15 @@ export const vModelWithAdditionalPropertiesEqTrue = v.objectWithRest({ }, v.unknown()); export const vNestedAnyOfArraysNullable = v.object({ - nullableArray: v.optional(v.union([v.array(v.unknown()), v.null()])) + nullableArray: v.nullish(v.array(v.unknown())) }); /** * An object that can be null */ -export const vNullableObject = v.optional(v.union([v.object({ - foo: v.optional(v.string()) - }), v.null()]), null); +export const vNullableObject = v.nullish(v.object({ + foo: v.optional(v.string()) +}), null); /** * Some % character @@ -747,21 +745,9 @@ export const vModelWithAnyOfConstantSizeArray = v.tuple([ export const vModelWithPrefixItemsConstantSizeArray = v.array(v.unknown()); export const vModelWithAnyOfConstantSizeArrayNullable = v.tuple([ - v.union([ - v.number(), - v.null(), - v.string() - ]), - v.union([ - v.number(), - v.null(), - v.string() - ]), - v.union([ - v.number(), - v.null(), - v.string() - ]) + v.nullable(v.union([v.number(), v.string()])), + v.nullable(v.union([v.number(), v.string()])), + v.nullable(v.union([v.number(), v.string()])) ]); export const vModelWithAnyOfConstantSizeArrayAndIntersect = v.tuple([v.intersect([v.number(), v.string()]), v.intersect([v.number(), v.string()])]); @@ -860,14 +846,14 @@ export const vAdditionalPropertiesIntegerIssue = v.objectWithRest({ export const vGenericSchemaDuplicateIssue1SystemBoolean = v.strictObject({ item: v.optional(v.boolean()), - error: v.optional(v.union([v.string(), v.null()])), + error: v.nullish(v.string()), hasError: v.optional(v.pipe(v.boolean(), v.readonly())), data: v.optional(v.strictObject({})) }); export const vGenericSchemaDuplicateIssue1SystemString = v.strictObject({ - item: v.optional(v.union([v.string(), v.null()])), - error: v.optional(v.union([v.string(), v.null()])), + item: v.nullish(v.string()), + error: v.nullish(v.string()), hasError: v.optional(v.pipe(v.boolean(), v.readonly())) }); @@ -887,7 +873,7 @@ export const vExternalRefB = vExternalSharedExternalSharedModel; */ export const vModelWithPropertiesWritable = v.object({ required: v.string(), - requiredAndNullable: v.union([v.string(), v.null()]), + requiredAndNullable: v.nullable(v.string()), string: v.optional(v.string()), number: v.optional(v.number()), boolean: v.optional(v.boolean()), @@ -943,13 +929,13 @@ export const vOneOfAllOfIssueWritable = v.union([v.intersect([v.union([vConstVal export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.strictObject({ item: v.optional(v.boolean()), - error: v.optional(v.union([v.string(), v.null()])), + error: v.nullish(v.string()), data: v.optional(v.strictObject({})) }); export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.strictObject({ - item: v.optional(v.union([v.string(), v.null()])), - error: v.optional(v.union([v.string(), v.null()])) + item: v.nullish(v.string()), + error: v.nullish(v.string()) }); /** @@ -962,12 +948,12 @@ export const vCompositionWithOneOfAndProperties = v.intersect([v.union([v.strict }), v.strictObject({ bar: vNonAsciiStringæøåÆøÅöôêÊ字符串 })]), v.object({ - baz: v.union([v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535')), v.null()]), + baz: v.nullable(v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535'))), qux: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(255, 'Invalid value: Expected uint8 to be <= 255')) })]); export const vModelWithOneOfAndProperties = v.intersect([v.union([vSimpleParameter, vNonAsciiStringæøåÆøÅöôêÊ字符串]), v.object({ - baz: v.union([v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535')), v.null()]), + baz: v.nullable(v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535'))), qux: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(255, 'Invalid value: Expected uint8 to be <= 255')) })]); @@ -1102,40 +1088,40 @@ export const vDeprecatedCallData = v.object({ path: v.optional(v.never()), query: v.optional(v.never()), headers: v.object({ - parameter: v.union([vDeprecatedModel, v.null()]) + parameter: v.nullable(vDeprecatedModel) }) }); export const vCallWithParametersData = v.object({ - body: v.union([v.record(v.string(), v.unknown()), v.null()]), + body: v.nullable(v.record(v.string(), v.unknown())), path: v.object({ - parameterPath: v.union([v.string(), v.null()]), - 'api-version': v.union([v.string(), v.null()]) + parameterPath: v.nullable(v.string()), + 'api-version': v.nullable(v.string()) }), query: v.object({ foo_ref_enum: v.optional(vModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: vModelWithNestedArrayEnumsDataFoo, - cursor: v.union([v.string(), v.null()]) + cursor: v.nullable(v.string()) }), headers: v.object({ - parameterHeader: v.union([v.string(), v.null()]) + parameterHeader: v.nullable(v.string()) }) }); export const vCallWithWeirdParameterNamesData = v.object({ - body: v.union([vModelWithString, v.null()]), + body: v.nullable(vModelWithString), path: v.object({ 'parameter.path.1': v.optional(v.string()), 'parameter-path-2': v.optional(v.string()), 'PARAMETER-PATH-3': v.optional(v.string()), - 'api-version': v.union([v.string(), v.null()]) + 'api-version': v.nullable(v.string()) }), query: v.object({ default: v.optional(v.string()), - 'parameter-query': v.union([v.string(), v.null()]) + 'parameter-query': v.nullable(v.string()) }), headers: v.object({ - 'parameter.header': v.union([v.string(), v.null()]) + 'parameter.header': v.nullable(v.string()) }) }); @@ -1149,7 +1135,7 @@ export const vGetCallWithOptionalParamData = v.object({ export const vPostCallWithOptionalParamData = v.object({ body: v.optional(v.object({ - offset: v.optional(v.union([v.number(), v.null()])) + offset: v.nullish(v.number()) })), path: v.optional(v.never()), query: v.object({ @@ -1179,15 +1165,15 @@ export const vCallWithDefaultParametersData = v.object({ body: v.optional(v.never()), path: v.optional(v.never()), query: v.optional(v.object({ - parameterString: v.optional(v.union([v.optional(v.string(), 'Hello World!'), v.null()]), 'Hello World!'), - parameterNumber: v.optional(v.union([v.optional(v.number(), 123), v.null()]), 123), - parameterBoolean: v.optional(v.union([v.optional(v.boolean(), true), v.null()]), true), + parameterString: v.nullish(v.string(), 'Hello World!'), + parameterNumber: v.nullish(v.number(), 123), + parameterBoolean: v.nullish(v.boolean(), true), parameterEnum: v.optional(v.picklist([ 'Success', 'Warning', 'Error' ])), - parameterModel: v.optional(v.union([vModelWithString, v.null()])) + parameterModel: v.nullish(vModelWithString) })) }); @@ -1217,8 +1203,8 @@ export const vCallToTestOrderOfParamsData = v.object({ parameterStringWithDefault: v.optional(v.string(), 'Hello World!'), parameterStringWithEmptyDefault: v.optional(v.string(), ''), parameterStringWithNoDefault: v.string(), - parameterStringNullableWithNoDefault: v.optional(v.union([v.string(), v.null()])), - parameterStringNullableWithDefault: v.optional(v.union([v.string(), v.null()]), null) + parameterStringNullableWithNoDefault: v.nullish(v.string()), + parameterStringNullableWithDefault: v.nullish(v.string(), null) }) }); @@ -1320,11 +1306,11 @@ export const vCollectionFormatData = v.object({ body: v.optional(v.never()), path: v.optional(v.never()), query: v.object({ - parameterArrayCSV: v.union([v.array(v.string()), v.null()]), - parameterArraySSV: v.union([v.array(v.string()), v.null()]), - parameterArrayTSV: v.union([v.array(v.string()), v.null()]), - parameterArrayPipes: v.union([v.array(v.string()), v.null()]), - parameterArrayMulti: v.union([v.array(v.string()), v.null()]) + parameterArrayCSV: v.nullable(v.array(v.string())), + parameterArraySSV: v.nullable(v.array(v.string())), + parameterArrayTSV: v.nullable(v.array(v.string())), + parameterArrayPipes: v.nullable(v.array(v.string())), + parameterArrayMulti: v.nullable(v.array(v.string())) }) }); @@ -1335,11 +1321,11 @@ export const vTypesData = v.object({ })), query: v.object({ parameterNumber: v.optional(v.number(), 123), - parameterString: v.optional(v.union([v.optional(v.string(), 'default'), v.null()]), 'default'), - parameterBoolean: v.optional(v.union([v.optional(v.boolean(), true), v.null()]), true), - parameterObject: v.optional(v.union([v.record(v.string(), v.unknown()), v.null()]), null), - parameterArray: v.union([v.array(v.string()), v.null()]), - parameterDictionary: v.union([v.record(v.string(), v.unknown()), v.null()]), + parameterString: v.nullish(v.string(), 'default'), + parameterBoolean: v.nullish(v.boolean(), true), + parameterObject: v.nullish(v.record(v.string(), v.unknown()), null), + parameterArray: v.nullable(v.array(v.string())), + parameterDictionary: v.nullable(v.record(v.string(), v.unknown())), parameterEnum: v.picklist([ 'Success', 'Warning', @@ -1358,7 +1344,7 @@ export const vTypesResponse = v.union([ export const vUploadFileData = v.object({ body: v.string(), path: v.object({ - 'api-version': v.union([v.string(), v.null()]) + 'api-version': v.nullable(v.string()) }), query: v.optional(v.never()) }); @@ -1419,7 +1405,7 @@ export const vMultipartResponseResponse = v.object({ export const vMultipartRequestData = v.object({ body: v.optional(v.object({ content: v.optional(v.string()), - data: v.optional(v.union([vModelWithString, v.null()])) + data: v.nullish(vModelWithString) })), path: v.optional(v.never()), query: v.optional(v.never()) @@ -1427,16 +1413,16 @@ export const vMultipartRequestData = v.object({ export const vComplexParamsData = v.object({ body: v.optional(v.object({ - key: v.pipe(v.union([v.pipe(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.readonly()), v.null()]), v.readonly()), - name: v.union([v.pipe(v.string(), v.maxLength(255)), v.null()]), + key: v.nullable(v.pipe(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.readonly())), + name: v.nullable(v.pipe(v.string(), v.maxLength(255))), enabled: v.optional(v.boolean(), true), type: v.picklist([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: v.optional(v.union([v.array(vModelWithString), v.null()])), - listOfStrings: v.optional(v.union([v.array(v.string()), v.null()])), + listOfModels: v.nullish(v.array(vModelWithString)), + listOfStrings: v.nullish(v.array(v.string())), parameters: v.union([ vModelWithString, vModelWithEnum, @@ -1445,7 +1431,7 @@ export const vComplexParamsData = v.object({ ]), user: v.optional(v.pipe(v.object({ id: v.optional(v.pipe(v.pipe(v.number(), v.integer(), v.minValue(-2147483648, 'Invalid value: Expected int32 to be >= -2147483648'), v.maxValue(2147483647, 'Invalid value: Expected int32 to be <= 2147483647')), v.readonly())), - name: v.optional(v.pipe(v.union([v.pipe(v.string(), v.readonly()), v.null()]), v.readonly())) + name: v.nullish(v.pipe(v.string(), v.readonly())) }), v.readonly())) })), path: v.object({ diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/validators/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/validators/valibot.gen.ts index 8a3624bb4..ca775cb85 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/validators/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/validators/valibot.gen.ts @@ -4,12 +4,12 @@ import * as v from 'valibot'; export const vBaz = v.optional(v.pipe(v.pipe(v.string(), v.regex(/foo\nbar/)), v.readonly()), 'baz'); -export const vFoo: v.GenericSchema = v.optional(v.union([v.object({ - foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), - bar: v.optional(v.lazy(() => vBar)), - baz: v.optional(v.array(v.lazy(() => vFoo))), - qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) - }), v.null()]), null); +export const vFoo: v.GenericSchema = v.nullish(v.object({ + foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: v.optional(v.lazy(() => vBar)), + baz: v.optional(v.array(v.lazy(() => vFoo))), + qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) +}), null); export const vBar = v.object({ foo: v.optional(vFoo) diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/valibot/default/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/valibot/default/valibot.gen.ts index 3b438ee78..3e9fb90d6 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/valibot/default/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/valibot/default/valibot.gen.ts @@ -81,7 +81,7 @@ export const vSimpleFile = v.string(); /** * This is a simple string */ -export const vSimpleStringWithPattern = v.union([v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.null()]); +export const vSimpleStringWithPattern = v.nullable(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -148,7 +148,7 @@ export const vArrayWithProperties = v.array(v.object({ export const vArrayWithAnyOfProperties = v.array(v.unknown()); export const vAnyOfAnyAndNull = v.object({ - data: v.optional(v.union([v.unknown(), v.null()])) + data: v.nullish(v.unknown()) }); /** @@ -243,10 +243,10 @@ export const vModelFromZendesk = v.string(); * This is a model with one string property */ export const vModelWithNullableString = v.object({ - nullableProp1: v.optional(v.union([v.string(), v.null()])), - nullableRequiredProp1: v.union([v.string(), v.null()]), - nullableProp2: v.optional(v.union([v.string(), v.null()])), - nullableRequiredProp2: v.union([v.string(), v.null()]), + nullableProp1: v.nullish(v.string()), + nullableRequiredProp1: v.nullable(v.string()), + nullableProp2: v.nullish(v.string()), + nullableRequiredProp2: v.nullable(v.string()), 'foo_bar-enum': v.optional(v.picklist([ 'Success', 'Warning', @@ -436,21 +436,20 @@ export const vConstValue = v.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const vCompositionWithNestedAnyOfAndNull = v.object({ - propA: v.optional(v.union([v.array(v.unknown()), v.null()])) + propA: v.nullish(v.array(v.unknown())) }); /** * This is a model with one property with a 'one of' relationship */ export const vCompositionWithOneOfAndNullable = v.object({ - propA: v.optional(v.union([ + propA: v.nullish(v.union([ v.object({ boolean: v.optional(v.boolean()) }), vModelWithEnum, vModelWithArray, - vModelWithDictionary, - v.null() + vModelWithDictionary ])) }); @@ -479,28 +478,27 @@ export const vCompositionWithOneOfAndComplexArrayDictionary = v.object({ * This is a model with one property with a 'all of' relationship */ export const vCompositionWithAllOfAndNullable = v.object({ - propA: v.optional(v.union([v.intersect([ - v.object({ - boolean: v.optional(v.boolean()) - }), - vModelWithEnum, - vModelWithArray, - vModelWithDictionary - ]), v.null()])) + propA: v.nullish(v.intersect([ + v.object({ + boolean: v.optional(v.boolean()) + }), + vModelWithEnum, + vModelWithArray, + vModelWithDictionary + ])) }); /** * This is a model with one property with a 'any of' relationship */ export const vCompositionWithAnyOfAndNullable = v.object({ - propA: v.optional(v.union([ + propA: v.nullish(v.union([ v.object({ boolean: v.optional(v.boolean()) }), vModelWithEnum, vModelWithArray, - vModelWithDictionary, - v.null() + vModelWithDictionary ])) }); @@ -527,7 +525,7 @@ export const vCompositionExtendedModel = v.intersect([vCompositionBaseModel, v.o export const vModelWithProperties = v.object({ required: v.string(), requiredAndReadOnly: v.pipe(v.string(), v.readonly()), - requiredAndNullable: v.union([v.string(), v.null()]), + requiredAndNullable: v.nullable(v.string()), string: v.optional(v.string()), number: v.optional(v.number()), boolean: v.optional(v.boolean()), @@ -550,11 +548,11 @@ export const vModelWithReference = v.object({ * This is a model with one nested property */ export const vModelWithNestedProperties = v.object({ - first: v.pipe(v.union([v.pipe(v.object({ - second: v.pipe(v.union([v.pipe(v.object({ - third: v.pipe(v.union([v.pipe(v.string(), v.readonly()), v.null()]), v.readonly()) - }), v.readonly()), v.null()]), v.readonly()) - }), v.readonly()), v.null()]), v.readonly()) + first: v.nullable(v.pipe(v.object({ + second: v.nullable(v.pipe(v.object({ + third: v.nullable(v.pipe(v.string(), v.readonly())) + }), v.readonly())) + }), v.readonly())) }); /** @@ -665,15 +663,15 @@ export const vModelWithAdditionalPropertiesEqTrue = v.objectWithRest({ }, v.unknown()); export const vNestedAnyOfArraysNullable = v.object({ - nullableArray: v.optional(v.union([v.array(v.unknown()), v.null()])) + nullableArray: v.nullish(v.array(v.unknown())) }); /** * An object that can be null */ -export const vNullableObject = v.optional(v.union([v.object({ - foo: v.optional(v.string()) - }), v.null()]), null); +export const vNullableObject = v.nullish(v.object({ + foo: v.optional(v.string()) +}), null); /** * Some % character @@ -751,21 +749,9 @@ export const vModelWithPrefixItemsConstantSizeArray = v.tuple([ ]); export const vModelWithAnyOfConstantSizeArrayNullable = v.tuple([ - v.union([ - v.number(), - v.null(), - v.string() - ]), - v.union([ - v.number(), - v.null(), - v.string() - ]), - v.union([ - v.number(), - v.null(), - v.string() - ]) + v.nullable(v.union([v.number(), v.string()])), + v.nullable(v.union([v.number(), v.string()])), + v.nullable(v.union([v.number(), v.string()])) ]); export const vModelWithAnyOfConstantSizeArrayAndIntersect = v.tuple([v.intersect([v.number(), v.string()]), v.intersect([v.number(), v.string()])]); @@ -864,14 +850,14 @@ export const vAdditionalPropertiesIntegerIssue = v.objectWithRest({ export const vGenericSchemaDuplicateIssue1SystemBoolean = v.strictObject({ item: v.optional(v.boolean()), - error: v.optional(v.union([v.string(), v.null()])), + error: v.nullish(v.string()), hasError: v.optional(v.pipe(v.boolean(), v.readonly())), data: v.optional(v.strictObject({})) }); export const vGenericSchemaDuplicateIssue1SystemString = v.strictObject({ - item: v.optional(v.union([v.string(), v.null()])), - error: v.optional(v.union([v.string(), v.null()])), + item: v.nullish(v.string()), + error: v.nullish(v.string()), hasError: v.optional(v.pipe(v.boolean(), v.readonly())) }); @@ -897,7 +883,7 @@ export const vExternalRefB = vExternalSharedExternalSharedModel; */ export const vModelWithPropertiesWritable = v.object({ required: v.string(), - requiredAndNullable: v.union([v.string(), v.null()]), + requiredAndNullable: v.nullable(v.string()), string: v.optional(v.string()), number: v.optional(v.number()), boolean: v.optional(v.boolean()), @@ -953,13 +939,13 @@ export const vOneOfAllOfIssueWritable = v.union([v.intersect([v.union([vConstVal export const vGenericSchemaDuplicateIssue1SystemBooleanWritable = v.strictObject({ item: v.optional(v.boolean()), - error: v.optional(v.union([v.string(), v.null()])), + error: v.nullish(v.string()), data: v.optional(v.strictObject({})) }); export const vGenericSchemaDuplicateIssue1SystemStringWritable = v.strictObject({ - item: v.optional(v.union([v.string(), v.null()])), - error: v.optional(v.union([v.string(), v.null()])) + item: v.nullish(v.string()), + error: v.nullish(v.string()) }); /** @@ -972,12 +958,12 @@ export const vCompositionWithOneOfAndProperties = v.intersect([v.union([v.strict }), v.strictObject({ bar: vNonAsciiStringæøåÆøÅöôêÊ字符串 })]), v.object({ - baz: v.union([v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535')), v.null()]), + baz: v.nullable(v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535'))), qux: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(255, 'Invalid value: Expected uint8 to be <= 255')) })]); export const vModelWithOneOfAndProperties = v.intersect([v.union([vSimpleParameter, vNonAsciiStringæøåÆøÅöôêÊ字符串]), v.object({ - baz: v.union([v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535')), v.null()]), + baz: v.nullable(v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(65535, 'Invalid value: Expected uint16 to be <= 65535'))), qux: v.pipe(v.number(), v.integer(), v.minValue(0), v.maxValue(255, 'Invalid value: Expected uint8 to be <= 255')) })]); @@ -1118,40 +1104,40 @@ export const vDeprecatedCallData = v.object({ path: v.optional(v.never()), query: v.optional(v.never()), headers: v.object({ - parameter: v.union([vDeprecatedModel, v.null()]) + parameter: v.nullable(vDeprecatedModel) }) }); export const vCallWithParametersData = v.object({ - body: v.union([v.record(v.string(), v.unknown()), v.null()]), + body: v.nullable(v.record(v.string(), v.unknown())), path: v.object({ - parameterPath: v.union([v.string(), v.null()]), - 'api-version': v.union([v.string(), v.null()]) + parameterPath: v.nullable(v.string()), + 'api-version': v.nullable(v.string()) }), query: v.object({ foo_ref_enum: v.optional(vModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: vModelWithNestedArrayEnumsDataFoo, - cursor: v.union([v.string(), v.null()]) + cursor: v.nullable(v.string()) }), headers: v.object({ - parameterHeader: v.union([v.string(), v.null()]) + parameterHeader: v.nullable(v.string()) }) }); export const vCallWithWeirdParameterNamesData = v.object({ - body: v.union([vModelWithString, v.null()]), + body: v.nullable(vModelWithString), path: v.object({ 'parameter.path.1': v.optional(v.string()), 'parameter-path-2': v.optional(v.string()), 'PARAMETER-PATH-3': v.optional(v.string()), - 'api-version': v.union([v.string(), v.null()]) + 'api-version': v.nullable(v.string()) }), query: v.object({ default: v.optional(v.string()), - 'parameter-query': v.union([v.string(), v.null()]) + 'parameter-query': v.nullable(v.string()) }), headers: v.object({ - 'parameter.header': v.union([v.string(), v.null()]) + 'parameter.header': v.nullable(v.string()) }) }); @@ -1165,7 +1151,7 @@ export const vGetCallWithOptionalParamData = v.object({ export const vPostCallWithOptionalParamData = v.object({ body: v.optional(v.object({ - offset: v.optional(v.union([v.number(), v.null()])) + offset: v.nullish(v.number()) })), path: v.optional(v.never()), query: v.object({ @@ -1195,15 +1181,15 @@ export const vCallWithDefaultParametersData = v.object({ body: v.optional(v.never()), path: v.optional(v.never()), query: v.optional(v.object({ - parameterString: v.optional(v.union([v.optional(v.string(), 'Hello World!'), v.null()]), 'Hello World!'), - parameterNumber: v.optional(v.union([v.optional(v.number(), 123), v.null()]), 123), - parameterBoolean: v.optional(v.union([v.optional(v.boolean(), true), v.null()]), true), + parameterString: v.nullish(v.string(), 'Hello World!'), + parameterNumber: v.nullish(v.number(), 123), + parameterBoolean: v.nullish(v.boolean(), true), parameterEnum: v.optional(v.picklist([ 'Success', 'Warning', 'Error' ])), - parameterModel: v.optional(v.union([v.optional(vModelWithString, { prop: 'Hello World!' }), v.null()])) + parameterModel: v.nullish(vModelWithString) })) }); @@ -1233,8 +1219,8 @@ export const vCallToTestOrderOfParamsData = v.object({ parameterStringWithDefault: v.optional(v.string(), 'Hello World!'), parameterStringWithEmptyDefault: v.optional(v.string(), ''), parameterStringWithNoDefault: v.string(), - parameterStringNullableWithNoDefault: v.optional(v.union([v.string(), v.null()])), - parameterStringNullableWithDefault: v.optional(v.union([v.string(), v.null()]), null) + parameterStringNullableWithNoDefault: v.nullish(v.string()), + parameterStringNullableWithDefault: v.nullish(v.string(), null) }) }); @@ -1336,11 +1322,11 @@ export const vCollectionFormatData = v.object({ body: v.optional(v.never()), path: v.optional(v.never()), query: v.object({ - parameterArrayCSV: v.union([v.array(v.string()), v.null()]), - parameterArraySSV: v.union([v.array(v.string()), v.null()]), - parameterArrayTSV: v.union([v.array(v.string()), v.null()]), - parameterArrayPipes: v.union([v.array(v.string()), v.null()]), - parameterArrayMulti: v.union([v.array(v.string()), v.null()]) + parameterArrayCSV: v.nullable(v.array(v.string())), + parameterArraySSV: v.nullable(v.array(v.string())), + parameterArrayTSV: v.nullable(v.array(v.string())), + parameterArrayPipes: v.nullable(v.array(v.string())), + parameterArrayMulti: v.nullable(v.array(v.string())) }) }); @@ -1351,17 +1337,16 @@ export const vTypesData = v.object({ })), query: v.object({ parameterNumber: v.optional(v.number(), 123), - parameterString: v.optional(v.union([v.optional(v.string(), 'default'), v.null()]), 'default'), - parameterBoolean: v.optional(v.union([v.optional(v.boolean(), true), v.null()]), true), - parameterObject: v.optional(v.union([v.record(v.string(), v.unknown()), v.null()]), null), - parameterArray: v.union([v.array(v.string()), v.null()]), - parameterDictionary: v.union([v.record(v.string(), v.unknown()), v.null()]), - parameterEnum: v.union([ + parameterString: v.nullish(v.string(), 'default'), + parameterBoolean: v.nullish(v.boolean(), true), + parameterObject: v.nullish(v.record(v.string(), v.unknown()), null), + parameterArray: v.nullable(v.array(v.string())), + parameterDictionary: v.nullable(v.record(v.string(), v.unknown())), + parameterEnum: v.nullable(v.union([ v.literal('Success'), v.literal('Warning'), - v.literal('Error'), - v.null() - ]) + v.literal('Error') + ])) }) }); @@ -1375,7 +1360,7 @@ export const vTypesResponse = v.union([ export const vUploadFileData = v.object({ body: v.string(), path: v.object({ - 'api-version': v.union([v.string(), v.null()]) + 'api-version': v.nullable(v.string()) }), query: v.optional(v.never()) }); @@ -1436,7 +1421,7 @@ export const vMultipartResponseResponse = v.object({ export const vMultipartRequestData = v.object({ body: v.optional(v.object({ content: v.optional(v.string()), - data: v.optional(v.union([vModelWithString, v.null()])) + data: v.nullish(vModelWithString) })), path: v.optional(v.never()), query: v.optional(v.never()) @@ -1444,16 +1429,16 @@ export const vMultipartRequestData = v.object({ export const vComplexParamsData = v.object({ body: v.optional(v.object({ - key: v.pipe(v.union([v.pipe(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.readonly()), v.null()]), v.readonly()), - name: v.union([v.pipe(v.string(), v.maxLength(255)), v.null()]), + key: v.nullable(v.pipe(v.pipe(v.string(), v.maxLength(64), v.regex(/^[a-zA-Z0-9_]*$/)), v.readonly())), + name: v.nullable(v.pipe(v.string(), v.maxLength(255))), enabled: v.optional(v.boolean(), true), type: v.picklist([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: v.optional(v.union([v.array(vModelWithString), v.null()])), - listOfStrings: v.optional(v.union([v.array(v.string()), v.null()])), + listOfModels: v.nullish(v.array(vModelWithString)), + listOfStrings: v.nullish(v.array(v.string())), parameters: v.union([ vModelWithString, vModelWithEnum, @@ -1462,7 +1447,7 @@ export const vComplexParamsData = v.object({ ]), user: v.optional(v.pipe(v.object({ id: v.optional(v.pipe(v.pipe(v.number(), v.integer(), v.minValue(-2147483648, 'Invalid value: Expected int32 to be >= -2147483648'), v.maxValue(2147483647, 'Invalid value: Expected int32 to be <= 2147483647')), v.readonly())), - name: v.optional(v.pipe(v.union([v.pipe(v.string(), v.readonly()), v.null()]), v.readonly())) + name: v.nullish(v.pipe(v.string(), v.readonly())) }), v.readonly())) })), path: v.object({ diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-circular-ref-2/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-circular-ref-2/valibot.gen.ts index 1dc875c6b..40575008c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-circular-ref-2/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-circular-ref-2/valibot.gen.ts @@ -3,7 +3,7 @@ import * as v from 'valibot'; export const vBar: v.GenericSchema = v.strictObject({ - bar: v.union([v.array(v.lazy(() => vBar)), v.null()]) + bar: v.nullable(v.array(v.lazy(() => vBar))) }); export const vFoo = v.strictObject({ diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-metadata/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-metadata/valibot.gen.ts index 149a0044b..8072a14be 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-metadata/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-metadata/valibot.gen.ts @@ -11,12 +11,12 @@ export const vQux = v.record(v.string(), v.object({ /** * This is Foo schema. */ -export const vFoo: v.GenericSchema = v.optional(v.union([v.object({ - foo: v.optional(v.pipe(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/)), v.metadata({ description: 'This is foo property.' }))), - bar: v.optional(v.lazy(() => vBar)), - baz: v.optional(v.pipe(v.array(v.lazy(() => vFoo)), v.metadata({ description: 'This is baz property.' }))), - qux: v.optional(v.pipe(v.pipe(v.number(), v.integer(), v.gtValue(0)), v.metadata({ description: 'This is qux property.' })), 0) - }), v.null()]), null); +export const vFoo: v.GenericSchema = v.nullish(v.object({ + foo: v.optional(v.pipe(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/)), v.metadata({ description: 'This is foo property.' }))), + bar: v.optional(v.lazy(() => vBar)), + baz: v.optional(v.pipe(v.array(v.lazy(() => vFoo)), v.metadata({ description: 'This is baz property.' }))), + qux: v.optional(v.pipe(v.pipe(v.number(), v.integer(), v.gtValue(0)), v.metadata({ description: 'This is qux property.' })), 0) +}), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-types/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-types/valibot.gen.ts index b5a5dfce3..621d1f914 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-types/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators-types/valibot.gen.ts @@ -11,12 +11,12 @@ export const vQux = v.record(v.string(), v.object({ /** * This is Foo schema. */ -export const vFoo: v.GenericSchema = v.optional(v.union([v.object({ - foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), - bar: v.optional(v.lazy(() => vBar)), - baz: v.optional(v.array(v.lazy(() => vFoo))), - qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) - }), v.null()]), null); +export const vFoo: v.GenericSchema = v.nullish(v.object({ + foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: v.optional(v.lazy(() => vBar)), + baz: v.optional(v.array(v.lazy(() => vFoo))), + qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) +}), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators/valibot.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators/valibot.gen.ts index b5a5dfce3..621d1f914 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators/valibot.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/validators/valibot.gen.ts @@ -11,12 +11,12 @@ export const vQux = v.record(v.string(), v.object({ /** * This is Foo schema. */ -export const vFoo: v.GenericSchema = v.optional(v.union([v.object({ - foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), - bar: v.optional(v.lazy(() => vBar)), - baz: v.optional(v.array(v.lazy(() => vFoo))), - qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) - }), v.null()]), null); +export const vFoo: v.GenericSchema = v.nullish(v.object({ + foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: v.optional(v.lazy(() => vBar)), + baz: v.optional(v.array(v.lazy(() => vFoo))), + qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0) +}), null); /** * This is Bar schema. diff --git a/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts b/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts index 49ee9fed3..edd0b4a00 100644 --- a/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts +++ b/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts @@ -1,11 +1,19 @@ import type { Refs, Symbol } from '@hey-api/codegen-core'; -import type { IR, Plugin, SchemaWithType } from '@hey-api/shared'; +import type { + IR, + Plugin, + SchemaResult, + SchemaVisitorContext, + SchemaWithType, + Walker, +} from '@hey-api/shared'; import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/utils/coerce'; import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats'; import type { $, DollarTsDsl } from '../../../ts-dsl'; import type { Pipe, PipeResult, Pipes, PipesUtils } from '../shared/pipes'; import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types'; +import type { ValibotPlugin } from '../types'; export type Resolvers = Plugin.Resolvers<{ /** @@ -70,7 +78,7 @@ export type Resolvers = Plugin.Resolvers<{ type ValidatorResolver = (ctx: ValidatorResolverContext) => PipeResult | null | undefined; type BaseContext = DollarTsDsl & - Pick & { + Pick & { /** * Functions for working with pipes. */ @@ -116,10 +124,6 @@ export interface EnumResolverContext extends BaseContext { */ isNullable: boolean; }; - /** - * Returns a nullable wrapper if the enum includes null, undefined otherwise. - */ - nullable: (ctx: EnumResolverContext) => PipeResult | undefined; }; schema: SchemaWithType<'enum'>; /** @@ -152,6 +156,7 @@ export interface NumberResolverContext extends BaseContext { } export interface ObjectResolverContext extends BaseContext { + applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; /** * Nodes used to build different parts of the object schema. */ @@ -172,6 +177,8 @@ export interface ObjectResolverContext extends BaseContext { ast: Partial>; state: Refs; }; + walk: Walker; + walkerCtx: SchemaVisitorContext; } export interface StringResolverContext extends BaseContext { diff --git a/packages/openapi-ts/src/plugins/valibot/shared/types.ts b/packages/openapi-ts/src/plugins/valibot/shared/types.ts index 0cb6b4815..aba45dc5a 100644 --- a/packages/openapi-ts/src/plugins/valibot/shared/types.ts +++ b/packages/openapi-ts/src/plugins/valibot/shared/types.ts @@ -1,10 +1,9 @@ import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; -import type { IR, SchemaExtractor } from '@hey-api/shared'; +import type { IR, Walker } from '@hey-api/shared'; import type ts from 'typescript'; import type { ValibotPlugin } from '../types'; import type { Pipes } from './pipes'; -import type { ProcessorContext } from './processor'; export type Ast = { hasLazyExpression?: boolean; @@ -15,10 +14,9 @@ export type Ast = { export type IrSchemaToAstOptions = { /** The plugin instance. */ plugin: ValibotPlugin['Instance']; - /** Optional schema extractor function. */ - schemaExtractor?: SchemaExtractor; /** The plugin state references. */ state: Refs; + walk: Walker; }; export type PluginState = Pick, 'path'> & diff --git a/packages/openapi-ts/src/plugins/valibot/v1/plugin.ts b/packages/openapi-ts/src/plugins/valibot/v1/plugin.ts index 1f8694a76..0870028f8 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/plugin.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/plugin.ts @@ -1,158 +1,9 @@ -import type { SymbolMeta } from '@hey-api/codegen-core'; -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { IR, SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema, pathToJsonPointer } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; -import { maybeBigInt } from '../../../plugins/shared/utils/coerce'; -import { $ } from '../../../ts-dsl'; import { irOperationToAst } from '../shared/operation'; -import { pipesToNode } from '../shared/pipes'; -import type { Ast, IrSchemaToAstOptions } from '../shared/types'; import { irWebhookToAst } from '../shared/webhook'; import type { ValibotPlugin } from '../types'; -import { identifiers } from './constants'; import { createProcessor } from './processor'; -import { irSchemaWithTypeToAst } from './toAst'; - -export function irSchemaToAst({ - optional, - plugin, - schema, - schemaExtractor, - state, -}: IrSchemaToAstOptions & { - /** - * Accept `optional` to handle optional object properties. We can't handle - * this inside the object function because `.optional()` must come before - * `.default()` which is handled in this function. - */ - optional?: boolean; - schema: IR.SchemaObject; -}): Ast { - if (schemaExtractor && !schema.$ref) { - const extracted = schemaExtractor({ - meta: { - resource: 'definition', - resourceId: pathToJsonPointer(fromRef(state.path)), - }, - naming: plugin.config.definitions, - path: fromRef(state.path), - plugin, - schema, - }); - if (extracted !== schema) schema = extracted; - } - - const ast: Ast = { - pipes: [], - }; - - const v = plugin.external('valibot.v'); - - if (schema.$ref) { - const query: SymbolMeta = { - category: 'schema', - resource: 'definition', - resourceId: schema.$ref, - tool: 'valibot', - }; - const refSymbol = plugin.referenceSymbol(query); - if (plugin.isSymbolRegistered(query)) { - const ref = $(refSymbol); - ast.pipes.push(ref); - } else { - const lazyExpression = $(v) - .attr(identifiers.schemas.lazy) - .call($.func().do($(refSymbol).return())); - ast.pipes.push(lazyExpression); - state.hasLazyExpression['~ref'] = true; - } - } else if (schema.type) { - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: schema as SchemaWithType, - schemaExtractor, - state, - }); - ast.typeName = typeAst.anyType; - ast.pipes.push(typeAst.expression); - - if (plugin.config.metadata && schema.description) { - const expression = $(v) - .attr(identifiers.actions.metadata) - .call($.object().prop('description', $.literal(schema.description))); - ast.pipes.push(expression); - } - } else if (schema.items) { - schema = deduplicateSchema({ schema }); - - if (schema.items) { - const itemsAst = schema.items.map((item, index) => { - const itemAst = irSchemaToAst({ - plugin, - schema: item, - schemaExtractor, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - return pipesToNode(itemAst.pipes, plugin); - }); - - if (schema.logicalOperator === 'and') { - const intersectExpression = $(v) - .attr(identifiers.schemas.intersect) - .call($.array(...itemsAst)); - ast.pipes.push(intersectExpression); - } else { - const unionExpression = $(v) - .attr(identifiers.schemas.union) - .call($.array(...itemsAst)); - ast.pipes.push(unionExpression); - } - } else { - const schemaPipes = irSchemaToAst({ plugin, schema, state }); - ast.pipes.push(...schemaPipes.pipes); - } - } else { - // catch-all fallback for failed schemas - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: { - type: 'unknown', - }, - schemaExtractor, - state, - }); - ast.typeName = typeAst.anyType; - ast.pipes.push(typeAst.expression); - } - - if (ast.pipes.length) { - if (schema.accessScope === 'read') { - const readonlyExpression = $(v).attr(identifiers.actions.readonly).call(); - ast.pipes.push(readonlyExpression); - } - - if (schema.default !== undefined) { - ast.pipes = [ - $(v) - .attr(identifiers.schemas.optional) - .call( - pipesToNode(ast.pipes, plugin), - schema.type === 'integer' || schema.type === 'number' - ? maybeBigInt(schema.default, schema.format) - : $.fromValue(schema.default), - ), - ]; - } else if (optional) { - ast.pipes = [$(v).attr(identifiers.schemas.optional).call(pipesToNode(ast.pipes, plugin))]; - } - } - - return ast as Ast; -} export const handlerV1: ValibotPlugin['Handler'] = ({ plugin }) => { plugin.symbol('v', { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/processor.ts b/packages/openapi-ts/src/plugins/valibot/v1/processor.ts index b267cdf79..f9713342c 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/processor.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/processor.ts @@ -1,12 +1,12 @@ -import { refs } from '@hey-api/codegen-core'; +import { ref, refs } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; -import { createSchemaProcessor, pathToJsonPointer } from '@hey-api/shared'; +import { createSchemaProcessor, createSchemaWalker, pathToJsonPointer } from '@hey-api/shared'; import { exportAst } from '../shared/export'; import type { ProcessorContext, ProcessorResult } from '../shared/processor'; import type { PluginState } from '../shared/types'; import type { ValibotPlugin } from '../types'; -import { irSchemaToAst } from './plugin'; +import { createVisitor } from './walker'; export function createProcessor(plugin: ValibotPlugin['Instance']): ProcessorResult { const processor = createSchemaProcessor(); @@ -43,12 +43,24 @@ export function createProcessor(plugin: ValibotPlugin['Instance']): ProcessorRes tags: ctx.tags, }); - const ast = irSchemaToAst({ - plugin, - schema: ctx.schema, + const visitor = createVisitor({ schemaExtractor: extractor, state, }); + const walk = createSchemaWalker(visitor); + + const result = walk(ctx.schema, { + path: ref(ctx.path), + plugin, + }); + const ast = + visitor.applyModifiers(result, { + path: ref(ctx.path), + plugin, + }) ?? result.expression; + if (result.hasLazyExpression) { + state.hasLazyExpression['~ref'] = true; + } exportAst({ ...ctx, ast, plugin, state }); }); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts index 3d80b460b..639c33cb0 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts @@ -1,20 +1,19 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema } from '@hey-api/shared'; +import type { SchemaResult, SchemaWithType } from '@hey-api/shared'; +import { childContext, deduplicateSchema } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { pipesToNode } from '../../shared/pipes'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; import { identifiers } from '../constants'; -import { irSchemaToAst } from '../plugin'; import { unknownToAst } from './unknown'; export function arrayToAst( options: IrSchemaToAstOptions & { + applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; schema: SchemaWithType<'array'>; }, ): Omit { - const { plugin } = options; + const { applyModifiers, plugin, walk } = options; let { schema } = options; const result: Omit = { @@ -39,18 +38,23 @@ export function arrayToAst( // at least one item is guaranteed const itemExpressions = schema.items!.map((item, index) => { - const itemAst = irSchemaToAst({ - ...options, - schema: item, - state: { - ...options.state, - path: ref([...fromRef(options.state.path), 'items', index]), - }, - }); - if (itemAst.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } - return pipesToNode(itemAst.pipes, plugin); + + const finalExpr = applyModifiers(itemResult, { optional: false }); + return pipesToNode(finalExpr.pipes, plugin); }); if (itemExpressions.length === 1) { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts index 0db949d27..635bc4f66 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/boolean.ts @@ -8,7 +8,7 @@ import { identifiers } from '../constants'; export function booleanToAst({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'boolean'>; }): ReturnType { const pipes: Array> = []; diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/enum.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/enum.ts index 56a547850..62c37f88e 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/enum.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/enum.ts @@ -38,15 +38,6 @@ function baseNode(ctx: EnumResolverContext): PipeResult { .call($.array(...enumMembers)); } -function nullableNode(ctx: EnumResolverContext): PipeResult | undefined { - const { symbols } = ctx; - const { v } = symbols; - const { isNullable } = ctx.nodes.items(ctx); - if (!isNullable) return; - const currentNode = ctx.pipes.toNode(ctx.pipes.current, ctx.plugin); - return $(v).attr(identifiers.schemas.nullable).call(currentNode); -} - function enumResolver(ctx: EnumResolverContext): PipeResult { const { enumMembers } = ctx.nodes.items(ctx); @@ -57,11 +48,6 @@ function enumResolver(ctx: EnumResolverContext): PipeResult { const baseExpression = ctx.nodes.base(ctx); ctx.pipes.push(ctx.pipes.current, baseExpression); - const nullableExpression = ctx.nodes.nullable(ctx); - if (nullableExpression) { - return nullableExpression; - } - return ctx.pipes.current; } @@ -69,14 +55,14 @@ export function enumToAst({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'enum'>; }): Pipe { const v = plugin.external('valibot.v'); const { enumMembers } = itemsNode({ $, - nodes: { base: baseNode, items: itemsNode, nullable: nullableNode }, + nodes: { base: baseNode, items: itemsNode }, pipes: { ...pipes, current: [] }, plugin, schema, @@ -90,7 +76,6 @@ export function enumToAst({ schema: { type: 'unknown', }, - state, }); } @@ -99,7 +84,6 @@ export function enumToAst({ nodes: { base: baseNode, items: itemsNode, - nullable: nullableNode, }, pipes: { ...pipes, diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts deleted file mode 100644 index 5ee4d3072..000000000 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/index.ts +++ /dev/null @@ -1,130 +0,0 @@ -import type { SchemaWithType } from '@hey-api/shared'; - -import { shouldCoerceToBigInt } from '../../../../plugins/shared/utils/coerce'; -import type { $ } from '../../../../ts-dsl'; -import { pipesToNode } from '../../shared/pipes'; -import type { IrSchemaToAstOptions } from '../../shared/types'; -import { arrayToAst } from './array'; -import { booleanToAst } from './boolean'; -import { enumToAst } from './enum'; -import { neverToAst } from './never'; -import { nullToAst } from './null'; -import { numberToNode } from './number'; -import { objectToAst } from './object'; -import { stringToNode } from './string'; -import { tupleToAst } from './tuple'; -import { undefinedToAst } from './undefined'; -import { unknownToAst } from './unknown'; -import { voidToAst } from './void'; - -export function irSchemaWithTypeToAst({ - schema, - ...args -}: IrSchemaToAstOptions & { - schema: SchemaWithType; -}): { - anyType?: string; - expression: ReturnType; -} { - switch (schema.type) { - case 'array': - return { - expression: pipesToNode( - arrayToAst({ - ...args, - schema: schema as SchemaWithType<'array'>, - }).pipes, - args.plugin, - ), - }; - case 'boolean': - return { - expression: booleanToAst({ - ...args, - schema: schema as SchemaWithType<'boolean'>, - }), - }; - case 'enum': - return { - expression: enumToAst({ - ...args, - schema: schema as SchemaWithType<'enum'>, - }), - }; - case 'integer': - case 'number': - return { - expression: numberToNode({ - ...args, - schema: schema as SchemaWithType<'integer' | 'number'>, - }), - }; - case 'never': - return { - expression: neverToAst({ - ...args, - schema: schema as SchemaWithType<'never'>, - }), - }; - case 'null': - return { - expression: nullToAst({ - ...args, - schema: schema as SchemaWithType<'null'>, - }), - }; - case 'object': - return { - expression: pipesToNode( - objectToAst({ - ...args, - schema: schema as SchemaWithType<'object'>, - }).pipes, - args.plugin, - ), - }; - case 'string': - return { - expression: shouldCoerceToBigInt(schema.format) - ? numberToNode({ - ...args, - schema: { ...schema, type: 'number' }, - }) - : stringToNode({ - ...args, - schema: schema as SchemaWithType<'string'>, - }), - }; - case 'tuple': - return { - expression: pipesToNode( - tupleToAst({ - ...args, - schema: schema as SchemaWithType<'tuple'>, - }).pipes, - args.plugin, - ), - }; - case 'undefined': - return { - expression: undefinedToAst({ - ...args, - schema: schema as SchemaWithType<'undefined'>, - }), - }; - case 'unknown': - return { - expression: unknownToAst({ - ...args, - schema: schema as SchemaWithType<'unknown'>, - }), - }; - case 'void': - return { - expression: voidToAst({ - ...args, - schema: schema as SchemaWithType<'void'>, - }), - }; - } -} diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/never.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/never.ts index 434650413..78c497442 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/never.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/never.ts @@ -6,7 +6,7 @@ import { identifiers } from '../constants'; export function neverToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'never'>; }) { const v = plugin.external('valibot.v'); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/null.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/null.ts index b0d373c34..59d408916 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/null.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/null.ts @@ -6,7 +6,7 @@ import { identifiers } from '../constants'; export function nullToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'null'>; }) { const v = plugin.external('valibot.v'); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts index 342012ed7..af11f187b 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/number.ts @@ -108,7 +108,7 @@ function numberResolver(ctx: NumberResolverContext): Pipes { export function numberToNode({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'integer' | 'number'>; }): Pipe { const ctx: NumberResolverContext = { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts index 60468eea3..ea88b4400 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts @@ -1,33 +1,44 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; +import type { SchemaResult, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import type { ObjectResolverContext } from '../../resolvers'; import type { Pipe, PipeResult } from '../../shared/pipes'; import { pipes } from '../../shared/pipes'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; +import type { ValibotPlugin } from '../../types'; import { identifiers } from '../constants'; -import { irSchemaToAst } from '../plugin'; -function additionalPropertiesNode(ctx: ObjectResolverContext): Pipe | null | undefined { - const { plugin, schema } = ctx; +type WalkerCtx = SchemaVisitorContext; + +interface ObjectToAstOptions extends IrSchemaToAstOptions { + applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; + schema: SchemaWithType<'object'>; + walk: Walker; + walkerCtx: WalkerCtx; +} + +type ExtendedContext = ObjectResolverContext & { + applyModifiers: ObjectToAstOptions['applyModifiers']; + walk: ObjectToAstOptions['walk']; + walkerCtx: ObjectToAstOptions['walkerCtx']; +}; + +function additionalPropertiesNode(ctx: ExtendedContext): Pipe | null | undefined { + const { plugin, schema, walk, walkerCtx } = ctx; if (!schema.additionalProperties || !schema.additionalProperties.type) return; if (schema.additionalProperties.type === 'never') return null; - const additionalAst = irSchemaToAst({ - ...ctx, - schema: schema.additionalProperties, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'additionalProperties']), - }, - }); - if (additionalAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - return pipes.toNode(additionalAst.pipes, plugin); + const additionalResult = walk( + schema.additionalProperties, + childContext(walkerCtx, 'additionalProperties'), + ); + if (additionalResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + return pipes.toNode(additionalResult.expression.pipes, plugin); } -function baseNode(ctx: ObjectResolverContext): PipeResult { +function baseNode(ctx: ExtendedContext): PipeResult { const { nodes, symbols } = ctx; const { v } = symbols; @@ -51,43 +62,38 @@ function baseNode(ctx: ObjectResolverContext): PipeResult { return $(v).attr(identifiers.schemas.object).call(shape); } -function objectResolver(ctx: ObjectResolverContext): PipeResult { +function objectResolver(ctx: ExtendedContext): PipeResult { // TODO: parser - handle constants return ctx.nodes.base(ctx); } -function shapeNode(ctx: ObjectResolverContext): ReturnType { - const { plugin, schema } = ctx; +function shapeNode(ctx: ExtendedContext): ReturnType { + const { applyModifiers, plugin, schema, walk, walkerCtx } = ctx; const shape = $.object().pretty(); for (const name in schema.properties) { const property = schema.properties[name]!; + const isOptional = !schema.required?.includes(name); + + const propertyResult = walk(property, childContext(walkerCtx, 'properties', name)); + if (propertyResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - const propertyAst = irSchemaToAst({ - ...ctx, - optional: !schema.required?.includes(name), - schema: property, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'properties', name]), - }, + const ast = applyModifiers(propertyResult, { + optional: isOptional, }); - if (propertyAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - shape.prop(name, pipes.toNode(propertyAst.pipes, plugin)); + + shape.prop(name, pipes.toNode(ast.pipes, plugin)); } return shape; } -export function objectToAst( - options: IrSchemaToAstOptions & { - schema: SchemaWithType<'object'>; - }, -): Omit { - const { plugin } = options; - const ctx: ObjectResolverContext = { +export function objectToAst(options: ObjectToAstOptions): Omit { + const { applyModifiers, plugin, walk, walkerCtx } = options; + const ctx: ExtendedContext = { ...options, $, + applyModifiers, nodes: { additionalProperties: additionalPropertiesNode, base: baseNode, @@ -104,6 +110,8 @@ export function objectToAst( ast: {}, state: options.state, }, + walk, + walkerCtx, }; const resolver = plugin.config['~resolvers']?.object; const node = resolver?.(ctx) ?? objectResolver(ctx); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts index 49f16c4bf..20f8fd968 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/string.ts @@ -101,7 +101,7 @@ function stringResolver(ctx: StringResolverContext): Pipes { export function stringToNode({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'string'>; }): Pipe { const ctx: StringResolverContext = { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts index 27db7382d..4eb99a28d 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts @@ -1,19 +1,19 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; +import type { SchemaResult, SchemaWithType } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { pipesToNode } from '../../shared/pipes'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; import { identifiers } from '../constants'; -import { irSchemaToAst } from '../plugin'; import { unknownToAst } from './unknown'; export function tupleToAst( options: IrSchemaToAstOptions & { + applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; schema: SchemaWithType<'tuple'>; }, ): Omit { - const { plugin, schema } = options; + const { applyModifiers, plugin, schema, walk } = options; const result: Partial> = {}; @@ -33,18 +33,23 @@ export function tupleToAst( if (schema.items) { const tupleElements = schema.items.map((item, index) => { - const schemaPipes = irSchemaToAst({ - ...options, - schema: item, - state: { - ...options.state, - path: ref([...fromRef(options.state.path), 'items', index]), - }, - }); - if (schemaPipes.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } - return pipesToNode(schemaPipes.pipes, plugin); + + const finalExpr = applyModifiers(itemResult, { optional: false }); + return pipesToNode(finalExpr.pipes, plugin); }); result.pipes = [ $(v) diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/undefined.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/undefined.ts index 80482d6eb..5320264cb 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/undefined.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/undefined.ts @@ -6,7 +6,7 @@ import { identifiers } from '../constants'; export function undefinedToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'undefined'>; }) { const v = plugin.external('valibot.v'); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/unknown.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/unknown.ts index 188042dae..cc45556e3 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/unknown.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/unknown.ts @@ -6,7 +6,7 @@ import { identifiers } from '../constants'; export function unknownToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'unknown'>; }) { const v = plugin.external('valibot.v'); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/void.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/void.ts index dbdf6bd1c..18a262c27 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/void.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/void.ts @@ -6,7 +6,7 @@ import { identifiers } from '../constants'; export function voidToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'void'>; }) { const v = plugin.external('valibot.v'); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/walker.ts b/packages/openapi-ts/src/plugins/valibot/v1/walker.ts new file mode 100644 index 000000000..7498c3056 --- /dev/null +++ b/packages/openapi-ts/src/plugins/valibot/v1/walker.ts @@ -0,0 +1,358 @@ +import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; +import { fromRef } from '@hey-api/codegen-core'; +import type { IR, SchemaExtractor, SchemaResult, SchemaVisitor } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; + +import { $ } from '../../../ts-dsl'; +import { maybeBigInt, shouldCoerceToBigInt } from '../../shared/utils/coerce'; +import { pipesToNode } from '../shared/pipes'; +import type { ProcessorContext } from '../shared/processor'; +import type { Ast, PluginState } from '../shared/types'; +import type { ValibotPlugin } from '../types'; +import { identifiers } from './constants'; +import { arrayToAst } from './toAst/array'; +import { booleanToAst } from './toAst/boolean'; +import { enumToAst } from './toAst/enum'; +import { neverToAst } from './toAst/never'; +import { nullToAst } from './toAst/null'; +import { numberToNode } from './toAst/number'; +import { objectToAst } from './toAst/object'; +import { stringToNode } from './toAst/string'; +import { tupleToAst } from './toAst/tuple'; +import { undefinedToAst } from './toAst/undefined'; +import { unknownToAst } from './toAst/unknown'; +import { voidToAst } from './toAst/void'; + +export interface VisitorConfig { + /** Optional schema extractor function. */ + schemaExtractor?: SchemaExtractor; + /** The plugin state references. */ + state: Refs; +} + +function getDefaultValue(result: SchemaResult) { + return result.format ? maybeBigInt(result.default, result.format) : $.fromValue(result.default); +} + +export function createVisitor( + config: VisitorConfig, +): SchemaVisitor { + const { schemaExtractor, state } = config; + return { + applyModifiers(result, ctx, options = {}) { + const { optional } = options; + const v = ctx.plugin.external('valibot.v'); + const pipes = [...result.expression.pipes]; + + if (result.readonly) { + pipes.push($(v).attr(identifiers.actions.readonly).call()); + } + + const hasDefault = result.default !== undefined; + const needsOptional = optional || hasDefault; + const needsNullable = result.nullable; + const innerNode = pipesToNode(pipes, ctx.plugin); + + if (needsOptional && needsNullable) { + if (hasDefault) { + return { + pipes: [ + $(v).attr(identifiers.schemas.nullish).call(innerNode, getDefaultValue(result)), + ], + }; + } + return { pipes: [$(v).attr(identifiers.schemas.nullish).call(innerNode)] }; + } + + if (needsOptional) { + if (hasDefault) { + return { + pipes: [ + $(v).attr(identifiers.schemas.optional).call(innerNode, getDefaultValue(result)), + ], + }; + } + return { pipes: [$(v).attr(identifiers.schemas.optional).call(innerNode)] }; + } + + if (needsNullable) { + return { pipes: [$(v).attr(identifiers.schemas.nullable).call(innerNode)] }; + } + + return { pipes }; + }, + array(schema, ctx, walk) { + const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts); + const ast = arrayToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: false, + }; + }, + boolean(schema, ctx) { + const pipe = booleanToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + enum(schema, ctx) { + const pipe = enumToAst({ ...ctx, schema, state }); + const hasNull = + schema.items?.some((item) => item.type === 'null' || item.const === null) ?? false; + return { + expression: { pipes: [pipe] }, + nullable: hasNull, + readonly: false, + }; + }, + integer(schema, ctx) { + const pipe = numberToNode({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + format: schema.format, + nullable: false, + readonly: false, + }; + }, + intercept(schema, ctx, walk) { + if (schemaExtractor && !schema.$ref) { + const extracted = schemaExtractor({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(fromRef(ctx.path)), + }, + naming: ctx.plugin.config.definitions, + path: fromRef(ctx.path), + plugin: ctx.plugin, + schema, + }); + if (extracted !== schema) { + return walk(extracted, ctx); + } + } + }, + intersection(items, schemas, ctx) { + const v = ctx.plugin.external('valibot.v'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + const itemNodes = items.map((item) => pipesToNode(item.expression.pipes, ctx.plugin)); + + return { + expression: { + pipes: [ + $(v) + .attr(identifiers.schemas.intersect) + .call($.array(...itemNodes)), + ], + }, + hasLazyExpression: hasAnyLazy, + nullable: items.some((i) => i.nullable), + readonly: items.some((i) => i.readonly), + }; + }, + never(schema, ctx) { + const pipe = neverToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + null(schema, ctx) { + const pipe = nullToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + number(schema, ctx) { + const pipe = numberToNode({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + format: schema.format, + nullable: false, + readonly: false, + }; + }, + object(schema, ctx, walk) { + const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts); + const ast = objectToAst({ + applyModifiers, + plugin: ctx.plugin, + schema, + state, + walk, + walkerCtx: ctx, + }); + return { + expression: ast, + hasLazyExpression: ast.hasLazyExpression ?? false, + nullable: false, + readonly: false, + }; + }, + postProcess(result, schema, ctx) { + if (ctx.plugin.config.metadata && schema.description) { + const v = ctx.plugin.external('valibot.v'); + const metadataExpr = $(v) + .attr(identifiers.actions.metadata) + .call($.object().prop('description', $.literal(schema.description))); + return { + ...result, + expression: { pipes: [...result.expression.pipes, metadataExpr] }, + }; + } + return result; + }, + reference($ref, schema, ctx) { + const v = ctx.plugin.external('valibot.v'); + const query: SymbolMeta = { + category: 'schema', + resource: 'definition', + resourceId: $ref, + tool: 'valibot', + }; + + const refSymbol = ctx.plugin.referenceSymbol(query); + + if (ctx.plugin.isSymbolRegistered(query)) { + return { + expression: { pipes: [$(refSymbol)] }, + nullable: false, + readonly: false, + }; + } + + state.hasLazyExpression['~ref'] = true; + return { + expression: { + pipes: [ + $(v) + .attr(identifiers.schemas.lazy) + .call($.func().do($(refSymbol).return())), + ], + }, + hasLazyExpression: true, + nullable: false, + readonly: false, + }; + }, + string(schema, ctx) { + if (shouldCoerceToBigInt(schema.format)) { + const pipe = numberToNode({ + plugin: ctx.plugin, + schema: { ...schema, type: 'number' }, + }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + } + + const pipe = stringToNode({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + tuple(schema, ctx, walk) { + const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts); + const ast = tupleToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: false, + }; + }, + undefined(schema, ctx) { + const pipe = undefinedToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + union(items, schemas, ctx) { + const v = ctx.plugin.external('valibot.v'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + const hasNull = schemas.some((s) => s.type === 'null') || items.some((i) => i.nullable); + + const nonNullItems: typeof items = []; + const nonNullSchemas: Array = []; + + items.forEach((item, index) => { + const schema = schemas[index]!; + if (schema.type !== 'null') { + nonNullItems.push(item); + nonNullSchemas.push(schema); + } + }); + + // Build union expression WITHOUT null - null is tracked via nullable flag + let expression: Ast; + if (nonNullItems.length === 0) { + // Union was only null + expression = { pipes: [$(v).attr(identifiers.schemas.null).call()] }; + } else if (nonNullItems.length === 1) { + // Single non-null item + expression = nonNullItems[0]!.expression; + } else { + // Multiple non-null items + const itemNodes = nonNullItems.map((i) => pipesToNode(i.expression.pipes, ctx.plugin)); + expression = { + pipes: [ + $(v) + .attr(identifiers.schemas.union) + .call($.array(...itemNodes)), + ], + }; + } + + return { + expression, + hasLazyExpression: hasAnyLazy, + nullable: hasNull, + readonly: false, + }; + }, + unknown(schema, ctx) { + const pipe = unknownToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + void(schema, ctx) { + const pipe = voidToAst({ ...ctx, schema }); + return { + expression: { pipes: [pipe] }, + nullable: false, + readonly: false, + }; + }, + }; +} diff --git a/packages/openapi-ts/src/plugins/zod/constants.ts b/packages/openapi-ts/src/plugins/zod/constants.ts index 58875daca..8acc57bf8 100644 --- a/packages/openapi-ts/src/plugins/zod/constants.ts +++ b/packages/openapi-ts/src/plugins/zod/constants.ts @@ -39,6 +39,7 @@ export const identifiers = { never: 'never', null: 'null', nullable: 'nullable', + nullish: 'nullish', number: 'number', object: 'object', optional: 'optional', diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 1d8ece6cb..53d35c6bd 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -58,6 +58,15 @@ export { parameterWithPagination, } from './ir/parameter'; export { deduplicateSchema } from './ir/schema'; +export type { + SchemaExtractor, + SchemaProcessor, + SchemaProcessorContext, + SchemaProcessorResult, +} from './ir/schema-processor'; +export { createSchemaProcessor } from './ir/schema-processor'; +export type { SchemaResult, SchemaVisitor, SchemaVisitorContext, Walker } from './ir/schema-walker'; +export { childContext, createSchemaWalker } from './ir/schema-walker'; export type { IR } from './ir/types'; export { addItemsToSchema } from './ir/utils'; export { parseOpenApiSpec } from './openApi'; @@ -87,13 +96,6 @@ export type { OpenApiSchemaObject, } from './openApi/types'; export type { Hooks } from './parser/hooks'; -export type { - SchemaExtractor, - SchemaProcessor, - SchemaProcessorContext, - SchemaProcessorResult, -} from './plugins/schema-processor'; -export { createSchemaProcessor } from './plugins/schema-processor'; export type { SchemaWithType } from './plugins/shared/types/schema'; export { definePluginConfig, mappers } from './plugins/shared/utils/config'; export type { PluginInstanceTypes } from './plugins/shared/utils/instance'; diff --git a/packages/shared/src/plugins/schema-processor.ts b/packages/shared/src/ir/schema-processor.ts similarity index 98% rename from packages/shared/src/plugins/schema-processor.ts rename to packages/shared/src/ir/schema-processor.ts index 74dd1993e..d7b6c1be1 100644 --- a/packages/shared/src/plugins/schema-processor.ts +++ b/packages/shared/src/ir/schema-processor.ts @@ -1,5 +1,5 @@ -import type { IR } from '../ir/types'; import { pathToJsonPointer } from '../utils/ref'; +import type { IR } from './types'; export interface SchemaProcessor { /** Current inherited context (set by withContext) */ diff --git a/packages/shared/src/ir/schema-walker.ts b/packages/shared/src/ir/schema-walker.ts new file mode 100644 index 000000000..2618fb102 --- /dev/null +++ b/packages/shared/src/ir/schema-walker.ts @@ -0,0 +1,283 @@ +import type { Ref } from '@hey-api/codegen-core'; +import { fromRef, ref } from '@hey-api/codegen-core'; + +import type { SchemaWithType } from '../plugins/shared/types/schema'; +import { deduplicateSchema } from './schema'; +import type { IR } from './types'; + +/** + * Result returned by visitor methods. Contains the expression plus metadata + * needed for modifier application. + */ +export interface SchemaResult { + /** Default value from schema, if any. */ + default?: unknown; + /** The core schema expression, WITHOUT optional/nullable/default applied. */ + expression: TExpr; + /** The original schema format. */ + format?: string; + /** For libraries that need lazy evaluation. */ + hasLazyExpression?: boolean; + /** Plugin-specific metadata bucket. */ + meta?: Record; + /** Does this schema explicitly allow null? */ + nullable: boolean; + /** Is this schema read-only? */ + readonly: boolean; +} + +/** + * Context passed to all visitor methods. + */ +export interface SchemaVisitorContext { + /** Current path in the schema tree. */ + path: Ref>; + /** The plugin instance. */ + plugin: TPlugin; +} + +/** + * The walk function signature. + */ +export type Walker = ( + schema: IR.SchemaObject, + ctx: SchemaVisitorContext, +) => SchemaResult; + +/** + * The visitor interface. Plugins implement this to define how schemas + * are transformed into their target representation. + */ +export interface SchemaVisitor { + /** + * Apply modifiers (optional/nullable/nullish/default) to a schema result. + */ + applyModifiers( + result: SchemaResult, + ctx: SchemaVisitorContext, + context?: { + /** Is this property optional? */ + optional?: boolean; + }, + ): TExpr; + array( + schema: SchemaWithType<'array'>, + ctx: SchemaVisitorContext, + walk: Walker, + ): SchemaResult; + boolean( + schema: SchemaWithType<'boolean'>, + ctx: SchemaVisitorContext, + ): SchemaResult; + enum( + schema: SchemaWithType<'enum'>, + ctx: SchemaVisitorContext, + walk: Walker, + ): SchemaResult; + integer( + schema: SchemaWithType<'integer'>, + ctx: SchemaVisitorContext, + ): SchemaResult; + /** + * Called before any dispatch logic. Return a result to short-circuit, + * or undefined to continue normal dispatch. + */ + intercept?( + schema: IR.SchemaObject, + ctx: SchemaVisitorContext, + walk: Walker, + ): SchemaResult | undefined; + /** + * Handle intersection types. Receives already-walked child results. + */ + intersection( + items: Array>, + schemas: ReadonlyArray, + ctx: SchemaVisitorContext, + ): SchemaResult; + never(schema: SchemaWithType<'never'>, ctx: SchemaVisitorContext): SchemaResult; + null(schema: SchemaWithType<'null'>, ctx: SchemaVisitorContext): SchemaResult; + number(schema: SchemaWithType<'number'>, ctx: SchemaVisitorContext): SchemaResult; + object( + schema: SchemaWithType<'object'>, + ctx: SchemaVisitorContext, + walk: Walker, + ): SchemaResult; + /** + * Called after each typed schema visitor returns. + */ + postProcess?( + result: SchemaResult, + schema: IR.SchemaObject, + ctx: SchemaVisitorContext, + ): SchemaResult; + /** + * Handle $ref to another schema. + */ + reference( + $ref: string, + schema: IR.SchemaObject, + ctx: SchemaVisitorContext, + ): SchemaResult; + string(schema: SchemaWithType<'string'>, ctx: SchemaVisitorContext): SchemaResult; + tuple( + schema: SchemaWithType<'tuple'>, + ctx: SchemaVisitorContext, + walk: Walker, + ): SchemaResult; + undefined( + schema: SchemaWithType<'undefined'>, + ctx: SchemaVisitorContext, + ): SchemaResult; + /** + * Handle union types. Receives already-walked child results. + */ + union( + items: Array>, + schemas: ReadonlyArray, + ctx: SchemaVisitorContext, + ): SchemaResult; + unknown( + schema: SchemaWithType<'unknown'>, + ctx: SchemaVisitorContext, + ): SchemaResult; + void(schema: SchemaWithType<'void'>, ctx: SchemaVisitorContext): SchemaResult; +} + +/** + * Create a schema walker from a visitor. + * + * The walker handles: + * - Dispatch order ($ref → type → items → fallback) + * - Deduplication of union/intersection schemas + * - Path tracking for child schemas + * - Calling the appropriate visitor method + */ +export function createSchemaWalker( + visitor: SchemaVisitor, +): Walker { + const walk: Walker = (schema, ctx) => { + // escape hatch + if (visitor.intercept) { + const intercepted = visitor.intercept(schema, ctx, walk); + if (intercepted !== undefined) { + return intercepted; + } + } + + const baseResult = { + default: schema.default, + readonly: schema.accessScope === 'read', + }; + + if (schema.$ref) { + const result = visitor.reference(schema.$ref, schema, ctx); + return { + ...result, + default: result.default ?? baseResult.default, + readonly: result.readonly || baseResult.readonly, + }; + } + + if (schema.type) { + let result = visitTyped(schema as SchemaWithType, ctx, visitor, walk); + if (visitor.postProcess) { + result = visitor.postProcess(result, schema, ctx); + } + return { + ...result, + default: result.default ?? baseResult.default, + readonly: result.readonly || baseResult.readonly, + }; + } + + if (schema.items) { + const deduplicated = deduplicateSchema({ schema }); + + // deduplication might collapse to a single schema + if (!deduplicated.items) { + return walk(deduplicated, ctx); + } + + const itemResults = deduplicated.items.map((item, index) => + walk(item, { + ...ctx, + path: ref([...fromRef(ctx.path), 'items', index]), + }), + ); + + const result = + deduplicated.logicalOperator === 'and' + ? visitor.intersection(itemResults, deduplicated.items, ctx) + : visitor.union(itemResults, deduplicated.items, ctx); + + return { + ...result, + default: result.default ?? baseResult.default, + readonly: result.readonly || baseResult.readonly, + }; + } + + // fallback + const result = visitor.unknown({ type: 'unknown' }, ctx); + return { + ...result, + default: result.default ?? baseResult.default, + readonly: result.readonly || baseResult.readonly, + }; + }; + + return walk; +} + +/** + * Dispatch to the appropriate visitor method based on schema type. + */ +function visitTyped( + schema: SchemaWithType, + ctx: SchemaVisitorContext, + visitor: SchemaVisitor, + walk: Walker, +): SchemaResult { + switch (schema.type) { + case 'array': + return visitor.array(schema as SchemaWithType<'array'>, ctx, walk); + case 'boolean': + return visitor.boolean(schema as SchemaWithType<'boolean'>, ctx); + case 'enum': + return visitor.enum(schema as SchemaWithType<'enum'>, ctx, walk); + case 'integer': + return visitor.integer(schema as SchemaWithType<'integer'>, ctx); + case 'never': + return visitor.never(schema as SchemaWithType<'never'>, ctx); + case 'null': + return visitor.null(schema as SchemaWithType<'null'>, ctx); + case 'number': + return visitor.number(schema as SchemaWithType<'number'>, ctx); + case 'object': + return visitor.object(schema as SchemaWithType<'object'>, ctx, walk); + case 'string': + return visitor.string(schema as SchemaWithType<'string'>, ctx); + case 'tuple': + return visitor.tuple(schema as SchemaWithType<'tuple'>, ctx, walk); + case 'undefined': + return visitor.undefined(schema as SchemaWithType<'undefined'>, ctx); + case 'unknown': + return visitor.unknown(schema as SchemaWithType<'unknown'>, ctx); + case 'void': + return visitor.void(schema as SchemaWithType<'void'>, ctx); + } +} + +/** + * Helper to create a child context with an extended path. + */ +export function childContext( + ctx: SchemaVisitorContext, + ...segments: ReadonlyArray +): SchemaVisitorContext { + return { + ...ctx, + path: ref([...fromRef(ctx.path), ...segments]), + }; +} diff --git a/packages/shared/src/parser/hooks.ts b/packages/shared/src/parser/hooks.ts index b159bb52d..93c69c041 100644 --- a/packages/shared/src/parser/hooks.ts +++ b/packages/shared/src/parser/hooks.ts @@ -1,7 +1,7 @@ import type { Node, Symbol, SymbolIn } from '@hey-api/codegen-core'; +import type { SchemaProcessorContext } from '../ir/schema-processor'; import type { IROperationObject } from '../ir/types'; -import type { SchemaProcessorContext } from '../plugins/schema-processor'; import type { PluginInstance } from '../plugins/shared/utils/instance'; export type Hooks = { diff --git a/pyproject.toml b/pyproject.toml index 616404b43..95e3d98e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.0.0" requires-python = ">=3.9" [dependency-groups] -dev = ["httpx>=0.27", "mypy>=1.15", "ruff>=0.11"] +dev = ["httpx>=0.27", "mypy>=1.15", "pydantic>=2.0", "ruff>=0.11"] [tool.mypy] python_version = "3.9" diff --git a/uv.lock b/uv.lock index 7db157b8a..76bf63a7b 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,15 @@ version = 1 revision = 3 requires-python = ">=3.9" +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + [[package]] name = "anyio" version = "4.12.1" @@ -55,6 +64,7 @@ source = { virtual = "." } dev = [ { name = "httpx" }, { name = "mypy" }, + { name = "pydantic" }, { name = "ruff" }, ] @@ -64,6 +74,7 @@ dev = [ dev = [ { name = "httpx", specifier = ">=0.27" }, { name = "mypy", specifier = ">=1.15" }, + { name = "pydantic", specifier = ">=2.0" }, { name = "ruff", specifier = ">=0.11" }, ] @@ -257,6 +268,152 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, ] +[[package]] +name = "pydantic" +version = "2.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/54/db/160dffb57ed9a3705c4cbcbff0ac03bdae45f1ca7d58ab74645550df3fbd/pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf", size = 2107999, upload-time = "2025-11-04T13:42:03.885Z" }, + { url = "https://files.pythonhosted.org/packages/a3/7d/88e7de946f60d9263cc84819f32513520b85c0f8322f9b8f6e4afc938383/pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5", size = 1929745, upload-time = "2025-11-04T13:42:06.075Z" }, + { url = "https://files.pythonhosted.org/packages/d5/c2/aef51e5b283780e85e99ff19db0f05842d2d4a8a8cd15e63b0280029b08f/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d", size = 1920220, upload-time = "2025-11-04T13:42:08.457Z" }, + { url = "https://files.pythonhosted.org/packages/c7/97/492ab10f9ac8695cd76b2fdb24e9e61f394051df71594e9bcc891c9f586e/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60", size = 2067296, upload-time = "2025-11-04T13:42:10.817Z" }, + { url = "https://files.pythonhosted.org/packages/ec/23/984149650e5269c59a2a4c41d234a9570adc68ab29981825cfaf4cfad8f4/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82", size = 2231548, upload-time = "2025-11-04T13:42:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/71/0c/85bcbb885b9732c28bec67a222dbed5ed2d77baee1f8bba2002e8cd00c5c/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5", size = 2362571, upload-time = "2025-11-04T13:42:16.208Z" }, + { url = "https://files.pythonhosted.org/packages/c0/4a/412d2048be12c334003e9b823a3fa3d038e46cc2d64dd8aab50b31b65499/pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3", size = 2068175, upload-time = "2025-11-04T13:42:18.911Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/c58b6a776b502d0a5540ad02e232514285513572060f0d78f7832ca3c98b/pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425", size = 2177203, upload-time = "2025-11-04T13:42:22.578Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ae/f06ea4c7e7a9eead3d165e7623cd2ea0cb788e277e4f935af63fc98fa4e6/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504", size = 2148191, upload-time = "2025-11-04T13:42:24.89Z" }, + { url = "https://files.pythonhosted.org/packages/c1/57/25a11dcdc656bf5f8b05902c3c2934ac3ea296257cc4a3f79a6319e61856/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5", size = 2343907, upload-time = "2025-11-04T13:42:27.683Z" }, + { url = "https://files.pythonhosted.org/packages/96/82/e33d5f4933d7a03327c0c43c65d575e5919d4974ffc026bc917a5f7b9f61/pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3", size = 2322174, upload-time = "2025-11-04T13:42:30.776Z" }, + { url = "https://files.pythonhosted.org/packages/81/45/4091be67ce9f469e81656f880f3506f6a5624121ec5eb3eab37d7581897d/pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460", size = 1990353, upload-time = "2025-11-04T13:42:33.111Z" }, + { url = "https://files.pythonhosted.org/packages/44/8a/a98aede18db6e9cd5d66bcacd8a409fcf8134204cdede2e7de35c5a2c5ef/pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b", size = 2015698, upload-time = "2025-11-04T13:42:35.484Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, +] + [[package]] name = "ruff" version = "0.14.14" @@ -345,3 +502,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac8 wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] -- 2.51.2 From 737730c9c6450c60a81a8949259336e790e9b4f4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 16 Feb 2026 10:04:08 +0100 Subject: [PATCH 2/2] refactor: zod plugin nullish --- .changeset/ninety-towns-act.md | 9 + .changeset/proud-trains-lay.md | 5 + dev/inputs.ts | 2 +- dev/python/plugins.ts | 8 +- dev/typescript/plugins.ts | 24 +- .../src/plugins/pydantic/v2/toAst/string.ts | 6 +- .../transformers/type-format-zod/zod.gen.ts | 8 +- .../transformers/type-format-zod/zod.gen.ts | 8 +- .../transformers/type-format-zod/zod.gen.ts | 8 +- .../3.1.x/string-with-format/zod.gen.ts | 2 +- .../__snapshots__/3.1.x/webhooks/zod.gen.ts | 506 ++++----- .../2.0.x/mini/default/zod.gen.ts | 24 +- .../__snapshots__/2.0.x/v3/default/zod.gen.ts | 20 +- .../2.0.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../__snapshots__/2.0.x/v4/default/zod.gen.ts | 426 ++++--- .../2.0.x/v4/type-format-zod/zod.gen.ts | 8 +- .../3.0.x/mini/circular/zod.gen.ts | 16 +- .../3.0.x/mini/default/zod.gen.ts | 331 ++---- .../3.0.x/mini/validators/zod.gen.ts | 19 +- .../__snapshots__/3.0.x/v3/default/zod.gen.ts | 321 ++---- .../3.0.x/v3/validators/zod.gen.ts | 15 +- .../3.0.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../v4/array-items-one-of-length-1/zod.gen.ts | 2 +- .../3.0.x/v4/circular/zod.gen.ts | 20 +- .../__snapshots__/3.0.x/v4/default/zod.gen.ts | 1003 +++++++---------- .../3.0.x/v4/enum-null/zod.gen.ts | 2 +- .../3.0.x/v4/type-format-zod/zod.gen.ts | 8 +- .../3.0.x/v4/validators/zod.gen.ts | 21 +- .../3.1.x/mini/default/zod.gen.ts | 333 ++---- .../mini/enum-resolver-permissive/zod.gen.ts | 2 +- .../mini/validators-circular-ref-2/zod.gen.ts | 5 +- .../mini/validators-circular-ref/zod.gen.ts | 4 +- .../3.1.x/mini/validators-dates/zod.gen.ts | 19 +- .../3.1.x/mini/validators-metadata/zod.gen.ts | 31 +- .../3.1.x/mini/validators-types/zod.gen.ts | 19 +- .../3.1.x/mini/validators/zod.gen.ts | 19 +- .../__snapshots__/3.1.x/v3/default/zod.gen.ts | 321 ++---- .../v3/enum-resolver-permissive/zod.gen.ts | 2 +- .../v3/validators-circular-ref-2/zod.gen.ts | 5 +- .../3.1.x/v3/validators-dates/zod.gen.ts | 15 +- .../3.1.x/v3/validators-metadata/zod.gen.ts | 15 +- .../3.1.x/v3/validators-types/zod.gen.ts | 15 +- .../3.1.x/v3/validators/zod.gen.ts | 15 +- .../3.1.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../v4/array-items-one-of-length-1/zod.gen.ts | 2 +- .../__snapshots__/3.1.x/v4/default/zod.gen.ts | 1001 +++++++--------- .../3.1.x/v4/enum-null/zod.gen.ts | 2 +- .../v4/enum-resolver-permissive/zod.gen.ts | 2 +- .../3.1.x/v4/schema-const/zod.gen.ts | 52 +- .../3.1.x/v4/type-format-zod/zod.gen.ts | 8 +- .../v4/validators-bigint-min-max/zod.gen.ts | 2 +- .../v4/validators-circular-ref-2/zod.gen.ts | 5 +- .../v4/validators-circular-ref/zod.gen.ts | 6 +- .../3.1.x/v4/validators-dates/zod.gen.ts | 51 +- .../3.1.x/v4/validators-metadata/zod.gen.ts | 65 +- .../3.1.x/v4/validators-types/zod.gen.ts | 51 +- .../v4/validators-union-merge/zod.gen.ts | 2 +- .../3.1.x/v4/validators/zod.gen.ts | 51 +- .../2.0.x/mini/default/zod.gen.ts | 24 +- .../__snapshots__/2.0.x/v3/default/zod.gen.ts | 20 +- .../2.0.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../__snapshots__/2.0.x/v4/default/zod.gen.ts | 426 ++++--- .../2.0.x/v4/type-format-zod/zod.gen.ts | 8 +- .../3.0.x/mini/circular/zod.gen.ts | 16 +- .../3.0.x/mini/default/zod.gen.ts | 331 ++---- .../3.0.x/mini/validators/zod.gen.ts | 19 +- .../__snapshots__/3.0.x/v3/default/zod.gen.ts | 321 ++---- .../3.0.x/v3/validators/zod.gen.ts | 15 +- .../3.0.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../v4/array-items-one-of-length-1/zod.gen.ts | 2 +- .../3.0.x/v4/circular/zod.gen.ts | 20 +- .../__snapshots__/3.0.x/v4/default/zod.gen.ts | 1003 +++++++---------- .../3.0.x/v4/enum-null/zod.gen.ts | 2 +- .../3.0.x/v4/type-format-zod/zod.gen.ts | 8 +- .../3.0.x/v4/validators/zod.gen.ts | 21 +- .../3.1.x/mini/default/zod.gen.ts | 333 ++---- .../defaults-with-ref-and-anyof/zod.gen.ts | 15 +- .../mini/enum-resolver-permissive/zod.gen.ts | 2 +- .../mini/validators-circular-ref-2/zod.gen.ts | 5 +- .../mini/validators-circular-ref/zod.gen.ts | 4 +- .../3.1.x/mini/validators-dates/zod.gen.ts | 19 +- .../3.1.x/mini/validators-metadata/zod.gen.ts | 31 +- .../3.1.x/mini/validators-types/zod.gen.ts | 19 +- .../3.1.x/mini/validators/zod.gen.ts | 19 +- .../__snapshots__/3.1.x/v3/default/zod.gen.ts | 321 ++---- .../v3/defaults-with-ref-and-anyof/zod.gen.ts | 15 +- .../v3/enum-resolver-permissive/zod.gen.ts | 2 +- .../v3/validators-circular-ref-2/zod.gen.ts | 5 +- .../3.1.x/v3/validators-dates/zod.gen.ts | 15 +- .../3.1.x/v3/validators-metadata/zod.gen.ts | 15 +- .../3.1.x/v3/validators-types/zod.gen.ts | 15 +- .../3.1.x/v3/validators/zod.gen.ts | 15 +- .../3.1.x/v4/array-items-all-of/zod.gen.ts | 10 +- .../v4/array-items-one-of-length-1/zod.gen.ts | 2 +- .../__snapshots__/3.1.x/v4/default/zod.gen.ts | 1001 +++++++--------- .../v4/defaults-with-ref-and-anyof/zod.gen.ts | 15 +- .../3.1.x/v4/enum-null/zod.gen.ts | 2 +- .../v4/enum-resolver-permissive/zod.gen.ts | 2 +- .../3.1.x/v4/schema-const/zod.gen.ts | 52 +- .../3.1.x/v4/type-format-zod/zod.gen.ts | 8 +- .../v4/validators-bigint-min-max/zod.gen.ts | 2 +- .../v4/validators-circular-ref-2/zod.gen.ts | 5 +- .../v4/validators-circular-ref/zod.gen.ts | 6 +- .../3.1.x/v4/validators-dates/zod.gen.ts | 51 +- .../3.1.x/v4/validators-metadata/zod.gen.ts | 65 +- .../3.1.x/v4/validators-types/zod.gen.ts | 51 +- .../v4/validators-union-merge/zod.gen.ts | 2 +- .../3.1.x/v4/validators/zod.gen.ts | 51 +- .../@hey-api/typescript/v1/toAst/array.ts | 6 +- .../@hey-api/typescript/v1/toAst/enum.ts | 6 +- .../@hey-api/typescript/v1/toAst/object.ts | 6 +- .../@hey-api/typescript/v1/toAst/tuple.ts | 6 +- .../@hey-api/typescript/v1/toAst/unknown.ts | 6 +- .../src/plugins/arktype/v2/toAst/object.ts | 6 +- .../src/plugins/valibot/resolvers/types.ts | 15 +- .../src/plugins/valibot/shared/types.ts | 27 +- .../src/plugins/valibot/v1/processor.ts | 6 +- .../src/plugins/valibot/v1/toAst/array.ts | 14 +- .../src/plugins/valibot/v1/toAst/object.ts | 21 +- .../src/plugins/valibot/v1/toAst/tuple.ts | 14 +- .../src/plugins/valibot/v1/walker.ts | 78 +- .../openapi-ts/src/plugins/zod/constants.ts | 2 + .../openapi-ts/src/plugins/zod/mini/plugin.ts | 166 +-- .../src/plugins/zod/mini/processor.ts | 26 +- .../src/plugins/zod/mini/toAst/array.ts | 58 +- .../src/plugins/zod/mini/toAst/boolean.ts | 2 +- .../src/plugins/zod/mini/toAst/enum.ts | 25 +- .../src/plugins/zod/mini/toAst/index.ts | 92 -- .../src/plugins/zod/mini/toAst/never.ts | 8 +- .../src/plugins/zod/mini/toAst/null.ts | 8 +- .../src/plugins/zod/mini/toAst/number.ts | 8 +- .../src/plugins/zod/mini/toAst/object.ts | 97 +- .../src/plugins/zod/mini/toAst/string.ts | 8 +- .../src/plugins/zod/mini/toAst/tuple.ts | 56 +- .../src/plugins/zod/mini/toAst/undefined.ts | 8 +- .../src/plugins/zod/mini/toAst/unknown.ts | 8 +- .../src/plugins/zod/mini/toAst/void.ts | 8 +- .../openapi-ts/src/plugins/zod/mini/walker.ts | 369 ++++++ .../src/plugins/zod/resolvers/types.ts | 56 +- .../src/plugins/zod/shared/export.ts | 5 +- .../src/plugins/zod/shared/types.ts | 35 +- .../openapi-ts/src/plugins/zod/v3/plugin.ts | 164 +-- .../src/plugins/zod/v3/processor.ts | 26 +- .../src/plugins/zod/v3/toAst/array.ts | 59 +- .../src/plugins/zod/v3/toAst/boolean.ts | 2 +- .../src/plugins/zod/v3/toAst/enum.ts | 24 +- .../src/plugins/zod/v3/toAst/index.ts | 112 -- .../src/plugins/zod/v3/toAst/never.ts | 8 +- .../src/plugins/zod/v3/toAst/null.ts | 8 +- .../src/plugins/zod/v3/toAst/number.ts | 8 +- .../src/plugins/zod/v3/toAst/object.ts | 103 +- .../src/plugins/zod/v3/toAst/string.ts | 8 +- .../src/plugins/zod/v3/toAst/tuple.ts | 56 +- .../src/plugins/zod/v3/toAst/undefined.ts | 8 +- .../src/plugins/zod/v3/toAst/unknown.ts | 8 +- .../src/plugins/zod/v3/toAst/void.ts | 8 +- .../openapi-ts/src/plugins/zod/v3/walker.ts | 395 +++++++ .../openapi-ts/src/plugins/zod/v4/plugin.ts | 168 +-- .../src/plugins/zod/v4/processor.ts | 26 +- .../src/plugins/zod/v4/toAst/array.ts | 58 +- .../src/plugins/zod/v4/toAst/boolean.ts | 2 +- .../src/plugins/zod/v4/toAst/enum.ts | 25 +- .../src/plugins/zod/v4/toAst/index.ts | 92 -- .../src/plugins/zod/v4/toAst/never.ts | 8 +- .../src/plugins/zod/v4/toAst/null.ts | 8 +- .../src/plugins/zod/v4/toAst/number.ts | 8 +- .../src/plugins/zod/v4/toAst/object.ts | 97 +- .../src/plugins/zod/v4/toAst/string.ts | 8 +- .../src/plugins/zod/v4/toAst/tuple.ts | 54 +- .../src/plugins/zod/v4/toAst/undefined.ts | 8 +- .../src/plugins/zod/v4/toAst/unknown.ts | 8 +- .../src/plugins/zod/v4/toAst/void.ts | 8 +- .../openapi-ts/src/plugins/zod/v4/walker.ts | 386 +++++++ packages/shared/src/index.ts | 2 +- packages/shared/src/ir/schema-walker.ts | 166 +-- 175 files changed, 5385 insertions(+), 7403 deletions(-) create mode 100644 .changeset/ninety-towns-act.md create mode 100644 .changeset/proud-trains-lay.md delete mode 100644 packages/openapi-ts/src/plugins/zod/mini/toAst/index.ts create mode 100644 packages/openapi-ts/src/plugins/zod/mini/walker.ts delete mode 100644 packages/openapi-ts/src/plugins/zod/v3/toAst/index.ts create mode 100644 packages/openapi-ts/src/plugins/zod/v3/walker.ts delete mode 100644 packages/openapi-ts/src/plugins/zod/v4/toAst/index.ts create mode 100644 packages/openapi-ts/src/plugins/zod/v4/walker.ts diff --git a/.changeset/ninety-towns-act.md b/.changeset/ninety-towns-act.md new file mode 100644 index 000000000..418e1e46a --- /dev/null +++ b/.changeset/ninety-towns-act.md @@ -0,0 +1,9 @@ +--- +"@hey-api/openapi-ts": minor +--- + +**plugin(zod)**: remove `enum.nodes.nullable` resolver node + +### Removed resolver node + +Zod plugin no longer exposes the `enum.nodes.nullable` node. It was refactored so that nullable values are handled outside of resolvers. diff --git a/.changeset/proud-trains-lay.md b/.changeset/proud-trains-lay.md new file mode 100644 index 000000000..93ae535ca --- /dev/null +++ b/.changeset/proud-trains-lay.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**plugin(zod)**: use `.nullable()` and `.nullish()` methods diff --git a/dev/inputs.ts b/dev/inputs.ts index 5ba6b7aae..0b341220e 100644 --- a/dev/inputs.ts +++ b/dev/inputs.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import { getSpecsPath } from '../packages/openapi-ts-tests/utils'; export const inputs = { - circular: path.resolve(getSpecsPath(), '3.1.x', 'circular.yaml'), + circular: path.resolve(getSpecsPath(), '3.0.x', 'circular.yaml'), full: path.resolve(getSpecsPath(), '3.1.x', 'full.yaml'), local: 'http://localhost:8000/openapi.json', opencode: path.resolve(getSpecsPath(), '3.1.x', 'opencode.yaml'), diff --git a/dev/python/plugins.ts b/dev/python/plugins.ts index 50696e7ec..cd6698d7d 100644 --- a/dev/python/plugins.ts +++ b/dev/python/plugins.ts @@ -3,8 +3,8 @@ import type { UserConfig } from '@hey-api/openapi-python'; type PluginConfig = NonNullable[number]>; export function sdk( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: '@hey-api/python-sdk' as const, ...options, @@ -12,8 +12,8 @@ export function sdk( } export function pydantic( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: 'pydantic' as const, ...options, diff --git a/dev/typescript/plugins.ts b/dev/typescript/plugins.ts index 6f7df3b12..9066c5da7 100644 --- a/dev/typescript/plugins.ts +++ b/dev/typescript/plugins.ts @@ -3,8 +3,8 @@ import type { UserConfig } from '@hey-api/openapi-ts'; type PluginConfig = NonNullable[number]>; export function typescript( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: '@hey-api/typescript' as const, ...options, @@ -12,15 +12,17 @@ export function typescript( } export function sdk( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: '@hey-api/sdk' as const, ...options, }; } -export function zod(options?: Partial, 'name'>>) { +export function zod( + options?: Omit, 'name'>, +): Extract { return { name: 'zod' as const, ...options, @@ -28,8 +30,8 @@ export function zod(options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: 'valibot' as const, ...options, @@ -37,8 +39,8 @@ export function valibot( } export function tanstackReactQuery( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: '@tanstack/react-query' as const, ...options, @@ -46,8 +48,8 @@ export function tanstackReactQuery( } export function transformers( - options?: Partial, 'name'>>, -) { + options?: Omit, 'name'>, +): Extract { return { name: '@hey-api/transformers' as const, ...options, diff --git a/packages/openapi-python/src/plugins/pydantic/v2/toAst/string.ts b/packages/openapi-python/src/plugins/pydantic/v2/toAst/string.ts index 2ef06c2bc..2f7a3bf94 100644 --- a/packages/openapi-python/src/plugins/pydantic/v2/toAst/string.ts +++ b/packages/openapi-python/src/plugins/pydantic/v2/toAst/string.ts @@ -3,11 +3,11 @@ import type { SchemaWithType } from '@hey-api/shared'; // import { $ } from '../../../../py-dsl'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const stringToNode = ({ +export function stringToNode({ schema, }: IrSchemaToAstOptions & { schema: SchemaWithType<'string'>; -}): Ast => { +}): Ast { const constraints: Record = {}; if (schema.minLength !== undefined) { @@ -45,4 +45,4 @@ export const stringToNode = ({ // pipes: [], typeAnnotation: 'str', }; -}; +} diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/transformers/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/string-with-format/zod.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/string-with-format/zod.gen.ts index c89666b67..e19b0d856 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/string-with-format/zod.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/string-with-format/zod.gen.ts @@ -3,5 +3,5 @@ import * as z from 'zod'; export const zFoo = z.object({ - foo: z.optional(z.array(z.union([z.string(), z.string()]))) + foo: z.array(z.union([z.string(), z.string()])).optional() }); diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/webhooks/zod.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/webhooks/zod.gen.ts index f0975b045..c357da977 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/webhooks/zod.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/webhooks/zod.gen.ts @@ -3,14 +3,14 @@ import * as z from 'zod'; export const zSessionUserPhoneCalloutRingingWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), session_key: z.string(), @@ -23,20 +23,20 @@ export const zSessionUserPhoneCalloutRingingWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserRoomSystemCalloutRingingWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), host_id: z.string(), @@ -48,13 +48,13 @@ export const zSessionUserRoomSystemCalloutRingingWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingStartedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_started']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -66,18 +66,18 @@ export const zSessionRecordingStartedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_file: z.object({ - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()) + recording_start: z.string().optional(), + recording_end: z.string().optional() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingResumedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_resumed']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -89,18 +89,18 @@ export const zSessionRecordingResumedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_file: z.object({ - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()) + recording_start: z.string().optional(), + recording_end: z.string().optional() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionLiveStreamingStoppedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.live_streaming_stopped']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -109,7 +109,7 @@ export const zSessionLiveStreamingStoppedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), start_time: z.iso.datetime(), live_streaming: z.object({ service: z.enum([ @@ -122,19 +122,19 @@ export const zSessionLiveStreamingStoppedWebhookRequest = z.object({ stream_url: z.string(), stream_key: z.string(), page_url: z.string(), - resolution: z.optional(z.string()) + resolution: z.string().optional() }), date_time: z.iso.datetime() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStreamIngestionStoppedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.stream_ingestion_stopped']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -142,31 +142,31 @@ export const zSessionStreamIngestionStoppedWebhookRequest = z.object({ object: z.object({ session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), stream_ingestion: z.object({ stream_id: z.string(), stream_name: z.string(), - stream_description: z.optional(z.string()), + stream_description: z.string().optional(), stream_key: z.string(), stream_url: z.string(), backup_stream_url: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserRoomSystemCalloutRejectedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), host_id: z.string(), @@ -178,13 +178,13 @@ export const zSessionUserRoomSystemCalloutRejectedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionAlertWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.alert']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -193,7 +193,7 @@ export const zSessionAlertWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), issues: z.array(z.enum([ 'Unstable audio quality', 'Unstable video quality', @@ -203,13 +203,13 @@ export const zSessionAlertWebhookRequest = z.object({ ])) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionSharingEndedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.sharing_ended']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -218,11 +218,11 @@ export const zSessionSharingEndedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), user: z.object({ id: z.string(), name: z.string(), - user_key: z.optional(z.string()), + user_key: z.string().optional(), sharing_details: z.object({ content: z.enum([ 'application', @@ -235,13 +235,13 @@ export const zSessionSharingEndedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingPausedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_paused']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -253,18 +253,18 @@ export const zSessionRecordingPausedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_file: z.object({ - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()) + recording_start: z.string().optional(), + recording_end: z.string().optional() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionEndedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.ended']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -273,18 +273,18 @@ export const zSessionEndedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), start_time: z.iso.datetime(), end_time: z.iso.datetime() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStartedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.started']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -293,17 +293,17 @@ export const zSessionStartedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), start_time: z.iso.datetime() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStreamIngestionUnbindWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.stream_ingestion_unbind']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -311,24 +311,24 @@ export const zSessionStreamIngestionUnbindWebhookRequest = z.object({ object: z.object({ session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), stream_ingestion: z.object({ stream_id: z.string(), stream_name: z.string(), - stream_description: z.optional(z.string()), + stream_description: z.string().optional(), stream_key: z.string(), stream_url: z.string(), backup_stream_url: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionLiveStreamingStartedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.live_streaming_started']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -337,7 +337,7 @@ export const zSessionLiveStreamingStartedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), start_time: z.iso.datetime(), live_streaming: z.object({ service: z.enum([ @@ -350,26 +350,26 @@ export const zSessionLiveStreamingStartedWebhookRequest = z.object({ stream_url: z.string(), stream_key: z.string(), page_url: z.string(), - resolution: z.optional(z.string()) + resolution: z.string().optional() }), date_time: z.iso.datetime() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserRoomSystemCalloutMissedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), host_id: z.string(), @@ -381,20 +381,20 @@ export const zSessionUserRoomSystemCalloutMissedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserPhoneCalloutAcceptedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), session_key: z.string(), @@ -407,13 +407,13 @@ export const zSessionUserPhoneCalloutAcceptedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserLeftWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.user_left']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -422,25 +422,25 @@ export const zSessionUserLeftWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), user: z.object({ id: z.string(), name: z.string(), leave_time: z.iso.datetime(), - leave_reason: z.optional(z.string()), - user_key: z.optional(z.string()), - phone_number: z.optional(z.string()), + leave_reason: z.string().optional(), + user_key: z.string().optional(), + phone_number: z.string().optional(), participant_uuid: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionSharingStartedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.sharing_started']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -449,11 +449,11 @@ export const zSessionSharingStartedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), user: z.object({ id: z.string(), name: z.string(), - user_key: z.optional(z.string()), + user_key: z.string().optional(), sharing_details: z.object({ content: z.enum([ 'application', @@ -466,13 +466,13 @@ export const zSessionSharingStartedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserPhoneCalloutCanceledWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -489,13 +489,13 @@ export const zSessionUserPhoneCalloutCanceledWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingTranscriptCompletedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_transcript_completed']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), download_token: z.string(), @@ -508,12 +508,12 @@ export const zSessionRecordingTranscriptCompletedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_files: z.array(z.object({ - id: z.optional(z.string()), - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()), - file_name: z.optional(z.string()), - file_path: z.optional(z.string()), - file_type: z.optional(z.enum([ + id: z.string().optional(), + recording_start: z.string().optional(), + recording_end: z.string().optional(), + file_name: z.string().optional(), + file_path: z.string().optional(), + file_type: z.enum([ 'MP4', 'M4A', 'CHAT', @@ -523,9 +523,9 @@ export const zSessionRecordingTranscriptCompletedWebhookRequest = z.object({ 'TB', 'CHAT_MESSAGE', 'TIMELINE' - ])), - file_size: z.optional(z.number()), - file_extension: z.optional(z.enum([ + ]).optional(), + file_size: z.number().optional(), + file_extension: z.enum([ 'MP4', 'M4A', 'TXT', @@ -533,10 +533,10 @@ export const zSessionRecordingTranscriptCompletedWebhookRequest = z.object({ 'CSV', 'JSON', 'JPG' - ])), - download_url: z.optional(z.string()), - status: z.optional(z.enum(['completed'])), - recording_type: z.optional(z.enum([ + ]).optional(), + download_url: z.string().optional(), + status: z.enum(['completed']).optional(), + recording_type: z.enum([ 'shared_screen_with_speaker_view(CC)', 'shared_screen_with_speaker_view', 'shared_screen_with_gallery_view', @@ -554,17 +554,17 @@ export const zSessionRecordingTranscriptCompletedWebhookRequest = z.object({ 'timeline', 'thumbnail', 'chat_message' - ])) + ]).optional() })) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingDeletedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_deleted']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -579,20 +579,20 @@ export const zSessionRecordingDeletedWebhookRequest = z.object({ timezone: z.string() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserRoomSystemCalloutFailedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), host_id: z.string(), @@ -619,13 +619,13 @@ export const zSessionUserRoomSystemCalloutFailedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingCompletedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_completed']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), download_token: z.string(), @@ -638,12 +638,12 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_files: z.array(z.object({ - id: z.optional(z.string()), - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()), - file_name: z.optional(z.string()), - file_path: z.optional(z.string()), - file_type: z.optional(z.enum([ + id: z.string().optional(), + recording_start: z.string().optional(), + recording_end: z.string().optional(), + file_name: z.string().optional(), + file_path: z.string().optional(), + file_type: z.enum([ 'MP4', 'M4A', 'CHAT', @@ -652,9 +652,9 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'CC', 'TB', 'CHAT_MESSAGE' - ])), - file_size: z.optional(z.number()), - file_extension: z.optional(z.enum([ + ]).optional(), + file_size: z.number().optional(), + file_extension: z.enum([ 'MP4', 'M4A', 'TXT', @@ -662,10 +662,10 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'CSV', 'JSON', 'JPG' - ])), - download_url: z.optional(z.string()), - status: z.optional(z.enum(['completed'])), - recording_type: z.optional(z.enum([ + ]).optional(), + download_url: z.string().optional(), + status: z.enum(['completed']).optional(), + recording_type: z.enum([ 'shared_screen_with_speaker_view(CC)', 'shared_screen_with_speaker_view', 'shared_screen_with_gallery_view', @@ -683,15 +683,15 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'timeline', 'thumbnail', 'chat_message' - ])) + ]).optional() })), - participant_audio_files: z.optional(z.array(z.object({ - id: z.optional(z.string()), - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()), - file_name: z.optional(z.string()), - file_path: z.optional(z.string()), - file_type: z.optional(z.enum([ + participant_audio_files: z.array(z.object({ + id: z.string().optional(), + recording_start: z.string().optional(), + recording_end: z.string().optional(), + file_name: z.string().optional(), + file_path: z.string().optional(), + file_type: z.enum([ 'MP4', 'M4A', 'CHAT', @@ -700,9 +700,9 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'CC', 'TB', 'CHAT_MESSAGE' - ])), - file_size: z.optional(z.number()), - file_extension: z.optional(z.enum([ + ]).optional(), + file_size: z.number().optional(), + file_extension: z.enum([ 'MP4', 'M4A', 'TXT', @@ -710,10 +710,10 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'CSV', 'JSON', 'JPG' - ])), - download_url: z.optional(z.string()), - status: z.optional(z.enum(['completed'])), - recording_type: z.optional(z.enum([ + ]).optional(), + download_url: z.string().optional(), + status: z.enum(['completed']).optional(), + recording_type: z.enum([ 'shared_screen_with_speaker_view(CC)', 'shared_screen_with_speaker_view', 'shared_screen_with_gallery_view', @@ -731,34 +731,34 @@ export const zSessionRecordingCompletedWebhookRequest = z.object({ 'timeline', 'thumbnail', 'chat_message' - ])), - user_id: z.optional(z.string()), - user_key: z.optional(z.string()) - }))), - participant_video_files: z.optional(z.array(z.object({ - id: z.optional(z.string()), - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()), - file_name: z.optional(z.string()), - file_path: z.optional(z.string()), - file_type: z.optional(z.enum(['MP4'])), - file_size: z.optional(z.number()), - file_extension: z.optional(z.enum(['MP4'])), - download_url: z.optional(z.string()), - status: z.optional(z.enum(['completed'])), - recording_type: z.optional(z.enum(['individual_user', 'individual_shared_screen'])), - user_id: z.optional(z.string()), - user_key: z.optional(z.string()) - }))) - }) - }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + ]).optional(), + user_id: z.string().optional(), + user_key: z.string().optional() + })).optional(), + participant_video_files: z.array(z.object({ + id: z.string().optional(), + recording_start: z.string().optional(), + recording_end: z.string().optional(), + file_name: z.string().optional(), + file_path: z.string().optional(), + file_type: z.enum(['MP4']).optional(), + file_size: z.number().optional(), + file_extension: z.enum(['MP4']).optional(), + download_url: z.string().optional(), + status: z.enum(['completed']).optional(), + recording_type: z.enum(['individual_user', 'individual_shared_screen']).optional(), + user_id: z.string().optional(), + user_key: z.string().optional() + })).optional() + }) + }) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingTranscriptFailedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_transcript_failed']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -771,13 +771,13 @@ export const zSessionRecordingTranscriptFailedWebhookRequest = z.object({ timezone: z.string() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingTrashedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_trashed']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -792,13 +792,13 @@ export const zSessionRecordingTrashedWebhookRequest = z.object({ timezone: z.string() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserJoinedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.user_joined']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -807,24 +807,24 @@ export const zSessionUserJoinedWebhookRequest = z.object({ id: z.string(), session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), user: z.object({ id: z.string(), name: z.string(), join_time: z.iso.datetime(), - user_key: z.optional(z.string()), - phone_number: z.optional(z.string()), + user_key: z.string().optional(), + phone_number: z.string().optional(), participant_uuid: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStreamIngestionStartedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.stream_ingestion_started']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -832,24 +832,24 @@ export const zSessionStreamIngestionStartedWebhookRequest = z.object({ object: z.object({ session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), stream_ingestion: z.object({ stream_id: z.string(), stream_name: z.string(), - stream_description: z.optional(z.string()), + stream_description: z.string().optional(), stream_key: z.string(), stream_url: z.string(), backup_stream_url: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStreamIngestionConnectedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.stream_ingestion_connected']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -857,24 +857,24 @@ export const zSessionStreamIngestionConnectedWebhookRequest = z.object({ object: z.object({ session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), stream_ingestion: z.object({ stream_id: z.string(), stream_name: z.string(), - stream_description: z.optional(z.string()), + stream_description: z.string().optional(), stream_key: z.string(), stream_url: z.string(), backup_stream_url: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionStreamIngestionDisconnectedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.stream_ingestion_disconnected']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -882,24 +882,24 @@ export const zSessionStreamIngestionDisconnectedWebhookRequest = z.object({ object: z.object({ session_id: z.string(), session_name: z.string(), - session_key: z.optional(z.string()), + session_key: z.string().optional(), stream_ingestion: z.object({ stream_id: z.string(), stream_name: z.string(), - stream_description: z.optional(z.string()), + stream_description: z.string().optional(), stream_key: z.string(), stream_url: z.string(), backup_stream_url: z.string() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingRecoveredWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_recovered']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -914,20 +914,20 @@ export const zSessionRecordingRecoveredWebhookRequest = z.object({ timezone: z.string() }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserPhoneCalloutMissedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), session_key: z.string(), @@ -940,20 +940,20 @@ export const zSessionUserPhoneCalloutMissedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserPhoneCalloutRejectedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), session_key: z.string(), @@ -966,20 +966,20 @@ export const zSessionUserPhoneCalloutRejectedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionUserRoomSystemCalloutAcceptedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.string(), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ account_id: z.string(), object: z.object({ - id: z.optional(z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })), - uuid: z.optional(z.string()), + id: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).optional(), + uuid: z.string().optional(), session_id: z.string(), session_name: z.string(), host_id: z.string(), @@ -991,13 +991,13 @@ export const zSessionUserRoomSystemCalloutAcceptedWebhookRequest = z.object({ }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zSessionRecordingStoppedWebhookRequest = z.object({ - body: z.optional(z.object({ + body: z.object({ event: z.enum(['session.recording_stopped']), event_ts: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }), payload: z.object({ @@ -1009,12 +1009,12 @@ export const zSessionRecordingStoppedWebhookRequest = z.object({ start_time: z.iso.datetime(), timezone: z.string(), recording_file: z.object({ - recording_start: z.optional(z.string()), - recording_end: z.optional(z.string()) + recording_start: z.string().optional(), + recording_end: z.string().optional() }) }) }) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/mini/default/zod.gen.ts index 3498fde56..b34b6cc9f 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/mini/default/zod.gen.ts @@ -217,14 +217,8 @@ export const zModelWithStringError = z.object({ * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.nullish(z.string()), + nullableRequiredProp: z.nullable(z.string()) }); /** @@ -293,9 +287,7 @@ export const zModelWithDictionary = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -605,14 +597,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v3/default/zod.gen.ts index 1b73135f9..e7c596b03 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v3/default/zod.gen.ts @@ -217,14 +217,8 @@ export const zModelWithStringError = z.object({ * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.string().nullish(), + nullableRequiredProp: z.string().nullable() }); /** @@ -603,14 +597,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts index 8ff0d5371..400acc952 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod/v4'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/default/zod.gen.ts index 102b4c10a..ba4b8db3c 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/default/zod.gen.ts @@ -136,8 +136,8 @@ export const zArrayWithStrings = z.array(z.string()); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** @@ -154,8 +154,8 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** @@ -167,21 +167,21 @@ export const zDate = z.string(); * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zSimpleReference = zModelWithString; @@ -210,92 +210,84 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.string().nullish(), + nullableRequiredProp: z.string().nullable() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - test: z.optional(z.enum([ + test: z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())) + ])).optional(), + arrayWithDescription: z.array(z.int()).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** @@ -304,22 +296,22 @@ export const zModelWithCircularReference = z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** @@ -337,45 +329,45 @@ export const zModelWithNestedProperties = z.object({ * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); /** @@ -384,40 +376,40 @@ export const zDefault = z.object({ export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zParameterActivityParams = z.object({ - description: z.optional(z.string()), - graduate_id: z.optional(z.int()), - organization_id: z.optional(z.int()), - parent_activity: z.optional(z.int()), - post_id: z.optional(z.int()) + description: z.string().optional(), + graduate_id: z.int().optional(), + organization_id: z.int().optional(), + parent_activity: z.int().optional(), + post_id: z.int().optional() }); export const zResponsePostActivityResponse = z.object({ - description: z.optional(z.string()), - graduate_id: z.optional(z.int()), - organization_id: z.optional(z.int()), - parent_activity_id: z.optional(z.int()), - post_id: z.optional(z.int()) + description: z.string().optional(), + graduate_id: z.int().optional(), + organization_id: z.int().optional(), + parent_activity_id: z.int().optional(), + post_id: z.int().optional() }); export const zFailureFailure = z.object({ - error: z.optional(z.string()), - message: z.optional(z.string()), - reference_code: z.optional(z.string()) + error: z.string().optional(), + message: z.string().optional(), + reference_code: z.string().optional() }); export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); export const zExternalRefA = zExternalSharedExternalSharedModel; @@ -429,20 +421,20 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -451,88 +443,88 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zServiceWithEmptyTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zCallWithParametersData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ parameterPath: z.string(), 'api-version': z.string() @@ -548,13 +540,13 @@ export const zCallWithParametersData = z.object({ export const zCallWithWeirdParameterNamesData = z.object({ body: z.string(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), 'api-version': z.string() }), query: z.object({ - default: z.optional(z.string()), + default: z.string().optional(), 'parameter-query': z.string() }), headers: z.object({ @@ -563,8 +555,8 @@ export const zCallWithWeirdParameterNamesData = z.object({ }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterString: z.string().default('Hello World!'), parameterNumber: z.number().default(123), @@ -575,81 +567,75 @@ export const zCallWithDefaultParametersData = z.object({ 'Error' ]), parameterModel: z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }).default({ prop: 'Hello World!' }) }) }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])) - })) + ]).optional() + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -658,21 +644,21 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -681,9 +667,9 @@ export const zCallWithResponseData = z.object({ export const zCallWithResponseResponse = zModelWithString; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -692,24 +678,24 @@ export const zCallWithDuplicateResponsesData = z.object({ export const zCallWithDuplicateResponsesResponse = zModelWithString; export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterArrayCSV: z.array(z.string()), parameterArraySSV: z.array(z.string()), @@ -720,10 +706,10 @@ export const zCollectionFormatData = z.object({ }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), parameterString: z.string().default('default'), @@ -746,18 +732,18 @@ export const zTypesResponse = z.union([ ]); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }) }) }); @@ -768,22 +754,22 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.string() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -796,8 +782,8 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = zNonAsciiStringæ export const zPostApiVbyApiVersionBodyData = z.object({ body: zParameterActivityParams, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts index 796146a69..9b6647e58 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/circular/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/circular/zod.gen.ts index 1563aa737..a6c351d2d 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/circular/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/circular/zod.gen.ts @@ -3,24 +3,16 @@ import * as z from 'zod/v4-mini'; export const zFoo = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.optional(z.lazy((): any => zQuux)) }); export const zBar = z.object({ - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.lazy((): any => zBaz)); - } + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.lazy((): any => zBaz)) }); export const zBaz = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.optional(z.lazy((): any => zQuux)) }); export const zQux = z.union([ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/default/zod.gen.ts index 8c943fbd9..ef26ce4a8 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)), - z.null() -]); +export const zSimpleStringWithPattern = z.nullable(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -279,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.nullish(z.string()), + nullableRequiredProp1: z.nullable(z.string()), + nullableProp2: z.nullish(z.string()), + nullableRequiredProp2: z.nullable(z.string()), 'foo_bar-enum': z.optional(z.enum([ 'Success', 'Warning', @@ -391,9 +376,7 @@ export const zDeprecatedModel = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -479,14 +462,8 @@ export const zCompositionWithAnyOfAnonymous = z.object({ */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ propA: z.optional(z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) + z.array(z.nullable(zModelWithDictionary)), + z.array(z.nullable(zModelWithArray)) ])) }); @@ -498,24 +475,20 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.nullish(z.array(z.union([z3eNum1Период, zConstValue]))) }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -553,26 +526,22 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.intersection(z.intersection(z.intersection(z.object({ - boolean: z.optional(z.boolean()) - }), zModelWithEnum), zModelWithArray), zModelWithDictionary), - z.null() - ])) + propA: z.nullish(z.intersection(z.intersection(z.intersection(z.object({ + boolean: z.optional(z.boolean()) + }), zModelWithEnum), zModelWithArray), zModelWithDictionary)) }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -599,10 +568,7 @@ export const zCompositionExtendedModel = z.intersection(zCompositionBaseModel, z export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.readonly(z.string()), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -625,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.readonly(z.union([ - z.readonly(z.object({ - second: z.readonly(z.union([ - z.readonly(z.object({ - third: z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ])) - })), - z.null() - ])) - })), - z.null() - ])) + first: z.nullable(z.readonly(z.object({ + second: z.nullable(z.readonly(z.object({ + third: z.nullable(z.readonly(z.string())) + }))) + }))) }); /** @@ -745,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.nullish(z.array(z.union([z.string(), z.boolean()]))) }); /** * An object that can be null */ -export const zNullableObject = z._default(z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]), null); +export const zNullableObject = z._default(z.nullable(z.object({ + foo: z.optional(z.string()) +})), null); /** * Some % character @@ -846,21 +797,18 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ ])); export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ - z.union([ + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]) + ])) ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -979,23 +927,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + item: z.nullish(z.string()), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())) }); @@ -1021,10 +960,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -1095,22 +1031,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.nullish(z.string()), + error: z.nullish(z.string()) }); /** @@ -1126,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1137,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1281,70 +1202,40 @@ export const zDeprecatedCallData = z.object({ path: z.optional(z.never()), query: z.optional(z.never()), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: z.nullable(zDeprecatedModel) }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.nullable(z.record(z.string(), z.unknown())), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.nullable(z.string()), + 'api-version': z.nullable(z.string()) }), query: z.object({ foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.nullable(z.string()) }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.nullable(z.string()) }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: z.nullable(zModelWithString), path: z.object({ 'parameter.path.1': z.optional(z.string()), 'parameter-path-2': z.optional(z.string()), 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.object({ default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.nullable(z.string()) }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.nullable(z.string()) }) }); @@ -1358,10 +1249,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) + offset: z.nullish(z.number()) })), path: z.optional(z.never()), query: z.object({ @@ -1394,27 +1282,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - parameterString: z._default(z.optional(z.union([ - z._default(z.string(), 'Hello World!'), - z.null() - ])), 'Hello World!'), - parameterNumber: z._default(z.optional(z.union([ - z._default(z.number(), 123), - z.null() - ])), 123), - parameterBoolean: z._default(z.optional(z.union([ - z._default(z.boolean(), true), - z.null() - ])), true), + parameterString: z._default(z.nullish(z.string()), 'Hello World!'), + parameterNumber: z._default(z.nullish(z.number()), 123), + parameterBoolean: z._default(z.nullish(z.boolean()), true), parameterEnum: z.optional(z.enum([ 'Success', 'Warning', 'Error' ])), - parameterModel: z.optional(z.union([ - zModelWithString, - z.null() - ])) + parameterModel: z.nullish(zModelWithString) })) }); @@ -1444,14 +1320,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); @@ -1559,26 +1429,11 @@ export const zCollectionFormatData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.nullable(z.array(z.string())), + parameterArraySSV: z.nullable(z.array(z.string())), + parameterArrayTSV: z.nullable(z.array(z.string())), + parameterArrayPipes: z.nullable(z.array(z.string())), + parameterArrayMulti: z.nullable(z.array(z.string())) }) }); @@ -1589,26 +1444,11 @@ export const zTypesData = z.object({ })), query: z.object({ parameterNumber: z._default(z.number(), 123), - parameterString: z._default(z.union([ - z._default(z.string(), 'default'), - z.null() - ]), 'default'), - parameterBoolean: z._default(z.union([ - z._default(z.boolean(), true), - z.null() - ]), true), - parameterObject: z._default(z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z._default(z.nullable(z.string()), 'default'), + parameterBoolean: z._default(z.nullable(z.boolean()), true), + parameterObject: z._default(z.nullable(z.record(z.string(), z.unknown())), null), + parameterArray: z.nullable(z.array(z.string())), + parameterDictionary: z.nullable(z.record(z.string(), z.unknown())), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1627,10 +1467,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.optional(z.never()) }); @@ -1691,10 +1528,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.optional(z.object({ content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) + data: z.nullish(zModelWithString) })), path: z.optional(z.never()), query: z.optional(z.never()) @@ -1702,28 +1536,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.optional(z.object({ - key: z.readonly(z.union([ - z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))), - z.null() - ])), - name: z.union([ - z.string().check(z.maxLength(255)), - z.null() - ]), + key: z.nullable(z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)))), + name: z.nullable(z.string().check(z.maxLength(255))), enabled: z._default(z.optional(z.boolean()), true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.nullish(z.array(zModelWithString)), + listOfStrings: z.nullish(z.array(z.string())), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1732,10 +1554,7 @@ export const zComplexParamsData = z.object({ ]), user: z.optional(z.readonly(z.object({ id: z.optional(z.readonly(z.int().check(z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })))), - name: z.optional(z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ]))) + name: z.nullish(z.readonly(z.string())) }))) })), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/validators/zod.gen.ts index cfa348c12..fd4b0647c 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/mini/validators/zod.gen.ts @@ -4,19 +4,12 @@ import * as z from 'zod/v4-mini'; export const zBaz = z._default(z.readonly(z.string().check(z.regex(/foo\nbar/))), 'baz'); -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); export const zBar = z.object({ foo: z.optional(zFoo) diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/default/zod.gen.ts index f12f1b5f4..3bacc0572 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -279,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -477,14 +462,8 @@ export const zCompositionWithAnyOfAnonymous = z.object({ */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ propA: z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) + z.array(zModelWithDictionary.nullable()), + z.array(zModelWithArray.nullable()) ]).optional() }); @@ -496,10 +475,7 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ]).optional() + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** @@ -512,9 +488,8 @@ export const zCompositionWithOneOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -551,12 +526,9 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.union([ - z.object({ - boolean: z.boolean().optional() - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ]).optional() + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** @@ -569,9 +541,8 @@ export const zCompositionWithAnyOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -597,10 +568,7 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -623,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** @@ -743,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ]).optional() + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.string().optional() - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -846,19 +799,16 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -977,23 +927,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + item: z.string().nullish(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional() }); @@ -1019,10 +960,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -1093,22 +1031,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional() + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1124,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1135,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1279,70 +1202,40 @@ export const zDeprecatedCallData = z.object({ path: z.never().optional(), query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.unknown()), - z.null() - ]), + body: z.record(z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ 'parameter.path.1': z.string().optional(), 'parameter-path-2': z.string().optional(), 'PARAMETER-PATH-3': z.string().optional(), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.object({ default: z.string().optional(), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); @@ -1356,10 +1249,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.object({ - offset: z.union([ - z.number(), - z.null() - ]).optional() + offset: z.number().nullish() }).optional(), path: z.never().optional(), query: z.object({ @@ -1392,27 +1282,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterString: z.union([ - z.string().default('Hello World!'), - z.null() - ]).optional().default('Hello World!'), - parameterNumber: z.union([ - z.number().default(123), - z.null() - ]).optional().default(123), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).optional().default(true), + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), parameterEnum: z.enum([ 'Success', 'Warning', 'Error' ]).optional(), - parameterModel: z.union([ - zModelWithString, - z.null() - ]).optional() + parameterModel: zModelWithString.nullish() }).optional() }); @@ -1442,14 +1320,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); @@ -1557,26 +1429,11 @@ export const zCollectionFormatData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); @@ -1587,26 +1444,11 @@ export const zTypesData = z.object({ }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.unknown()).nullable(), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1625,10 +1467,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.never().optional() }); @@ -1689,10 +1528,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.object({ content: z.string().optional(), - data: z.union([ - zModelWithString, - z.null() - ]).optional() + data: zModelWithString.nullish() }).optional(), path: z.never().optional(), query: z.never().optional() @@ -1700,28 +1536,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.union([ - z.array(zModelWithString), - z.null() - ]).optional(), - listOfStrings: z.union([ - z.array(z.string()), - z.null() - ]).optional(), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1730,10 +1554,7 @@ export const zComplexParamsData = z.object({ ]), user: z.object({ id: z.number().int().min(-2147483648, { message: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { message: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), - name: z.union([ - z.string().readonly(), - z.null() - ]).readonly().optional() + name: z.string().readonly().nullish() }).readonly().optional() }).optional(), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/validators/zod.gen.ts index 9d727f32d..a1fd0b756 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v3/validators/zod.gen.ts @@ -4,15 +4,12 @@ import { z } from 'zod'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); export const zBar = z.object({ foo: zFoo.optional() diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts index 8ff0d5371..400acc952 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod/v4'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts index e1f2e86f8..92dfb2397 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts @@ -5,5 +5,5 @@ import * as z from 'zod/v4'; export const zBar = z.string(); export const zFoo = z.object({ - foo: z.optional(z.array(zBar).min(1).max(2147483647)) + foo: z.array(zBar).min(1).max(2147483647).optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/circular/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/circular/zod.gen.ts index 33afdca46..f17d72150 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/circular/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/circular/zod.gen.ts @@ -3,24 +3,16 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.lazy((): any => zQuux).optional() }); export const zBar = z.object({ - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.lazy((): any => zBaz)); - } + bar: z.lazy((): any => zBar).optional(), + baz: z.lazy((): any => zBaz).optional() }); export const zBaz = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.lazy((): any => zQuux).optional() }); export const zQux = z.union([ @@ -33,9 +25,9 @@ export const zQux = z.union([ ]); export const zQuux = z.object({ - qux: z.optional(zQux) + qux: zQux.optional() }); export const zCorge = z.object({ - baz: z.optional(z.array(zBaz)) + baz: z.array(zBaz).optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/default/zod.gen.ts index dbf7906f6..022229c77 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -166,32 +163,32 @@ export const zArrayWithStrings = z.array(z.string()).default(['test']); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - '16x16': z.optional(zCamelCaseCommentWithBreaks), - bar: z.optional(z.string()) + '16x16': zCamelCaseCommentWithBreaks.optional(), + bar: z.string().optional() })); /** * This is a simple array with any of properties */ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ - foo: z.optional(z.string()).default('test') + foo: z.string().optional().default('test') }), z.object({ - bar: z.optional(z.string()) + bar: z.string().optional() })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.unknown()) + data: z.unknown().optional() }); /** * This is a simple array with any of properties */ export const zAnyOfArrays = z.object({ - results: z.optional(z.array(z.union([z.object({ - foo: z.optional(z.string()) + results: z.array(z.union([z.object({ + foo: z.string().optional() }), z.object({ - bar: z.optional(z.string()) - })]))) + bar: z.string().optional() + })])).optional() }); /** @@ -200,8 +197,8 @@ export const zAnyOfArrays = z.object({ export const zDictionaryWithString = z.record(z.string(), z.string()); export const zDictionaryWithPropertiesAndAdditionalProperties = z.object({ - foo: z.optional(z.number()), - bar: z.optional(z.boolean()) + foo: z.number().optional(), + bar: z.boolean().optional() }); /** @@ -213,29 +210,29 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -267,7 +264,7 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -279,103 +276,91 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), - 'foo_bar-enum': z.optional(z.enum([ + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - 'foo_bar-enum': z.optional(z.enum([ + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum with escaped name */ export const zModelWithEnumWithHyphen = z.object({ - 'foo-bar-baz-qux': z.optional(z.enum(['3.0'])) + 'foo-bar-baz-qux': z.enum(['3.0']).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())), - 'foo_bar-enum': z.optional(z.enum([ + ])).optional(), + arrayWithDescription: z.array(z.int()).optional(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** @@ -384,41 +369,39 @@ export const zModelWithDictionary = z.object({ * @deprecated */ export const zDeprecatedModel = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'one of' relationship where the options are not $ref */ export const zCompositionWithOneOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** @@ -426,7 +409,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ */ export const zModelCircle = z.object({ kind: z.string(), - radius: z.optional(z.number()) + radius: z.number().optional() }); /** @@ -434,7 +417,7 @@ export const zModelCircle = z.object({ */ export const zModelSquare = z.object({ kind: z.string(), - sideLength: z.optional(z.number()) + sideLength: z.number().optional() }); /** @@ -453,41 +436,35 @@ export const zCompositionWithOneOfDiscriminator = z.union([ * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithAnyOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** * This is a model with nested 'any of' property with a type null */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) - ])) + propA: z.union([ + z.array(zModelWithDictionary.nullable()), + z.array(zModelWithArray.nullable()) + ]).optional() }); export const z3eNum1Период = z.enum(['Bird', 'Dog']); @@ -498,90 +475,82 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a model that contains a simple dictionary within composition */ export const zCompositionWithOneOfAndSimpleDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.number()) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of simple arrays within composition */ export const zCompositionWithOneOfAndSimpleArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.boolean())) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of complex arrays (composited) within composition */ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.union([z.number(), z.string()]))) - ])) + ]).optional() }); /** * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.object({ - boolean: z.optional(z.boolean()) - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ])) + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a base model with two simple optional properties */ export const zCompositionBaseModel = z.object({ - firstName: z.optional(z.string()), - lastname: z.optional(z.string()) + firstName: z.string().optional(), + lastname: z.string().optional() }); /** @@ -599,87 +568,75 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); /** @@ -688,31 +645,31 @@ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends). export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFile = z.object({ - id: z.optional(z.string().min(1).readonly()), - updated_at: z.optional(z.iso.datetime().readonly()), - created_at: z.optional(z.iso.datetime().readonly()), + id: z.string().min(1).readonly().optional(), + updated_at: z.iso.datetime().readonly().optional(), + created_at: z.iso.datetime().readonly().optional(), mime: z.string().min(1).max(24), - file: z.optional(z.url().readonly()) + file: z.url().readonly().optional() }); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); export const zPageable = z.object({ - page: z.optional(z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })).default(0), - size: z.optional(z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })), - sort: z.optional(z.array(z.string())) + page: z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(0), + size: z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + sort: z.array(z.string()).optional() }); /** @@ -731,35 +688,29 @@ export const zFreeFormObjectWithAdditionalPropertiesEqTrue = z.record(z.string() export const zFreeFormObjectWithAdditionalPropertiesEqEmptyObject = z.record(z.string(), z.unknown()); export const zModelWithConst = z.object({ - String: z.optional(z.enum(['String'])), - number: z.optional(z.literal(0)), - null: z.optional(z.unknown()), - withType: z.optional(z.enum(['Some string'])) + String: z.enum(['String']).optional(), + number: z.literal(0).optional(), + null: z.unknown().optional(), + withType: z.enum(['Some string']).optional() }); /** * This is a model with one property and additionalProperties: true */ export const zModelWithAdditionalPropertiesEqTrue = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -767,7 +718,7 @@ export const zNullableObject = z.union([ export const zCharactersInDescription = z.string(); export const zModelWithNullableObject = z.object({ - data: z.optional(zNullableObject) + data: zNullableObject.optional() }); export const zModelWithOneOfEnum = z.union([ @@ -795,17 +746,17 @@ export const zModelWithNestedArrayEnumsDataFoo = z.enum(['foo', 'bar']); export const zModelWithNestedArrayEnumsDataBar = z.enum(['baz', 'qux']); export const zModelWithNestedArrayEnumsData = z.object({ - foo: z.optional(z.array(zModelWithNestedArrayEnumsDataFoo)), - bar: z.optional(z.array(zModelWithNestedArrayEnumsDataBar)) + foo: z.array(zModelWithNestedArrayEnumsDataFoo).optional(), + bar: z.array(zModelWithNestedArrayEnumsDataBar).optional() }); export const zModelWithNestedArrayEnums = z.object({ - array_strings: z.optional(z.array(z.string())), - data: z.optional(zModelWithNestedArrayEnumsData) + array_strings: z.array(z.string()).optional(), + data: zModelWithNestedArrayEnumsData.optional() }); export const zModelWithNestedCompositionEnums = z.object({ - foo: z.optional(zModelWithNestedArrayEnumsDataFoo) + foo: zModelWithNestedArrayEnumsDataFoo.optional() }); export const zModelWithReadOnlyAndWriteOnly = z.object({ @@ -817,9 +768,9 @@ export const zModelWithReadOnlyAndWriteOnly = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnly = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnly)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnly).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithConstantSizeArray = z.tuple([z.number(), z.number()]); @@ -848,25 +799,22 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); export const zModelWithNumericEnumUnion = z.object({ - value: z.optional(z.union([ + value: z.union([ z.literal(-10), z.literal(-1), z.literal(0), @@ -874,14 +822,14 @@ export const zModelWithNumericEnumUnion = z.object({ z.literal(3), z.literal(6), z.literal(12) - ])) + ]).optional() }); /** * Some description with `back ticks` */ export const zModelWithBackticksInDescription = z.object({ - template: z.optional(z.string()) + template: z.string().optional() }); /** @@ -923,40 +871,40 @@ export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([z.un ])]); export const zSchemaWithFormRestrictedKeys = z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()), - object: z.optional(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - })), - array: z.optional(z.array(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - }))) + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional(), + object: z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + }).optional(), + array: z.array(z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + })).optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1Preconditions = z.object({ - resourceVersion: z.optional(z.string()), - uid: z.optional(z.string()) + resourceVersion: z.string().optional(), + uid: z.string().optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1DeleteOptions = z.object({ - preconditions: z.optional(zIoK8sApimachineryPkgApisMetaV1Preconditions) + preconditions: zIoK8sApimachineryPkgApisMetaV1Preconditions.optional() }); export const zAdditionalPropertiesUnknownIssue = z.record(z.string(), z.union([ @@ -978,25 +926,16 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ }); export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()) + item: z.string().nullish(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional() }); export const zOneOfAllOfIssue = z.union([ @@ -1009,7 +948,7 @@ export const zOneOfAllOfIssue = z.union([ export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); export const zExternalRefA = zExternalSharedExternalSharedModel; @@ -1021,24 +960,21 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -1047,11 +983,11 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFileWritable = z.object({ @@ -1067,9 +1003,9 @@ export const zModelWithReadOnlyAndWriteOnlyWritable = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnlyWritable = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnlyWritable)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnlyWritable).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = z.tuple([z.union([ @@ -1094,23 +1030,14 @@ export const zOneOfAllOfIssueWritable = z.union([ ]); export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1126,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1137,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1154,15 +1075,15 @@ export const zSimpleRequestBody = zModelWithString; export const zSimpleFormData = zModelWithString; export const zExportData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zImportData = z.object({ @@ -1170,8 +1091,8 @@ export const zImportData = z.object({ zModelWithReadOnlyAndWriteOnlyWritable, zModelWithArrayReadOnlyAndWriteOnlyWritable ]), - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export const zImportResponse = z.union([ @@ -1180,15 +1101,15 @@ export const zImportResponse = z.union([ ]); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zApiVVersionODataControllerCountData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1197,11 +1118,11 @@ export const zApiVVersionODataControllerCountData = z.object({ export const zApiVVersionODataControllerCountResponse = zModelFromZendesk; export const zGetApiVbyApiVersionSimpleOperationData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1210,160 +1131,127 @@ export const zGetApiVbyApiVersionSimpleOperationData = z.object({ export const zGetApiVbyApiVersionSimpleOperationResponse = z.number(); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteFooData3 = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string(), BarParam: z.string() }), - query: z.optional(z.never()), + query: z.never().optional(), headers: z.object({ 'x-Foo-Bar': zModelWithString }) }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zDeprecatedCallData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.record(z.string(), z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ - foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), + foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), + 'api-version': z.string().nullable() }), query: z.object({ - default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + default: z.string().optional(), + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); export const zGetCallWithOptionalParamData = z.object({ body: zModelWithOneOfEnum, - path: z.optional(z.never()), - query: z.optional(z.object({ - page: z.optional(z.number()) - })) + path: z.never().optional(), + query: z.object({ + page: z.number().optional() + }).optional() }); export const zPostCallWithOptionalParamData = z.object({ - body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) - })), - path: z.optional(z.never()), + body: z.object({ + offset: z.number().nullish() + }).optional(), + path: z.never().optional(), query: z.object({ parameter: zPageable }) @@ -1375,114 +1263,96 @@ export const zPostCallWithOptionalParamResponse = z.union([ ]); export const zPostApiVbyApiVersionRequestBodyData = z.object({ - body: z.optional(zSimpleRequestBody), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleRequestBody.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zPostApiVbyApiVersionFormDataData = z.object({ - body: z.optional(zSimpleFormData), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleFormData.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.union([ - z.string().default('Hello World!'), - z.null() - ])).default('Hello World!'), - parameterNumber: z.optional(z.union([ - z.number().default(123), - z.null() - ])).default(123), - parameterBoolean: z.optional(z.union([ - z.boolean().default(true), - z.null() - ])).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })) + ]).optional(), + parameterModel: zModelWithString.nullish() + }).optional() }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(zModelWithString) - })) + ]).optional(), + parameterModel: zModelWithString.optional() + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1491,9 +1361,9 @@ export const zCallWithNoContentResponseData = z.object({ export const zCallWithNoContentResponseResponse = z.void(); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -1502,17 +1372,17 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyAResponse = z400; export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1521,17 +1391,17 @@ export const zDummyBData = z.object({ export const zDummyBResponse = z.void(); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseResponse = zImport; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDuplicateResponsesResponse = z.union([ @@ -1540,75 +1410,45 @@ export const zCallWithDuplicateResponsesResponse = z.union([ ]); export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.string(), z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.string(), z.unknown()).nullable(), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1627,23 +1467,20 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), - query: z.optional(z.never()) + query: z.never().optional() }); export const zUploadFileResponse = z.boolean(); export const zFileResponseData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ id: z.string(), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1652,15 +1489,15 @@ export const zFileResponseData = z.object({ export const zFileResponseResponse = z.string(); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: zModelWithString }) @@ -1672,77 +1509,59 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zMultipartResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** * OK */ export const zMultipartResponseResponse = z.object({ - file: z.optional(z.string()), - metadata: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) - })) + file: z.string().optional(), + metadata: z.object({ + foo: z.string().optional(), + bar: z.string().optional() + }).optional() }); export const zMultipartRequestData = z.object({ - body: z.optional(z.object({ - content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.object({ + content: z.string().optional(), + data: zModelWithString.nullish() + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zComplexParamsData = z.object({ - body: z.optional(z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), - enabled: z.optional(z.boolean()).default(true), + body: z.object({ + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), + enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary ]), - user: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly()), - name: z.optional(z.union([ - z.string().readonly(), - z.null() - ]).readonly()) - }).readonly()) - })), + user: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), + name: z.string().readonly().nullish() + }).readonly().optional() + }).optional(), path: z.object({ id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1751,22 +1570,22 @@ export const zComplexParamsData = z.object({ export const zComplexParamsResponse = zModelWithString; export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.int() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -1779,6 +1598,6 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = z.array(zNonAsciiS export const zPutWithFormUrlEncodedData = z.object({ body: zArrayWithStrings, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts index d75ecfc9c..60e4c5a54 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod/v4'; -export const zFoo = z.nullable(z.enum(['foo', 'bar'])); +export const zFoo = z.enum(['foo', 'bar']).nullable(); export const zBar = z.enum(['foo', 'bar']); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts index 796146a69..9b6647e58 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/validators/zod.gen.ts index ee041b409..7618e3266 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.0.x/v4/validators/zod.gen.ts @@ -4,20 +4,13 @@ import * as z from 'zod/v4'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/default/zod.gen.ts index 66435ffcc..4fc868122 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)), - z.null() -]); +export const zSimpleStringWithPattern = z.nullable(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -180,10 +177,7 @@ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.union([ - z.unknown(), - z.null() - ])) + data: z.nullish(z.unknown()) }); /** @@ -282,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.nullish(z.string()), + nullableRequiredProp1: z.nullable(z.string()), + nullableProp2: z.nullish(z.string()), + nullableRequiredProp2: z.nullable(z.string()), 'foo_bar-enum': z.optional(z.enum([ 'Success', 'Warning', @@ -394,9 +376,7 @@ export const zDeprecatedModel = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -495,24 +475,20 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.nullish(z.array(z.union([z3eNum1Период, zConstValue]))) }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -550,26 +526,22 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.intersection(z.intersection(z.intersection(z.object({ - boolean: z.optional(z.boolean()) - }), zModelWithEnum), zModelWithArray), zModelWithDictionary), - z.null() - ])) + propA: z.nullish(z.intersection(z.intersection(z.intersection(z.object({ + boolean: z.optional(z.boolean()) + }), zModelWithEnum), zModelWithArray), zModelWithDictionary)) }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -596,10 +568,7 @@ export const zCompositionExtendedModel = z.intersection(zCompositionBaseModel, z export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.readonly(z.string()), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -622,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.readonly(z.union([ - z.readonly(z.object({ - second: z.readonly(z.union([ - z.readonly(z.object({ - third: z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ])) - })), - z.null() - ])) - })), - z.null() - ])) + first: z.nullable(z.readonly(z.object({ + second: z.nullable(z.readonly(z.object({ + third: z.nullable(z.readonly(z.string())) + }))) + }))) }); /** @@ -742,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.nullish(z.array(z.union([z.string(), z.boolean()]))) }); /** * An object that can be null */ -export const zNullableObject = z._default(z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]), null); +export const zNullableObject = z._default(z.nullable(z.object({ + foo: z.optional(z.string()) +})), null); /** * Some % character @@ -846,21 +800,18 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ ]); export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ - z.union([ + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]) + ])) ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -979,23 +930,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + item: z.nullish(z.string()), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())) }); @@ -1027,10 +969,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -1101,22 +1040,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.nullish(z.string()), + error: z.nullish(z.string()) }); /** @@ -1132,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1143,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1296,70 +1220,40 @@ export const zDeprecatedCallData = z.object({ path: z.optional(z.never()), query: z.optional(z.never()), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: z.nullable(zDeprecatedModel) }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.nullable(z.record(z.string(), z.unknown())), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.nullable(z.string()), + 'api-version': z.nullable(z.string()) }), query: z.object({ foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.nullable(z.string()) }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.nullable(z.string()) }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: z.nullable(zModelWithString), path: z.object({ 'parameter.path.1': z.optional(z.string()), 'parameter-path-2': z.optional(z.string()), 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.object({ default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.nullable(z.string()) }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.nullable(z.string()) }) }); @@ -1373,10 +1267,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) + offset: z.nullish(z.number()) })), path: z.optional(z.never()), query: z.object({ @@ -1409,27 +1300,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - parameterString: z._default(z.optional(z.union([ - z._default(z.string(), 'Hello World!'), - z.null() - ])), 'Hello World!'), - parameterNumber: z._default(z.optional(z.union([ - z._default(z.number(), 123), - z.null() - ])), 123), - parameterBoolean: z._default(z.optional(z.union([ - z._default(z.boolean(), true), - z.null() - ])), true), + parameterString: z._default(z.nullish(z.string()), 'Hello World!'), + parameterNumber: z._default(z.nullish(z.number()), 123), + parameterBoolean: z._default(z.nullish(z.boolean()), true), parameterEnum: z.optional(z.enum([ 'Success', 'Warning', 'Error' ])), - parameterModel: z.optional(z.union([ - z._default(zModelWithString, { prop: 'Hello World!' }), - z.null() - ])) + parameterModel: z.nullish(zModelWithString) })) }); @@ -1459,14 +1338,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); @@ -1574,26 +1447,11 @@ export const zCollectionFormatData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.nullable(z.array(z.string())), + parameterArraySSV: z.nullable(z.array(z.string())), + parameterArrayTSV: z.nullable(z.array(z.string())), + parameterArrayPipes: z.nullable(z.array(z.string())), + parameterArrayMulti: z.nullable(z.array(z.string())) }) }); @@ -1604,32 +1462,16 @@ export const zTypesData = z.object({ })), query: z.object({ parameterNumber: z._default(z.number(), 123), - parameterString: z._default(z.union([ - z._default(z.string(), 'default'), - z.null() - ]), 'default'), - parameterBoolean: z._default(z.union([ - z._default(z.boolean(), true), - z.null() - ]), true), - parameterObject: z._default(z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), - parameterEnum: z.union([ + parameterString: z._default(z.nullable(z.string()), 'default'), + parameterBoolean: z._default(z.nullable(z.boolean()), true), + parameterObject: z._default(z.nullable(z.record(z.string(), z.unknown())), null), + parameterArray: z.nullable(z.array(z.string())), + parameterDictionary: z.nullable(z.record(z.string(), z.unknown())), + parameterEnum: z.nullable(z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ])) }) }); @@ -1643,10 +1485,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.optional(z.never()) }); @@ -1707,10 +1546,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.optional(z.object({ content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) + data: z.nullish(zModelWithString) })), path: z.optional(z.never()), query: z.optional(z.never()) @@ -1718,28 +1554,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.optional(z.object({ - key: z.readonly(z.union([ - z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))), - z.null() - ])), - name: z.union([ - z.string().check(z.maxLength(255)), - z.null() - ]), + key: z.nullable(z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)))), + name: z.nullable(z.string().check(z.maxLength(255))), enabled: z._default(z.optional(z.boolean()), true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.nullish(z.array(zModelWithString)), + listOfStrings: z.nullish(z.array(z.string())), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1748,10 +1572,7 @@ export const zComplexParamsData = z.object({ ]), user: z.optional(z.readonly(z.object({ id: z.optional(z.readonly(z.int().check(z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })))), - name: z.optional(z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ]))) + name: z.nullish(z.readonly(z.string())) }))) })), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts index 60ea6ed96..6f60a52cf 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod/v4-mini'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.nullable(z.union([z.enum(['foo', 'bar']), z.string()])); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts index 3a8f1806c..133c88c8f 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import * as z from 'zod/v4-mini'; export const zBar = z.object({ - bar: z.union([ - z.array(z.lazy((): any => zBar)), - z.null() - ]) + bar: z.nullable(z.array(z.lazy((): any => zBar))) }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts index dda5d4694..d1aa42ffa 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts @@ -3,9 +3,7 @@ import * as z from 'zod/v4-mini'; export const zBar = z.object({ - get bar() { - return z.optional(z.array(z.lazy((): any => zBar))); - } + bar: z.optional(z.array(z.lazy((): any => zBar))) }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts index 8ecedac9a..9b93e42fc 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts @@ -11,19 +11,12 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts index 789eb6d8a..87ec55918 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts @@ -11,25 +11,18 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/)).register(z.globalRegistry, { - description: 'This is foo property.' - })), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { - description: 'This is baz property.' - })); - }, - qux: z._default(z.optional(z.int().check(z.gt(0)).register(z.globalRegistry, { - description: 'This is qux property.' - })), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/)).register(z.globalRegistry, { + description: 'This is foo property.' + })), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { + description: 'This is baz property.' + })), + qux: z._default(z.optional(z.int().check(z.gt(0)).register(z.globalRegistry, { + description: 'This is qux property.' + })), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts index a8353e832..272e5ee8b 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts @@ -15,19 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); export type FooZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators/zod.gen.ts index 304d89bb5..e21539a88 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/mini/validators/zod.gen.ts @@ -11,19 +11,12 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/default/zod.gen.ts index d61228f60..4742b6e60 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -180,10 +177,7 @@ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ })])); export const zAnyOfAnyAndNull = z.object({ - data: z.union([ - z.unknown(), - z.null() - ]).optional() + data: z.unknown().nullish() }); /** @@ -282,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -493,10 +475,7 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ]).optional() + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** @@ -509,9 +488,8 @@ export const zCompositionWithOneOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -548,12 +526,9 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.union([ - z.object({ - boolean: z.boolean().optional() - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ]).optional() + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** @@ -566,9 +541,8 @@ export const zCompositionWithAnyOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -594,10 +568,7 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -620,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** @@ -740,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ]).optional() + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.string().optional() - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -846,19 +802,16 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -977,23 +930,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + item: z.string().nullish(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional() }); @@ -1025,10 +969,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -1099,22 +1040,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional() + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1130,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1141,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1294,70 +1220,40 @@ export const zDeprecatedCallData = z.object({ path: z.never().optional(), query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.unknown()), - z.null() - ]), + body: z.record(z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ 'parameter.path.1': z.string().optional(), 'parameter-path-2': z.string().optional(), 'PARAMETER-PATH-3': z.string().optional(), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.object({ default: z.string().optional(), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); @@ -1371,10 +1267,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.object({ - offset: z.union([ - z.number(), - z.null() - ]).optional() + offset: z.number().nullish() }).optional(), path: z.never().optional(), query: z.object({ @@ -1407,27 +1300,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterString: z.union([ - z.string().default('Hello World!'), - z.null() - ]).optional().default('Hello World!'), - parameterNumber: z.union([ - z.number().default(123), - z.null() - ]).optional().default(123), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).optional().default(true), + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), parameterEnum: z.enum([ 'Success', 'Warning', 'Error' ]).optional(), - parameterModel: z.union([ - zModelWithString.default({ prop: 'Hello World!' }), - z.null() - ]).optional() + parameterModel: zModelWithString.nullish() }).optional() }); @@ -1457,14 +1338,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); @@ -1572,26 +1447,11 @@ export const zCollectionFormatData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); @@ -1602,32 +1462,16 @@ export const zTypesData = z.object({ }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.unknown()).nullable(), parameterEnum: z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ]).nullable() }) }); @@ -1641,10 +1485,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.never().optional() }); @@ -1705,10 +1546,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.object({ content: z.string().optional(), - data: z.union([ - zModelWithString, - z.null() - ]).optional() + data: zModelWithString.nullish() }).optional(), path: z.never().optional(), query: z.never().optional() @@ -1716,28 +1554,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.union([ - z.array(zModelWithString), - z.null() - ]).optional(), - listOfStrings: z.union([ - z.array(z.string()), - z.null() - ]).optional(), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1746,10 +1572,7 @@ export const zComplexParamsData = z.object({ ]), user: z.object({ id: z.number().int().min(-2147483648, { message: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { message: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), - name: z.union([ - z.string().readonly(), - z.null() - ]).readonly().optional() + name: z.string().readonly().nullish() }).readonly().optional() }).optional(), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts index 8e2f23122..ebf95932f 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]).nullable(); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts index f2c188be3..b2db86b0e 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import { z } from 'zod'; export const zBar: z.AnyZodObject = z.object({ - bar: z.union([ - z.array(z.lazy(() => zBar)), - z.null() - ]) + bar: z.array(z.lazy(() => zBar)).nullable() }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts index c9317d591..56a06552a 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts index 58ea4d7b8..685be7b15 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).describe('This is foo property.').optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).describe('This is baz property.').optional(), - qux: z.number().int().gt(0).describe('This is qux property.').optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).describe('This is foo property.').optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).describe('This is baz property.').optional(), + qux: z.number().int().gt(0).describe('This is qux property.').optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts index c26d40cf3..89abc2a22 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts @@ -15,15 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); export type FooZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators/zod.gen.ts index 8e5318a8c..9ccffb61d 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v3/validators/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts index 8ff0d5371..400acc952 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod/v4'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts index e1f2e86f8..92dfb2397 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts @@ -5,5 +5,5 @@ import * as z from 'zod/v4'; export const zBar = z.string(); export const zFoo = z.object({ - foo: z.optional(z.array(zBar).min(1).max(2147483647)) + foo: z.array(zBar).min(1).max(2147483647).optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/default/zod.gen.ts index 2b94366c7..5fd7046ad 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -166,35 +163,32 @@ export const zArrayWithStrings = z.array(z.string()).default(['test']); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - '16x16': z.optional(zCamelCaseCommentWithBreaks), - bar: z.optional(z.string()) + '16x16': zCamelCaseCommentWithBreaks.optional(), + bar: z.string().optional() })); /** * This is a simple array with any of properties */ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ - foo: z.optional(z.string()).default('test') + foo: z.string().optional().default('test') }), z.object({ - bar: z.optional(z.string()) + bar: z.string().optional() })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.union([ - z.unknown(), - z.null() - ])) + data: z.unknown().nullish() }); /** * This is a simple array with any of properties */ export const zAnyOfArrays = z.object({ - results: z.optional(z.array(z.union([z.object({ - foo: z.optional(z.string()) + results: z.array(z.union([z.object({ + foo: z.string().optional() }), z.object({ - bar: z.optional(z.string()) - })]))) + bar: z.string().optional() + })])).optional() }); /** @@ -203,8 +197,8 @@ export const zAnyOfArrays = z.object({ export const zDictionaryWithString = z.record(z.string(), z.string()); export const zDictionaryWithPropertiesAndAdditionalProperties = z.object({ - foo: z.optional(z.number()), - bar: z.optional(z.boolean()) + foo: z.number().optional(), + bar: z.boolean().optional() }); /** @@ -216,29 +210,29 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -270,7 +264,7 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -282,103 +276,91 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), - 'foo_bar-enum': z.optional(z.enum([ + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - 'foo_bar-enum': z.optional(z.enum([ + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum with escaped name */ export const zModelWithEnumWithHyphen = z.object({ - 'foo-bar-baz-qux': z.optional(z.enum(['3.0'])) + 'foo-bar-baz-qux': z.enum(['3.0']).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())), - 'foo_bar-enum': z.optional(z.enum([ + ])).optional(), + arrayWithDescription: z.array(z.int()).optional(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** @@ -387,41 +369,39 @@ export const zModelWithDictionary = z.object({ * @deprecated */ export const zDeprecatedModel = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'one of' relationship where the options are not $ref */ export const zCompositionWithOneOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** @@ -429,7 +409,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ */ export const zModelCircle = z.object({ kind: z.string(), - radius: z.optional(z.number()) + radius: z.number().optional() }); /** @@ -437,7 +417,7 @@ export const zModelCircle = z.object({ */ export const zModelSquare = z.object({ kind: z.string(), - sideLength: z.optional(z.number()) + sideLength: z.number().optional() }); /** @@ -456,35 +436,35 @@ export const zCompositionWithOneOfDiscriminator = z.union([ * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithAnyOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** * This is a model with nested 'any of' property with a type null */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.array(z.union([zModelWithDictionary, z.null()])), z.array(z.union([zModelWithArray, z.null()])) - ])) + ]).optional() }); export const z3eNum1Период = z.enum(['Bird', 'Dog']); @@ -495,90 +475,82 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a model that contains a simple dictionary within composition */ export const zCompositionWithOneOfAndSimpleDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.number()) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of simple arrays within composition */ export const zCompositionWithOneOfAndSimpleArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.boolean())) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of complex arrays (composited) within composition */ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.union([z.number(), z.string()]))) - ])) + ]).optional() }); /** * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.object({ - boolean: z.optional(z.boolean()) - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ])) + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a base model with two simple optional properties */ export const zCompositionBaseModel = z.object({ - firstName: z.optional(z.string()), - lastname: z.optional(z.string()) + firstName: z.string().optional(), + lastname: z.string().optional() }); /** @@ -596,87 +568,75 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); /** @@ -685,31 +645,31 @@ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends). export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFile = z.object({ - id: z.optional(z.string().min(1).readonly()), - updated_at: z.optional(z.iso.datetime().readonly()), - created_at: z.optional(z.iso.datetime().readonly()), + id: z.string().min(1).readonly().optional(), + updated_at: z.iso.datetime().readonly().optional(), + created_at: z.iso.datetime().readonly().optional(), mime: z.string().min(1).max(24), - file: z.optional(z.url().readonly()) + file: z.url().readonly().optional() }); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); export const zPageable = z.object({ - page: z.optional(z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })).default(0), - size: z.optional(z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })), - sort: z.optional(z.array(z.string())) + page: z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(0), + size: z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + sort: z.array(z.string()).optional() }); /** @@ -728,35 +688,29 @@ export const zFreeFormObjectWithAdditionalPropertiesEqTrue = z.record(z.string() export const zFreeFormObjectWithAdditionalPropertiesEqEmptyObject = z.record(z.string(), z.unknown()); export const zModelWithConst = z.object({ - String: z.optional(z.literal('String')), - number: z.optional(z.literal(0)), - null: z.optional(z.null()), - withType: z.optional(z.literal('Some string')) + String: z.literal('String').optional(), + number: z.literal(0).optional(), + null: z.null().optional(), + withType: z.literal('Some string').optional() }); /** * This is a model with one property and additionalProperties: true */ export const zModelWithAdditionalPropertiesEqTrue = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -764,7 +718,7 @@ export const zNullableObject = z.union([ export const zCharactersInDescription = z.string(); export const zModelWithNullableObject = z.object({ - data: z.optional(zNullableObject) + data: zNullableObject.optional() }); export const zModelWithOneOfEnum = z.union([ @@ -792,17 +746,17 @@ export const zModelWithNestedArrayEnumsDataFoo = z.enum(['foo', 'bar']); export const zModelWithNestedArrayEnumsDataBar = z.enum(['baz', 'qux']); export const zModelWithNestedArrayEnumsData = z.object({ - foo: z.optional(z.array(zModelWithNestedArrayEnumsDataFoo)), - bar: z.optional(z.array(zModelWithNestedArrayEnumsDataBar)) + foo: z.array(zModelWithNestedArrayEnumsDataFoo).optional(), + bar: z.array(zModelWithNestedArrayEnumsDataBar).optional() }); export const zModelWithNestedArrayEnums = z.object({ - array_strings: z.optional(z.array(z.string())), - data: z.optional(zModelWithNestedArrayEnumsData) + array_strings: z.array(z.string()).optional(), + data: zModelWithNestedArrayEnumsData.optional() }); export const zModelWithNestedCompositionEnums = z.object({ - foo: z.optional(zModelWithNestedArrayEnumsDataFoo) + foo: zModelWithNestedArrayEnumsDataFoo.optional() }); export const zModelWithReadOnlyAndWriteOnly = z.object({ @@ -814,9 +768,9 @@ export const zModelWithReadOnlyAndWriteOnly = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnly = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnly)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnly).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithConstantSizeArray = z.tuple([z.number(), z.number()]); @@ -848,25 +802,22 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); export const zModelWithNumericEnumUnion = z.object({ - value: z.optional(z.union([ + value: z.union([ z.literal(-10), z.literal(-1), z.literal(0), @@ -874,14 +825,14 @@ export const zModelWithNumericEnumUnion = z.object({ z.literal(3), z.literal(6), z.literal(12) - ])) + ]).optional() }); /** * Some description with `back ticks` */ export const zModelWithBackticksInDescription = z.object({ - template: z.optional(z.string()) + template: z.string().optional() }); /** @@ -923,40 +874,40 @@ export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([z.un ])]); export const zSchemaWithFormRestrictedKeys = z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()), - object: z.optional(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - })), - array: z.optional(z.array(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - }))) + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional(), + object: z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + }).optional(), + array: z.array(z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + })).optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1Preconditions = z.object({ - resourceVersion: z.optional(z.string()), - uid: z.optional(z.string()) + resourceVersion: z.string().optional(), + uid: z.string().optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1DeleteOptions = z.object({ - preconditions: z.optional(zIoK8sApimachineryPkgApisMetaV1Preconditions) + preconditions: zIoK8sApimachineryPkgApisMetaV1Preconditions.optional() }); export const zAdditionalPropertiesUnknownIssue = z.record(z.string(), z.union([ @@ -978,25 +929,16 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ }); export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()) + item: z.string().nullish(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional() }); export const zOneOfAllOfIssue = z.union([ @@ -1009,7 +951,7 @@ export const zOneOfAllOfIssue = z.union([ export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); /** @@ -1027,24 +969,21 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -1053,11 +992,11 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFileWritable = z.object({ @@ -1073,9 +1012,9 @@ export const zModelWithReadOnlyAndWriteOnlyWritable = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnlyWritable = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnlyWritable)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnlyWritable).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = z.tuple([z.union([ @@ -1100,23 +1039,14 @@ export const zOneOfAllOfIssueWritable = z.union([ ]); export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1132,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1143,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1166,15 +1090,15 @@ export const zSimpleRequestBody = zModelWithString; export const zSimpleFormData = zModelWithString; export const zExportData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zImportData = z.object({ @@ -1182,8 +1106,8 @@ export const zImportData = z.object({ zModelWithReadOnlyAndWriteOnlyWritable, zModelWithArrayReadOnlyAndWriteOnlyWritable ]), - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export const zImportResponse = z.union([ @@ -1192,15 +1116,15 @@ export const zImportResponse = z.union([ ]); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zApiVVersionODataControllerCountData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1209,14 +1133,14 @@ export const zApiVVersionODataControllerCountData = z.object({ export const zApiVVersionODataControllerCountResponse = zModelFromZendesk; export const zGetApiVbyApiVersionSimpleOperationData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.union([ z.string(), z.uuid() ]) }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1225,160 +1149,127 @@ export const zGetApiVbyApiVersionSimpleOperationData = z.object({ export const zGetApiVbyApiVersionSimpleOperationResponse = z.number(); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteFooData3 = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string(), BarParam: z.string() }), - query: z.optional(z.never()), + query: z.never().optional(), headers: z.object({ 'x-Foo-Bar': zModelWithString }) }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zDeprecatedCallData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.record(z.string(), z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ - foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), + foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), + 'api-version': z.string().nullable() }), query: z.object({ - default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + default: z.string().optional(), + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); export const zGetCallWithOptionalParamData = z.object({ body: zModelWithOneOfEnum, - path: z.optional(z.never()), - query: z.optional(z.object({ - page: z.optional(z.number()) - })) + path: z.never().optional(), + query: z.object({ + page: z.number().optional() + }).optional() }); export const zPostCallWithOptionalParamData = z.object({ - body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) - })), - path: z.optional(z.never()), + body: z.object({ + offset: z.number().nullish() + }).optional(), + path: z.never().optional(), query: z.object({ parameter: zPageable }) @@ -1390,114 +1281,96 @@ export const zPostCallWithOptionalParamResponse = z.union([ ]); export const zPostApiVbyApiVersionRequestBodyData = z.object({ - body: z.optional(zSimpleRequestBody), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleRequestBody.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zPostApiVbyApiVersionFormDataData = z.object({ - body: z.optional(zSimpleFormData), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleFormData.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.union([ - z.string().default('Hello World!'), - z.null() - ])).default('Hello World!'), - parameterNumber: z.optional(z.union([ - z.number().default(123), - z.null() - ])).default(123), - parameterBoolean: z.optional(z.union([ - z.boolean().default(true), - z.null() - ])).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(z.union([ - zModelWithString.default({ prop: 'Hello World!' }), - z.null() - ])) - })) + ]).optional(), + parameterModel: zModelWithString.nullish() + }).optional() }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(zModelWithString).default({ prop: 'Hello World!' }) - })) + ]).optional(), + parameterModel: zModelWithString.optional().default({ prop: 'Hello World!' }) + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1506,9 +1379,9 @@ export const zCallWithNoContentResponseData = z.object({ export const zCallWithNoContentResponseResponse = z.void(); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -1517,17 +1390,17 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyAResponse = z400; export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1536,17 +1409,17 @@ export const zDummyBData = z.object({ export const zDummyBResponse = z.void(); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseResponse = zImport; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDuplicateResponsesResponse = z.union([ @@ -1555,81 +1428,50 @@ export const zCallWithDuplicateResponsesResponse = z.union([ ]); export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.string(), z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.string(), z.unknown()).nullable(), parameterEnum: z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ]).nullable() }) }); @@ -1643,23 +1485,20 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), - query: z.optional(z.never()) + query: z.never().optional() }); export const zUploadFileResponse = z.boolean(); export const zFileResponseData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ id: z.string(), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1668,15 +1507,15 @@ export const zFileResponseData = z.object({ export const zFileResponseResponse = z.string(); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: zModelWithString }) @@ -1688,77 +1527,59 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zMultipartResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** * OK */ export const zMultipartResponseResponse = z.object({ - file: z.optional(z.string()), - metadata: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) - })) + file: z.string().optional(), + metadata: z.object({ + foo: z.string().optional(), + bar: z.string().optional() + }).optional() }); export const zMultipartRequestData = z.object({ - body: z.optional(z.object({ - content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.object({ + content: z.string().optional(), + data: zModelWithString.nullish() + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zComplexParamsData = z.object({ - body: z.optional(z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), - enabled: z.optional(z.boolean()).default(true), + body: z.object({ + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), + enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary ]), - user: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly()), - name: z.optional(z.union([ - z.string().readonly(), - z.null() - ]).readonly()) - }).readonly()) - })), + user: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), + name: z.string().readonly().nullish() + }).readonly().optional() + }).optional(), path: z.object({ id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1767,22 +1588,22 @@ export const zComplexParamsData = z.object({ export const zComplexParamsResponse = zModelWithString; export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.int() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -1795,6 +1616,6 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = z.array(zNonAsciiS export const zPutWithFormUrlEncodedData = z.object({ body: zArrayWithStrings, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts index d75ecfc9c..60e4c5a54 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod/v4'; -export const zFoo = z.nullable(z.enum(['foo', 'bar'])); +export const zFoo = z.enum(['foo', 'bar']).nullable(); export const zBar = z.enum(['foo', 'bar']); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts index f71dd3169..d5f405a0e 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod/v4'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]).nullable(); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts index e4eb78007..3f4e8d91b 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts @@ -3,35 +3,35 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - foo: z.optional(z.literal('foo')), - bar: z.optional(z.literal(3.2)), - baz: z.optional(z.literal(-1)), - qux: z.optional(z.literal(true)), - quux: z.optional(z.tuple([ + foo: z.literal('foo').optional(), + bar: z.literal(3.2).optional(), + baz: z.literal(-1).optional(), + qux: z.literal(true).optional(), + quux: z.tuple([ z.literal(1), z.literal(2), z.literal(3), z.literal('foo'), z.literal(true) - ])), - corge: z.optional(z.record(z.string(), z.unknown())), - garply: z.optional(z.literal(BigInt('10'))), - numberInt8: z.optional(z.literal(100)), - numberInt16: z.optional(z.literal(1000)), - numberInt32: z.optional(z.literal(100000)), - numberInt64: z.optional(z.literal(BigInt(1000000000000))), - numberUint8: z.optional(z.literal(200)), - numberUint16: z.optional(z.literal(50000)), - numberUint32: z.optional(z.literal(3000000000)), - numberUint64: z.optional(z.literal(BigInt(18000000000000000000))), - integerInt8: z.optional(z.literal(-100)), - integerInt16: z.optional(z.literal(-1000)), - integerInt32: z.optional(z.literal(-100000)), - integerInt64: z.optional(z.literal(BigInt(-1000000000000))), - integerUint8: z.optional(z.literal(255)), - integerUint16: z.optional(z.literal(65535)), - integerUint32: z.optional(z.literal(4294967295)), - integerUint64: z.optional(z.literal(BigInt('18446744073709551615'))), - stringInt64: z.optional(z.literal(BigInt('-9223372036854775808'))), - stringUint64: z.optional(z.literal(BigInt('18446744073709551615'))) + ]).optional(), + corge: z.record(z.string(), z.unknown()).optional(), + garply: z.literal(BigInt('10')).optional(), + numberInt8: z.literal(100).optional(), + numberInt16: z.literal(1000).optional(), + numberInt32: z.literal(100000).optional(), + numberInt64: z.literal(BigInt(1000000000000)).optional(), + numberUint8: z.literal(200).optional(), + numberUint16: z.literal(50000).optional(), + numberUint32: z.literal(3000000000).optional(), + numberUint64: z.literal(BigInt(18000000000000000000)).optional(), + integerInt8: z.literal(-100).optional(), + integerInt16: z.literal(-1000).optional(), + integerInt32: z.literal(-100000).optional(), + integerInt64: z.literal(BigInt(-1000000000000)).optional(), + integerUint8: z.literal(255).optional(), + integerUint16: z.literal(65535).optional(), + integerUint32: z.literal(4294967295).optional(), + integerUint64: z.literal(BigInt('18446744073709551615')).optional(), + stringInt64: z.literal(BigInt('-9223372036854775808')).optional(), + stringUint64: z.literal(BigInt('18446744073709551615')).optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts index 796146a69..9b6647e58 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts index da0f87120..b87ef9569 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts @@ -3,5 +3,5 @@ import * as z from 'zod/v4'; export const zFoo = z.object({ - foo: z.optional(z.coerce.bigint().gte(BigInt(0)).lte(BigInt(100))) + foo: z.coerce.bigint().gte(BigInt(0)).lte(BigInt(100)).optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts index 9994ed379..19e8bf98d 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import * as z from 'zod/v4'; export const zBar = z.object({ - bar: z.union([ - z.array(z.lazy((): any => zBar)), - z.null() - ]) + bar: z.array(z.lazy((): any => zBar)).nullable() }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts index 5aa01a341..a7eb7ba7b 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts @@ -3,13 +3,11 @@ import * as z from 'zod/v4'; export const zBar = z.object({ - get bar() { - return z.optional(z.array(z.lazy((): any => zBar))); - } + bar: z.array(z.lazy((): any => zBar)).optional() }); export const zFoo = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zBaz = z.lazy((): any => zQux); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts index 71ced48b6..400ed387a 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts @@ -5,31 +5,24 @@ import * as z from 'zod/v4'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); /** @@ -38,27 +31,27 @@ export const zBar = z.object({ export const zFoo2 = z.string(); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime({ offset: true })) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime({ offset: true }).optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts index cccb35d6d..8adbe94ba 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts @@ -5,37 +5,30 @@ import * as z from 'zod/v4'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/).register(z.globalRegistry, { - description: 'This is foo property.' - })), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { - description: 'This is baz property.' - })); - }, - qux: z.optional(z.int().gt(0).register(z.globalRegistry, { - description: 'This is qux property.' - })).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).register(z.globalRegistry, { + description: 'This is foo property.' + }).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { + description: 'This is baz property.' + }).optional(), + qux: z.int().gt(0).register(z.globalRegistry, { + description: 'This is qux property.' + }).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }).register(z.globalRegistry, { description: 'This is Bar schema.' }); @@ -48,29 +41,29 @@ export const zFoo2 = z.string().register(z.globalRegistry, { }); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string().register(z.globalRegistry, { + path: z.never().optional(), + query: z.object({ + foo: z.string().register(z.globalRegistry, { description: 'This is Foo parameter.' - })), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + }).optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts index 267a75881..2fcda22b9 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts @@ -7,7 +7,7 @@ export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export type BazZodType = z.infer; export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); export type QuxZodType = z.infer; @@ -15,19 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); export type FooZodType = z.infer; @@ -35,7 +28,7 @@ export type FooZodType = z.infer; * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); export type BarZodType = z.infer; @@ -48,33 +41,33 @@ export const zFoo2 = z.string(); export type FooZodType2 = z.infer; export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export type FooZodType3 = z.infer; export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export type PatchFooDataZodType = z.infer; export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export type PostFooDataZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts index d5b3d03c2..2358fb8df 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts @@ -32,7 +32,7 @@ export const zCatDetails = z.object({ export const zPetStore = z.object({ animals: z.array(z.object({ name: z.string(), - type: z.optional(z.enum(['dog', 'cat'])), + type: z.enum(['dog', 'cat']).optional(), details: z.union([ zDogDetails, zCatDetails diff --git a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators/zod.gen.ts index fa38d9c13..d6b4bb64a 100644 --- a/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v3/__snapshots__/3.1.x/v4/validators/zod.gen.ts @@ -5,31 +5,24 @@ import * as z from 'zod/v4'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); /** @@ -38,27 +31,27 @@ export const zBar = z.object({ export const zFoo2 = z.string(); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/mini/default/zod.gen.ts index 635fd26df..4e30c7716 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/mini/default/zod.gen.ts @@ -217,14 +217,8 @@ export const zModelWithStringError = z.object({ * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.nullish(z.string()), + nullableRequiredProp: z.nullable(z.string()) }); /** @@ -293,9 +287,7 @@ export const zModelWithDictionary = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -605,14 +597,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v3/default/zod.gen.ts index 1d61a080e..75e09687d 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v3/default/zod.gen.ts @@ -217,14 +217,8 @@ export const zModelWithStringError = z.object({ * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.string().nullish(), + nullableRequiredProp: z.string().nullable() }); /** @@ -603,14 +597,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts index 5a58c7fcc..37fd72b6a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/default/zod.gen.ts index 4bb0f5e24..70c6dd200 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/default/zod.gen.ts @@ -136,8 +136,8 @@ export const zArrayWithStrings = z.array(z.string()); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** @@ -154,8 +154,8 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** @@ -167,21 +167,21 @@ export const zDate = z.string(); * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zSimpleReference = zModelWithString; @@ -210,92 +210,84 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp: z.union([ - z.string(), - z.null() - ]) + nullableProp: z.string().nullish(), + nullableRequiredProp: z.string().nullable() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - test: z.optional(z.enum([ + test: z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())) + ])).optional(), + arrayWithDescription: z.array(z.int()).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** @@ -304,22 +296,22 @@ export const zModelWithCircularReference = z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** @@ -337,45 +329,45 @@ export const zModelWithNestedProperties = z.object({ * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); /** @@ -384,40 +376,40 @@ export const zDefault = z.object({ export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zParameterActivityParams = z.object({ - description: z.optional(z.string()), - graduate_id: z.optional(z.int()), - organization_id: z.optional(z.int()), - parent_activity: z.optional(z.int()), - post_id: z.optional(z.int()) + description: z.string().optional(), + graduate_id: z.int().optional(), + organization_id: z.int().optional(), + parent_activity: z.int().optional(), + post_id: z.int().optional() }); export const zResponsePostActivityResponse = z.object({ - description: z.optional(z.string()), - graduate_id: z.optional(z.int()), - organization_id: z.optional(z.int()), - parent_activity_id: z.optional(z.int()), - post_id: z.optional(z.int()) + description: z.string().optional(), + graduate_id: z.int().optional(), + organization_id: z.int().optional(), + parent_activity_id: z.int().optional(), + post_id: z.int().optional() }); export const zFailureFailure = z.object({ - error: z.optional(z.string()), - message: z.optional(z.string()), - reference_code: z.optional(z.string()) + error: z.string().optional(), + message: z.string().optional(), + reference_code: z.string().optional() }); export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); export const zExternalRefA = zExternalSharedExternalSharedModel; @@ -429,20 +421,20 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -451,88 +443,88 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zServiceWithEmptyTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zCallWithParametersData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ parameterPath: z.string(), 'api-version': z.string() @@ -548,13 +540,13 @@ export const zCallWithParametersData = z.object({ export const zCallWithWeirdParameterNamesData = z.object({ body: z.string(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), 'api-version': z.string() }), query: z.object({ - default: z.optional(z.string()), + default: z.string().optional(), 'parameter-query': z.string() }), headers: z.object({ @@ -563,8 +555,8 @@ export const zCallWithWeirdParameterNamesData = z.object({ }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterString: z.string().default('Hello World!'), parameterNumber: z.number().default(123), @@ -575,81 +567,75 @@ export const zCallWithDefaultParametersData = z.object({ 'Error' ]), parameterModel: z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }).default({ prop: 'Hello World!' }) }) }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])) - })) + ]).optional() + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -658,21 +644,21 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -681,9 +667,9 @@ export const zCallWithResponseData = z.object({ export const zCallWithResponseResponse = zModelWithString; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -692,24 +678,24 @@ export const zCallWithDuplicateResponsesData = z.object({ export const zCallWithDuplicateResponsesResponse = zModelWithString; export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterArrayCSV: z.array(z.string()), parameterArraySSV: z.array(z.string()), @@ -720,10 +706,10 @@ export const zCollectionFormatData = z.object({ }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), parameterString: z.string().default('default'), @@ -746,18 +732,18 @@ export const zTypesResponse = z.union([ ]); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }) }) }); @@ -768,22 +754,22 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.string() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -796,8 +782,8 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = zNonAsciiStringæ export const zPostApiVbyApiVersionBodyData = z.object({ body: zParameterActivityParams, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/2.0.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/circular/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/circular/zod.gen.ts index 7cced9697..c9bffc923 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/circular/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/circular/zod.gen.ts @@ -3,24 +3,16 @@ import * as z from 'zod/mini'; export const zFoo = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.optional(z.lazy((): any => zQuux)) }); export const zBar = z.object({ - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.lazy((): any => zBaz)); - } + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.lazy((): any => zBaz)) }); export const zBaz = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.optional(z.lazy((): any => zQuux)) }); export const zQux = z.union([ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/default/zod.gen.ts index 38d4da2fe..7e22b891c 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)), - z.null() -]); +export const zSimpleStringWithPattern = z.nullable(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -279,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.nullish(z.string()), + nullableRequiredProp1: z.nullable(z.string()), + nullableProp2: z.nullish(z.string()), + nullableRequiredProp2: z.nullable(z.string()), 'foo_bar-enum': z.optional(z.enum([ 'Success', 'Warning', @@ -391,9 +376,7 @@ export const zDeprecatedModel = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -479,14 +462,8 @@ export const zCompositionWithAnyOfAnonymous = z.object({ */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ propA: z.optional(z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) + z.array(z.nullable(zModelWithDictionary)), + z.array(z.nullable(zModelWithArray)) ])) }); @@ -498,24 +475,20 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.nullish(z.array(z.union([z3eNum1Период, zConstValue]))) }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -553,26 +526,22 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.intersection(z.intersection(z.intersection(z.object({ - boolean: z.optional(z.boolean()) - }), zModelWithEnum), zModelWithArray), zModelWithDictionary), - z.null() - ])) + propA: z.nullish(z.intersection(z.intersection(z.intersection(z.object({ + boolean: z.optional(z.boolean()) + }), zModelWithEnum), zModelWithArray), zModelWithDictionary)) }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -599,10 +568,7 @@ export const zCompositionExtendedModel = z.intersection(zCompositionBaseModel, z export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.readonly(z.string()), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -625,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.readonly(z.union([ - z.readonly(z.object({ - second: z.readonly(z.union([ - z.readonly(z.object({ - third: z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ])) - })), - z.null() - ])) - })), - z.null() - ])) + first: z.nullable(z.readonly(z.object({ + second: z.nullable(z.readonly(z.object({ + third: z.nullable(z.readonly(z.string())) + }))) + }))) }); /** @@ -745,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.nullish(z.array(z.union([z.string(), z.boolean()]))) }); /** * An object that can be null */ -export const zNullableObject = z._default(z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]), null); +export const zNullableObject = z._default(z.nullable(z.object({ + foo: z.optional(z.string()) +})), null); /** * Some % character @@ -846,21 +797,18 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ ])); export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ - z.union([ + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]) + ])) ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -979,23 +927,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + item: z.nullish(z.string()), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())) }); @@ -1021,10 +960,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -1095,22 +1031,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.nullish(z.string()), + error: z.nullish(z.string()) }); /** @@ -1126,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1137,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1281,70 +1202,40 @@ export const zDeprecatedCallData = z.object({ path: z.optional(z.never()), query: z.optional(z.never()), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: z.nullable(zDeprecatedModel) }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.nullable(z.record(z.string(), z.unknown())), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.nullable(z.string()), + 'api-version': z.nullable(z.string()) }), query: z.object({ foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.nullable(z.string()) }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.nullable(z.string()) }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: z.nullable(zModelWithString), path: z.object({ 'parameter.path.1': z.optional(z.string()), 'parameter-path-2': z.optional(z.string()), 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.object({ default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.nullable(z.string()) }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.nullable(z.string()) }) }); @@ -1358,10 +1249,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) + offset: z.nullish(z.number()) })), path: z.optional(z.never()), query: z.object({ @@ -1394,27 +1282,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - parameterString: z._default(z.optional(z.union([ - z._default(z.string(), 'Hello World!'), - z.null() - ])), 'Hello World!'), - parameterNumber: z._default(z.optional(z.union([ - z._default(z.number(), 123), - z.null() - ])), 123), - parameterBoolean: z._default(z.optional(z.union([ - z._default(z.boolean(), true), - z.null() - ])), true), + parameterString: z._default(z.nullish(z.string()), 'Hello World!'), + parameterNumber: z._default(z.nullish(z.number()), 123), + parameterBoolean: z._default(z.nullish(z.boolean()), true), parameterEnum: z.optional(z.enum([ 'Success', 'Warning', 'Error' ])), - parameterModel: z.optional(z.union([ - zModelWithString, - z.null() - ])) + parameterModel: z.nullish(zModelWithString) })) }); @@ -1444,14 +1320,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); @@ -1559,26 +1429,11 @@ export const zCollectionFormatData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.nullable(z.array(z.string())), + parameterArraySSV: z.nullable(z.array(z.string())), + parameterArrayTSV: z.nullable(z.array(z.string())), + parameterArrayPipes: z.nullable(z.array(z.string())), + parameterArrayMulti: z.nullable(z.array(z.string())) }) }); @@ -1589,26 +1444,11 @@ export const zTypesData = z.object({ })), query: z.object({ parameterNumber: z._default(z.number(), 123), - parameterString: z._default(z.union([ - z._default(z.string(), 'default'), - z.null() - ]), 'default'), - parameterBoolean: z._default(z.union([ - z._default(z.boolean(), true), - z.null() - ]), true), - parameterObject: z._default(z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z._default(z.nullable(z.string()), 'default'), + parameterBoolean: z._default(z.nullable(z.boolean()), true), + parameterObject: z._default(z.nullable(z.record(z.string(), z.unknown())), null), + parameterArray: z.nullable(z.array(z.string())), + parameterDictionary: z.nullable(z.record(z.string(), z.unknown())), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1627,10 +1467,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.optional(z.never()) }); @@ -1691,10 +1528,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.optional(z.object({ content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) + data: z.nullish(zModelWithString) })), path: z.optional(z.never()), query: z.optional(z.never()) @@ -1702,28 +1536,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.optional(z.object({ - key: z.readonly(z.union([ - z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))), - z.null() - ])), - name: z.union([ - z.string().check(z.maxLength(255)), - z.null() - ]), + key: z.nullable(z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)))), + name: z.nullable(z.string().check(z.maxLength(255))), enabled: z._default(z.optional(z.boolean()), true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.nullish(z.array(zModelWithString)), + listOfStrings: z.nullish(z.array(z.string())), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1732,10 +1554,7 @@ export const zComplexParamsData = z.object({ ]), user: z.optional(z.readonly(z.object({ id: z.optional(z.readonly(z.int().check(z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })))), - name: z.optional(z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ]))) + name: z.nullish(z.readonly(z.string())) }))) })), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/validators/zod.gen.ts index 7a5c78486..e80f1ac17 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/mini/validators/zod.gen.ts @@ -4,19 +4,12 @@ import * as z from 'zod/mini'; export const zBaz = z._default(z.readonly(z.string().check(z.regex(/foo\nbar/))), 'baz'); -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); export const zBar = z.object({ foo: z.optional(zFoo) diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/default/zod.gen.ts index 6a2d2968e..fa53f469b 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -279,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -477,14 +462,8 @@ export const zCompositionWithAnyOfAnonymous = z.object({ */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ propA: z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) + z.array(zModelWithDictionary.nullable()), + z.array(zModelWithArray.nullable()) ]).optional() }); @@ -496,10 +475,7 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ]).optional() + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** @@ -512,9 +488,8 @@ export const zCompositionWithOneOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -551,12 +526,9 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.union([ - z.object({ - boolean: z.boolean().optional() - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ]).optional() + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** @@ -569,9 +541,8 @@ export const zCompositionWithAnyOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -597,10 +568,7 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -623,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** @@ -743,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ]).optional() + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.string().optional() - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -846,19 +799,16 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -977,23 +927,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + item: z.string().nullish(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional() }); @@ -1019,10 +960,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -1093,22 +1031,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional() + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1124,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1135,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1279,70 +1202,40 @@ export const zDeprecatedCallData = z.object({ path: z.never().optional(), query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.unknown()), - z.null() - ]), + body: z.record(z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ 'parameter.path.1': z.string().optional(), 'parameter-path-2': z.string().optional(), 'PARAMETER-PATH-3': z.string().optional(), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.object({ default: z.string().optional(), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); @@ -1356,10 +1249,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.object({ - offset: z.union([ - z.number(), - z.null() - ]).optional() + offset: z.number().nullish() }).optional(), path: z.never().optional(), query: z.object({ @@ -1392,27 +1282,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterString: z.union([ - z.string().default('Hello World!'), - z.null() - ]).optional().default('Hello World!'), - parameterNumber: z.union([ - z.number().default(123), - z.null() - ]).optional().default(123), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).optional().default(true), + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), parameterEnum: z.enum([ 'Success', 'Warning', 'Error' ]).optional(), - parameterModel: z.union([ - zModelWithString, - z.null() - ]).optional() + parameterModel: zModelWithString.nullish() }).optional() }); @@ -1442,14 +1320,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); @@ -1557,26 +1429,11 @@ export const zCollectionFormatData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); @@ -1587,26 +1444,11 @@ export const zTypesData = z.object({ }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.unknown()).nullable(), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1625,10 +1467,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.never().optional() }); @@ -1689,10 +1528,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.object({ content: z.string().optional(), - data: z.union([ - zModelWithString, - z.null() - ]).optional() + data: zModelWithString.nullish() }).optional(), path: z.never().optional(), query: z.never().optional() @@ -1700,28 +1536,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.union([ - z.array(zModelWithString), - z.null() - ]).optional(), - listOfStrings: z.union([ - z.array(z.string()), - z.null() - ]).optional(), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1730,10 +1554,7 @@ export const zComplexParamsData = z.object({ ]), user: z.object({ id: z.number().int().min(-2147483648, { message: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { message: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), - name: z.union([ - z.string().readonly(), - z.null() - ]).readonly().optional() + name: z.string().readonly().nullish() }).readonly().optional() }).optional(), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/validators/zod.gen.ts index bdddc5775..1e7523b1f 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v3/validators/zod.gen.ts @@ -4,15 +4,12 @@ import { z } from 'zod/v3'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); export const zBar = z.object({ foo: zFoo.optional() diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts index 5a58c7fcc..37fd72b6a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts index d4647f04a..a7e66aa30 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/array-items-one-of-length-1/zod.gen.ts @@ -5,5 +5,5 @@ import * as z from 'zod'; export const zBar = z.string(); export const zFoo = z.object({ - foo: z.optional(z.array(zBar).min(1).max(2147483647)) + foo: z.array(zBar).min(1).max(2147483647).optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/circular/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/circular/zod.gen.ts index a953c8432..6fdddaf32 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/circular/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/circular/zod.gen.ts @@ -3,24 +3,16 @@ import * as z from 'zod'; export const zFoo = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.lazy((): any => zQuux).optional() }); export const zBar = z.object({ - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.lazy((): any => zBaz)); - } + bar: z.lazy((): any => zBar).optional(), + baz: z.lazy((): any => zBaz).optional() }); export const zBaz = z.object({ - get quux() { - return z.optional(z.lazy((): any => zQuux)); - } + quux: z.lazy((): any => zQuux).optional() }); export const zQux = z.union([ @@ -33,9 +25,9 @@ export const zQux = z.union([ ]); export const zQuux = z.object({ - qux: z.optional(zQux) + qux: zQux.optional() }); export const zCorge = z.object({ - baz: z.optional(z.array(zBaz)) + baz: z.array(zBaz).optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/default/zod.gen.ts index af76f6c56..de9892891 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -166,32 +163,32 @@ export const zArrayWithStrings = z.array(z.string()).default(['test']); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - '16x16': z.optional(zCamelCaseCommentWithBreaks), - bar: z.optional(z.string()) + '16x16': zCamelCaseCommentWithBreaks.optional(), + bar: z.string().optional() })); /** * This is a simple array with any of properties */ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ - foo: z.optional(z.string()).default('test') + foo: z.string().optional().default('test') }), z.object({ - bar: z.optional(z.string()) + bar: z.string().optional() })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.unknown()) + data: z.unknown().optional() }); /** * This is a simple array with any of properties */ export const zAnyOfArrays = z.object({ - results: z.optional(z.array(z.union([z.object({ - foo: z.optional(z.string()) + results: z.array(z.union([z.object({ + foo: z.string().optional() }), z.object({ - bar: z.optional(z.string()) - })]))) + bar: z.string().optional() + })])).optional() }); /** @@ -200,8 +197,8 @@ export const zAnyOfArrays = z.object({ export const zDictionaryWithString = z.record(z.string(), z.string()); export const zDictionaryWithPropertiesAndAdditionalProperties = z.object({ - foo: z.optional(z.number()), - bar: z.optional(z.boolean()) + foo: z.number().optional(), + bar: z.boolean().optional() }); /** @@ -213,29 +210,29 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -267,7 +264,7 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -279,103 +276,91 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), - 'foo_bar-enum': z.optional(z.enum([ + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - 'foo_bar-enum': z.optional(z.enum([ + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum with escaped name */ export const zModelWithEnumWithHyphen = z.object({ - 'foo-bar-baz-qux': z.optional(z.enum(['3.0'])) + 'foo-bar-baz-qux': z.enum(['3.0']).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())), - 'foo_bar-enum': z.optional(z.enum([ + ])).optional(), + arrayWithDescription: z.array(z.int()).optional(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** @@ -384,41 +369,39 @@ export const zModelWithDictionary = z.object({ * @deprecated */ export const zDeprecatedModel = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'one of' relationship where the options are not $ref */ export const zCompositionWithOneOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** @@ -426,7 +409,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ */ export const zModelCircle = z.object({ kind: z.string(), - radius: z.optional(z.number()) + radius: z.number().optional() }); /** @@ -434,7 +417,7 @@ export const zModelCircle = z.object({ */ export const zModelSquare = z.object({ kind: z.string(), - sideLength: z.optional(z.number()) + sideLength: z.number().optional() }); /** @@ -453,41 +436,35 @@ export const zCompositionWithOneOfDiscriminator = z.union([ * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithAnyOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** * This is a model with nested 'any of' property with a type null */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([ - zModelWithDictionary, - z.null() - ])), - z.array(z.union([ - zModelWithArray, - z.null() - ])) - ])) + propA: z.union([ + z.array(zModelWithDictionary.nullable()), + z.array(zModelWithArray.nullable()) + ]).optional() }); export const z3eNum1Период = z.enum(['Bird', 'Dog']); @@ -498,90 +475,82 @@ export const zConstValue = z.enum(['ConstValue']); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a model that contains a simple dictionary within composition */ export const zCompositionWithOneOfAndSimpleDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.number()) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of simple arrays within composition */ export const zCompositionWithOneOfAndSimpleArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.boolean())) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of complex arrays (composited) within composition */ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.union([z.number(), z.string()]))) - ])) + ]).optional() }); /** * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.object({ - boolean: z.optional(z.boolean()) - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ])) + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a base model with two simple optional properties */ export const zCompositionBaseModel = z.object({ - firstName: z.optional(z.string()), - lastname: z.optional(z.string()) + firstName: z.string().optional(), + lastname: z.string().optional() }); /** @@ -599,87 +568,75 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); /** @@ -688,31 +645,31 @@ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends). export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFile = z.object({ - id: z.optional(z.string().min(1).readonly()), - updated_at: z.optional(z.iso.datetime().readonly()), - created_at: z.optional(z.iso.datetime().readonly()), + id: z.string().min(1).readonly().optional(), + updated_at: z.iso.datetime().readonly().optional(), + created_at: z.iso.datetime().readonly().optional(), mime: z.string().min(1).max(24), - file: z.optional(z.url().readonly()) + file: z.url().readonly().optional() }); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); export const zPageable = z.object({ - page: z.optional(z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })).default(0), - size: z.optional(z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })), - sort: z.optional(z.array(z.string())) + page: z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(0), + size: z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + sort: z.array(z.string()).optional() }); /** @@ -731,35 +688,29 @@ export const zFreeFormObjectWithAdditionalPropertiesEqTrue = z.record(z.string() export const zFreeFormObjectWithAdditionalPropertiesEqEmptyObject = z.record(z.string(), z.unknown()); export const zModelWithConst = z.object({ - String: z.optional(z.enum(['String'])), - number: z.optional(z.literal(0)), - null: z.optional(z.unknown()), - withType: z.optional(z.enum(['Some string'])) + String: z.enum(['String']).optional(), + number: z.literal(0).optional(), + null: z.unknown().optional(), + withType: z.enum(['Some string']).optional() }); /** * This is a model with one property and additionalProperties: true */ export const zModelWithAdditionalPropertiesEqTrue = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -767,7 +718,7 @@ export const zNullableObject = z.union([ export const zCharactersInDescription = z.string(); export const zModelWithNullableObject = z.object({ - data: z.optional(zNullableObject) + data: zNullableObject.optional() }); export const zModelWithOneOfEnum = z.union([ @@ -795,17 +746,17 @@ export const zModelWithNestedArrayEnumsDataFoo = z.enum(['foo', 'bar']); export const zModelWithNestedArrayEnumsDataBar = z.enum(['baz', 'qux']); export const zModelWithNestedArrayEnumsData = z.object({ - foo: z.optional(z.array(zModelWithNestedArrayEnumsDataFoo)), - bar: z.optional(z.array(zModelWithNestedArrayEnumsDataBar)) + foo: z.array(zModelWithNestedArrayEnumsDataFoo).optional(), + bar: z.array(zModelWithNestedArrayEnumsDataBar).optional() }); export const zModelWithNestedArrayEnums = z.object({ - array_strings: z.optional(z.array(z.string())), - data: z.optional(zModelWithNestedArrayEnumsData) + array_strings: z.array(z.string()).optional(), + data: zModelWithNestedArrayEnumsData.optional() }); export const zModelWithNestedCompositionEnums = z.object({ - foo: z.optional(zModelWithNestedArrayEnumsDataFoo) + foo: zModelWithNestedArrayEnumsDataFoo.optional() }); export const zModelWithReadOnlyAndWriteOnly = z.object({ @@ -817,9 +768,9 @@ export const zModelWithReadOnlyAndWriteOnly = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnly = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnly)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnly).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithConstantSizeArray = z.tuple([z.number(), z.number()]); @@ -848,25 +799,22 @@ export const zModelWithPrefixItemsConstantSizeArray = z.array(z.union([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); export const zModelWithNumericEnumUnion = z.object({ - value: z.optional(z.union([ + value: z.union([ z.literal(-10), z.literal(-1), z.literal(0), @@ -874,14 +822,14 @@ export const zModelWithNumericEnumUnion = z.object({ z.literal(3), z.literal(6), z.literal(12) - ])) + ]).optional() }); /** * Some description with `back ticks` */ export const zModelWithBackticksInDescription = z.object({ - template: z.optional(z.string()) + template: z.string().optional() }); /** @@ -923,40 +871,40 @@ export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([z.un ])]); export const zSchemaWithFormRestrictedKeys = z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()), - object: z.optional(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - })), - array: z.optional(z.array(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - }))) + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional(), + object: z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + }).optional(), + array: z.array(z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + })).optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1Preconditions = z.object({ - resourceVersion: z.optional(z.string()), - uid: z.optional(z.string()) + resourceVersion: z.string().optional(), + uid: z.string().optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1DeleteOptions = z.object({ - preconditions: z.optional(zIoK8sApimachineryPkgApisMetaV1Preconditions) + preconditions: zIoK8sApimachineryPkgApisMetaV1Preconditions.optional() }); export const zAdditionalPropertiesUnknownIssue = z.record(z.string(), z.union([ @@ -978,25 +926,16 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ }); export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()) + item: z.string().nullish(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional() }); export const zOneOfAllOfIssue = z.union([ @@ -1009,7 +948,7 @@ export const zOneOfAllOfIssue = z.union([ export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); export const zExternalRefA = zExternalSharedExternalSharedModel; @@ -1021,24 +960,21 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -1047,11 +983,11 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFileWritable = z.object({ @@ -1067,9 +1003,9 @@ export const zModelWithReadOnlyAndWriteOnlyWritable = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnlyWritable = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnlyWritable)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnlyWritable).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = z.tuple([z.union([ @@ -1094,23 +1030,14 @@ export const zOneOfAllOfIssueWritable = z.union([ ]); export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1126,10 +1053,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1137,10 +1061,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1154,15 +1075,15 @@ export const zSimpleRequestBody = zModelWithString; export const zSimpleFormData = zModelWithString; export const zExportData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zImportData = z.object({ @@ -1170,8 +1091,8 @@ export const zImportData = z.object({ zModelWithReadOnlyAndWriteOnlyWritable, zModelWithArrayReadOnlyAndWriteOnlyWritable ]), - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export const zImportResponse = z.union([ @@ -1180,15 +1101,15 @@ export const zImportResponse = z.union([ ]); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zApiVVersionODataControllerCountData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1197,11 +1118,11 @@ export const zApiVVersionODataControllerCountData = z.object({ export const zApiVVersionODataControllerCountResponse = zModelFromZendesk; export const zGetApiVbyApiVersionSimpleOperationData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1210,160 +1131,127 @@ export const zGetApiVbyApiVersionSimpleOperationData = z.object({ export const zGetApiVbyApiVersionSimpleOperationResponse = z.number(); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteFooData3 = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string(), BarParam: z.string() }), - query: z.optional(z.never()), + query: z.never().optional(), headers: z.object({ 'x-Foo-Bar': zModelWithString }) }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zDeprecatedCallData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.record(z.string(), z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ - foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), + foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), + 'api-version': z.string().nullable() }), query: z.object({ - default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + default: z.string().optional(), + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); export const zGetCallWithOptionalParamData = z.object({ body: zModelWithOneOfEnum, - path: z.optional(z.never()), - query: z.optional(z.object({ - page: z.optional(z.number()) - })) + path: z.never().optional(), + query: z.object({ + page: z.number().optional() + }).optional() }); export const zPostCallWithOptionalParamData = z.object({ - body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) - })), - path: z.optional(z.never()), + body: z.object({ + offset: z.number().nullish() + }).optional(), + path: z.never().optional(), query: z.object({ parameter: zPageable }) @@ -1375,114 +1263,96 @@ export const zPostCallWithOptionalParamResponse = z.union([ ]); export const zPostApiVbyApiVersionRequestBodyData = z.object({ - body: z.optional(zSimpleRequestBody), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleRequestBody.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zPostApiVbyApiVersionFormDataData = z.object({ - body: z.optional(zSimpleFormData), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleFormData.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.union([ - z.string().default('Hello World!'), - z.null() - ])).default('Hello World!'), - parameterNumber: z.optional(z.union([ - z.number().default(123), - z.null() - ])).default(123), - parameterBoolean: z.optional(z.union([ - z.boolean().default(true), - z.null() - ])).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })) + ]).optional(), + parameterModel: zModelWithString.nullish() + }).optional() }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(zModelWithString) - })) + ]).optional(), + parameterModel: zModelWithString.optional() + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1491,9 +1361,9 @@ export const zCallWithNoContentResponseData = z.object({ export const zCallWithNoContentResponseResponse = z.void(); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -1502,17 +1372,17 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyAResponse = z400; export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1521,17 +1391,17 @@ export const zDummyBData = z.object({ export const zDummyBResponse = z.void(); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseResponse = zImport; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDuplicateResponsesResponse = z.union([ @@ -1540,75 +1410,45 @@ export const zCallWithDuplicateResponsesResponse = z.union([ ]); export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.string(), z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.string(), z.unknown()).nullable(), parameterEnum: z.enum([ 'Success', 'Warning', @@ -1627,23 +1467,20 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), - query: z.optional(z.never()) + query: z.never().optional() }); export const zUploadFileResponse = z.boolean(); export const zFileResponseData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ id: z.string(), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1652,15 +1489,15 @@ export const zFileResponseData = z.object({ export const zFileResponseResponse = z.string(); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: zModelWithString }) @@ -1672,77 +1509,59 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zMultipartResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** * OK */ export const zMultipartResponseResponse = z.object({ - file: z.optional(z.string()), - metadata: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) - })) + file: z.string().optional(), + metadata: z.object({ + foo: z.string().optional(), + bar: z.string().optional() + }).optional() }); export const zMultipartRequestData = z.object({ - body: z.optional(z.object({ - content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.object({ + content: z.string().optional(), + data: zModelWithString.nullish() + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zComplexParamsData = z.object({ - body: z.optional(z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), - enabled: z.optional(z.boolean()).default(true), + body: z.object({ + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), + enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary ]), - user: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly()), - name: z.optional(z.union([ - z.string().readonly(), - z.null() - ]).readonly()) - }).readonly()) - })), + user: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), + name: z.string().readonly().nullish() + }).readonly().optional() + }).optional(), path: z.object({ id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1751,22 +1570,22 @@ export const zComplexParamsData = z.object({ export const zComplexParamsResponse = zModelWithString; export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.int() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -1779,6 +1598,6 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = z.array(zNonAsciiS export const zPutWithFormUrlEncodedData = z.object({ body: zArrayWithStrings, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts index 75b7a3bf7..991382570 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/enum-null/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod'; -export const zFoo = z.nullable(z.enum(['foo', 'bar'])); +export const zFoo = z.enum(['foo', 'bar']).nullable(); export const zBar = z.enum(['foo', 'bar']); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/validators/zod.gen.ts index d367aa3a1..09932afd1 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.0.x/v4/validators/zod.gen.ts @@ -4,20 +4,13 @@ import * as z from 'zod'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/default/zod.gen.ts index 5c3ff1e8f..c1347b77d 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)), - z.null() -]); +export const zSimpleStringWithPattern = z.nullable(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))); /** * This is a simple enum with strings @@ -180,10 +177,7 @@ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.union([ - z.unknown(), - z.null() - ])) + data: z.nullish(z.unknown()) }); /** @@ -282,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.nullish(z.string()), + nullableRequiredProp1: z.nullable(z.string()), + nullableProp2: z.nullish(z.string()), + nullableRequiredProp2: z.nullable(z.string()), 'foo_bar-enum': z.optional(z.enum([ 'Success', 'Warning', @@ -394,9 +376,7 @@ export const zDeprecatedModel = z.object({ * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.optional(z.lazy((): any => zModelWithCircularReference)) }); /** @@ -495,24 +475,20 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.nullish(z.array(z.union([z3eNum1Период, zConstValue]))) }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -550,26 +526,22 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.intersection(z.intersection(z.intersection(z.object({ - boolean: z.optional(z.boolean()) - }), zModelWithEnum), zModelWithArray), zModelWithDictionary), - z.null() - ])) + propA: z.nullish(z.intersection(z.intersection(z.intersection(z.object({ + boolean: z.optional(z.boolean()) + }), zModelWithEnum), zModelWithArray), zModelWithDictionary)) }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.nullish(z.union([ z.object({ boolean: z.optional(z.boolean()) }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() + zModelWithDictionary ])) }); @@ -596,10 +568,7 @@ export const zCompositionExtendedModel = z.intersection(zCompositionBaseModel, z export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.readonly(z.string()), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -622,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.readonly(z.union([ - z.readonly(z.object({ - second: z.readonly(z.union([ - z.readonly(z.object({ - third: z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ])) - })), - z.null() - ])) - })), - z.null() - ])) + first: z.nullable(z.readonly(z.object({ + second: z.nullable(z.readonly(z.object({ + third: z.nullable(z.readonly(z.string())) + }))) + }))) }); /** @@ -742,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.nullish(z.array(z.union([z.string(), z.boolean()]))) }); /** * An object that can be null */ -export const zNullableObject = z._default(z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]), null); +export const zNullableObject = z._default(z.nullable(z.object({ + foo: z.optional(z.string()) +})), null); /** * Some % character @@ -846,21 +800,18 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ ]); export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ - z.union([ + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]), - z.union([ + ])), + z.nullable(z.union([ z.number(), - z.null(), z.string() - ]) + ])) ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -979,23 +930,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + item: z.nullish(z.string()), + error: z.nullish(z.string()), hasError: z.optional(z.readonly(z.boolean())) }); @@ -1027,10 +969,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.nullable(z.string()), string: z.optional(z.string()), number: z.optional(z.number()), boolean: z.optional(z.boolean()), @@ -1101,22 +1040,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), + error: z.nullish(z.string()), data: z.optional(z.record(z.string(), z.never())) }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.nullish(z.string()), + error: z.nullish(z.string()) }); /** @@ -1132,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1143,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' })), - z.null() - ]), + baz: z.nullable(z.int().check(z.gte(0), z.maximum(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }))), qux: z.int().check(z.gte(0), z.maximum(255, { error: 'Invalid value: Expected uint8 to be <= 255' })) })); @@ -1296,70 +1220,40 @@ export const zDeprecatedCallData = z.object({ path: z.optional(z.never()), query: z.optional(z.never()), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: z.nullable(zDeprecatedModel) }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.nullable(z.record(z.string(), z.unknown())), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.nullable(z.string()), + 'api-version': z.nullable(z.string()) }), query: z.object({ foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.nullable(z.string()) }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.nullable(z.string()) }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: z.nullable(zModelWithString), path: z.object({ 'parameter.path.1': z.optional(z.string()), 'parameter-path-2': z.optional(z.string()), 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.object({ default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.nullable(z.string()) }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.nullable(z.string()) }) }); @@ -1373,10 +1267,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) + offset: z.nullish(z.number()) })), path: z.optional(z.never()), query: z.object({ @@ -1409,27 +1300,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.optional(z.object({ - parameterString: z._default(z.optional(z.union([ - z._default(z.string(), 'Hello World!'), - z.null() - ])), 'Hello World!'), - parameterNumber: z._default(z.optional(z.union([ - z._default(z.number(), 123), - z.null() - ])), 123), - parameterBoolean: z._default(z.optional(z.union([ - z._default(z.boolean(), true), - z.null() - ])), true), + parameterString: z._default(z.nullish(z.string()), 'Hello World!'), + parameterNumber: z._default(z.nullish(z.number()), 123), + parameterBoolean: z._default(z.nullish(z.boolean()), true), parameterEnum: z.optional(z.enum([ 'Success', 'Warning', 'Error' ])), - parameterModel: z.optional(z.union([ - z._default(zModelWithString, { prop: 'Hello World!' }), - z.null() - ])) + parameterModel: z.nullish(zModelWithString) })) }); @@ -1459,14 +1338,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z._default(z.string(), 'Hello World!'), parameterStringWithEmptyDefault: z._default(z.string(), ''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + parameterStringNullableWithNoDefault: z.nullish(z.string()), + parameterStringNullableWithDefault: z._default(z.nullish(z.string()), null) }) }); @@ -1574,26 +1447,11 @@ export const zCollectionFormatData = z.object({ body: z.optional(z.never()), path: z.optional(z.never()), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.nullable(z.array(z.string())), + parameterArraySSV: z.nullable(z.array(z.string())), + parameterArrayTSV: z.nullable(z.array(z.string())), + parameterArrayPipes: z.nullable(z.array(z.string())), + parameterArrayMulti: z.nullable(z.array(z.string())) }) }); @@ -1604,32 +1462,16 @@ export const zTypesData = z.object({ })), query: z.object({ parameterNumber: z._default(z.number(), 123), - parameterString: z._default(z.union([ - z._default(z.string(), 'default'), - z.null() - ]), 'default'), - parameterBoolean: z._default(z.union([ - z._default(z.boolean(), true), - z.null() - ]), true), - parameterObject: z._default(z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), - parameterEnum: z.union([ + parameterString: z._default(z.nullable(z.string()), 'default'), + parameterBoolean: z._default(z.nullable(z.boolean()), true), + parameterObject: z._default(z.nullable(z.record(z.string(), z.unknown())), null), + parameterArray: z.nullable(z.array(z.string())), + parameterDictionary: z.nullable(z.record(z.string(), z.unknown())), + parameterEnum: z.nullable(z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ])) }) }); @@ -1643,10 +1485,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.nullable(z.string()) }), query: z.optional(z.never()) }); @@ -1707,10 +1546,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.optional(z.object({ content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) + data: z.nullish(zModelWithString) })), path: z.optional(z.never()), query: z.optional(z.never()) @@ -1718,28 +1554,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.optional(z.object({ - key: z.readonly(z.union([ - z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/))), - z.null() - ])), - name: z.union([ - z.string().check(z.maxLength(255)), - z.null() - ]), + key: z.nullable(z.readonly(z.string().check(z.maxLength(64), z.regex(/^[a-zA-Z0-9_]*$/)))), + name: z.nullable(z.string().check(z.maxLength(255))), enabled: z._default(z.optional(z.boolean()), true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.nullish(z.array(zModelWithString)), + listOfStrings: z.nullish(z.array(z.string())), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1748,10 +1572,7 @@ export const zComplexParamsData = z.object({ ]), user: z.optional(z.readonly(z.object({ id: z.optional(z.readonly(z.int().check(z.minimum(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }), z.maximum(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })))), - name: z.optional(z.readonly(z.union([ - z.readonly(z.string()), - z.null() - ]))) + name: z.nullish(z.readonly(z.string())) }))) })), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/defaults-with-ref-and-anyof/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/defaults-with-ref-and-anyof/zod.gen.ts index 108ce0565..94a18b570 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/defaults-with-ref-and-anyof/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/defaults-with-ref-and-anyof/zod.gen.ts @@ -19,16 +19,7 @@ export const zTestSchema = z.object({ primitiveDefault: z._default(z.number(), 42), refWithPrimitiveDefault: z._default(zAudioFormat, 'pcm_16bit_44.1khz'), refWithObjectDefault: z._default(zNestedConfig, { model: 'gpt-4', temperature: 1 }), - anyOfWithNullDefault: z._default(z.union([ - z.number(), - z.null() - ]), null), - anyOfWithRefAndNullDefault: z._default(z.union([ - zLanguage, - z.null() - ]), null), - optionalAnyOfWithDefault: z._default(z.optional(z.union([ - z.string(), - z.null() - ])), null) + anyOfWithNullDefault: z._default(z.nullable(z.number()), null), + anyOfWithRefAndNullDefault: z._default(z.nullable(zLanguage), null), + optionalAnyOfWithDefault: z._default(z.nullish(z.string()), null) }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts index 5e88b6e80..c19fb9266 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod/mini'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.nullable(z.union([z.enum(['foo', 'bar']), z.string()])); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts index 6014595af..4a395a61a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import * as z from 'zod/mini'; export const zBar = z.object({ - bar: z.union([ - z.array(z.lazy((): any => zBar)), - z.null() - ]) + bar: z.nullable(z.array(z.lazy((): any => zBar))) }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts index ee8b0c76e..3ea103c76 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-circular-ref/zod.gen.ts @@ -3,9 +3,7 @@ import * as z from 'zod/mini'; export const zBar = z.object({ - get bar() { - return z.optional(z.array(z.lazy((): any => zBar))); - } + bar: z.optional(z.array(z.lazy((): any => zBar))) }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts index 9ac32990c..47eb9503a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-dates/zod.gen.ts @@ -11,19 +11,12 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts index e263d218e..004b5e06d 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-metadata/zod.gen.ts @@ -11,25 +11,18 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/)).register(z.globalRegistry, { - description: 'This is foo property.' - })), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { - description: 'This is baz property.' - })); - }, - qux: z._default(z.optional(z.int().check(z.gt(0)).register(z.globalRegistry, { - description: 'This is qux property.' - })), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/)).register(z.globalRegistry, { + description: 'This is foo property.' + })), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { + description: 'This is baz property.' + })), + qux: z._default(z.optional(z.int().check(z.gt(0)).register(z.globalRegistry, { + description: 'This is qux property.' + })), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts index 669174c0a..e69e527ef 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators-types/zod.gen.ts @@ -15,19 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); export type FooZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators/zod.gen.ts index b786abd75..3b365dc73 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/mini/validators/zod.gen.ts @@ -11,19 +11,12 @@ export const zQux = z.record(z.string(), z.object({ /** * This is Foo schema. */ -export const zFoo = z._default(z.union([ - z.object({ - foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z._default(z.optional(z.int().check(z.gt(0))), 0) - }), - z.null() -]), null); +export const zFoo = z._default(z.nullable(z.object({ + foo: z.optional(z.string().check(z.regex(/^\d{3}-\d{2}-\d{4}$/))), + bar: z.optional(z.lazy((): any => zBar)), + baz: z.optional(z.array(z.lazy((): any => zFoo))), + qux: z._default(z.optional(z.int().check(z.gt(0))), 0) +})), null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/default/zod.gen.ts index 856dbff23..34434e376 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -180,10 +177,7 @@ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ })])); export const zAnyOfAnyAndNull = z.object({ - data: z.union([ - z.unknown(), - z.null() - ]).optional() + data: z.unknown().nullish() }); /** @@ -282,22 +276,10 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.union([ - z.string(), - z.null() - ]).optional(), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), 'foo_bar-enum': z.enum([ 'Success', 'Warning', @@ -493,10 +475,7 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ]).optional() + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** @@ -509,9 +488,8 @@ export const zCompositionWithOneOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -548,12 +526,9 @@ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.union([ - z.object({ - boolean: z.boolean().optional() - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ]).optional() + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** @@ -566,9 +541,8 @@ export const zCompositionWithAnyOfAndNullable = z.object({ }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ]).optional() + zModelWithDictionary + ]).nullish() }); /** @@ -594,10 +568,7 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -620,20 +591,11 @@ export const zModelWithReference = z.object({ * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** @@ -740,21 +702,15 @@ export const zModelWithAdditionalPropertiesEqTrue = z.object({ }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ]).optional() + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.string().optional() - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -846,19 +802,16 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); @@ -977,23 +930,14 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + item: z.string().nullish(), + error: z.string().nullish(), hasError: z.boolean().readonly().optional() }); @@ -1025,10 +969,7 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), + requiredAndNullable: z.string().nullable(), string: z.string().optional(), number: z.number().optional(), boolean: z.boolean().optional(), @@ -1099,22 +1040,13 @@ export const zOneOfAllOfIssueWritable = z.union([ export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ item: z.boolean().optional(), - error: z.union([ - z.string(), - z.null() - ]).optional(), + error: z.string().nullish(), data: z.record(z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.union([ - z.string(), - z.null() - ]).optional(), - error: z.union([ - z.string(), - z.null() - ]).optional() + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1130,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1141,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.number().int().gte(0).max(65535, { message: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.number().int().gte(0).max(255, { message: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1294,70 +1220,40 @@ export const zDeprecatedCallData = z.object({ path: z.never().optional(), query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.unknown()), - z.null() - ]), + body: z.record(z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ 'parameter.path.1': z.string().optional(), 'parameter-path-2': z.string().optional(), 'PARAMETER-PATH-3': z.string().optional(), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.object({ default: z.string().optional(), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); @@ -1371,10 +1267,7 @@ export const zGetCallWithOptionalParamData = z.object({ export const zPostCallWithOptionalParamData = z.object({ body: z.object({ - offset: z.union([ - z.number(), - z.null() - ]).optional() + offset: z.number().nullish() }).optional(), path: z.never().optional(), query: z.object({ @@ -1407,27 +1300,15 @@ export const zCallWithDefaultParametersData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterString: z.union([ - z.string().default('Hello World!'), - z.null() - ]).optional().default('Hello World!'), - parameterNumber: z.union([ - z.number().default(123), - z.null() - ]).optional().default(123), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).optional().default(true), + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), parameterEnum: z.enum([ 'Success', 'Warning', 'Error' ]).optional(), - parameterModel: z.union([ - zModelWithString.default({ prop: 'Hello World!' }), - z.null() - ]).optional() + parameterModel: zModelWithString.nullish() }).optional() }); @@ -1457,14 +1338,8 @@ export const zCallToTestOrderOfParamsData = z.object({ parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.union([ - z.string(), - z.null() - ]).optional(), - parameterStringNullableWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); @@ -1572,26 +1447,11 @@ export const zCollectionFormatData = z.object({ body: z.never().optional(), path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); @@ -1602,32 +1462,16 @@ export const zTypesData = z.object({ }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.unknown()).nullable(), parameterEnum: z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ]).nullable() }) }); @@ -1641,10 +1485,7 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), query: z.never().optional() }); @@ -1705,10 +1546,7 @@ export const zMultipartResponseResponse = z.object({ export const zMultipartRequestData = z.object({ body: z.object({ content: z.string().optional(), - data: z.union([ - zModelWithString, - z.null() - ]).optional() + data: zModelWithString.nullish() }).optional(), path: z.never().optional(), query: z.never().optional() @@ -1716,28 +1554,16 @@ export const zMultipartRequestData = z.object({ export const zComplexParamsData = z.object({ body: z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.union([ - z.array(zModelWithString), - z.null() - ]).optional(), - listOfStrings: z.union([ - z.array(z.string()), - z.null() - ]).optional(), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, @@ -1746,10 +1572,7 @@ export const zComplexParamsData = z.object({ ]), user: z.object({ id: z.number().int().min(-2147483648, { message: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { message: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), - name: z.union([ - z.string().readonly(), - z.null() - ]).readonly().optional() + name: z.string().readonly().nullish() }).readonly().optional() }).optional(), path: z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/defaults-with-ref-and-anyof/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/defaults-with-ref-and-anyof/zod.gen.ts index 7c2861e7b..7de645541 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/defaults-with-ref-and-anyof/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/defaults-with-ref-and-anyof/zod.gen.ts @@ -19,16 +19,7 @@ export const zTestSchema = z.object({ primitiveDefault: z.number().default(42), refWithPrimitiveDefault: zAudioFormat.default('pcm_16bit_44.1khz'), refWithObjectDefault: zNestedConfig.default({ model: 'gpt-4', temperature: 1 }), - anyOfWithNullDefault: z.union([ - z.number(), - z.null() - ]).default(null), - anyOfWithRefAndNullDefault: z.union([ - zLanguage, - z.null() - ]).default(null), - optionalAnyOfWithDefault: z.union([ - z.string(), - z.null() - ]).optional().default(null) + anyOfWithNullDefault: z.number().nullable().default(null), + anyOfWithRefAndNullDefault: zLanguage.nullable().default(null), + optionalAnyOfWithDefault: z.string().nullish().default(null) }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts index ad12dc37a..bfc87fb8a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import { z } from 'zod/v3'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]).nullable(); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts index 4d47e4d61..9b4022d16 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import { z } from 'zod/v3'; export const zBar: z.AnyZodObject = z.object({ - bar: z.union([ - z.array(z.lazy(() => zBar)), - z.null() - ]) + bar: z.array(z.lazy(() => zBar)).nullable() }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts index 68a0a720f..752d86c56 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-dates/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts index 10af4babe..4c243e93f 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-metadata/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).describe('This is foo property.').optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).describe('This is baz property.').optional(), - qux: z.number().int().gt(0).describe('This is qux property.').optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).describe('This is foo property.').optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).describe('This is baz property.').optional(), + qux: z.number().int().gt(0).describe('This is qux property.').optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts index 2b0fa9eed..e2734ee19 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators-types/zod.gen.ts @@ -15,15 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); export type FooZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators/zod.gen.ts index 15850f6a2..89bcb622f 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v3/validators/zod.gen.ts @@ -11,15 +11,12 @@ export const zQux = z.record(z.object({ /** * This is Foo schema. */ -export const zFoo: z.ZodTypeAny = z.union([ - z.object({ - foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), - bar: z.lazy(() => zBar).optional(), - baz: z.array(z.lazy(() => zFoo)).optional(), - qux: z.number().int().gt(0).optional().default(0) - }), - z.null() -]).default(null); +export const zFoo: z.ZodTypeAny = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy(() => zBar).optional(), + baz: z.array(z.lazy(() => zFoo)).optional(), + qux: z.number().int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts index 5a58c7fcc..37fd72b6a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-all-of/zod.gen.ts @@ -3,18 +3,18 @@ import * as z from 'zod'; export const zArrayWithAllOfObjects = z.array(z.object({ - id: z.optional(z.int()) + id: z.int().optional() }).and(z.object({ - name: z.optional(z.string()) + name: z.string().optional() }))); export const zArrayWithAllOfPrimitives = z.array(z.intersection(z.number(), z.string())); export const zBaseModel = z.object({ - id: z.optional(z.int()), - createdAt: z.optional(z.iso.datetime()) + id: z.int().optional(), + createdAt: z.iso.datetime().optional() }); export const zArrayWithAllOfRefs = z.array(zBaseModel.and(z.object({ - extra: z.optional(z.string()) + extra: z.string().optional() }))); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts index d4647f04a..a7e66aa30 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/array-items-one-of-length-1/zod.gen.ts @@ -5,5 +5,5 @@ import * as z from 'zod'; export const zBar = z.string(); export const zFoo = z.object({ - foo: z.optional(z.array(zBar).min(1).max(2147483647)) + foo: z.array(zBar).min(1).max(2147483647).optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/default/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/default/zod.gen.ts index 559e8c246..242940984 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/default/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/default/zod.gen.ts @@ -81,10 +81,7 @@ export const zSimpleFile = z.string(); /** * This is a simple string */ -export const zSimpleStringWithPattern = z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), - z.null() -]); +export const zSimpleStringWithPattern = z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).nullable(); /** * This is a simple enum with strings @@ -166,35 +163,32 @@ export const zArrayWithStrings = z.array(z.string()).default(['test']); * This is a simple array with properties */ export const zArrayWithProperties = z.array(z.object({ - '16x16': z.optional(zCamelCaseCommentWithBreaks), - bar: z.optional(z.string()) + '16x16': zCamelCaseCommentWithBreaks.optional(), + bar: z.string().optional() })); /** * This is a simple array with any of properties */ export const zArrayWithAnyOfProperties = z.array(z.union([z.object({ - foo: z.optional(z.string()).default('test') + foo: z.string().optional().default('test') }), z.object({ - bar: z.optional(z.string()) + bar: z.string().optional() })])); export const zAnyOfAnyAndNull = z.object({ - data: z.optional(z.union([ - z.unknown(), - z.null() - ])) + data: z.unknown().nullish() }); /** * This is a simple array with any of properties */ export const zAnyOfArrays = z.object({ - results: z.optional(z.array(z.union([z.object({ - foo: z.optional(z.string()) + results: z.array(z.union([z.object({ + foo: z.string().optional() }), z.object({ - bar: z.optional(z.string()) - })]))) + bar: z.string().optional() + })])).optional() }); /** @@ -203,8 +197,8 @@ export const zAnyOfArrays = z.object({ export const zDictionaryWithString = z.record(z.string(), z.string()); export const zDictionaryWithPropertiesAndAdditionalProperties = z.object({ - foo: z.optional(z.number()), - bar: z.optional(z.boolean()) + foo: z.number().optional(), + bar: z.boolean().optional() }); /** @@ -216,29 +210,29 @@ export const zDictionaryWithDictionary = z.record(z.string(), z.record(z.string( * This is a complex dictionary */ export const zDictionaryWithProperties = z.record(z.string(), z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) + foo: z.string().optional(), + bar: z.string().optional() })); /** * This is a model with one number property */ export const zModelWithInteger = z.object({ - prop: z.optional(z.int()) + prop: z.int().optional() }); /** * This is a model with one boolean property */ export const zModelWithBoolean = z.object({ - prop: z.optional(z.boolean()) + prop: z.boolean().optional() }); /** * This is a model with one string property */ export const zModelWithString = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -270,7 +264,7 @@ export const zDictionaryWithArray = z.record(z.string(), z.array(zModelWithStrin * This is a model with one string property */ export const zModelWithStringError = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** @@ -282,103 +276,91 @@ export const zModelFromZendesk = z.string(); * This is a model with one string property */ export const zModelWithNullableString = z.object({ - nullableProp1: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp1: z.union([ - z.string(), - z.null() - ]), - nullableProp2: z.optional(z.union([ - z.string(), - z.null() - ])), - nullableRequiredProp2: z.union([ - z.string(), - z.null() - ]), - 'foo_bar-enum': z.optional(z.enum([ + nullableProp1: z.string().nullish(), + nullableRequiredProp1: z.string().nullable(), + nullableProp2: z.string().nullish(), + nullableRequiredProp2: z.string().nullable(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one enum */ export const zModelWithEnum = z.object({ - 'foo_bar-enum': z.optional(z.enum([ + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])), - statusCode: z.optional(z.enum([ + ]).optional(), + statusCode: z.enum([ '100', '200 FOO', '300 FOO_BAR', '400 foo-bar', '500 foo.bar', '600 foo&bar' - ])), - bool: z.optional(z.literal(true)) + ]).optional(), + bool: z.literal(true).optional() }); /** * This is a model with one enum with escaped name */ export const zModelWithEnumWithHyphen = z.object({ - 'foo-bar-baz-qux': z.optional(z.enum(['3.0'])) + 'foo-bar-baz-qux': z.enum(['3.0']).optional() }); /** * This is a model with one enum */ export const zModelWithEnumFromDescription = z.object({ - test: z.optional(z.int()) + test: z.int().optional() }); /** * This is a model with nested enums */ export const zModelWithNestedEnums = z.object({ - dictionaryWithEnum: z.optional(z.record(z.string(), z.enum([ + dictionaryWithEnum: z.record(z.string(), z.enum([ 'Success', 'Warning', 'Error' - ]))), - dictionaryWithEnumFromDescription: z.optional(z.record(z.string(), z.int())), - arrayWithEnum: z.optional(z.array(z.enum([ + ])).optional(), + dictionaryWithEnumFromDescription: z.record(z.string(), z.int()).optional(), + arrayWithEnum: z.array(z.enum([ 'Success', 'Warning', 'Error' - ]))), - arrayWithDescription: z.optional(z.array(z.int())), - 'foo_bar-enum': z.optional(z.enum([ + ])).optional(), + arrayWithDescription: z.array(z.int()).optional(), + 'foo_bar-enum': z.enum([ 'Success', 'Warning', 'Error', 'ØÆÅ字符串' - ])) + ]).optional() }); /** * This is a model with one property containing an array */ export const zModelWithArray = z.object({ - prop: z.optional(z.array(zModelWithString)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithString).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); /** * This is a model with one property containing a dictionary */ export const zModelWithDictionary = z.object({ - prop: z.optional(z.record(z.string(), z.string())) + prop: z.record(z.string(), z.string()).optional() }); /** @@ -387,41 +369,39 @@ export const zModelWithDictionary = z.object({ * @deprecated */ export const zDeprecatedModel = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); /** * This is a model with one property containing a circular reference */ export const zModelWithCircularReference = z.object({ - get prop() { - return z.optional(z.lazy((): any => zModelWithCircularReference)); - } + prop: z.lazy((): any => zModelWithCircularReference).optional() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'one of' relationship where the options are not $ref */ export const zCompositionWithOneOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** @@ -429,7 +409,7 @@ export const zCompositionWithOneOfAnonymous = z.object({ */ export const zModelCircle = z.object({ kind: z.string(), - radius: z.optional(z.number()) + radius: z.number().optional() }); /** @@ -437,7 +417,7 @@ export const zModelCircle = z.object({ */ export const zModelSquare = z.object({ kind: z.string(), - sideLength: z.optional(z.number()) + sideLength: z.number().optional() }); /** @@ -456,35 +436,35 @@ export const zCompositionWithOneOfDiscriminator = z.union([ * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOf = z.object({ - propA: z.optional(z.union([ + propA: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary - ])) + ]).optional() }); /** * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithAnyOfAnonymous = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - propA: z.optional(z.string()) + propA: z.string().optional() }), z.string(), z.int() - ])) + ]).optional() }); /** * This is a model with nested 'any of' property with a type null */ export const zCompositionWithNestedAnyAndTypeNull = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.array(z.union([zModelWithDictionary, z.null()])), z.array(z.union([zModelWithArray, z.null()])) - ])) + ]).optional() }); export const z3eNum1Период = z.enum(['Bird', 'Dog']); @@ -495,90 +475,82 @@ export const zConstValue = z.literal('ConstValue'); * This is a model with one property with a 'any of' relationship where the options are not $ref */ export const zCompositionWithNestedAnyOfAndNull = z.object({ - propA: z.optional(z.union([ - z.array(z.union([z3eNum1Период, zConstValue])), - z.null() - ])) + propA: z.array(z.union([z3eNum1Период, zConstValue])).nullish() }); /** * This is a model with one property with a 'one of' relationship */ export const zCompositionWithOneOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a model that contains a simple dictionary within composition */ export const zCompositionWithOneOfAndSimpleDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.number()) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of simple arrays within composition */ export const zCompositionWithOneOfAndSimpleArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.boolean())) - ])) + ]).optional() }); /** * This is a model that contains a dictionary of complex arrays (composited) within composition */ export const zCompositionWithOneOfAndComplexArrayDictionary = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.boolean(), z.record(z.string(), z.array(z.union([z.number(), z.string()]))) - ])) + ]).optional() }); /** * This is a model with one property with a 'all of' relationship */ export const zCompositionWithAllOfAndNullable = z.object({ - propA: z.optional(z.union([ - z.object({ - boolean: z.optional(z.boolean()) - }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary), - z.null() - ])) + propA: z.object({ + boolean: z.boolean().optional() + }).and(zModelWithEnum).and(zModelWithArray).and(zModelWithDictionary).nullish() }); /** * This is a model with one property with a 'any of' relationship */ export const zCompositionWithAnyOfAndNullable = z.object({ - propA: z.optional(z.union([ + propA: z.union([ z.object({ - boolean: z.optional(z.boolean()) + boolean: z.boolean().optional() }), zModelWithEnum, zModelWithArray, - zModelWithDictionary, - z.null() - ])) + zModelWithDictionary + ]).nullish() }); /** * This is a base model with two simple optional properties */ export const zCompositionBaseModel = z.object({ - firstName: z.optional(z.string()), - lastname: z.optional(z.string()) + firstName: z.string().optional(), + lastname: z.string().optional() }); /** @@ -596,87 +568,75 @@ export const zCompositionExtendedModel = zCompositionBaseModel.and(z.object({ export const zModelWithProperties = z.object({ required: z.string(), requiredAndReadOnly: z.string().readonly(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()), - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional(), + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReference = z.object({ - prop: z.optional(zModelWithProperties) + prop: zModelWithProperties.optional() }); /** * This is a model with one nested property */ export const zModelWithNestedProperties = z.object({ - first: z.union([ - z.object({ - second: z.union([ - z.object({ - third: z.union([ - z.string().readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() - }).readonly(), - z.null() - ]).readonly() + first: z.object({ + second: z.object({ + third: z.string().readonly().nullable() + }).readonly().nullable() + }).readonly().nullable() }); /** * This is a model with duplicated properties */ export const zModelWithDuplicateProperties = z.object({ - prop: z.optional(zModelWithString) + prop: zModelWithString.optional() }); /** * This is a model with ordered properties */ export const zModelWithOrderedProperties = z.object({ - zebra: z.optional(z.string()), - apple: z.optional(z.string()), - hawaii: z.optional(z.string()) + zebra: z.string().optional(), + apple: z.string().optional(), + hawaii: z.string().optional() }); /** * This is a model with duplicated imports */ export const zModelWithDuplicateImports = z.object({ - propA: z.optional(zModelWithString), - propB: z.optional(zModelWithString), - propC: z.optional(zModelWithString) + propA: zModelWithString.optional(), + propB: zModelWithString.optional(), + propC: zModelWithString.optional() }); /** * This is a model that extends another model */ export const zModelThatExtends = zModelWithString.and(z.object({ - propExtendsA: z.optional(z.string()), - propExtendsB: z.optional(zModelWithString) + propExtendsA: z.string().optional(), + propExtendsB: zModelWithString.optional() })); /** * This is a model that extends another model */ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends).and(z.object({ - propExtendsC: z.optional(z.string()), - propExtendsD: z.optional(zModelWithString) + propExtendsC: z.string().optional(), + propExtendsD: zModelWithString.optional() })); /** @@ -685,31 +645,31 @@ export const zModelThatExtendsExtends = zModelWithString.and(zModelThatExtends). export const zModelWithPattern = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - enabled: z.optional(z.boolean().readonly()), - modified: z.optional(z.iso.datetime().readonly()), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + enabled: z.boolean().readonly().optional(), + modified: z.iso.datetime().readonly().optional(), + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFile = z.object({ - id: z.optional(z.string().min(1).readonly()), - updated_at: z.optional(z.iso.datetime().readonly()), - created_at: z.optional(z.iso.datetime().readonly()), + id: z.string().min(1).readonly().optional(), + updated_at: z.iso.datetime().readonly().optional(), + created_at: z.iso.datetime().readonly().optional(), mime: z.string().min(1).max(24), - file: z.optional(z.url().readonly()) + file: z.url().readonly().optional() }); export const zDefault = z.object({ - name: z.optional(z.string()) + name: z.string().optional() }); export const zPageable = z.object({ - page: z.optional(z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })).default(0), - size: z.optional(z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })), - sort: z.optional(z.array(z.string())) + page: z.int().gte(0).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional().default(0), + size: z.int().gte(1).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional(), + sort: z.array(z.string()).optional() }); /** @@ -728,35 +688,29 @@ export const zFreeFormObjectWithAdditionalPropertiesEqTrue = z.record(z.string() export const zFreeFormObjectWithAdditionalPropertiesEqEmptyObject = z.record(z.string(), z.unknown()); export const zModelWithConst = z.object({ - String: z.optional(z.literal('String')), - number: z.optional(z.literal(0)), - null: z.optional(z.null()), - withType: z.optional(z.literal('Some string')) + String: z.literal('String').optional(), + number: z.literal(0).optional(), + null: z.null().optional(), + withType: z.literal('Some string').optional() }); /** * This is a model with one property and additionalProperties: true */ export const zModelWithAdditionalPropertiesEqTrue = z.object({ - prop: z.optional(z.string()) + prop: z.string().optional() }); export const zNestedAnyOfArraysNullable = z.object({ - nullableArray: z.optional(z.union([ - z.array(z.union([z.string(), z.boolean()])), - z.null() - ])) + nullableArray: z.array(z.union([z.string(), z.boolean()])).nullish() }); /** * An object that can be null */ -export const zNullableObject = z.union([ - z.object({ - foo: z.optional(z.string()) - }), - z.null() -]).default(null); +export const zNullableObject = z.object({ + foo: z.string().optional() +}).nullable().default(null); /** * Some % character @@ -764,7 +718,7 @@ export const zNullableObject = z.union([ export const zCharactersInDescription = z.string(); export const zModelWithNullableObject = z.object({ - data: z.optional(zNullableObject) + data: zNullableObject.optional() }); export const zModelWithOneOfEnum = z.union([ @@ -792,17 +746,17 @@ export const zModelWithNestedArrayEnumsDataFoo = z.enum(['foo', 'bar']); export const zModelWithNestedArrayEnumsDataBar = z.enum(['baz', 'qux']); export const zModelWithNestedArrayEnumsData = z.object({ - foo: z.optional(z.array(zModelWithNestedArrayEnumsDataFoo)), - bar: z.optional(z.array(zModelWithNestedArrayEnumsDataBar)) + foo: z.array(zModelWithNestedArrayEnumsDataFoo).optional(), + bar: z.array(zModelWithNestedArrayEnumsDataBar).optional() }); export const zModelWithNestedArrayEnums = z.object({ - array_strings: z.optional(z.array(z.string())), - data: z.optional(zModelWithNestedArrayEnumsData) + array_strings: z.array(z.string()).optional(), + data: zModelWithNestedArrayEnumsData.optional() }); export const zModelWithNestedCompositionEnums = z.object({ - foo: z.optional(zModelWithNestedArrayEnumsDataFoo) + foo: zModelWithNestedArrayEnumsDataFoo.optional() }); export const zModelWithReadOnlyAndWriteOnly = z.object({ @@ -814,9 +768,9 @@ export const zModelWithReadOnlyAndWriteOnly = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnly = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnly)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnly).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithConstantSizeArray = z.tuple([z.number(), z.number()]); @@ -848,25 +802,22 @@ export const zModelWithPrefixItemsConstantSizeArray = z.tuple([ export const zModelWithAnyOfConstantSizeArrayNullable = z.tuple([ z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]), + ]).nullable(), z.union([ z.number(), - z.null(), z.string() - ]) + ]).nullable() ]); export const zModelWithAnyOfConstantSizeArrayAndIntersect = z.tuple([z.intersection(z.number(), z.string()), z.intersection(z.number(), z.string())]); export const zModelWithNumericEnumUnion = z.object({ - value: z.optional(z.union([ + value: z.union([ z.literal(-10), z.literal(-1), z.literal(0), @@ -874,14 +825,14 @@ export const zModelWithNumericEnumUnion = z.object({ z.literal(3), z.literal(6), z.literal(12) - ])) + ]).optional() }); /** * Some description with `back ticks` */ export const zModelWithBackticksInDescription = z.object({ - template: z.optional(z.string()) + template: z.string().optional() }); /** @@ -923,40 +874,40 @@ export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = z.tuple([z.un ])]); export const zSchemaWithFormRestrictedKeys = z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()), - object: z.optional(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - })), - array: z.optional(z.array(z.object({ - description: z.optional(z.string()), - 'x-enum-descriptions': z.optional(z.string()), - 'x-enum-varnames': z.optional(z.string()), - 'x-enumNames': z.optional(z.string()), - title: z.optional(z.string()) - }))) + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional(), + object: z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + }).optional(), + array: z.array(z.object({ + description: z.string().optional(), + 'x-enum-descriptions': z.string().optional(), + 'x-enum-varnames': z.string().optional(), + 'x-enumNames': z.string().optional(), + title: z.string().optional() + })).optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1Preconditions = z.object({ - resourceVersion: z.optional(z.string()), - uid: z.optional(z.string()) + resourceVersion: z.string().optional(), + uid: z.string().optional() }); /** * This schema was giving PascalCase transformations a hard time */ export const zIoK8sApimachineryPkgApisMetaV1DeleteOptions = z.object({ - preconditions: z.optional(zIoK8sApimachineryPkgApisMetaV1Preconditions) + preconditions: zIoK8sApimachineryPkgApisMetaV1Preconditions.optional() }); export const zAdditionalPropertiesUnknownIssue = z.record(z.string(), z.union([ @@ -978,25 +929,16 @@ export const zAdditionalPropertiesIntegerIssue = z.object({ }); export const zGenericSchemaDuplicateIssue1SystemBoolean = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemString = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - hasError: z.optional(z.boolean().readonly()) + item: z.string().nullish(), + error: z.string().nullish(), + hasError: z.boolean().readonly().optional() }); export const zOneOfAllOfIssue = z.union([ @@ -1009,7 +951,7 @@ export const zOneOfAllOfIssue = z.union([ export const zExternalSharedExternalSharedModel = z.object({ id: z.string(), - name: z.optional(z.string()) + name: z.string().optional() }); /** @@ -1027,24 +969,21 @@ export const zExternalRefB = zExternalSharedExternalSharedModel; */ export const zModelWithPropertiesWritable = z.object({ required: z.string(), - requiredAndNullable: z.union([ - z.string(), - z.null() - ]), - string: z.optional(z.string()), - number: z.optional(z.number()), - boolean: z.optional(z.boolean()), - reference: z.optional(zModelWithString), - 'property with space': z.optional(z.string()), - default: z.optional(z.string()), - try: z.optional(z.string()) + requiredAndNullable: z.string().nullable(), + string: z.string().optional(), + number: z.number().optional(), + boolean: z.boolean().optional(), + reference: zModelWithString.optional(), + 'property with space': z.string().optional(), + default: z.string().optional(), + try: z.string().optional() }); /** * This is a model with one property containing a reference */ export const zModelWithReferenceWritable = z.object({ - prop: z.optional(zModelWithPropertiesWritable) + prop: zModelWithPropertiesWritable.optional() }); /** @@ -1053,11 +992,11 @@ export const zModelWithReferenceWritable = z.object({ export const zModelWithPatternWritable = z.object({ key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/), name: z.string().max(255), - id: z.optional(z.string().regex(/^\d{2}-\d{3}-\d{4}$/)), - text: z.optional(z.string().regex(/^\w+$/)), - patternWithSingleQuotes: z.optional(z.string().regex(/^[a-zA-Z0-9']*$/)), - patternWithNewline: z.optional(z.string().regex(/aaa\nbbb/)), - patternWithBacktick: z.optional(z.string().regex(/aaa`bbb/)) + id: z.string().regex(/^\d{2}-\d{3}-\d{4}$/).optional(), + text: z.string().regex(/^\w+$/).optional(), + patternWithSingleQuotes: z.string().regex(/^[a-zA-Z0-9']*$/).optional(), + patternWithNewline: z.string().regex(/aaa\nbbb/).optional(), + patternWithBacktick: z.string().regex(/aaa`bbb/).optional() }); export const zFileWritable = z.object({ @@ -1073,9 +1012,9 @@ export const zModelWithReadOnlyAndWriteOnlyWritable = z.object({ * This is a model with one property containing an array */ export const zModelWithArrayReadOnlyAndWriteOnlyWritable = z.object({ - prop: z.optional(z.array(zModelWithReadOnlyAndWriteOnlyWritable)), - propWithFile: z.optional(z.array(z.string())), - propWithNumber: z.optional(z.array(z.number())) + prop: z.array(zModelWithReadOnlyAndWriteOnlyWritable).optional(), + propWithFile: z.array(z.string()).optional(), + propWithNumber: z.array(z.number()).optional() }); export const zModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = z.tuple([z.union([ @@ -1100,23 +1039,14 @@ export const zOneOfAllOfIssueWritable = z.union([ ]); export const zGenericSchemaDuplicateIssue1SystemBooleanWritable = z.object({ - item: z.optional(z.boolean()), - error: z.optional(z.union([ - z.string(), - z.null() - ])), - data: z.optional(z.record(z.string(), z.never())) + item: z.boolean().optional(), + error: z.string().nullish(), + data: z.record(z.string(), z.never()).optional() }); export const zGenericSchemaDuplicateIssue1SystemStringWritable = z.object({ - item: z.optional(z.union([ - z.string(), - z.null() - ])), - error: z.optional(z.union([ - z.string(), - z.null() - ])) + item: z.string().nullish(), + error: z.string().nullish() }); /** @@ -1132,10 +1062,7 @@ export const zCompositionWithOneOfAndProperties = z.intersection(z.union([ bar: zNonAsciiStringæøåÆøÅöôêÊ字符串 }) ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1143,10 +1070,7 @@ export const zModelWithOneOfAndProperties = z.intersection(z.union([ zSimpleParameter, zNonAsciiStringæøåÆøÅöôêÊ字符串 ]), z.object({ - baz: z.union([ - z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }), - z.null() - ]), + baz: z.int().gte(0).max(65535, { error: 'Invalid value: Expected uint16 to be <= 65535' }).nullable(), qux: z.int().gte(0).max(255, { error: 'Invalid value: Expected uint8 to be <= 255' }) })); @@ -1166,15 +1090,15 @@ export const zSimpleRequestBody = zModelWithString; export const zSimpleFormData = zModelWithString; export const zExportData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchApiVbyApiVersionNoTagData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zImportData = z.object({ @@ -1182,8 +1106,8 @@ export const zImportData = z.object({ zModelWithReadOnlyAndWriteOnlyWritable, zModelWithArrayReadOnlyAndWriteOnlyWritable ]), - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export const zImportResponse = z.union([ @@ -1192,15 +1116,15 @@ export const zImportResponse = z.union([ ]); export const zFooWowData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zApiVVersionODataControllerCountData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1209,14 +1133,14 @@ export const zApiVVersionODataControllerCountData = z.object({ export const zApiVVersionODataControllerCountResponse = zModelFromZendesk; export const zGetApiVbyApiVersionSimpleOperationData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.union([ z.string(), z.uuid() ]) }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1225,160 +1149,127 @@ export const zGetApiVbyApiVersionSimpleOperationData = z.object({ export const zGetApiVbyApiVersionSimpleOperationResponse = z.number(); export const zDeleteCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zGetCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zHeadCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zOptionsCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPatchCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPostCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zPutCallWithoutParametersAndResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDeleteFooData3 = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ foo_param: z.string(), BarParam: z.string() }), - query: z.optional(z.never()), + query: z.never().optional(), headers: z.object({ 'x-Foo-Bar': zModelWithString }) }); export const zCallWithDescriptionsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterWithBreaks: z.optional(z.string()), - parameterWithBackticks: z.optional(z.string()), - parameterWithSlashes: z.optional(z.string()), - parameterWithExpressionPlaceholders: z.optional(z.string()), - parameterWithQuotes: z.optional(z.string()), - parameterWithReservedCharacters: z.optional(z.string()) - })) + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterWithBreaks: z.string().optional(), + parameterWithBackticks: z.string().optional(), + parameterWithSlashes: z.string().optional(), + parameterWithExpressionPlaceholders: z.string().optional(), + parameterWithQuotes: z.string().optional(), + parameterWithReservedCharacters: z.string().optional() + }).optional() }); export const zDeprecatedCallData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional(), headers: z.object({ - parameter: z.union([ - zDeprecatedModel, - z.null() - ]) + parameter: zDeprecatedModel.nullable() }) }); export const zCallWithParametersData = z.object({ - body: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + body: z.record(z.string(), z.unknown()).nullable(), path: z.object({ - parameterPath: z.union([ - z.string(), - z.null() - ]), - 'api-version': z.union([ - z.string(), - z.null() - ]) + parameterPath: z.string().nullable(), + 'api-version': z.string().nullable() }), query: z.object({ - foo_ref_enum: z.optional(zModelWithNestedArrayEnumsDataFoo), + foo_ref_enum: zModelWithNestedArrayEnumsDataFoo.optional(), foo_all_of_enum: zModelWithNestedArrayEnumsDataFoo, - cursor: z.union([ - z.string(), - z.null() - ]) + cursor: z.string().nullable() }), headers: z.object({ - parameterHeader: z.union([ - z.string(), - z.null() - ]) + parameterHeader: z.string().nullable() }) }); export const zCallWithWeirdParameterNamesData = z.object({ - body: z.union([ - zModelWithString, - z.null() - ]), + body: zModelWithString.nullable(), path: z.object({ - 'parameter.path.1': z.optional(z.string()), - 'parameter-path-2': z.optional(z.string()), - 'PARAMETER-PATH-3': z.optional(z.string()), - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'parameter.path.1': z.string().optional(), + 'parameter-path-2': z.string().optional(), + 'PARAMETER-PATH-3': z.string().optional(), + 'api-version': z.string().nullable() }), query: z.object({ - default: z.optional(z.string()), - 'parameter-query': z.union([ - z.string(), - z.null() - ]) + default: z.string().optional(), + 'parameter-query': z.string().nullable() }), headers: z.object({ - 'parameter.header': z.union([ - z.string(), - z.null() - ]) + 'parameter.header': z.string().nullable() }) }); export const zGetCallWithOptionalParamData = z.object({ body: zModelWithOneOfEnum, - path: z.optional(z.never()), - query: z.optional(z.object({ - page: z.optional(z.number()) - })) + path: z.never().optional(), + query: z.object({ + page: z.number().optional() + }).optional() }); export const zPostCallWithOptionalParamData = z.object({ - body: z.optional(z.object({ - offset: z.optional(z.union([ - z.number(), - z.null() - ])) - })), - path: z.optional(z.never()), + body: z.object({ + offset: z.number().nullish() + }).optional(), + path: z.never().optional(), query: z.object({ parameter: zPageable }) @@ -1390,114 +1281,96 @@ export const zPostCallWithOptionalParamResponse = z.union([ ]); export const zPostApiVbyApiVersionRequestBodyData = z.object({ - body: z.optional(zSimpleRequestBody), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleRequestBody.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zPostApiVbyApiVersionFormDataData = z.object({ - body: z.optional(zSimpleFormData), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameter: z.optional(z.string()) - })) + body: zSimpleFormData.optional(), + path: z.never().optional(), + query: z.object({ + parameter: z.string().optional() + }).optional() }); export const zCallWithDefaultParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.union([ - z.string().default('Hello World!'), - z.null() - ])).default('Hello World!'), - parameterNumber: z.optional(z.union([ - z.number().default(123), - z.null() - ])).default(123), - parameterBoolean: z.optional(z.union([ - z.boolean().default(true), - z.null() - ])).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().nullish().default('Hello World!'), + parameterNumber: z.number().nullish().default(123), + parameterBoolean: z.boolean().nullish().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(z.union([ - zModelWithString.default({ prop: 'Hello World!' }), - z.null() - ])) - })) + ]).optional(), + parameterModel: zModelWithString.nullish() + }).optional() }); export const zCallWithDefaultOptionalParametersData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.object({ - parameterString: z.optional(z.string()).default('Hello World!'), - parameterNumber: z.optional(z.number()).default(123), - parameterBoolean: z.optional(z.boolean()).default(true), - parameterEnum: z.optional(z.enum([ + body: z.never().optional(), + path: z.never().optional(), + query: z.object({ + parameterString: z.string().optional().default('Hello World!'), + parameterNumber: z.number().optional().default(123), + parameterBoolean: z.boolean().optional().default(true), + parameterEnum: z.enum([ 'Success', 'Warning', 'Error' - ])), - parameterModel: z.optional(zModelWithString).default({ prop: 'Hello World!' }) - })) + ]).optional(), + parameterModel: zModelWithString.optional().default({ prop: 'Hello World!' }) + }).optional() }); export const zCallToTestOrderOfParamsData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterOptionalStringWithDefault: z.optional(z.string()).default('Hello World!'), - parameterOptionalStringWithEmptyDefault: z.optional(z.string()).default(''), - parameterOptionalStringWithNoDefault: z.optional(z.string()), + parameterOptionalStringWithDefault: z.string().optional().default('Hello World!'), + parameterOptionalStringWithEmptyDefault: z.string().optional().default(''), + parameterOptionalStringWithNoDefault: z.string().optional(), parameterStringWithDefault: z.string().default('Hello World!'), parameterStringWithEmptyDefault: z.string().default(''), parameterStringWithNoDefault: z.string(), - parameterStringNullableWithNoDefault: z.optional(z.union([ - z.string(), - z.null() - ])), - parameterStringNullableWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + parameterStringNullableWithNoDefault: z.string().nullish(), + parameterStringNullableWithDefault: z.string().nullish().default(null) }) }); export const zDuplicateNameData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName2Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName3Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDuplicateName4Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1506,9 +1379,9 @@ export const zCallWithNoContentResponseData = z.object({ export const zCallWithNoContentResponseResponse = z.void(); export const zCallWithResponseAndNoContentResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseAndNoContentResponseResponse = z.union([ @@ -1517,17 +1390,17 @@ export const zCallWithResponseAndNoContentResponseResponse = z.union([ ]); export const zDummyAData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zDummyAResponse = z400; export const zDummyBData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** @@ -1536,17 +1409,17 @@ export const zDummyBData = z.object({ export const zDummyBResponse = z.void(); export const zCallWithResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponseResponse = zImport; export const zCallWithDuplicateResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithDuplicateResponsesResponse = z.union([ @@ -1555,81 +1428,50 @@ export const zCallWithDuplicateResponsesResponse = z.union([ ]); export const zCallWithResponsesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zCallWithResponsesResponse = z.union([ z.object({ - '@namespace.string': z.optional(z.string().readonly()), - '@namespace.integer': z.optional(z.int().readonly()), - value: z.optional(z.array(zModelWithString).readonly()) + '@namespace.string': z.string().readonly().optional(), + '@namespace.integer': z.int().readonly().optional(), + value: z.array(zModelWithString).readonly().optional() }), zModelThatExtends, zModelThatExtendsExtends ]); export const zCollectionFormatData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ - parameterArrayCSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArraySSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayTSV: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayPipes: z.union([ - z.array(z.string()), - z.null() - ]), - parameterArrayMulti: z.union([ - z.array(z.string()), - z.null() - ]) + parameterArrayCSV: z.array(z.string()).nullable(), + parameterArraySSV: z.array(z.string()).nullable(), + parameterArrayTSV: z.array(z.string()).nullable(), + parameterArrayPipes: z.array(z.string()).nullable(), + parameterArrayMulti: z.array(z.string()).nullable() }) }); export const zTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' })) - })), + body: z.never().optional(), + path: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).optional() + }).optional(), query: z.object({ parameterNumber: z.number().default(123), - parameterString: z.union([ - z.string().default('default'), - z.null() - ]).default('default'), - parameterBoolean: z.union([ - z.boolean().default(true), - z.null() - ]).default(true), - parameterObject: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]).default(null), - parameterArray: z.union([ - z.array(z.string()), - z.null() - ]), - parameterDictionary: z.union([ - z.record(z.string(), z.unknown()), - z.null() - ]), + parameterString: z.string().nullable().default('default'), + parameterBoolean: z.boolean().nullable().default(true), + parameterObject: z.record(z.string(), z.unknown()).nullable().default(null), + parameterArray: z.array(z.string()).nullable(), + parameterDictionary: z.record(z.string(), z.unknown()).nullable(), parameterEnum: z.union([ z.literal('Success'), z.literal('Warning'), - z.literal('Error'), - z.null() - ]) + z.literal('Error') + ]).nullable() }) }); @@ -1643,23 +1485,20 @@ export const zTypesResponse = z.union([ export const zUploadFileData = z.object({ body: z.string(), path: z.object({ - 'api-version': z.union([ - z.string(), - z.null() - ]) + 'api-version': z.string().nullable() }), - query: z.optional(z.never()) + query: z.never().optional() }); export const zUploadFileResponse = z.boolean(); export const zFileResponseData = z.object({ - body: z.optional(z.never()), + body: z.never().optional(), path: z.object({ id: z.string(), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1668,15 +1507,15 @@ export const zFileResponseData = z.object({ export const zFileResponseResponse = z.string(); export const zComplexTypesData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ parameterObject: z.object({ - first: z.optional(z.object({ - second: z.optional(z.object({ - third: z.optional(z.string()) - })) - })) + first: z.object({ + second: z.object({ + third: z.string().optional() + }).optional() + }).optional() }), parameterReference: zModelWithString }) @@ -1688,77 +1527,59 @@ export const zComplexTypesData = z.object({ export const zComplexTypesResponse = z.array(zModelWithString); export const zMultipartResponseData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** * OK */ export const zMultipartResponseResponse = z.object({ - file: z.optional(z.string()), - metadata: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(z.string()) - })) + file: z.string().optional(), + metadata: z.object({ + foo: z.string().optional(), + bar: z.string().optional() + }).optional() }); export const zMultipartRequestData = z.object({ - body: z.optional(z.object({ - content: z.optional(z.string()), - data: z.optional(z.union([ - zModelWithString, - z.null() - ])) - })), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.object({ + content: z.string().optional(), + data: zModelWithString.nullish() + }).optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zComplexParamsData = z.object({ - body: z.optional(z.object({ - key: z.union([ - z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly(), - z.null() - ]).readonly(), - name: z.union([ - z.string().max(255), - z.null() - ]), - enabled: z.optional(z.boolean()).default(true), + body: z.object({ + key: z.string().max(64).regex(/^[a-zA-Z0-9_]*$/).readonly().nullable(), + name: z.string().max(255).nullable(), + enabled: z.boolean().optional().default(true), type: z.enum([ 'Monkey', 'Horse', 'Bird' ]), - listOfModels: z.optional(z.union([ - z.array(zModelWithString), - z.null() - ])), - listOfStrings: z.optional(z.union([ - z.array(z.string()), - z.null() - ])), + listOfModels: z.array(zModelWithString).nullish(), + listOfStrings: z.array(z.string()).nullish(), parameters: z.union([ zModelWithString, zModelWithEnum, zModelWithArray, zModelWithDictionary ]), - user: z.optional(z.object({ - id: z.optional(z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly()), - name: z.optional(z.union([ - z.string().readonly(), - z.null() - ]).readonly()) - }).readonly()) - })), + user: z.object({ + id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }).readonly().optional(), + name: z.string().readonly().nullish() + }).readonly().optional() + }).optional(), path: z.object({ id: z.int().min(-2147483648, { error: 'Invalid value: Expected int32 to be >= -2147483648' }).max(2147483647, { error: 'Invalid value: Expected int32 to be <= 2147483647' }), 'api-version': z.string() }), - query: z.optional(z.never()) + query: z.never().optional() }); /** @@ -1767,22 +1588,22 @@ export const zComplexParamsData = z.object({ export const zComplexParamsResponse = zModelWithString; export const zCallWithResultFromHeaderData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); export const zTestErrorCodeData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ status: z.int() }) }); export const zNonAsciiæøåÆøÅöôêÊ字符串Data = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), + body: z.never().optional(), + path: z.never().optional(), query: z.object({ nonAsciiParamæøåÆØÅöôêÊ: z.int() }) @@ -1795,6 +1616,6 @@ export const zNonAsciiæøåÆøÅöôêÊ字符串Response = z.array(zNonAsciiS export const zPutWithFormUrlEncodedData = z.object({ body: zArrayWithStrings, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/defaults-with-ref-and-anyof/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/defaults-with-ref-and-anyof/zod.gen.ts index 2fe0a3019..c546b3aa9 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/defaults-with-ref-and-anyof/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/defaults-with-ref-and-anyof/zod.gen.ts @@ -19,16 +19,7 @@ export const zTestSchema = z.object({ primitiveDefault: z.number().default(42), refWithPrimitiveDefault: zAudioFormat.default('pcm_16bit_44.1khz'), refWithObjectDefault: zNestedConfig.default({ model: 'gpt-4', temperature: 1 }), - anyOfWithNullDefault: z.union([ - z.number(), - z.null() - ]).default(null), - anyOfWithRefAndNullDefault: z.union([ - zLanguage, - z.null() - ]).default(null), - optionalAnyOfWithDefault: z.optional(z.union([ - z.string(), - z.null() - ])).default(null) + anyOfWithNullDefault: z.number().nullable().default(null), + anyOfWithRefAndNullDefault: zLanguage.nullable().default(null), + optionalAnyOfWithDefault: z.string().nullish().default(null) }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts index 75b7a3bf7..991382570 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-null/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod'; -export const zFoo = z.nullable(z.enum(['foo', 'bar'])); +export const zFoo = z.enum(['foo', 'bar']).nullable(); export const zBar = z.enum(['foo', 'bar']); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts index 76bf417b2..8e742f44e 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/enum-resolver-permissive/zod.gen.ts @@ -2,7 +2,7 @@ import * as z from 'zod'; -export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]); +export const zFoo = z.union([z.enum(['foo', 'bar']), z.string()]).nullable(); export const zBar = z.union([z.enum(['foo', 'bar']), z.string()]); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts index 90862440d..cc881e866 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/schema-const/zod.gen.ts @@ -3,35 +3,35 @@ import * as z from 'zod'; export const zFoo = z.object({ - foo: z.optional(z.literal('foo')), - bar: z.optional(z.literal(3.2)), - baz: z.optional(z.literal(-1)), - qux: z.optional(z.literal(true)), - quux: z.optional(z.tuple([ + foo: z.literal('foo').optional(), + bar: z.literal(3.2).optional(), + baz: z.literal(-1).optional(), + qux: z.literal(true).optional(), + quux: z.tuple([ z.literal(1), z.literal(2), z.literal(3), z.literal('foo'), z.literal(true) - ])), - corge: z.optional(z.record(z.string(), z.unknown())), - garply: z.optional(z.literal(BigInt('10'))), - numberInt8: z.optional(z.literal(100)), - numberInt16: z.optional(z.literal(1000)), - numberInt32: z.optional(z.literal(100000)), - numberInt64: z.optional(z.literal(BigInt(1000000000000))), - numberUint8: z.optional(z.literal(200)), - numberUint16: z.optional(z.literal(50000)), - numberUint32: z.optional(z.literal(3000000000)), - numberUint64: z.optional(z.literal(BigInt(18000000000000000000))), - integerInt8: z.optional(z.literal(-100)), - integerInt16: z.optional(z.literal(-1000)), - integerInt32: z.optional(z.literal(-100000)), - integerInt64: z.optional(z.literal(BigInt(-1000000000000))), - integerUint8: z.optional(z.literal(255)), - integerUint16: z.optional(z.literal(65535)), - integerUint32: z.optional(z.literal(4294967295)), - integerUint64: z.optional(z.literal(BigInt('18446744073709551615'))), - stringInt64: z.optional(z.literal(BigInt('-9223372036854775808'))), - stringUint64: z.optional(z.literal(BigInt('18446744073709551615'))) + ]).optional(), + corge: z.record(z.string(), z.unknown()).optional(), + garply: z.literal(BigInt('10')).optional(), + numberInt8: z.literal(100).optional(), + numberInt16: z.literal(1000).optional(), + numberInt32: z.literal(100000).optional(), + numberInt64: z.literal(BigInt(1000000000000)).optional(), + numberUint8: z.literal(200).optional(), + numberUint16: z.literal(50000).optional(), + numberUint32: z.literal(3000000000).optional(), + numberUint64: z.literal(BigInt(18000000000000000000)).optional(), + integerInt8: z.literal(-100).optional(), + integerInt16: z.literal(-1000).optional(), + integerInt32: z.literal(-100000).optional(), + integerInt64: z.literal(BigInt(-1000000000000)).optional(), + integerUint8: z.literal(255).optional(), + integerUint16: z.literal(65535).optional(), + integerUint32: z.literal(4294967295).optional(), + integerUint64: z.literal(BigInt('18446744073709551615')).optional(), + stringInt64: z.literal(BigInt('-9223372036854775808')).optional(), + stringUint64: z.literal(BigInt('18446744073709551615')).optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts index b4eb8a8ef..bb1956f79 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/type-format-zod/zod.gen.ts @@ -3,7 +3,7 @@ import * as z from 'zod'; export const zFoo = z.object({ - bar: z.optional(z.int()), + bar: z.int().optional(), foo: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' }).default(BigInt(0)), id: z.string() }); @@ -13,9 +13,9 @@ export const zBar = z.object({ }); export const zPostFooData = z.object({ - body: z.optional(z.never()), - path: z.optional(z.never()), - query: z.optional(z.never()) + body: z.never().optional(), + path: z.never().optional(), + query: z.never().optional() }); /** diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts index 89a650cbb..df6a412ac 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-bigint-min-max/zod.gen.ts @@ -3,5 +3,5 @@ import * as z from 'zod'; export const zFoo = z.object({ - foo: z.optional(z.coerce.bigint().gte(BigInt(0)).lte(BigInt(100))) + foo: z.coerce.bigint().gte(BigInt(0)).lte(BigInt(100)).optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts index 8762c33e4..7f27bf16c 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref-2/zod.gen.ts @@ -3,10 +3,7 @@ import * as z from 'zod'; export const zBar = z.object({ - bar: z.union([ - z.array(z.lazy((): any => zBar)), - z.null() - ]) + bar: z.array(z.lazy((): any => zBar)).nullable() }); export const zFoo = z.object({ diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts index 17d574229..bb9072294 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-circular-ref/zod.gen.ts @@ -3,13 +3,11 @@ import * as z from 'zod'; export const zBar = z.object({ - get bar() { - return z.optional(z.array(z.lazy((): any => zBar))); - } + bar: z.array(z.lazy((): any => zBar)).optional() }); export const zFoo = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zBaz = z.lazy((): any => zQux); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts index c0332c774..cc4b41933 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-dates/zod.gen.ts @@ -5,31 +5,24 @@ import * as z from 'zod'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); /** @@ -38,27 +31,27 @@ export const zBar = z.object({ export const zFoo2 = z.string(); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime({ offset: true })) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime({ offset: true }).optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts index 4f634ac6e..ebee5444a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-metadata/zod.gen.ts @@ -5,37 +5,30 @@ import * as z from 'zod'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/).register(z.globalRegistry, { - description: 'This is foo property.' - })), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { - description: 'This is baz property.' - })); - }, - qux: z.optional(z.int().gt(0).register(z.globalRegistry, { - description: 'This is qux property.' - })).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).register(z.globalRegistry, { + description: 'This is foo property.' + }).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).register(z.globalRegistry, { + description: 'This is baz property.' + }).optional(), + qux: z.int().gt(0).register(z.globalRegistry, { + description: 'This is qux property.' + }).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }).register(z.globalRegistry, { description: 'This is Bar schema.' }); @@ -48,29 +41,29 @@ export const zFoo2 = z.string().register(z.globalRegistry, { }); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string().register(z.globalRegistry, { + path: z.never().optional(), + query: z.object({ + foo: z.string().register(z.globalRegistry, { description: 'This is Foo parameter.' - })), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + }).optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts index 8950aeab2..75fc6f38a 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-types/zod.gen.ts @@ -7,7 +7,7 @@ export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export type BazZodType = z.infer; export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); export type QuxZodType = z.infer; @@ -15,19 +15,12 @@ export type QuxZodType = z.infer; /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); export type FooZodType = z.infer; @@ -35,7 +28,7 @@ export type FooZodType = z.infer; * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); export type BarZodType = z.infer; @@ -48,33 +41,33 @@ export const zFoo2 = z.string(); export type FooZodType2 = z.infer; export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export type FooZodType3 = z.infer; export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export type PatchFooDataZodType = z.infer; export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); export type PostFooDataZodType = z.infer; diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts index ede17a854..2531cfc11 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators-union-merge/zod.gen.ts @@ -32,7 +32,7 @@ export const zCatDetails = z.object({ export const zPetStore = z.object({ animals: z.array(z.object({ name: z.string(), - type: z.optional(z.enum(['dog', 'cat'])), + type: z.enum(['dog', 'cat']).optional(), details: z.union([ zDogDetails, zCatDetails diff --git a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators/zod.gen.ts b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators/zod.gen.ts index 7f171ef13..7c70ac7f1 100644 --- a/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators/zod.gen.ts +++ b/packages/openapi-ts-tests/zod/v4/__snapshots__/3.1.x/v4/validators/zod.gen.ts @@ -5,31 +5,24 @@ import * as z from 'zod'; export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz'); export const zQux = z.record(z.string(), z.object({ - qux: z.optional(z.string()) + qux: z.string().optional() })); /** * This is Foo schema. */ -export const zFoo = z.union([ - z.object({ - foo: z.optional(z.string().regex(/^\d{3}-\d{2}-\d{4}$/)), - get bar() { - return z.optional(z.lazy((): any => zBar)); - }, - get baz() { - return z.optional(z.array(z.lazy((): any => zFoo))); - }, - qux: z.optional(z.int().gt(0)).default(0) - }), - z.null() -]).default(null); +export const zFoo = z.object({ + foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(), + bar: z.lazy((): any => zBar).optional(), + baz: z.array(z.lazy((): any => zFoo)).optional(), + qux: z.int().gt(0).optional().default(0) +}).nullable().default(null); /** * This is Bar schema. */ export const zBar = z.object({ - foo: z.optional(zFoo) + foo: zFoo.optional() }); /** @@ -38,27 +31,27 @@ export const zBar = z.object({ export const zFoo2 = z.string(); export const zFoo3 = z.object({ - foo: z.optional(zBar) + foo: zBar.optional() }); export const zPatchFooData = z.object({ body: z.object({ - foo: z.optional(z.string()) + foo: z.string().optional() }), - path: z.optional(z.never()), - query: z.optional(z.object({ - foo: z.optional(z.string()), - bar: z.optional(zBar), - baz: z.optional(z.object({ - baz: z.optional(z.string()) - })), - qux: z.optional(z.iso.date()), - quux: z.optional(z.iso.datetime()) - })) + path: z.never().optional(), + query: z.object({ + foo: z.string().optional(), + bar: zBar.optional(), + baz: z.object({ + baz: z.string().optional() + }).optional(), + qux: z.iso.date().optional(), + quux: z.iso.datetime().optional() + }).optional() }); export const zPostFooData = z.object({ body: zFoo3, - path: z.optional(z.never()), - query: z.optional(z.never()) + path: z.never().optional(), + query: z.never().optional() }); diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/array.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/array.ts index ce5dd3bc9..36eecacf2 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/array.ts @@ -7,13 +7,13 @@ import { $ } from '../../../../../ts-dsl'; import type { IrSchemaToAstOptions } from '../../shared/types'; import { irSchemaToAst } from '../plugin'; -export const arrayToAst = ({ +export function arrayToAst({ plugin, schema, state, }: IrSchemaToAstOptions & { schema: SchemaWithType<'array'>; -}): TypeTsDsl => { +}): TypeTsDsl { if (!schema.items) { return $.type('Array').generic($.type(plugin.config.topType)); } @@ -43,4 +43,4 @@ export const arrayToAst = ({ return schema.logicalOperator === 'and' ? $.type('Array').generic($.type.and(...itemTypes)) : $.type('Array').generic($.type.or(...itemTypes)); -}; +} diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/enum.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/enum.ts index bf1151cb5..d47831e10 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/enum.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/enum.ts @@ -4,13 +4,13 @@ import type { MaybeTsDsl, TypeTsDsl } from '../../../../../ts-dsl'; import type { IrSchemaToAstOptions } from '../../shared/types'; import { irSchemaToAst } from '../plugin'; -export const enumToAst = ({ +export function enumToAst({ plugin, schema, state, }: IrSchemaToAstOptions & { schema: SchemaWithType<'enum'>; -}): MaybeTsDsl => { +}): MaybeTsDsl { const type = irSchemaToAst({ plugin, schema: { @@ -20,4 +20,4 @@ export const enumToAst = ({ state, }); return type; -}; +} diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/object.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/object.ts index c06359350..b8f31cf37 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/object.ts @@ -8,13 +8,13 @@ import { $ } from '../../../../../ts-dsl'; import type { IrSchemaToAstOptions } from '../../shared/types'; import { irSchemaToAst } from '../plugin'; -export const objectToAst = ({ +export function objectToAst({ plugin, schema, state, }: IrSchemaToAstOptions & { schema: SchemaWithType<'object'>; -}): TypeTsDsl => { +}): TypeTsDsl { // TODO: parser - handle constants const shape = $.type.object(); const required = schema.required ?? []; @@ -110,4 +110,4 @@ export const objectToAst = ({ } return shape; -}; +} diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/tuple.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/tuple.ts index e7be8d462..f8e9be260 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/tuple.ts @@ -6,13 +6,13 @@ import { $ } from '../../../../../ts-dsl'; import type { IrSchemaToAstOptions } from '../../shared/types'; import { irSchemaToAst } from '../plugin'; -export const tupleToAst = ({ +export function tupleToAst({ plugin, schema, state, }: IrSchemaToAstOptions & { schema: SchemaWithType<'tuple'>; -}): MaybeTsDsl => { +}): MaybeTsDsl { let itemTypes: Array> = []; if (schema.const && Array.isArray(schema.const)) { @@ -32,4 +32,4 @@ export const tupleToAst = ({ } return $.type.tuple(...itemTypes); -}; +} diff --git a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/unknown.ts b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/unknown.ts index 2150895ba..43b6f006a 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/unknown.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/typescript/v1/toAst/unknown.ts @@ -4,11 +4,11 @@ import type { TypeTsDsl } from '../../../../../ts-dsl'; import { $ } from '../../../../../ts-dsl'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const unknownToAst = ({ +export function unknownToAst({ plugin, }: IrSchemaToAstOptions & { schema: SchemaWithType<'unknown'>; -}): TypeTsDsl => { +}): TypeTsDsl { const node = $.type(plugin.config.topType); return node; -}; +} diff --git a/packages/openapi-ts/src/plugins/arktype/v2/toAst/object.ts b/packages/openapi-ts/src/plugins/arktype/v2/toAst/object.ts index 817937c1f..eac0fb7f6 100644 --- a/packages/openapi-ts/src/plugins/arktype/v2/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/arktype/v2/toAst/object.ts @@ -6,13 +6,13 @@ import { $ } from '../../../../ts-dsl'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; import { irSchemaToAst } from '../plugin'; -export const objectToAst = ({ +export function objectToAst({ plugin, schema, state, }: IrSchemaToAstOptions & { schema: SchemaWithType<'object'>; -}): Omit => { +}): Omit { const result: Partial> = {}; // TODO: parser - handle constants @@ -106,4 +106,4 @@ export const objectToAst = ({ } return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts b/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts index edd0b4a00..384ab5082 100644 --- a/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts +++ b/packages/openapi-ts/src/plugins/valibot/resolvers/types.ts @@ -1,18 +1,11 @@ import type { Refs, Symbol } from '@hey-api/codegen-core'; -import type { - IR, - Plugin, - SchemaResult, - SchemaVisitorContext, - SchemaWithType, - Walker, -} from '@hey-api/shared'; +import type { IR, Plugin, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/utils/coerce'; import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats'; import type { $, DollarTsDsl } from '../../../ts-dsl'; import type { Pipe, PipeResult, Pipes, PipesUtils } from '../shared/pipes'; -import type { Ast, IrSchemaToAstOptions, PluginState } from '../shared/types'; +import type { Ast, IrSchemaToAstOptions, PluginState, ValibotSchemaResult } from '../shared/types'; import type { ValibotPlugin } from '../types'; export type Resolvers = Plugin.Resolvers<{ @@ -156,7 +149,7 @@ export interface NumberResolverContext extends BaseContext { } export interface ObjectResolverContext extends BaseContext { - applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; + applyModifiers: (result: ValibotSchemaResult, opts: { optional?: boolean }) => Ast; /** * Nodes used to build different parts of the object schema. */ @@ -177,7 +170,7 @@ export interface ObjectResolverContext extends BaseContext { ast: Partial>; state: Refs; }; - walk: Walker; + walk: Walker; walkerCtx: SchemaVisitorContext; } diff --git a/packages/openapi-ts/src/plugins/valibot/shared/types.ts b/packages/openapi-ts/src/plugins/valibot/shared/types.ts index aba45dc5a..6ac39925b 100644 --- a/packages/openapi-ts/src/plugins/valibot/shared/types.ts +++ b/packages/openapi-ts/src/plugins/valibot/shared/types.ts @@ -16,7 +16,7 @@ export type IrSchemaToAstOptions = { plugin: ValibotPlugin['Instance']; /** The plugin state references. */ state: Refs; - walk: Walker; + walk: Walker; }; export type PluginState = Pick, 'path'> & @@ -28,3 +28,28 @@ export type ValidatorArgs = { operation: IR.OperationObject; plugin: ValibotPlugin['Instance']; }; + +/** + * The result from schema walking. + */ +export interface ValibotSchemaResult { + /** Default value from schema, if any. */ + default?: unknown; + /** The Valibot pipes AST. */ + expression: { pipes: Pipes }; + /** The original schema format (for BigInt coercion). */ + format?: string; + /** Whether any child contains a lazy expression. */ + hasLazyExpression?: boolean; + /** Does this schema explicitly allow null? */ + nullable: boolean; + /** Is this schema read-only? */ + readonly: boolean; +} + +/** + * The finalized expression after applyModifiers. + */ +export interface ValibotAppliedResult { + pipes: Pipes; +} diff --git a/packages/openapi-ts/src/plugins/valibot/v1/processor.ts b/packages/openapi-ts/src/plugins/valibot/v1/processor.ts index f9713342c..8c0073140 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/processor.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/processor.ts @@ -4,7 +4,7 @@ import { createSchemaProcessor, createSchemaWalker, pathToJsonPointer } from '@h import { exportAst } from '../shared/export'; import type { ProcessorContext, ProcessorResult } from '../shared/processor'; -import type { PluginState } from '../shared/types'; +import type { PluginState, ValibotAppliedResult } from '../shared/types'; import type { ValibotPlugin } from '../types'; import { createVisitor } from './walker'; @@ -54,10 +54,10 @@ export function createProcessor(plugin: ValibotPlugin['Instance']): ProcessorRes plugin, }); const ast = - visitor.applyModifiers(result, { + (visitor.applyModifiers(result, { path: ref(ctx.path), plugin, - }) ?? result.expression; + }) as ValibotAppliedResult) ?? result.expression; if (result.hasLazyExpression) { state.hasLazyExpression['~ref'] = true; } diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts index 639c33cb0..c4e453a93 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/array.ts @@ -1,15 +1,23 @@ -import type { SchemaResult, SchemaWithType } from '@hey-api/shared'; +import type { SchemaWithType } from '@hey-api/shared'; import { childContext, deduplicateSchema } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { pipesToNode } from '../../shared/pipes'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; +import type { + Ast, + IrSchemaToAstOptions, + ValibotAppliedResult, + ValibotSchemaResult, +} from '../../shared/types'; import { identifiers } from '../constants'; import { unknownToAst } from './unknown'; export function arrayToAst( options: IrSchemaToAstOptions & { - applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; + applyModifiers: ( + result: ValibotSchemaResult, + opts: { optional?: boolean }, + ) => ValibotAppliedResult; schema: SchemaWithType<'array'>; }, ): Omit { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts index ea88b4400..33b6abdb1 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/object.ts @@ -1,20 +1,28 @@ -import type { SchemaResult, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; +import type { SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import type { ObjectResolverContext } from '../../resolvers'; import type { Pipe, PipeResult } from '../../shared/pipes'; import { pipes } from '../../shared/pipes'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; +import type { + Ast, + IrSchemaToAstOptions, + ValibotAppliedResult, + ValibotSchemaResult, +} from '../../shared/types'; import type { ValibotPlugin } from '../../types'; import { identifiers } from '../constants'; type WalkerCtx = SchemaVisitorContext; interface ObjectToAstOptions extends IrSchemaToAstOptions { - applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; + applyModifiers: ( + result: ValibotSchemaResult, + opts: { optional?: boolean }, + ) => ValibotAppliedResult; schema: SchemaWithType<'object'>; - walk: Walker; + walk: Walker; walkerCtx: WalkerCtx; } @@ -89,11 +97,10 @@ function shapeNode(ctx: ExtendedContext): ReturnType { } export function objectToAst(options: ObjectToAstOptions): Omit { - const { applyModifiers, plugin, walk, walkerCtx } = options; + const { plugin } = options; const ctx: ExtendedContext = { ...options, $, - applyModifiers, nodes: { additionalProperties: additionalPropertiesNode, base: baseNode, @@ -110,8 +117,6 @@ export function objectToAst(options: ObjectToAstOptions): Omit ast: {}, state: options.state, }, - walk, - walkerCtx, }; const resolver = plugin.config['~resolvers']?.object; const node = resolver?.(ctx) ?? objectResolver(ctx); diff --git a/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts b/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts index 4eb99a28d..ba3a2e7d7 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/toAst/tuple.ts @@ -1,15 +1,23 @@ -import type { SchemaResult, SchemaWithType } from '@hey-api/shared'; +import type { SchemaWithType } from '@hey-api/shared'; import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { pipesToNode } from '../../shared/pipes'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; +import type { + Ast, + IrSchemaToAstOptions, + ValibotAppliedResult, + ValibotSchemaResult, +} from '../../shared/types'; import { identifiers } from '../constants'; import { unknownToAst } from './unknown'; export function tupleToAst( options: IrSchemaToAstOptions & { - applyModifiers: (result: SchemaResult, opts: { optional?: boolean }) => Ast; + applyModifiers: ( + result: ValibotSchemaResult, + opts: { optional?: boolean }, + ) => ValibotAppliedResult; schema: SchemaWithType<'tuple'>; }, ): Omit { diff --git a/packages/openapi-ts/src/plugins/valibot/v1/walker.ts b/packages/openapi-ts/src/plugins/valibot/v1/walker.ts index 7498c3056..739bbf394 100644 --- a/packages/openapi-ts/src/plugins/valibot/v1/walker.ts +++ b/packages/openapi-ts/src/plugins/valibot/v1/walker.ts @@ -1,13 +1,13 @@ import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; import { fromRef } from '@hey-api/codegen-core'; -import type { IR, SchemaExtractor, SchemaResult, SchemaVisitor } from '@hey-api/shared'; +import type { SchemaExtractor, SchemaVisitor } from '@hey-api/shared'; import { pathToJsonPointer } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import { maybeBigInt, shouldCoerceToBigInt } from '../../shared/utils/coerce'; import { pipesToNode } from '../shared/pipes'; import type { ProcessorContext } from '../shared/processor'; -import type { Ast, PluginState } from '../shared/types'; +import type { PluginState, ValibotAppliedResult, ValibotSchemaResult } from '../shared/types'; import type { ValibotPlugin } from '../types'; import { identifiers } from './constants'; import { arrayToAst } from './toAst/array'; @@ -30,16 +30,16 @@ export interface VisitorConfig { state: Refs; } -function getDefaultValue(result: SchemaResult) { +function getDefaultValue(result: ValibotSchemaResult) { return result.format ? maybeBigInt(result.default, result.format) : $.fromValue(result.default); } export function createVisitor( config: VisitorConfig, -): SchemaVisitor { +): SchemaVisitor { const { schemaExtractor, state } = config; return { - applyModifiers(result, ctx, options = {}) { + applyModifiers(result, ctx, options = {}): ValibotAppliedResult { const { optional } = options; const v = ctx.plugin.external('valibot.v'); const pipes = [...result.expression.pipes]; @@ -82,8 +82,8 @@ export function createVisitor( return { pipes }; }, array(schema, ctx, walk) { - const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => - this.applyModifiers(result, ctx, opts); + const applyModifiers = (result: ValibotSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ValibotAppliedResult; const ast = arrayToAst({ ...ctx, applyModifiers, @@ -92,18 +92,20 @@ export function createVisitor( walk, }); return { + default: schema.default, expression: ast, hasLazyExpression: state.hasLazyExpression['~ref'], nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, boolean(schema, ctx) { const pipe = booleanToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, enum(schema, ctx) { @@ -111,18 +113,20 @@ export function createVisitor( const hasNull = schema.items?.some((item) => item.type === 'null' || item.const === null) ?? false; return { + default: schema.default, expression: { pipes: [pipe] }, nullable: hasNull, - readonly: false, + readonly: schema.accessScope === 'read', }; }, integer(schema, ctx) { const pipe = numberToNode({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, format: schema.format, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, intercept(schema, ctx, walk) { @@ -142,12 +146,13 @@ export function createVisitor( } } }, - intersection(items, schemas, ctx) { + intersection(items, schemas, parentSchema, ctx) { const v = ctx.plugin.external('valibot.v'); const hasAnyLazy = items.some((item) => item.hasLazyExpression); const itemNodes = items.map((item) => pipesToNode(item.expression.pipes, ctx.plugin)); return { + default: parentSchema.default, expression: { pipes: [ $(v) @@ -163,6 +168,7 @@ export function createVisitor( never(schema, ctx) { const pipe = neverToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, readonly: false, @@ -171,6 +177,7 @@ export function createVisitor( null(schema, ctx) { const pipe = nullToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, readonly: false, @@ -179,15 +186,16 @@ export function createVisitor( number(schema, ctx) { const pipe = numberToNode({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, format: schema.format, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, object(schema, ctx, walk) { - const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => - this.applyModifiers(result, ctx, opts); + const applyModifiers = (result: ValibotSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ValibotAppliedResult; const ast = objectToAst({ applyModifiers, plugin: ctx.plugin, @@ -197,10 +205,11 @@ export function createVisitor( walkerCtx: ctx, }); return { + default: schema.default, expression: ast, - hasLazyExpression: ast.hasLazyExpression ?? false, + hasLazyExpression: state.hasLazyExpression['~ref'], nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, postProcess(result, schema, ctx) { @@ -229,14 +238,16 @@ export function createVisitor( if (ctx.plugin.isSymbolRegistered(query)) { return { + default: schema.default, expression: { pipes: [$(refSymbol)] }, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; } state.hasLazyExpression['~ref'] = true; return { + default: schema.default, expression: { pipes: [ $(v) @@ -246,7 +257,7 @@ export function createVisitor( }, hasLazyExpression: true, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, string(schema, ctx) { @@ -256,22 +267,24 @@ export function createVisitor( schema: { ...schema, type: 'number' }, }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; } const pipe = stringToNode({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, tuple(schema, ctx, walk) { - const applyModifiers = (result: SchemaResult, opts: { optional?: boolean }) => - this.applyModifiers(result, ctx, opts); + const applyModifiers = (result: ValibotSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ValibotAppliedResult; const ast = tupleToAst({ ...ctx, applyModifiers, @@ -280,47 +293,43 @@ export function createVisitor( walk, }); return { + default: schema.default, expression: ast, hasLazyExpression: state.hasLazyExpression['~ref'], nullable: false, - readonly: false, + readonly: schema.accessScope === 'read', }; }, undefined(schema, ctx) { const pipe = undefinedToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, readonly: false, }; }, - union(items, schemas, ctx) { + union(items, schemas, parentSchema, ctx) { const v = ctx.plugin.external('valibot.v'); const hasAnyLazy = items.some((item) => item.hasLazyExpression); const hasNull = schemas.some((s) => s.type === 'null') || items.some((i) => i.nullable); const nonNullItems: typeof items = []; - const nonNullSchemas: Array = []; items.forEach((item, index) => { const schema = schemas[index]!; if (schema.type !== 'null') { nonNullItems.push(item); - nonNullSchemas.push(schema); } }); - // Build union expression WITHOUT null - null is tracked via nullable flag - let expression: Ast; + let expression: ValibotSchemaResult['expression']; if (nonNullItems.length === 0) { - // Union was only null expression = { pipes: [$(v).attr(identifiers.schemas.null).call()] }; } else if (nonNullItems.length === 1) { - // Single non-null item expression = nonNullItems[0]!.expression; } else { - // Multiple non-null items const itemNodes = nonNullItems.map((i) => pipesToNode(i.expression.pipes, ctx.plugin)); expression = { pipes: [ @@ -332,15 +341,17 @@ export function createVisitor( } return { + default: parentSchema.default, expression, hasLazyExpression: hasAnyLazy, nullable: hasNull, - readonly: false, + readonly: items.some((i) => i.readonly), }; }, unknown(schema, ctx) { const pipe = unknownToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, readonly: false, @@ -349,6 +360,7 @@ export function createVisitor( void(schema, ctx) { const pipe = voidToAst({ ...ctx, schema }); return { + default: schema.default, expression: { pipes: [pipe] }, nullable: false, readonly: false, diff --git a/packages/openapi-ts/src/plugins/zod/constants.ts b/packages/openapi-ts/src/plugins/zod/constants.ts index 8acc57bf8..0fa9a60e2 100644 --- a/packages/openapi-ts/src/plugins/zod/constants.ts +++ b/packages/openapi-ts/src/plugins/zod/constants.ts @@ -1,7 +1,9 @@ // TODO: this is inaccurate, it combines identifiers for all supported versions export const identifiers = { + AnyZodObject: 'AnyZodObject', ZodMiniOptional: 'ZodMiniOptional', ZodOptional: 'ZodOptional', + ZodTypeAny: 'ZodTypeAny', _default: '_default', and: 'and', array: 'array', diff --git a/packages/openapi-ts/src/plugins/zod/mini/plugin.ts b/packages/openapi-ts/src/plugins/zod/mini/plugin.ts index fa1a823c2..002c11748 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/plugin.ts @@ -1,174 +1,10 @@ -import type { SymbolMeta } from '@hey-api/codegen-core'; -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { IR, SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema, pathToJsonPointer } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; -import { maybeBigInt } from '../../../plugins/shared/utils/coerce'; -import { $ } from '../../../ts-dsl'; -import { identifiers } from '../constants'; import { getZodModule } from '../shared/module'; import { irOperationToAst } from '../shared/operation'; -import type { Ast, IrSchemaToAstOptions } from '../shared/types'; import { irWebhookToAst } from '../shared/webhook'; import type { ZodPlugin } from '../types'; import { createProcessor } from './processor'; -import { irSchemaWithTypeToAst } from './toAst'; - -export function irSchemaToAst({ - optional, - plugin, - schema, - schemaExtractor, - state, -}: IrSchemaToAstOptions & { - /** - * Accept `optional` to handle optional object properties. We can't handle - * this inside the object function because `.optional()` must come before - * `.default()` which is handled in this function. - */ - optional?: boolean; - schema: IR.SchemaObject; -}): Ast { - if (schemaExtractor && !schema.$ref) { - const extracted = schemaExtractor({ - meta: { - resource: 'definition', - resourceId: pathToJsonPointer(fromRef(state.path)), - }, - naming: plugin.config.definitions, - path: fromRef(state.path), - plugin, - schema, - }); - if (extracted !== schema) schema = extracted; - } - - let ast: Partial = {}; - - const z = plugin.external('zod.z'); - - if (schema.$ref) { - const query: SymbolMeta = { - category: 'schema', - resource: 'definition', - resourceId: schema.$ref, - tool: 'zod', - }; - const refSymbol = plugin.referenceSymbol(query); - if (plugin.isSymbolRegistered(query)) { - ast.expression = $(refSymbol); - } else { - ast.expression = $(z) - .attr(identifiers.lazy) - .call($.func().returns('any').do($(refSymbol).return())); - ast.hasLazyExpression = true; - state.hasLazyExpression['~ref'] = true; - } - } else if (schema.type) { - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: schema as SchemaWithType, - state, - }); - ast.expression = typeAst.expression; - ast.hasLazyExpression = typeAst.hasLazyExpression; - - if (plugin.config.metadata && schema.description) { - ast.expression = ast.expression - .attr(identifiers.register) - .call( - $(z).attr(identifiers.globalRegistry), - $.object().pretty().prop('description', $.literal(schema.description)), - ); - } - } else if (schema.items) { - schema = deduplicateSchema({ schema }); - - if (schema.items) { - const itemSchemas = schema.items.map((item, index) => - irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }), - ); - - if (schema.logicalOperator === 'and') { - const firstSchema = schema.items[0]!; - // we want to add an intersection, but not every schema can use the same API. - // if the first item contains another array or not an object, we cannot use - // `.merge()` as that does not exist on `.union()` and non-object schemas. - if ( - firstSchema.logicalOperator === 'or' || - (firstSchema.type && firstSchema.type !== 'object') - ) { - ast.expression = $(z) - .attr(identifiers.intersection) - .call(...itemSchemas.map((schema) => schema.expression)); - } else { - ast.expression = itemSchemas[0]!.expression; - itemSchemas.slice(1).forEach((schema) => { - ast.expression = $(z) - .attr(identifiers.intersection) - .call( - ast.expression, - schema.hasLazyExpression - ? $(z).attr(identifiers.lazy).call($.func().do(schema.expression.return())) - : schema.expression, - ); - }); - } - } else { - ast.expression = $(z) - .attr(identifiers.union) - .call( - $.array() - .pretty() - .elements(...itemSchemas.map((schema) => schema.expression)), - ); - } - } else { - ast = irSchemaToAst({ plugin, schema, state }); - } - } else { - // catch-all fallback for failed schemas - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: { - type: 'unknown', - }, - state, - }); - ast.expression = typeAst.expression; - } - - if (ast.expression) { - if (schema.accessScope === 'read') { - ast.expression = $(z).attr(identifiers.readonly).call(ast.expression); - } - - if (optional) { - ast.expression = $(z).attr(identifiers.optional).call(ast.expression); - ast.typeName = identifiers.ZodMiniOptional; - } - - if (schema.default !== undefined) { - ast.expression = $(z) - .attr(identifiers._default) - .call( - ast.expression, - schema.type === 'integer' || schema.type === 'number' - ? maybeBigInt(schema.default, schema.format) - : $.fromValue(schema.default), - ); - } - } - - return ast as Ast; -} export const handlerMini: ZodPlugin['Handler'] = ({ plugin }) => { plugin.symbol('z', { diff --git a/packages/openapi-ts/src/plugins/zod/mini/processor.ts b/packages/openapi-ts/src/plugins/zod/mini/processor.ts index 5b4364774..9868559f1 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/processor.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/processor.ts @@ -1,12 +1,12 @@ -import { refs } from '@hey-api/codegen-core'; +import { ref, refs } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; -import { createSchemaProcessor, pathToJsonPointer } from '@hey-api/shared'; +import { createSchemaProcessor, createSchemaWalker, pathToJsonPointer } from '@hey-api/shared'; import { exportAst } from '../shared/export'; import type { ProcessorContext, ProcessorResult } from '../shared/processor'; -import type { PluginState } from '../shared/types'; +import type { PluginState, ZodAppliedResult } from '../shared/types'; import type { ZodPlugin } from '../types'; -import { irSchemaToAst } from './plugin'; +import { createVisitor } from './walker'; export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult { const processor = createSchemaProcessor(); @@ -43,12 +43,24 @@ export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult tags: ctx.tags, }); - const ast = irSchemaToAst({ - plugin, - schema: ctx.schema, + const visitor = createVisitor({ schemaExtractor: extractor, state, }); + const walk = createSchemaWalker(visitor); + + const result = walk(ctx.schema, { + path: ref(ctx.path), + plugin, + }); + const ast = + (visitor.applyModifiers(result, { + path: ref(ctx.path), + plugin, + }) as ZodAppliedResult) ?? result.expression; + if (result.hasLazyExpression) { + state.hasLazyExpression['~ref'] = true; + } exportAst({ ...ctx, ast, plugin, state }); }); diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/array.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/array.ts index c71b88df7..809a6c69f 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/array.ts @@ -1,34 +1,37 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema } from '@hey-api/shared'; +import { childContext, deduplicateSchema } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; import { unknownToAst } from './unknown'; -export const arrayToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'array'>; -}): Omit => { - const z = plugin.external('zod.z'); +export function arrayToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'array'>; + }, +): Omit { + const { applyModifiers, plugin, walk } = options; + let { schema } = options; const result: Partial> = {}; + const z = plugin.external('zod.z'); const functionName = $(z).attr(identifiers.array); if (!schema.items) { result.expression = functionName.call( unknownToAst({ - plugin, + ...options, schema: { type: 'unknown', }, - state, }).expression, ); } else { @@ -36,18 +39,23 @@ export const arrayToAst = ({ // at least one item is guaranteed const itemExpressions = schema.items!.map((item, index) => { - const itemAst = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - if (itemAst.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } - return itemAst.expression; + + const finalExpr = applyModifiers(itemResult, { optional: false }); + return finalExpr.expression; }); if (itemExpressions.length === 1) { @@ -107,4 +115,4 @@ export const arrayToAst = ({ } return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/boolean.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/boolean.ts index 8f13b8335..4abdfe633 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/boolean.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/boolean.ts @@ -7,7 +7,7 @@ import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; export function booleanToAst({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'boolean'>; }): Omit { const result: Partial> = {}; diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/enum.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/enum.ts index f40ea631e..a78949a6b 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/enum.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/enum.ts @@ -64,14 +64,6 @@ function baseNode(ctx: EnumResolverContext): Chain { } } -function nullableNode(ctx: EnumResolverContext): Chain | undefined { - const { chain, symbols } = ctx; - const { z } = symbols; - const { isNullable } = ctx.nodes.items(ctx); - if (!isNullable) return; - return $(z).attr(identifiers.nullable).call(chain.current); -} - function enumResolver(ctx: EnumResolverContext): Chain { const { literalMembers } = ctx.nodes.items(ctx); @@ -82,27 +74,22 @@ function enumResolver(ctx: EnumResolverContext): Chain { const baseExpression = ctx.nodes.base(ctx); ctx.chain.current = baseExpression; - const nullableExpression = ctx.nodes.nullable(ctx); - if (nullableExpression) { - ctx.chain.current = nullableExpression; - } - return ctx.chain.current; } -export const enumToAst = ({ +export function enumToAst({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'enum'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const { literalMembers } = itemsNode({ $, chain: { current: $(z) }, - nodes: { base: baseNode, items: itemsNode, nullable: nullableNode }, + nodes: { base: baseNode, items: itemsNode }, plugin, schema, symbols: { z }, @@ -115,7 +102,6 @@ export const enumToAst = ({ schema: { type: 'unknown', }, - state, }); } @@ -127,7 +113,6 @@ export const enumToAst = ({ nodes: { base: baseNode, items: itemsNode, - nullable: nullableNode, }, plugin, schema, @@ -146,4 +131,4 @@ export const enumToAst = ({ return { expression: node, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/index.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/index.ts deleted file mode 100644 index f4962c0ee..000000000 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/index.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { SchemaWithType } from '@hey-api/shared'; - -import { shouldCoerceToBigInt } from '../../../../plugins/shared/utils/coerce'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { arrayToAst } from './array'; -import { booleanToAst } from './boolean'; -import { enumToAst } from './enum'; -import { neverToAst } from './never'; -import { nullToAst } from './null'; -import { numberToNode } from './number'; -import { objectToAst } from './object'; -import { stringToNode } from './string'; -import { tupleToAst } from './tuple'; -import { undefinedToAst } from './undefined'; -import { unknownToAst } from './unknown'; -import { voidToAst } from './void'; - -export function irSchemaWithTypeToAst({ - schema, - ...args -}: IrSchemaToAstOptions & { - schema: SchemaWithType; -}): Omit { - switch (schema.type) { - case 'array': - return arrayToAst({ - ...args, - schema: schema as SchemaWithType<'array'>, - }); - case 'boolean': - return booleanToAst({ - ...args, - schema: schema as SchemaWithType<'boolean'>, - }); - case 'enum': - return enumToAst({ - ...args, - schema: schema as SchemaWithType<'enum'>, - }); - case 'integer': - case 'number': - return numberToNode({ - ...args, - schema: schema as SchemaWithType<'integer' | 'number'>, - }); - case 'never': - return neverToAst({ - ...args, - schema: schema as SchemaWithType<'never'>, - }); - case 'null': - return nullToAst({ - ...args, - schema: schema as SchemaWithType<'null'>, - }); - case 'object': - return objectToAst({ - ...args, - schema: schema as SchemaWithType<'object'>, - }); - case 'string': - return shouldCoerceToBigInt(schema.format) - ? numberToNode({ - ...args, - schema: { ...schema, type: 'number' }, - }) - : stringToNode({ - ...args, - schema: schema as SchemaWithType<'string'>, - }); - case 'tuple': - return tupleToAst({ - ...args, - schema: schema as SchemaWithType<'tuple'>, - }); - case 'undefined': - return undefinedToAst({ - ...args, - schema: schema as SchemaWithType<'undefined'>, - }); - case 'unknown': - return unknownToAst({ - ...args, - schema: schema as SchemaWithType<'unknown'>, - }); - case 'void': - return voidToAst({ - ...args, - schema: schema as SchemaWithType<'void'>, - }); - } -} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/never.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/never.ts index faa0793e0..f890dcfc9 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/never.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/never.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const neverToAst = ({ +export function neverToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'never'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const result: Partial> = {}; result.expression = $(z).attr(identifiers.never).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/null.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/null.ts index 09f3e4373..dfbfad11c 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/null.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/null.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const nullToAst = ({ +export function nullToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'null'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const result: Partial> = {}; result.expression = $(z).attr(identifiers.null).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/number.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/number.ts index 5a47145f3..f3af724d8 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/number.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/number.ts @@ -99,13 +99,13 @@ function numberResolver(ctx: NumberResolverContext): Chain { return ctx.chain.current; } -export const numberToNode = ({ +export function numberToNode({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'integer' | 'number'>; -}): Omit => { +}): Omit { const ast: Partial> = {}; const z = plugin.external('zod.z'); const ctx: NumberResolverContext = { @@ -136,4 +136,4 @@ export const numberToNode = ({ const node = resolver?.(ctx) ?? numberResolver(ctx); ast.expression = node; return ast as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/object.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/object.ts index 89fc16a2d..1de13fb14 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/object.ts @@ -1,35 +1,52 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; +import type { SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { ObjectResolverContext } from '../../resolvers'; import type { Chain } from '../../shared/chain'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; +import type { ZodPlugin } from '../../types'; -function additionalPropertiesNode(ctx: ObjectResolverContext): Chain | null | undefined { - const { plugin, schema } = ctx; +type WalkerCtx = SchemaVisitorContext; + +interface ObjectToAstOptions extends IrSchemaToAstOptions { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'object'>; + walk: Walker; + walkerCtx: WalkerCtx; +} + +type ExtendedContext = ObjectResolverContext & { + applyModifiers: ObjectToAstOptions['applyModifiers']; + walk: ObjectToAstOptions['walk']; + walkerCtx: ObjectToAstOptions['walkerCtx']; +}; + +function additionalPropertiesNode(ctx: ExtendedContext): Chain | null | undefined { + const { schema, walk, walkerCtx } = ctx; if ( !schema.additionalProperties || (schema.properties && Object.keys(schema.properties).length > 0) - ) + ) { return; + } - const additionalAst = irSchemaToAst({ - plugin, - schema: schema.additionalProperties, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'additionalProperties']), - }, - }); - if (additionalAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - return additionalAst.expression; + const additionalResult = walk( + schema.additionalProperties, + childContext(walkerCtx, 'additionalProperties'), + ); + if (additionalResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + return additionalResult.expression.expression; } -function baseNode(ctx: ObjectResolverContext): Chain { +function baseNode(ctx: ExtendedContext): Chain { const { nodes, symbols } = ctx; const { z } = symbols; @@ -43,48 +60,43 @@ function baseNode(ctx: ObjectResolverContext): Chain { return $(z).attr(identifiers.object).call(shape); } -function objectResolver(ctx: ObjectResolverContext): Chain { +function objectResolver(ctx: ExtendedContext): Chain { // TODO: parser - handle constants return ctx.nodes.base(ctx); } -function shapeNode(ctx: ObjectResolverContext): ReturnType { - const { plugin, schema } = ctx; +function shapeNode(ctx: ExtendedContext): ReturnType { + const { applyModifiers, schema, walk, walkerCtx } = ctx; const shape = $.object().pretty(); for (const name in schema.properties) { const property = schema.properties[name]!; + const isOptional = !schema.required?.includes(name); - const propertyAst = irSchemaToAst({ - optional: !schema.required?.includes(name), - plugin, - schema: property, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'properties', name]), - }, + const propertyResult = walk(property, childContext(walkerCtx, 'properties', name)); + if (propertyResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + + const ast = applyModifiers(propertyResult, { + optional: isOptional, }); - if (propertyAst.hasLazyExpression) { + + if (ast.hasLazyExpression) { ctx.utils.ast.hasLazyExpression = true; - shape.getter(name, propertyAst.expression.return()); + shape.getter(name, ast.expression.return()); } else { - shape.prop(name, propertyAst.expression); + shape.prop(name, ast.expression); } } return shape; } -export const objectToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'object'>; -}): Omit => { +export function objectToAst(options: ObjectToAstOptions): Omit { + const { plugin } = options; const ast: Partial> = {}; const z = plugin.external('zod.z'); - const ctx: ObjectResolverContext = { + const ctx: ExtendedContext = { + ...options, $, chain: { current: $(z), @@ -95,17 +107,16 @@ export const objectToAst = ({ shape: shapeNode, }, plugin, - schema, symbols: { z, }, utils: { ast, - state, + state: options.state, }, }; const resolver = plugin.config['~resolvers']?.object; const node = resolver?.(ctx) ?? objectResolver(ctx); ast.expression = node; return ast as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/string.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/string.ts index d6c3ff3fb..199c370ff 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/string.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/string.ts @@ -115,12 +115,12 @@ function stringResolver(ctx: StringResolverContext): Chain { return ctx.chain.current; } -export const stringToNode = ({ +export function stringToNode({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'string'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const ctx: StringResolverContext = { $, @@ -147,4 +147,4 @@ export const stringToNode = ({ return { expression: node, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/tuple.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/tuple.ts index 6b6ba3e19..b18c1b664 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/tuple.ts @@ -1,22 +1,27 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; - -export const tupleToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'tuple'>; -}): Omit => { - const z = plugin.external('zod.z'); +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; + +export function tupleToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'tuple'>; + }, +): Omit { + const { applyModifiers, plugin, schema, walk } = options; const result: Partial> = {}; + const z = plugin.external('zod.z'); + if (schema.const && Array.isArray(schema.const)) { const tupleElements = schema.const.map((value) => $(z).attr(identifiers.literal).call($.fromValue(value)), @@ -31,18 +36,23 @@ export const tupleToAst = ({ if (schema.items) { schema.items.forEach((item, index) => { - const itemSchema = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - tupleElements.push(itemSchema.expression); - if (itemSchema.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } + + const finalExpr = applyModifiers(itemResult, { optional: false }); + tupleElements.push(finalExpr.expression); }); } @@ -51,4 +61,4 @@ export const tupleToAst = ({ .call($.array(...tupleElements)); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/undefined.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/undefined.ts index f6c650cb7..5713da531 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/undefined.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/undefined.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const undefinedToAst = ({ +export function undefinedToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'undefined'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const result: Partial> = {}; result.expression = $(z).attr(identifiers.undefined).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/unknown.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/unknown.ts index c3897754f..722a472eb 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/unknown.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/unknown.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const unknownToAst = ({ +export function unknownToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'unknown'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const result: Partial> = {}; result.expression = $(z).attr(identifiers.unknown).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/toAst/void.ts b/packages/openapi-ts/src/plugins/zod/mini/toAst/void.ts index 9a2505303..710057712 100644 --- a/packages/openapi-ts/src/plugins/zod/mini/toAst/void.ts +++ b/packages/openapi-ts/src/plugins/zod/mini/toAst/void.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const voidToAst = ({ +export function voidToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'void'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const result: Partial> = {}; result.expression = $(z).attr(identifiers.void).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/mini/walker.ts b/packages/openapi-ts/src/plugins/zod/mini/walker.ts new file mode 100644 index 000000000..c17e77a7a --- /dev/null +++ b/packages/openapi-ts/src/plugins/zod/mini/walker.ts @@ -0,0 +1,369 @@ +import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; +import { fromRef } from '@hey-api/codegen-core'; +import type { SchemaExtractor, SchemaVisitor } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; + +import { $ } from '../../../ts-dsl'; +import { maybeBigInt, shouldCoerceToBigInt } from '../../shared/utils/coerce'; +import { identifiers } from '../constants'; +import type { ProcessorContext } from '../shared/processor'; +import type { Ast, PluginState, ZodAppliedResult, ZodSchemaResult } from '../shared/types'; +import type { ZodPlugin } from '../types'; +import { arrayToAst } from './toAst/array'; +import { booleanToAst } from './toAst/boolean'; +import { enumToAst } from './toAst/enum'; +import { neverToAst } from './toAst/never'; +import { nullToAst } from './toAst/null'; +import { numberToNode } from './toAst/number'; +import { objectToAst } from './toAst/object'; +import { stringToNode } from './toAst/string'; +import { tupleToAst } from './toAst/tuple'; +import { undefinedToAst } from './toAst/undefined'; +import { unknownToAst } from './toAst/unknown'; +import { voidToAst } from './toAst/void'; + +export interface VisitorConfig { + /** Optional schema extractor function. */ + schemaExtractor?: SchemaExtractor; + /** The plugin state references. */ + state: Refs; +} + +export function createVisitor( + config: VisitorConfig, +): SchemaVisitor { + const { schemaExtractor, state } = config; + return { + applyModifiers(result, ctx, options = {}): ZodAppliedResult { + const { optional } = options; + const z = ctx.plugin.external('zod.z'); + let expression = result.expression.expression; + + if (result.readonly) { + expression = $(z).attr(identifiers.readonly).call(expression); + } + + const hasDefault = result.default !== undefined; + const needsNullable = result.nullable; + + if (optional && needsNullable) { + expression = $(z).attr(identifiers.nullish).call(expression); + } else if (optional) { + expression = $(z).attr(identifiers.optional).call(expression); + } else if (needsNullable) { + expression = $(z).attr(identifiers.nullable).call(expression); + } + + if (hasDefault) { + expression = $(z) + .attr(identifiers._default) + .call( + expression, + result.format + ? maybeBigInt(result.default, result.format) + : $.fromValue(result.default), + ); + } + + return { expression }; + }, + array(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = arrayToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + boolean(schema, ctx) { + const ast = booleanToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + enum(schema, ctx) { + const ast = enumToAst({ ...ctx, schema, state }); + const hasNull = + schema.items?.some((item) => item.type === 'null' || item.const === null) ?? false; + return { + default: schema.default, + expression: ast, + nullable: hasNull, + readonly: schema.accessScope === 'read', + }; + }, + integer(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: ast, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + intercept(schema, ctx, walk) { + if (schemaExtractor && !schema.$ref) { + const extracted = schemaExtractor({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(fromRef(ctx.path)), + }, + naming: ctx.plugin.config.definitions, + path: fromRef(ctx.path), + plugin: ctx.plugin, + schema, + }); + if (extracted !== schema) { + return walk(extracted, ctx); + } + } + }, + intersection(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + let expression = items[0]!.expression.expression; + items.slice(1).forEach((item) => { + expression = $(z) + .attr(identifiers.intersection) + .call( + expression, + item.hasLazyExpression + ? $(z).attr(identifiers.lazy).call($.func().do(item.expression.expression.return())) + : item.expression.expression, + ); + }); + + return { + default: parentSchema.default, + expression: { expression }, + hasLazyExpression: hasAnyLazy, + nullable: items.some((i) => i.nullable), + readonly: items.some((i) => i.readonly), + }; + }, + never(schema, ctx) { + const ast = neverToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + null(schema, ctx) { + const ast = nullToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + number(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: ast, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + object(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = objectToAst({ + applyModifiers, + plugin: ctx.plugin, + schema, + state, + walk, + walkerCtx: ctx, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + postProcess(result, schema, ctx) { + if (ctx.plugin.config.metadata && schema.description) { + const z = ctx.plugin.external('zod.z'); + return { + ...result, + expression: { + expression: result.expression.expression + .attr(identifiers.register) + .call( + $(z).attr(identifiers.globalRegistry), + $.object().pretty().prop('description', $.literal(schema.description)), + ), + }, + }; + } + return result; + }, + reference($ref, schema, ctx) { + const z = ctx.plugin.external('zod.z'); + const query: SymbolMeta = { + category: 'schema', + resource: 'definition', + resourceId: $ref, + tool: 'zod', + }; + + const refSymbol = ctx.plugin.referenceSymbol(query); + + if (ctx.plugin.isSymbolRegistered(query)) { + return { + default: schema.default, + expression: { + expression: $(refSymbol), + }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + state.hasLazyExpression['~ref'] = true; + return { + default: schema.default, + expression: { + expression: $(z) + .attr(identifiers.lazy) + .call($.func().returns('any').do($(refSymbol).return())), + }, + hasLazyExpression: true, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + string(schema, ctx) { + if (shouldCoerceToBigInt(schema.format)) { + const ast = numberToNode({ + plugin: ctx.plugin, + schema: { ...schema, type: 'number' }, + state, + }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + const ast = stringToNode({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + tuple(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = tupleToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + undefined(schema, ctx) { + const ast = undefinedToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + union(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + const hasNull = schemas.some((s) => s.type === 'null') || items.some((i) => i.nullable); + + const nonNullItems: typeof items = []; + + items.forEach((item, index) => { + const schema = schemas[index]!; + if (schema.type !== 'null') { + nonNullItems.push(item); + } + }); + + let expression: Ast; + if (nonNullItems.length === 0) { + expression = { + expression: $(z).attr(identifiers.null).call(), + }; + } else if (nonNullItems.length === 1) { + expression = nonNullItems[0]!.expression; + } else { + expression = { + expression: $(z) + .attr(identifiers.union) + .call( + $.array() + .pretty() + .elements(...nonNullItems.map((item) => item.expression.expression)), + ), + }; + } + + return { + default: parentSchema.default, + expression, + hasLazyExpression: hasAnyLazy, + nullable: hasNull, + readonly: items.some((i) => i.readonly), + }; + }, + unknown(schema, ctx) { + const ast = unknownToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + void(schema, ctx) { + const ast = voidToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + }; +} diff --git a/packages/openapi-ts/src/plugins/zod/resolvers/types.ts b/packages/openapi-ts/src/plugins/zod/resolvers/types.ts index 6de7ffaa5..2983b35da 100644 --- a/packages/openapi-ts/src/plugins/zod/resolvers/types.ts +++ b/packages/openapi-ts/src/plugins/zod/resolvers/types.ts @@ -1,5 +1,5 @@ import type { Refs, Symbol } from '@hey-api/codegen-core'; -import type { IR, Plugin, SchemaWithType } from '@hey-api/shared'; +import type { IR, Plugin, SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; import type { MaybeArray } from '@hey-api/types'; import type ts from 'typescript'; @@ -7,7 +7,7 @@ import type { MaybeBigInt, ShouldCoerceToBigInt } from '../../../plugins/shared/ import type { GetIntegerLimit } from '../../../plugins/shared/utils/formats'; import type { $, DollarTsDsl, TsDsl } from '../../../ts-dsl'; import type { Chain } from '../shared/chain'; -import type { Ast, PluginState } from '../shared/types'; +import type { Ast, IrSchemaToAstOptions, PluginState, ZodSchemaResult } from '../shared/types'; import type { ZodPlugin } from '../types'; export type Resolvers = Plugin.Resolvers<{ @@ -74,33 +74,30 @@ type ValidatorResolver = ( ctx: ValidatorResolverContext, ) => MaybeArray> | null | undefined; -interface BaseContext extends DollarTsDsl { - /** - * Functions for working with chains. - */ - chain: { +type BaseContext = DollarTsDsl & + Pick & { /** - * The current chain. - * - * In Zod, this represents a chain of call expressions ("chains") - * being assembled to form a schema definition. - * - * Each chain can be extended, modified, or replaced to customize - * the resulting schema. + * Functions for working with chains. */ - current: Chain; - }; - /** - * The plugin instance. - */ - plugin: ZodPlugin['Instance']; - /** - * Provides access to commonly used symbols within the plugin. - */ - symbols: { - z: Symbol; + chain: { + /** + * The current chain. + * + * In Zod, this represents a chain of call expressions ("chains") + * being assembled to form a schema definition. + * + * Each chain can be extended, modified, or replaced to customize + * the resulting schema. + */ + current: Chain; + }; + /** + * Provides access to commonly used symbols within the plugin. + */ + symbols: { + z: Symbol; + }; }; -} export interface EnumResolverContext extends BaseContext { /** @@ -132,10 +129,6 @@ export interface EnumResolverContext extends BaseContext { */ literalMembers: Array; }; - /** - * Returns a nullable wrapper if the enum includes null, undefined otherwise. - */ - nullable: (ctx: EnumResolverContext) => Chain | undefined; }; schema: SchemaWithType<'enum'>; /** @@ -171,6 +164,7 @@ export interface NumberResolverContext extends BaseContext { } export interface ObjectResolverContext extends BaseContext { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => Ast; /** * Nodes used to build different parts of the object schema. */ @@ -191,6 +185,8 @@ export interface ObjectResolverContext extends BaseContext { ast: Partial>; state: Refs; }; + walk: Walker; + walkerCtx: SchemaVisitorContext; } export interface StringResolverContext extends BaseContext { diff --git a/packages/openapi-ts/src/plugins/zod/shared/export.ts b/packages/openapi-ts/src/plugins/zod/shared/export.ts index 6ea280d11..9fd5295e1 100644 --- a/packages/openapi-ts/src/plugins/zod/shared/export.ts +++ b/packages/openapi-ts/src/plugins/zod/shared/export.ts @@ -14,6 +14,7 @@ export function exportAst({ path, plugin, schema, + state, tags, }: Pick & ProcessorContext & { @@ -48,7 +49,9 @@ export function exportAst({ const statement = $.const(symbol) .export() .$if(plugin.config.comments && createSchemaComment(schema), (c, v) => c.doc(v)) - .$if(ast.typeName, (c, v) => c.type($.type(z).attr(v))) + .$if(state.hasLazyExpression['~ref'] && state.anyType?.['~ref'], (c, v) => + c.type($.type(z).attr(v)), + ) .assign(ast.expression); plugin.node(statement); diff --git a/packages/openapi-ts/src/plugins/zod/shared/types.ts b/packages/openapi-ts/src/plugins/zod/shared/types.ts index 10081009f..923386ec6 100644 --- a/packages/openapi-ts/src/plugins/zod/shared/types.ts +++ b/packages/openapi-ts/src/plugins/zod/shared/types.ts @@ -1,12 +1,12 @@ import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; -import type { FeatureToggle, IR, NamingOptions, SchemaExtractor } from '@hey-api/shared'; +import type { FeatureToggle, IR, NamingOptions, Walker } from '@hey-api/shared'; import type ts from 'typescript'; import type { $ } from '../../../ts-dsl'; import type { ZodPlugin } from '../types'; -import type { ProcessorContext } from './processor'; export type Ast = { + anyType?: string; expression: ReturnType; hasLazyExpression?: boolean; typeName?: string | ts.Identifier; @@ -15,14 +15,14 @@ export type Ast = { export type IrSchemaToAstOptions = { /** The plugin instance. */ plugin: ZodPlugin['Instance']; - /** Optional schema extractor function. */ - schemaExtractor?: SchemaExtractor; /** The plugin state references. */ state: Refs; + walk: Walker; }; export type PluginState = Pick, 'path'> & Pick, 'tags'> & { + anyType?: string; hasLazyExpression: boolean; }; @@ -38,3 +38,30 @@ export type ValidatorArgs = { operation: IR.OperationObject; plugin: ZodPlugin['Instance']; }; + +/** + * The result from schema walking. + */ +export interface ZodSchemaResult { + /** Default value from schema, if any. */ + default?: unknown; + /** The Zod expression AST. */ + expression: { expression: ReturnType }; + /** The original schema format (for BigInt coercion). */ + format?: string; + /** Whether any child contains a lazy expression. */ + hasLazyExpression?: boolean; + /** Whether THIS result is itself lazy (not just inherited). */ + isLazy?: boolean; + /** Does this schema explicitly allow null? */ + nullable: boolean; + /** Is this schema read-only? */ + readonly: boolean; +} + +/** + * The finalized expression after applyModifiers. + */ +export interface ZodAppliedResult { + expression: ReturnType; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/plugin.ts b/packages/openapi-ts/src/plugins/zod/v3/plugin.ts index 500807bd1..8dc72f613 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/plugin.ts @@ -1,172 +1,10 @@ -import type { SymbolMeta } from '@hey-api/codegen-core'; -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { IR, SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema, pathToJsonPointer } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; -import { maybeBigInt } from '../../../plugins/shared/utils/coerce'; -import { $ } from '../../../ts-dsl'; -import { identifiers } from '../constants'; import { getZodModule } from '../shared/module'; import { irOperationToAst } from '../shared/operation'; -import type { Ast, IrSchemaToAstOptions } from '../shared/types'; import { irWebhookToAst } from '../shared/webhook'; import type { ZodPlugin } from '../types'; import { createProcessor } from './processor'; -import { irSchemaWithTypeToAst } from './toAst'; - -export function irSchemaToAst({ - optional, - plugin, - schema, - schemaExtractor, - state, -}: IrSchemaToAstOptions & { - /** - * Accept `optional` to handle optional object properties. We can't handle - * this inside the object function because `.optional()` must come before - * `.default()` which is handled in this function. - */ - optional?: boolean; - schema: IR.SchemaObject; -}): Ast { - if (schemaExtractor && !schema.$ref) { - const extracted = schemaExtractor({ - meta: { - resource: 'definition', - resourceId: pathToJsonPointer(fromRef(state.path)), - }, - naming: plugin.config.definitions, - path: fromRef(state.path), - plugin, - schema, - }); - if (extracted !== schema) schema = extracted; - } - - let ast: Partial = {}; - - const z = plugin.external('zod.z'); - - if (schema.$ref) { - const query: SymbolMeta = { - category: 'schema', - resource: 'definition', - resourceId: schema.$ref, - tool: 'zod', - }; - const refSymbol = plugin.referenceSymbol(query); - if (plugin.isSymbolRegistered(query)) { - ast.expression = $(refSymbol); - } else { - ast.expression = $(z) - .attr(identifiers.lazy) - .call($.func().do($(refSymbol).return())); - ast.hasLazyExpression = true; - state.hasLazyExpression['~ref'] = true; - } - } else if (schema.type) { - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: schema as SchemaWithType, - state, - }); - ast.expression = typeAst.expression; - ast.typeName = typeAst.anyType; - - if (plugin.config.metadata && schema.description) { - ast.expression = ast.expression - .attr(identifiers.describe) - .call($.literal(schema.description)); - } - } else if (schema.items) { - schema = deduplicateSchema({ schema }); - - if (schema.items) { - const itemTypes = schema.items.map((item, index) => { - const typeAst = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - return typeAst.expression; - }); - - if (schema.logicalOperator === 'and') { - const firstSchema = schema.items[0]!; - // we want to add an intersection, but not every schema can use the same API. - // if the first item contains another array or not an object, we cannot use - // `.merge()` as that does not exist on `.union()` and non-object schemas. - if ( - firstSchema.logicalOperator === 'or' || - (firstSchema.type && firstSchema.type !== 'object') - ) { - ast.expression = $(z) - .attr(identifiers.intersection) - .call(...itemTypes); - } else { - ast.expression = itemTypes[0]; - itemTypes.slice(1).forEach((item) => { - ast.expression = ast.expression!.attr(identifiers.and).call(item); - }); - } - } else { - ast.expression = $(z) - .attr(identifiers.union) - .call( - $.array() - .pretty() - .elements(...itemTypes), - ); - } - } else { - ast = irSchemaToAst({ plugin, schema, state }); - } - } else { - // catch-all fallback for failed schemas - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: { - type: 'unknown', - }, - state, - }); - ast.expression = typeAst.expression; - ast.typeName = typeAst.anyType; - } - - if (ast.expression) { - if (schema.accessScope === 'read') { - ast.expression = ast.expression.attr(identifiers.readonly).call(); - } - - if (optional) { - ast.expression = ast.expression.attr(identifiers.optional).call(); - } - - if (schema.default !== undefined) { - ast.expression = ast.expression - .attr(identifiers.default) - .call( - schema.type === 'integer' || schema.type === 'number' - ? maybeBigInt(schema.default, schema.format) - : $.fromValue(schema.default), - ); - } - } - - if (state.hasLazyExpression['~ref']) { - if (!ast.typeName) { - ast.typeName = 'ZodTypeAny'; - } - } else if (ast.typeName) { - ast.typeName = undefined; - } - - return ast as Ast; -} export const handlerV3: ZodPlugin['Handler'] = ({ plugin }) => { plugin.symbol('z', { diff --git a/packages/openapi-ts/src/plugins/zod/v3/processor.ts b/packages/openapi-ts/src/plugins/zod/v3/processor.ts index 5b4364774..9868559f1 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/processor.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/processor.ts @@ -1,12 +1,12 @@ -import { refs } from '@hey-api/codegen-core'; +import { ref, refs } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; -import { createSchemaProcessor, pathToJsonPointer } from '@hey-api/shared'; +import { createSchemaProcessor, createSchemaWalker, pathToJsonPointer } from '@hey-api/shared'; import { exportAst } from '../shared/export'; import type { ProcessorContext, ProcessorResult } from '../shared/processor'; -import type { PluginState } from '../shared/types'; +import type { PluginState, ZodAppliedResult } from '../shared/types'; import type { ZodPlugin } from '../types'; -import { irSchemaToAst } from './plugin'; +import { createVisitor } from './walker'; export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult { const processor = createSchemaProcessor(); @@ -43,12 +43,24 @@ export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult tags: ctx.tags, }); - const ast = irSchemaToAst({ - plugin, - schema: ctx.schema, + const visitor = createVisitor({ schemaExtractor: extractor, state, }); + const walk = createSchemaWalker(visitor); + + const result = walk(ctx.schema, { + path: ref(ctx.path), + plugin, + }); + const ast = + (visitor.applyModifiers(result, { + path: ref(ctx.path), + plugin, + }) as ZodAppliedResult) ?? result.expression; + if (result.hasLazyExpression) { + state.hasLazyExpression['~ref'] = true; + } exportAst({ ...ctx, ast, plugin, state }); }); diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/array.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/array.ts index c75a4d0a0..9794cdfca 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/array.ts @@ -1,22 +1,25 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema } from '@hey-api/shared'; +import { childContext, deduplicateSchema } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; import { unknownToAst } from './unknown'; -export const arrayToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'array'>; -}): Omit & { - anyType?: string; -} => { +export function arrayToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'array'>; + }, +): Omit { + const { applyModifiers, plugin, walk } = options; + let { schema } = options; + const z = plugin.external('zod.z'); const functionName = $(z).attr(identifiers.array); @@ -27,11 +30,10 @@ export const arrayToAst = ({ if (!schema.items) { arrayExpression = functionName.call( unknownToAst({ - plugin, + ...options, schema: { type: 'unknown', }, - state, }), ); } else { @@ -39,18 +41,23 @@ export const arrayToAst = ({ // at least one item is guaranteed const itemExpressions = schema.items!.map((item, index) => { - const itemAst = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - if (itemAst.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { hasLazyExpression = true; } - return itemAst.expression; + + const finalExpr = applyModifiers(itemResult, { optional: false }); + return finalExpr.expression; }); if (itemExpressions.length === 1) { @@ -107,4 +114,4 @@ export const arrayToAst = ({ expression: arrayExpression, hasLazyExpression, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/boolean.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/boolean.ts index 86c7dde0e..32ce71ed5 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/boolean.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/boolean.ts @@ -7,7 +7,7 @@ import type { IrSchemaToAstOptions } from '../../shared/types'; export function booleanToAst({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'boolean'>; }): ReturnType { let chain: ReturnType; diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/enum.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/enum.ts index ee252c4bf..2a5f46446 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/enum.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/enum.ts @@ -64,13 +64,6 @@ function baseNode(ctx: EnumResolverContext): Chain { } } -function nullableNode(ctx: EnumResolverContext): Chain | undefined { - const { chain } = ctx; - const { isNullable } = ctx.nodes.items(ctx); - if (!isNullable) return; - return chain.current.attr(identifiers.nullable).call(); -} - function enumResolver(ctx: EnumResolverContext): Chain { const { literalMembers } = ctx.nodes.items(ctx); @@ -81,27 +74,22 @@ function enumResolver(ctx: EnumResolverContext): Chain { const baseExpression = ctx.nodes.base(ctx); ctx.chain.current = baseExpression; - const nullableExpression = ctx.nodes.nullable(ctx); - if (nullableExpression) { - ctx.chain.current = nullableExpression; - } - return ctx.chain.current; } -export const enumToAst = ({ +export function enumToAst({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'enum'>; -}): Chain => { +}): Chain { const z = plugin.external('zod.z'); const { literalMembers } = itemsNode({ $, chain: { current: $(z) }, - nodes: { base: baseNode, items: itemsNode, nullable: nullableNode }, + nodes: { base: baseNode, items: itemsNode }, plugin, schema, symbols: { z }, @@ -114,7 +102,6 @@ export const enumToAst = ({ schema: { type: 'unknown', }, - state, }); } @@ -126,7 +113,6 @@ export const enumToAst = ({ nodes: { base: baseNode, items: itemsNode, - nullable: nullableNode, }, plugin, schema, @@ -141,4 +127,4 @@ export const enumToAst = ({ const resolver = plugin.config['~resolvers']?.enum; return resolver?.(ctx) ?? enumResolver(ctx); -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/index.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/index.ts deleted file mode 100644 index 00a1b5fef..000000000 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/index.ts +++ /dev/null @@ -1,112 +0,0 @@ -import type { SchemaWithType } from '@hey-api/shared'; - -import { shouldCoerceToBigInt } from '../../../../plugins/shared/utils/coerce'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { arrayToAst } from './array'; -import { booleanToAst } from './boolean'; -import { enumToAst } from './enum'; -import { neverToAst } from './never'; -import { nullToAst } from './null'; -import { numberToNode } from './number'; -import { objectToAst } from './object'; -import { stringToNode } from './string'; -import { tupleToAst } from './tuple'; -import { undefinedToAst } from './undefined'; -import { unknownToAst } from './unknown'; -import { voidToAst } from './void'; - -export function irSchemaWithTypeToAst({ - schema, - ...args -}: IrSchemaToAstOptions & { - schema: SchemaWithType; -}): Omit & { - anyType?: string; -} { - switch (schema.type) { - case 'array': - return arrayToAst({ - ...args, - schema: schema as SchemaWithType<'array'>, - }); - case 'boolean': - return { - expression: booleanToAst({ - ...args, - schema: schema as SchemaWithType<'boolean'>, - }), - }; - case 'enum': - return { - expression: enumToAst({ - ...args, - schema: schema as SchemaWithType<'enum'>, - }), - }; - case 'integer': - case 'number': - return { - expression: numberToNode({ - ...args, - schema: schema as SchemaWithType<'integer' | 'number'>, - }), - }; - case 'never': - return { - expression: neverToAst({ - ...args, - schema: schema as SchemaWithType<'never'>, - }), - }; - case 'null': - return { - expression: nullToAst({ - ...args, - schema: schema as SchemaWithType<'null'>, - }), - }; - case 'object': - return objectToAst({ - ...args, - schema: schema as SchemaWithType<'object'>, - }); - case 'string': - return { - expression: shouldCoerceToBigInt(schema.format) - ? numberToNode({ - ...args, - schema: { ...schema, type: 'number' }, - }) - : stringToNode({ - ...args, - schema: schema as SchemaWithType<'string'>, - }), - }; - case 'tuple': - return tupleToAst({ - ...args, - schema: schema as SchemaWithType<'tuple'>, - }); - case 'undefined': - return { - expression: undefinedToAst({ - ...args, - schema: schema as SchemaWithType<'undefined'>, - }), - }; - case 'unknown': - return { - expression: unknownToAst({ - ...args, - schema: schema as SchemaWithType<'unknown'>, - }), - }; - case 'void': - return { - expression: voidToAst({ - ...args, - schema: schema as SchemaWithType<'void'>, - }), - }; - } -} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/never.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/never.ts index 4e2d8cd0b..193cca1c7 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/never.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/never.ts @@ -4,12 +4,12 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const neverToAst = ({ +export function neverToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'never'>; -}) => { +}) { const z = plugin.external('zod.z'); const expression = $(z).attr(identifiers.never).call(); return expression; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/null.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/null.ts index 3fca17b54..40049d135 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/null.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/null.ts @@ -4,12 +4,12 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const nullToAst = ({ +export function nullToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'null'>; -}) => { +}) { const z = plugin.external('zod.z'); const expression = $(z).attr(identifiers.null).call(); return expression; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/number.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/number.ts index 4dd2472e9..ebcf8fc5a 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/number.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/number.ts @@ -95,13 +95,13 @@ function numberResolver(ctx: NumberResolverContext): Chain { return ctx.chain.current; } -export const numberToNode = ({ +export function numberToNode({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'integer' | 'number'>; -}): Chain => { +}): Chain { const ast: Partial> = {}; const z = plugin.external('zod.z'); const ctx: NumberResolverContext = { @@ -131,4 +131,4 @@ export const numberToNode = ({ const resolver = plugin.config['~resolvers']?.number; const node = resolver?.(ctx) ?? numberResolver(ctx); return node; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/object.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/object.ts index 2d37b4ea7..c64c1a1a6 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/object.ts @@ -1,35 +1,52 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; +import type { SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { ObjectResolverContext } from '../../resolvers'; import type { Chain } from '../../shared/chain'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; +import type { ZodPlugin } from '../../types'; -function additionalPropertiesNode(ctx: ObjectResolverContext): Chain | null | undefined { - const { plugin, schema } = ctx; +type WalkerCtx = SchemaVisitorContext; + +interface ObjectToAstOptions extends IrSchemaToAstOptions { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'object'>; + walk: Walker; + walkerCtx: WalkerCtx; +} + +type ExtendedContext = ObjectResolverContext & { + applyModifiers: ObjectToAstOptions['applyModifiers']; + walk: ObjectToAstOptions['walk']; + walkerCtx: ObjectToAstOptions['walkerCtx']; +}; + +function additionalPropertiesNode(ctx: ExtendedContext): Chain | null | undefined { + const { schema, walk, walkerCtx } = ctx; if ( !schema.additionalProperties || (schema.properties && Object.keys(schema.properties).length > 0) - ) + ) { return; + } - const additionalAst = irSchemaToAst({ - plugin, - schema: schema.additionalProperties, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'additionalProperties']), - }, - }); - if (additionalAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - return additionalAst.expression; + const additionalResult = walk( + schema.additionalProperties, + childContext(walkerCtx, 'additionalProperties'), + ); + if (additionalResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + return additionalResult.expression.expression; } -function baseNode(ctx: ObjectResolverContext): Chain { +function baseNode(ctx: ExtendedContext): Chain { const { nodes, symbols } = ctx; const { z } = symbols; @@ -43,46 +60,39 @@ function baseNode(ctx: ObjectResolverContext): Chain { return $(z).attr(identifiers.object).call(shape); } -function objectResolver(ctx: ObjectResolverContext): Chain { +function objectResolver(ctx: ExtendedContext): Chain { // TODO: parser - handle constants return ctx.nodes.base(ctx); } -function shapeNode(ctx: ObjectResolverContext): ReturnType { - const { plugin, schema } = ctx; +function shapeNode(ctx: ExtendedContext): ReturnType { + const { applyModifiers, schema, walk, walkerCtx } = ctx; const shape = $.object().pretty(); for (const name in schema.properties) { const property = schema.properties[name]!; + const isOptional = !schema.required?.includes(name); + + const propertyResult = walk(property, childContext(walkerCtx, 'properties', name)); + if (propertyResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - const propertyAst = irSchemaToAst({ - optional: !schema.required?.includes(name), - plugin, - schema: property, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'properties', name]), - }, + const ast = applyModifiers(propertyResult, { + optional: isOptional, }); - if (propertyAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - shape.prop(name, propertyAst.expression); + + if (ast.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + shape.prop(name, ast.expression); } return shape; } -export const objectToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'object'>; -}): Omit & { - anyType?: string; -} => { +export function objectToAst(options: ObjectToAstOptions): Omit { + const { plugin } = options; const ast: Partial> = {}; const z = plugin.external('zod.z'); - const ctx: ObjectResolverContext = { + const ctx: ExtendedContext = { + ...options, $, chain: { current: $(z), @@ -93,13 +103,12 @@ export const objectToAst = ({ shape: shapeNode, }, plugin, - schema, symbols: { z, }, utils: { ast, - state, + state: options.state, }, }; const resolver = plugin.config['~resolvers']?.object; @@ -107,8 +116,6 @@ export const objectToAst = ({ ast.expression = node; return { ...ast, - anyType: 'AnyZodObject', - } as Omit & { - anyType: string; - }; -}; + anyType: identifiers.AnyZodObject, + } as Omit; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/string.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/string.ts index bb0d90fa8..a8977dc14 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/string.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/string.ts @@ -100,12 +100,12 @@ function stringResolver(ctx: StringResolverContext): Chain { return ctx.chain.current; } -export const stringToNode = ({ +export function stringToNode({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'string'>; -}): Chain => { +}): Chain { const z = plugin.external('zod.z'); const ctx: StringResolverContext = { $, @@ -130,4 +130,4 @@ export const stringToNode = ({ const resolver = plugin.config['~resolvers']?.string; const node = resolver?.(ctx) ?? stringResolver(ctx); return node; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/tuple.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/tuple.ts index 59796e793..8950b7933 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/tuple.ts @@ -1,20 +1,23 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; - -export const tupleToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'tuple'>; -}): Omit & { - anyType?: string; -} => { +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; + +export function tupleToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'tuple'>; + }, +): Omit { + const { applyModifiers, plugin, schema, walk } = options; + const z = plugin.external('zod.z'); let hasLazyExpression = false; @@ -36,18 +39,23 @@ export const tupleToAst = ({ if (schema.items) { schema.items.forEach((item, index) => { - const itemSchema = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - tupleElements.push(itemSchema.expression); - if (itemSchema.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { hasLazyExpression = true; } + + const finalExpr = applyModifiers(itemResult, { optional: false }); + tupleElements.push(finalExpr.expression); }); } @@ -59,4 +67,4 @@ export const tupleToAst = ({ expression, hasLazyExpression, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/undefined.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/undefined.ts index 39f9c8155..edaa97db4 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/undefined.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/undefined.ts @@ -4,12 +4,12 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const undefinedToAst = ({ +export function undefinedToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'undefined'>; -}) => { +}) { const z = plugin.external('zod.z'); const expression = $(z).attr(identifiers.undefined).call(); return expression; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/unknown.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/unknown.ts index 171437bed..4a2b65469 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/unknown.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/unknown.ts @@ -4,12 +4,12 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const unknownToAst = ({ +export function unknownToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'unknown'>; -}) => { +}) { const z = plugin.external('zod.z'); const expression = $(z).attr(identifiers.unknown).call(); return expression; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/toAst/void.ts b/packages/openapi-ts/src/plugins/zod/v3/toAst/void.ts index e52cb85d6..3fa0b7a4c 100644 --- a/packages/openapi-ts/src/plugins/zod/v3/toAst/void.ts +++ b/packages/openapi-ts/src/plugins/zod/v3/toAst/void.ts @@ -4,12 +4,12 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { IrSchemaToAstOptions } from '../../shared/types'; -export const voidToAst = ({ +export function voidToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'void'>; -}) => { +}) { const z = plugin.external('zod.z'); const expression = $(z).attr(identifiers.void).call(); return expression; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v3/walker.ts b/packages/openapi-ts/src/plugins/zod/v3/walker.ts new file mode 100644 index 000000000..39ac82ab9 --- /dev/null +++ b/packages/openapi-ts/src/plugins/zod/v3/walker.ts @@ -0,0 +1,395 @@ +import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; +import { fromRef, ref } from '@hey-api/codegen-core'; +import type { SchemaExtractor, SchemaVisitor } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; + +import { $ } from '../../../ts-dsl'; +import { maybeBigInt, shouldCoerceToBigInt } from '../../shared/utils/coerce'; +import { identifiers } from '../constants'; +import type { ProcessorContext } from '../shared/processor'; +import type { PluginState, ZodAppliedResult, ZodSchemaResult } from '../shared/types'; +import type { ZodPlugin } from '../types'; +import { arrayToAst } from './toAst/array'; +import { booleanToAst } from './toAst/boolean'; +import { enumToAst } from './toAst/enum'; +import { neverToAst } from './toAst/never'; +import { nullToAst } from './toAst/null'; +import { numberToNode } from './toAst/number'; +import { objectToAst } from './toAst/object'; +import { stringToNode } from './toAst/string'; +import { tupleToAst } from './toAst/tuple'; +import { undefinedToAst } from './toAst/undefined'; +import { unknownToAst } from './toAst/unknown'; +import { voidToAst } from './toAst/void'; + +export interface VisitorConfig { + /** Optional schema extractor function. */ + schemaExtractor?: SchemaExtractor; + /** The plugin state references. */ + state: Refs; +} + +export function createVisitor( + config: VisitorConfig, +): SchemaVisitor { + const { schemaExtractor, state } = config; + return { + applyModifiers(result, ctx, options = {}): ZodAppliedResult { + const { optional } = options; + let expression = result.expression.expression; + + if (result.readonly) { + expression = expression.attr(identifiers.readonly).call(); + } + + const hasDefault = result.default !== undefined; + const needsNullable = result.nullable; + + if (optional && needsNullable) { + expression = expression.attr(identifiers.nullish).call(); + } else if (optional) { + expression = expression.attr(identifiers.optional).call(); + } else if (needsNullable) { + expression = expression.attr(identifiers.nullable).call(); + } + + if (hasDefault) { + expression = expression + .attr(identifiers.default) + .call( + result.format + ? maybeBigInt(result.default, result.format) + : $.fromValue(result.default), + ); + } + + return { expression }; + }, + array(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = arrayToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + boolean(schema, ctx) { + const ast = booleanToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + enum(schema, ctx) { + const ast = enumToAst({ ...ctx, schema, state }); + const hasNull = + schema.items?.some((item) => item.type === 'null' || item.const === null) ?? false; + return { + default: schema.default, + expression: { expression: ast }, + nullable: hasNull, + readonly: schema.accessScope === 'read', + }; + }, + integer(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: { expression: ast }, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + intercept(schema, ctx, walk) { + if (schemaExtractor && !schema.$ref) { + const extracted = schemaExtractor({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(fromRef(ctx.path)), + }, + naming: ctx.plugin.config.definitions, + path: fromRef(ctx.path), + plugin: ctx.plugin, + schema, + }); + if (extracted !== schema) { + return walk(extracted, ctx); + } + } + }, + intersection(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + if (hasAnyLazy) { + state.anyType = ref(identifiers.ZodTypeAny); + } + + const firstSchema = schemas[0]; + let expression: ZodSchemaResult['expression']; + + // If first item is a union or non-object, use z.intersection() + // Otherwise use .and() chaining for better type inference + if ( + firstSchema?.logicalOperator === 'or' || + (firstSchema?.type && firstSchema.type !== 'object') + ) { + expression = { + expression: $(z) + .attr(identifiers.intersection) + .call(...items.map((item) => item.expression.expression)), + }; + } else { + expression = items[0]!.expression; + items.slice(1).forEach((item) => { + expression = { + expression: expression.expression + .attr(identifiers.and) + .call( + item.hasLazyExpression && !item.isLazy + ? $(z) + .attr(identifiers.lazy) + .call($.func().do(item.expression.expression.return())) + : item.expression.expression, + ), + }; + }); + } + + return { + default: parentSchema.default, + expression, + hasLazyExpression: hasAnyLazy, + nullable: items.some((i) => i.nullable), + readonly: items.some((i) => i.readonly), + }; + }, + never(schema, ctx) { + const ast = neverToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: false, + }; + }, + null(schema, ctx) { + const ast = nullToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: false, + }; + }, + number(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: { expression: ast }, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + object(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = objectToAst({ + applyModifiers, + plugin: ctx.plugin, + schema, + state, + walk, + walkerCtx: ctx, + }); + if (state.hasLazyExpression['~ref'] && ast.anyType) { + state.anyType = ref(ast.anyType); + } + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + postProcess(result, schema, ctx) { + if (ctx.plugin.config.metadata && schema.description) { + return { + ...result, + expression: { + expression: result.expression.expression + .attr(identifiers.describe) + .call($.literal(schema.description)), + }, + }; + } + return result; + }, + reference($ref, schema, ctx) { + const z = ctx.plugin.external('zod.z'); + const query: SymbolMeta = { + category: 'schema', + resource: 'definition', + resourceId: $ref, + tool: 'zod', + }; + + const refSymbol = ctx.plugin.referenceSymbol(query); + + if (ctx.plugin.isSymbolRegistered(query)) { + return { + default: schema.default, + expression: { + expression: $(refSymbol), + }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + state.hasLazyExpression['~ref'] = true; + state.anyType = ref(identifiers.ZodTypeAny); + return { + default: schema.default, + expression: { + expression: $(z) + .attr(identifiers.lazy) + .call($.func().do($(refSymbol).return())), + }, + hasLazyExpression: true, + isLazy: true, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + string(schema, ctx) { + if (shouldCoerceToBigInt(schema.format)) { + const ast = numberToNode({ + plugin: ctx.plugin, + schema: { ...schema, type: 'number' }, + state, + }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + const ast = stringToNode({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + tuple(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = tupleToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + undefined(schema, ctx) { + const ast = undefinedToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: false, + }; + }, + union(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + const hasNull = schemas.some((s) => s.type === 'null') || items.some((i) => i.nullable); + + if (hasAnyLazy) { + state.anyType = ref(identifiers.ZodTypeAny); + } + + const nonNullItems: typeof items = []; + + items.forEach((item, index) => { + const schema = schemas[index]!; + if (schema.type !== 'null') { + nonNullItems.push(item); + } + }); + + let expression: ZodSchemaResult['expression']; + if (nonNullItems.length === 0) { + expression = { + expression: $(z).attr(identifiers.null).call(), + }; + } else if (nonNullItems.length === 1) { + expression = nonNullItems[0]!.expression; + } else { + expression = { + expression: $(z) + .attr(identifiers.union) + .call( + $.array() + .pretty() + .elements(...nonNullItems.map((item) => item.expression.expression)), + ), + }; + } + + return { + default: parentSchema.default, + expression, + hasLazyExpression: hasAnyLazy, + nullable: hasNull, + readonly: items.some((i) => i.readonly), + }; + }, + unknown(schema, ctx) { + const ast = unknownToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: false, + }; + }, + void(schema, ctx) { + const ast = voidToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: { expression: ast }, + nullable: false, + readonly: false, + }; + }, + }; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/plugin.ts b/packages/openapi-ts/src/plugins/zod/v4/plugin.ts index adc6bda38..d8a4aa03a 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/plugin.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/plugin.ts @@ -1,176 +1,10 @@ -import type { SymbolMeta } from '@hey-api/codegen-core'; -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { IR, SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema, pathToJsonPointer } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; -import { maybeBigInt } from '../../../plugins/shared/utils/coerce'; -import { $ } from '../../../ts-dsl'; -import { identifiers } from '../constants'; import { getZodModule } from '../shared/module'; import { irOperationToAst } from '../shared/operation'; -import type { Ast, IrSchemaToAstOptions } from '../shared/types'; import { irWebhookToAst } from '../shared/webhook'; import type { ZodPlugin } from '../types'; import { createProcessor } from './processor'; -import { irSchemaWithTypeToAst } from './toAst'; - -export function irSchemaToAst({ - optional, - plugin, - schema, - schemaExtractor, - state, -}: IrSchemaToAstOptions & { - /** - * Accept `optional` to handle optional object properties. We can't handle - * this inside the object function because `.optional()` must come before - * `.default()` which is handled in this function. - */ - optional?: boolean; - schema: IR.SchemaObject; -}): Ast { - if (schemaExtractor && !schema.$ref) { - const extracted = schemaExtractor({ - meta: { - resource: 'definition', - resourceId: pathToJsonPointer(fromRef(state.path)), - }, - naming: plugin.config.definitions, - path: fromRef(state.path), - plugin, - schema, - }); - if (extracted !== schema) schema = extracted; - } - - let ast: Partial = {}; - - const z = plugin.external('zod.z'); - - if (schema.$ref) { - const query: SymbolMeta = { - category: 'schema', - resource: 'definition', - resourceId: schema.$ref, - tool: 'zod', - }; - const refSymbol = plugin.referenceSymbol(query); - if (plugin.isSymbolRegistered(query)) { - ast.expression = $(refSymbol); - } else { - ast.expression = $(z) - .attr(identifiers.lazy) - .call($.func().returns('any').do($(refSymbol).return())); - ast.hasLazyExpression = true; - state.hasLazyExpression['~ref'] = true; - } - } else if (schema.type) { - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: schema as SchemaWithType, - state, - }); - ast.expression = typeAst.expression; - ast.hasLazyExpression = typeAst.hasLazyExpression; - - if (plugin.config.metadata && schema.description) { - ast.expression = ast.expression - .attr(identifiers.register) - .call( - $(z).attr(identifiers.globalRegistry), - $.object().pretty().prop('description', $.literal(schema.description)), - ); - } - } else if (schema.items) { - schema = deduplicateSchema({ schema }); - - if (schema.items) { - const itemSchemas = schema.items.map((item, index) => - irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }), - ); - - if (schema.logicalOperator === 'and') { - const firstSchema = schema.items[0]!; - // we want to add an intersection, but not every schema can use the same API. - // if the first item contains another array or not an object, we cannot use - // `.merge()` as that does not exist on `.union()` and non-object schemas. - if ( - firstSchema.logicalOperator === 'or' || - (firstSchema.type && firstSchema.type !== 'object') - ) { - ast.expression = $(z) - .attr(identifiers.intersection) - .call(...itemSchemas.map((schema) => schema.expression)); - } else { - ast.expression = itemSchemas[0]!.expression; - itemSchemas.slice(1).forEach((schema) => { - ast.expression = ast - .expression!.attr(identifiers.and) - .call( - schema.hasLazyExpression - ? $(z).attr(identifiers.lazy).call($.func().do(schema.expression.return())) - : schema.expression, - ); - }); - } - } else { - ast.expression = $(z) - .attr(identifiers.union) - .call( - $.array() - .pretty() - .elements(...itemSchemas.map((schema) => schema.expression)), - ); - } - } else { - ast = irSchemaToAst({ - plugin, - schema, - state, - }); - } - } else { - // catch-all fallback for failed schemas - const typeAst = irSchemaWithTypeToAst({ - plugin, - schema: { - type: 'unknown', - }, - state, - }); - ast.expression = typeAst.expression; - } - - if (ast.expression) { - if (schema.accessScope === 'read') { - ast.expression = ast.expression.attr(identifiers.readonly).call(); - } - - if (optional) { - ast.expression = $(z).attr(identifiers.optional).call(ast.expression); - ast.typeName = identifiers.ZodOptional; - } - - if (schema.default !== undefined) { - ast.expression = ast.expression - .attr(identifiers.default) - .call( - schema.type === 'integer' || schema.type === 'number' - ? maybeBigInt(schema.default, schema.format) - : $.fromValue(schema.default), - ); - } - } - - return ast as Ast; -} export const handlerV4: ZodPlugin['Handler'] = ({ plugin }) => { plugin.symbol('z', { diff --git a/packages/openapi-ts/src/plugins/zod/v4/processor.ts b/packages/openapi-ts/src/plugins/zod/v4/processor.ts index 5b4364774..9868559f1 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/processor.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/processor.ts @@ -1,12 +1,12 @@ -import { refs } from '@hey-api/codegen-core'; +import { ref, refs } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; -import { createSchemaProcessor, pathToJsonPointer } from '@hey-api/shared'; +import { createSchemaProcessor, createSchemaWalker, pathToJsonPointer } from '@hey-api/shared'; import { exportAst } from '../shared/export'; import type { ProcessorContext, ProcessorResult } from '../shared/processor'; -import type { PluginState } from '../shared/types'; +import type { PluginState, ZodAppliedResult } from '../shared/types'; import type { ZodPlugin } from '../types'; -import { irSchemaToAst } from './plugin'; +import { createVisitor } from './walker'; export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult { const processor = createSchemaProcessor(); @@ -43,12 +43,24 @@ export function createProcessor(plugin: ZodPlugin['Instance']): ProcessorResult tags: ctx.tags, }); - const ast = irSchemaToAst({ - plugin, - schema: ctx.schema, + const visitor = createVisitor({ schemaExtractor: extractor, state, }); + const walk = createSchemaWalker(visitor); + + const result = walk(ctx.schema, { + path: ref(ctx.path), + plugin, + }); + const ast = + (visitor.applyModifiers(result, { + path: ref(ctx.path), + plugin, + }) as ZodAppliedResult) ?? result.expression; + if (result.hasLazyExpression) { + state.hasLazyExpression['~ref'] = true; + } exportAst({ ...ctx, ast, plugin, state }); }); diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/array.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/array.ts index 26ffab156..2672ac90a 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/array.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/array.ts @@ -1,34 +1,37 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; -import { deduplicateSchema } from '@hey-api/shared'; +import { childContext, deduplicateSchema } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; import { unknownToAst } from './unknown'; -export const arrayToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'array'>; -}): Omit => { +export function arrayToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'array'>; + }, +): Omit { + const { applyModifiers, plugin, walk } = options; + let { schema } = options; + const result: Partial> = {}; const z = plugin.external('zod.z'); - const functionName = $(z).attr(identifiers.array); if (!schema.items) { result.expression = functionName.call( unknownToAst({ - plugin, + ...options, schema: { type: 'unknown', }, - state, }).expression, ); } else { @@ -36,18 +39,23 @@ export const arrayToAst = ({ // at least one item is guaranteed const itemExpressions = schema.items!.map((item, index) => { - const itemAst = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - if (itemAst.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } - return itemAst.expression; + + const finalExpr = applyModifiers(itemResult, { optional: false }); + return finalExpr.expression; }); if (itemExpressions.length === 1) { @@ -107,4 +115,4 @@ export const arrayToAst = ({ } return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/boolean.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/boolean.ts index 8f13b8335..4abdfe633 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/boolean.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/boolean.ts @@ -7,7 +7,7 @@ import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; export function booleanToAst({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'boolean'>; }): Omit { const result: Partial> = {}; diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/enum.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/enum.ts index f40ea631e..a78949a6b 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/enum.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/enum.ts @@ -64,14 +64,6 @@ function baseNode(ctx: EnumResolverContext): Chain { } } -function nullableNode(ctx: EnumResolverContext): Chain | undefined { - const { chain, symbols } = ctx; - const { z } = symbols; - const { isNullable } = ctx.nodes.items(ctx); - if (!isNullable) return; - return $(z).attr(identifiers.nullable).call(chain.current); -} - function enumResolver(ctx: EnumResolverContext): Chain { const { literalMembers } = ctx.nodes.items(ctx); @@ -82,27 +74,22 @@ function enumResolver(ctx: EnumResolverContext): Chain { const baseExpression = ctx.nodes.base(ctx); ctx.chain.current = baseExpression; - const nullableExpression = ctx.nodes.nullable(ctx); - if (nullableExpression) { - ctx.chain.current = nullableExpression; - } - return ctx.chain.current; } -export const enumToAst = ({ +export function enumToAst({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'enum'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const { literalMembers } = itemsNode({ $, chain: { current: $(z) }, - nodes: { base: baseNode, items: itemsNode, nullable: nullableNode }, + nodes: { base: baseNode, items: itemsNode }, plugin, schema, symbols: { z }, @@ -115,7 +102,6 @@ export const enumToAst = ({ schema: { type: 'unknown', }, - state, }); } @@ -127,7 +113,6 @@ export const enumToAst = ({ nodes: { base: baseNode, items: itemsNode, - nullable: nullableNode, }, plugin, schema, @@ -146,4 +131,4 @@ export const enumToAst = ({ return { expression: node, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/index.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/index.ts deleted file mode 100644 index f4962c0ee..000000000 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/index.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { SchemaWithType } from '@hey-api/shared'; - -import { shouldCoerceToBigInt } from '../../../../plugins/shared/utils/coerce'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { arrayToAst } from './array'; -import { booleanToAst } from './boolean'; -import { enumToAst } from './enum'; -import { neverToAst } from './never'; -import { nullToAst } from './null'; -import { numberToNode } from './number'; -import { objectToAst } from './object'; -import { stringToNode } from './string'; -import { tupleToAst } from './tuple'; -import { undefinedToAst } from './undefined'; -import { unknownToAst } from './unknown'; -import { voidToAst } from './void'; - -export function irSchemaWithTypeToAst({ - schema, - ...args -}: IrSchemaToAstOptions & { - schema: SchemaWithType; -}): Omit { - switch (schema.type) { - case 'array': - return arrayToAst({ - ...args, - schema: schema as SchemaWithType<'array'>, - }); - case 'boolean': - return booleanToAst({ - ...args, - schema: schema as SchemaWithType<'boolean'>, - }); - case 'enum': - return enumToAst({ - ...args, - schema: schema as SchemaWithType<'enum'>, - }); - case 'integer': - case 'number': - return numberToNode({ - ...args, - schema: schema as SchemaWithType<'integer' | 'number'>, - }); - case 'never': - return neverToAst({ - ...args, - schema: schema as SchemaWithType<'never'>, - }); - case 'null': - return nullToAst({ - ...args, - schema: schema as SchemaWithType<'null'>, - }); - case 'object': - return objectToAst({ - ...args, - schema: schema as SchemaWithType<'object'>, - }); - case 'string': - return shouldCoerceToBigInt(schema.format) - ? numberToNode({ - ...args, - schema: { ...schema, type: 'number' }, - }) - : stringToNode({ - ...args, - schema: schema as SchemaWithType<'string'>, - }); - case 'tuple': - return tupleToAst({ - ...args, - schema: schema as SchemaWithType<'tuple'>, - }); - case 'undefined': - return undefinedToAst({ - ...args, - schema: schema as SchemaWithType<'undefined'>, - }); - case 'unknown': - return unknownToAst({ - ...args, - schema: schema as SchemaWithType<'unknown'>, - }); - case 'void': - return voidToAst({ - ...args, - schema: schema as SchemaWithType<'void'>, - }); - } -} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/never.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/never.ts index efa4d55dc..a8d88a6fd 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/never.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/never.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const neverToAst = ({ +export function neverToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'never'>; -}): Omit => { +}): Omit { const result: Partial> = {}; const z = plugin.external('zod.z'); result.expression = $(z).attr(identifiers.never).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/null.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/null.ts index 467b08d91..aa6a47d18 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/null.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/null.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const nullToAst = ({ +export function nullToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'null'>; -}): Omit => { +}): Omit { const result: Partial> = {}; const z = plugin.external('zod.z'); result.expression = $(z).attr(identifiers.null).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/number.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/number.ts index 76bb67e68..a64e561e8 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/number.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/number.ts @@ -95,13 +95,13 @@ function numberResolver(ctx: NumberResolverContext): Chain { return ctx.chain.current; } -export const numberToNode = ({ +export function numberToNode({ plugin, schema, state, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'integer' | 'number'>; -}): Omit => { +}): Omit { const ast: Partial> = {}; const z = plugin.external('zod.z'); const ctx: NumberResolverContext = { @@ -132,4 +132,4 @@ export const numberToNode = ({ const node = resolver?.(ctx) ?? numberResolver(ctx); ast.expression = node; return ast as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/object.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/object.ts index 89fc16a2d..1de13fb14 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/object.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/object.ts @@ -1,35 +1,52 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; -import type { SchemaWithType } from '@hey-api/shared'; +import type { SchemaVisitorContext, SchemaWithType, Walker } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { ObjectResolverContext } from '../../resolvers'; import type { Chain } from '../../shared/chain'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; +import type { ZodPlugin } from '../../types'; -function additionalPropertiesNode(ctx: ObjectResolverContext): Chain | null | undefined { - const { plugin, schema } = ctx; +type WalkerCtx = SchemaVisitorContext; + +interface ObjectToAstOptions extends IrSchemaToAstOptions { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'object'>; + walk: Walker; + walkerCtx: WalkerCtx; +} + +type ExtendedContext = ObjectResolverContext & { + applyModifiers: ObjectToAstOptions['applyModifiers']; + walk: ObjectToAstOptions['walk']; + walkerCtx: ObjectToAstOptions['walkerCtx']; +}; + +function additionalPropertiesNode(ctx: ExtendedContext): Chain | null | undefined { + const { schema, walk, walkerCtx } = ctx; if ( !schema.additionalProperties || (schema.properties && Object.keys(schema.properties).length > 0) - ) + ) { return; + } - const additionalAst = irSchemaToAst({ - plugin, - schema: schema.additionalProperties, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'additionalProperties']), - }, - }); - if (additionalAst.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; - return additionalAst.expression; + const additionalResult = walk( + schema.additionalProperties, + childContext(walkerCtx, 'additionalProperties'), + ); + if (additionalResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + return additionalResult.expression.expression; } -function baseNode(ctx: ObjectResolverContext): Chain { +function baseNode(ctx: ExtendedContext): Chain { const { nodes, symbols } = ctx; const { z } = symbols; @@ -43,48 +60,43 @@ function baseNode(ctx: ObjectResolverContext): Chain { return $(z).attr(identifiers.object).call(shape); } -function objectResolver(ctx: ObjectResolverContext): Chain { +function objectResolver(ctx: ExtendedContext): Chain { // TODO: parser - handle constants return ctx.nodes.base(ctx); } -function shapeNode(ctx: ObjectResolverContext): ReturnType { - const { plugin, schema } = ctx; +function shapeNode(ctx: ExtendedContext): ReturnType { + const { applyModifiers, schema, walk, walkerCtx } = ctx; const shape = $.object().pretty(); for (const name in schema.properties) { const property = schema.properties[name]!; + const isOptional = !schema.required?.includes(name); - const propertyAst = irSchemaToAst({ - optional: !schema.required?.includes(name), - plugin, - schema: property, - state: { - ...ctx.utils.state, - path: ref([...fromRef(ctx.utils.state.path), 'properties', name]), - }, + const propertyResult = walk(property, childContext(walkerCtx, 'properties', name)); + if (propertyResult.hasLazyExpression) ctx.utils.ast.hasLazyExpression = true; + + const ast = applyModifiers(propertyResult, { + optional: isOptional, }); - if (propertyAst.hasLazyExpression) { + + if (ast.hasLazyExpression) { ctx.utils.ast.hasLazyExpression = true; - shape.getter(name, propertyAst.expression.return()); + shape.getter(name, ast.expression.return()); } else { - shape.prop(name, propertyAst.expression); + shape.prop(name, ast.expression); } } return shape; } -export const objectToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'object'>; -}): Omit => { +export function objectToAst(options: ObjectToAstOptions): Omit { + const { plugin } = options; const ast: Partial> = {}; const z = plugin.external('zod.z'); - const ctx: ObjectResolverContext = { + const ctx: ExtendedContext = { + ...options, $, chain: { current: $(z), @@ -95,17 +107,16 @@ export const objectToAst = ({ shape: shapeNode, }, plugin, - schema, symbols: { z, }, utils: { ast, - state, + state: options.state, }, }; const resolver = plugin.config['~resolvers']?.object; const node = resolver?.(ctx) ?? objectResolver(ctx); ast.expression = node; return ast as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/string.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/string.ts index ad579a15a..9e489646d 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/string.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/string.ts @@ -105,12 +105,12 @@ function stringResolver(ctx: StringResolverContext): Chain { return ctx.chain.current; } -export const stringToNode = ({ +export function stringToNode({ plugin, schema, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'string'>; -}): Omit => { +}): Omit { const z = plugin.external('zod.z'); const ctx: StringResolverContext = { $, @@ -137,4 +137,4 @@ export const stringToNode = ({ return { expression: node, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/tuple.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/tuple.ts index 962965069..b18c1b664 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/tuple.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/tuple.ts @@ -1,18 +1,23 @@ -import { fromRef, ref } from '@hey-api/codegen-core'; import type { SchemaWithType } from '@hey-api/shared'; +import { childContext } from '@hey-api/shared'; import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; -import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -import { irSchemaToAst } from '../plugin'; - -export const tupleToAst = ({ - plugin, - schema, - state, -}: IrSchemaToAstOptions & { - schema: SchemaWithType<'tuple'>; -}): Omit => { +import type { + Ast, + IrSchemaToAstOptions, + ZodAppliedResult, + ZodSchemaResult, +} from '../../shared/types'; + +export function tupleToAst( + options: IrSchemaToAstOptions & { + applyModifiers: (result: ZodSchemaResult, opts: { optional?: boolean }) => ZodAppliedResult; + schema: SchemaWithType<'tuple'>; + }, +): Omit { + const { applyModifiers, plugin, schema, walk } = options; + const result: Partial> = {}; const z = plugin.external('zod.z'); @@ -31,18 +36,23 @@ export const tupleToAst = ({ if (schema.items) { schema.items.forEach((item, index) => { - const itemSchema = irSchemaToAst({ - plugin, - schema: item, - state: { - ...state, - path: ref([...fromRef(state.path), 'items', index]), - }, - }); - tupleElements.push(itemSchema.expression); - if (itemSchema.hasLazyExpression) { + const itemResult = walk( + item, + childContext( + { + path: options.state.path, + plugin: options.plugin, + }, + 'items', + index, + ), + ); + if (itemResult.hasLazyExpression) { result.hasLazyExpression = true; } + + const finalExpr = applyModifiers(itemResult, { optional: false }); + tupleElements.push(finalExpr.expression); }); } @@ -51,4 +61,4 @@ export const tupleToAst = ({ .call($.array(...tupleElements)); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/undefined.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/undefined.ts index f52d9fbff..95b3548d3 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/undefined.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/undefined.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const undefinedToAst = ({ +export function undefinedToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'undefined'>; -}): Omit => { +}): Omit { const result: Partial> = {}; const z = plugin.external('zod.z'); result.expression = $(z).attr(identifiers.undefined).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/unknown.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/unknown.ts index d858d60bb..3667ca961 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/unknown.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/unknown.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const unknownToAst = ({ +export function unknownToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'unknown'>; -}): Omit => { +}): Omit { const result: Partial> = {}; const z = plugin.external('zod.z'); result.expression = $(z).attr(identifiers.unknown).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/toAst/void.ts b/packages/openapi-ts/src/plugins/zod/v4/toAst/void.ts index 76b566a27..269219ace 100644 --- a/packages/openapi-ts/src/plugins/zod/v4/toAst/void.ts +++ b/packages/openapi-ts/src/plugins/zod/v4/toAst/void.ts @@ -4,13 +4,13 @@ import { $ } from '../../../../ts-dsl'; import { identifiers } from '../../constants'; import type { Ast, IrSchemaToAstOptions } from '../../shared/types'; -export const voidToAst = ({ +export function voidToAst({ plugin, -}: IrSchemaToAstOptions & { +}: Pick & { schema: SchemaWithType<'void'>; -}): Omit => { +}): Omit { const result: Partial> = {}; const z = plugin.external('zod.z'); result.expression = $(z).attr(identifiers.void).call(); return result as Omit; -}; +} diff --git a/packages/openapi-ts/src/plugins/zod/v4/walker.ts b/packages/openapi-ts/src/plugins/zod/v4/walker.ts new file mode 100644 index 000000000..28c80111b --- /dev/null +++ b/packages/openapi-ts/src/plugins/zod/v4/walker.ts @@ -0,0 +1,386 @@ +import type { Refs, SymbolMeta } from '@hey-api/codegen-core'; +import { fromRef } from '@hey-api/codegen-core'; +import type { SchemaExtractor, SchemaVisitor } from '@hey-api/shared'; +import { pathToJsonPointer } from '@hey-api/shared'; + +import { $ } from '../../../ts-dsl'; +import { maybeBigInt, shouldCoerceToBigInt } from '../../shared/utils/coerce'; +import { identifiers } from '../constants'; +import type { ProcessorContext } from '../shared/processor'; +import type { Ast, PluginState, ZodAppliedResult, ZodSchemaResult } from '../shared/types'; +import type { ZodPlugin } from '../types'; +import { arrayToAst } from './toAst/array'; +import { booleanToAst } from './toAst/boolean'; +import { enumToAst } from './toAst/enum'; +import { neverToAst } from './toAst/never'; +import { nullToAst } from './toAst/null'; +import { numberToNode } from './toAst/number'; +import { objectToAst } from './toAst/object'; +import { stringToNode } from './toAst/string'; +import { tupleToAst } from './toAst/tuple'; +import { undefinedToAst } from './toAst/undefined'; +import { unknownToAst } from './toAst/unknown'; +import { voidToAst } from './toAst/void'; + +export interface VisitorConfig { + /** Optional schema extractor function. */ + schemaExtractor?: SchemaExtractor; + /** The plugin state references. */ + state: Refs; +} + +export function createVisitor( + config: VisitorConfig, +): SchemaVisitor { + const { schemaExtractor, state } = config; + return { + applyModifiers(result, ctx, options = {}): ZodAppliedResult { + const { optional } = options; + let expression = result.expression.expression; + + if (result.readonly) { + expression = expression.attr(identifiers.readonly).call(); + } + + const hasDefault = result.default !== undefined; + const needsNullable = result.nullable; + + if (optional && needsNullable) { + expression = expression.attr(identifiers.nullish).call(); + } else if (optional) { + expression = expression.attr(identifiers.optional).call(); + } else if (needsNullable) { + expression = expression.attr(identifiers.nullable).call(); + } + + if (hasDefault) { + expression = expression + .attr(identifiers.default) + .call( + result.format + ? maybeBigInt(result.default, result.format) + : $.fromValue(result.default), + ); + } + + return { expression }; + }, + array(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = arrayToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + boolean(schema, ctx) { + const ast = booleanToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + enum(schema, ctx) { + const ast = enumToAst({ ...ctx, schema, state }); + const hasNull = + schema.items?.some((item) => item.type === 'null' || item.const === null) ?? false; + return { + default: schema.default, + expression: ast, + nullable: hasNull, + readonly: schema.accessScope === 'read', + }; + }, + integer(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: ast, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + intercept(schema, ctx, walk) { + if (schemaExtractor && !schema.$ref) { + const extracted = schemaExtractor({ + meta: { + resource: 'definition', + resourceId: pathToJsonPointer(fromRef(ctx.path)), + }, + naming: ctx.plugin.config.definitions, + path: fromRef(ctx.path), + plugin: ctx.plugin, + schema, + }); + if (extracted !== schema) { + return walk(extracted, ctx); + } + } + }, + intersection(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + const firstSchema = schemas[0]; + let expression: ZodSchemaResult['expression']; + + // If first item is a union or non-object, use z.intersection() + // Otherwise use .and() chaining for better type inference + if ( + firstSchema?.logicalOperator === 'or' || + (firstSchema?.type && firstSchema.type !== 'object') + ) { + expression = { + expression: $(z) + .attr(identifiers.intersection) + .call(...items.map((item) => item.expression.expression)), + }; + } else { + expression = items[0]!.expression; + items.slice(1).forEach((item) => { + expression = { + expression: expression.expression + .attr(identifiers.and) + .call( + item.hasLazyExpression + ? $(z) + .attr(identifiers.lazy) + .call($.func().do(item.expression.expression.return())) + : item.expression.expression, + ), + }; + }); + } + + return { + default: parentSchema.default, + expression, + hasLazyExpression: hasAnyLazy, + nullable: items.some((i) => i.nullable), + readonly: items.some((i) => i.readonly), + }; + }, + never(schema, ctx) { + const ast = neverToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + null(schema, ctx) { + const ast = nullToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + number(schema, ctx) { + const ast = numberToNode({ ...ctx, schema, state }); + return { + default: schema.default, + expression: ast, + format: schema.format, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + object(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = objectToAst({ + applyModifiers, + plugin: ctx.plugin, + schema, + state, + walk, + walkerCtx: ctx, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + postProcess(result, schema, ctx) { + if (ctx.plugin.config.metadata && schema.description) { + const z = ctx.plugin.external('zod.z'); + return { + ...result, + expression: { + expression: result.expression.expression + .attr(identifiers.register) + .call( + $(z).attr(identifiers.globalRegistry), + $.object().pretty().prop('description', $.literal(schema.description)), + ), + }, + }; + } + return result; + }, + reference($ref, schema, ctx) { + const z = ctx.plugin.external('zod.z'); + const query: SymbolMeta = { + category: 'schema', + resource: 'definition', + resourceId: $ref, + tool: 'zod', + }; + + const refSymbol = ctx.plugin.referenceSymbol(query); + + if (ctx.plugin.isSymbolRegistered(query)) { + return { + default: schema.default, + expression: { + expression: $(refSymbol), + }, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + state.hasLazyExpression['~ref'] = true; + return { + default: schema.default, + expression: { + expression: $(z) + .attr(identifiers.lazy) + .call($.func().returns('any').do($(refSymbol).return())), + }, + hasLazyExpression: true, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + string(schema, ctx) { + if (shouldCoerceToBigInt(schema.format)) { + const ast = numberToNode({ + plugin: ctx.plugin, + schema: { ...schema, type: 'number' }, + state, + }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + } + + const ast = stringToNode({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + tuple(schema, ctx, walk) { + const applyModifiers = (result: ZodSchemaResult, opts: { optional?: boolean }) => + this.applyModifiers(result, ctx, opts) as ZodAppliedResult; + const ast = tupleToAst({ + ...ctx, + applyModifiers, + schema, + state, + walk, + }); + return { + default: schema.default, + expression: ast, + hasLazyExpression: state.hasLazyExpression['~ref'], + nullable: false, + readonly: schema.accessScope === 'read', + }; + }, + undefined(schema, ctx) { + const ast = undefinedToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + union(items, schemas, parentSchema, ctx) { + const z = ctx.plugin.external('zod.z'); + const hasAnyLazy = items.some((item) => item.hasLazyExpression); + + const hasNull = schemas.some((s) => s.type === 'null') || items.some((i) => i.nullable); + + const nonNullItems: typeof items = []; + + items.forEach((item, index) => { + const schema = schemas[index]!; + if (schema.type !== 'null') { + nonNullItems.push(item); + } + }); + + let expression: Ast; + if (nonNullItems.length === 0) { + expression = { + expression: $(z).attr(identifiers.null).call(), + }; + } else if (nonNullItems.length === 1) { + expression = nonNullItems[0]!.expression; + } else { + expression = { + expression: $(z) + .attr(identifiers.union) + .call( + $.array() + .pretty() + .elements(...nonNullItems.map((item) => item.expression.expression)), + ), + }; + } + + return { + default: parentSchema.default, + expression, + hasLazyExpression: hasAnyLazy, + nullable: hasNull, + readonly: items.some((i) => i.readonly), + }; + }, + unknown(schema, ctx) { + const ast = unknownToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + void(schema, ctx) { + const ast = voidToAst({ ...ctx, schema }); + return { + default: schema.default, + expression: ast, + nullable: false, + readonly: false, + }; + }, + }; +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 53d35c6bd..6122573c9 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -65,7 +65,7 @@ export type { SchemaProcessorResult, } from './ir/schema-processor'; export { createSchemaProcessor } from './ir/schema-processor'; -export type { SchemaResult, SchemaVisitor, SchemaVisitorContext, Walker } from './ir/schema-walker'; +export type { SchemaVisitor, SchemaVisitorContext, Walker } from './ir/schema-walker'; export { childContext, createSchemaWalker } from './ir/schema-walker'; export type { IR } from './ir/types'; export { addItemsToSchema } from './ir/utils'; diff --git a/packages/shared/src/ir/schema-walker.ts b/packages/shared/src/ir/schema-walker.ts index 2618fb102..6c2770bf5 100644 --- a/packages/shared/src/ir/schema-walker.ts +++ b/packages/shared/src/ir/schema-walker.ts @@ -5,27 +5,6 @@ import type { SchemaWithType } from '../plugins/shared/types/schema'; import { deduplicateSchema } from './schema'; import type { IR } from './types'; -/** - * Result returned by visitor methods. Contains the expression plus metadata - * needed for modifier application. - */ -export interface SchemaResult { - /** Default value from schema, if any. */ - default?: unknown; - /** The core schema expression, WITHOUT optional/nullable/default applied. */ - expression: TExpr; - /** The original schema format. */ - format?: string; - /** For libraries that need lazy evaluation. */ - hasLazyExpression?: boolean; - /** Plugin-specific metadata bucket. */ - meta?: Record; - /** Does this schema explicitly allow null? */ - nullable: boolean; - /** Is this schema read-only? */ - readonly: boolean; -} - /** * Context passed to all visitor methods. */ @@ -37,47 +16,43 @@ export interface SchemaVisitorContext { } /** - * The walk function signature. + * The walk function signature. Fully generic over TResult. */ -export type Walker = ( +export type Walker = ( schema: IR.SchemaObject, ctx: SchemaVisitorContext, -) => SchemaResult; +) => TResult; /** - * The visitor interface. Plugins implement this to define how schemas - * are transformed into their target representation. + * The visitor interface. Plugins define their own TResult type. + * + * The walker handles orchestration (dispatch, deduplication, path tracking). + * Result shape and semantics are entirely plugin-defined. */ -export interface SchemaVisitor { +export interface SchemaVisitor { /** - * Apply modifiers (optional/nullable/nullish/default) to a schema result. + * Apply modifiers to a result. */ applyModifiers( - result: SchemaResult, + result: TResult, ctx: SchemaVisitorContext, context?: { /** Is this property optional? */ optional?: boolean; }, - ): TExpr; + ): unknown; array( schema: SchemaWithType<'array'>, ctx: SchemaVisitorContext, - walk: Walker, - ): SchemaResult; - boolean( - schema: SchemaWithType<'boolean'>, - ctx: SchemaVisitorContext, - ): SchemaResult; + walk: Walker, + ): TResult; + boolean(schema: SchemaWithType<'boolean'>, ctx: SchemaVisitorContext): TResult; enum( schema: SchemaWithType<'enum'>, ctx: SchemaVisitorContext, - walk: Walker, - ): SchemaResult; - integer( - schema: SchemaWithType<'integer'>, - ctx: SchemaVisitorContext, - ): SchemaResult; + walk: Walker, + ): TResult; + integer(schema: SchemaWithType<'integer'>, ctx: SchemaVisitorContext): TResult; /** * Called before any dispatch logic. Return a result to short-circuit, * or undefined to continue normal dispatch. @@ -85,63 +60,55 @@ export interface SchemaVisitor { intercept?( schema: IR.SchemaObject, ctx: SchemaVisitorContext, - walk: Walker, - ): SchemaResult | undefined; + walk: Walker, + ): TResult | undefined; /** * Handle intersection types. Receives already-walked child results. */ intersection( - items: Array>, + items: Array, schemas: ReadonlyArray, + parentSchema: IR.SchemaObject, ctx: SchemaVisitorContext, - ): SchemaResult; - never(schema: SchemaWithType<'never'>, ctx: SchemaVisitorContext): SchemaResult; - null(schema: SchemaWithType<'null'>, ctx: SchemaVisitorContext): SchemaResult; - number(schema: SchemaWithType<'number'>, ctx: SchemaVisitorContext): SchemaResult; + ): TResult; + never(schema: SchemaWithType<'never'>, ctx: SchemaVisitorContext): TResult; + null(schema: SchemaWithType<'null'>, ctx: SchemaVisitorContext): TResult; + number(schema: SchemaWithType<'number'>, ctx: SchemaVisitorContext): TResult; object( schema: SchemaWithType<'object'>, ctx: SchemaVisitorContext, - walk: Walker, - ): SchemaResult; + walk: Walker, + ): TResult; /** * Called after each typed schema visitor returns. */ postProcess?( - result: SchemaResult, + result: TResult, schema: IR.SchemaObject, ctx: SchemaVisitorContext, - ): SchemaResult; + ): TResult; /** * Handle $ref to another schema. */ - reference( - $ref: string, - schema: IR.SchemaObject, - ctx: SchemaVisitorContext, - ): SchemaResult; - string(schema: SchemaWithType<'string'>, ctx: SchemaVisitorContext): SchemaResult; + reference($ref: string, schema: IR.SchemaObject, ctx: SchemaVisitorContext): TResult; + string(schema: SchemaWithType<'string'>, ctx: SchemaVisitorContext): TResult; tuple( schema: SchemaWithType<'tuple'>, ctx: SchemaVisitorContext, - walk: Walker, - ): SchemaResult; - undefined( - schema: SchemaWithType<'undefined'>, - ctx: SchemaVisitorContext, - ): SchemaResult; + walk: Walker, + ): TResult; + undefined(schema: SchemaWithType<'undefined'>, ctx: SchemaVisitorContext): TResult; /** * Handle union types. Receives already-walked child results. */ union( - items: Array>, + items: Array, schemas: ReadonlyArray, + parentSchema: IR.SchemaObject, ctx: SchemaVisitorContext, - ): SchemaResult; - unknown( - schema: SchemaWithType<'unknown'>, - ctx: SchemaVisitorContext, - ): SchemaResult; - void(schema: SchemaWithType<'void'>, ctx: SchemaVisitorContext): SchemaResult; + ): TResult; + unknown(schema: SchemaWithType<'unknown'>, ctx: SchemaVisitorContext): TResult; + void(schema: SchemaWithType<'void'>, ctx: SchemaVisitorContext): TResult; } /** @@ -151,12 +118,11 @@ export interface SchemaVisitor { * - Dispatch order ($ref → type → items → fallback) * - Deduplication of union/intersection schemas * - Path tracking for child schemas - * - Calling the appropriate visitor method */ -export function createSchemaWalker( - visitor: SchemaVisitor, -): Walker { - const walk: Walker = (schema, ctx) => { +export function createSchemaWalker( + visitor: SchemaVisitor, +): Walker { + const walk: Walker = (schema, ctx) => { // escape hatch if (visitor.intercept) { const intercepted = visitor.intercept(schema, ctx, walk); @@ -165,18 +131,8 @@ export function createSchemaWalker( } } - const baseResult = { - default: schema.default, - readonly: schema.accessScope === 'read', - }; - if (schema.$ref) { - const result = visitor.reference(schema.$ref, schema, ctx); - return { - ...result, - default: result.default ?? baseResult.default, - readonly: result.readonly || baseResult.readonly, - }; + return visitor.reference(schema.$ref, schema, ctx); } if (schema.type) { @@ -184,11 +140,7 @@ export function createSchemaWalker( if (visitor.postProcess) { result = visitor.postProcess(result, schema, ctx); } - return { - ...result, - default: result.default ?? baseResult.default, - readonly: result.readonly || baseResult.readonly, - }; + return result; } if (schema.items) { @@ -206,25 +158,13 @@ export function createSchemaWalker( }), ); - const result = - deduplicated.logicalOperator === 'and' - ? visitor.intersection(itemResults, deduplicated.items, ctx) - : visitor.union(itemResults, deduplicated.items, ctx); - - return { - ...result, - default: result.default ?? baseResult.default, - readonly: result.readonly || baseResult.readonly, - }; + return deduplicated.logicalOperator === 'and' + ? visitor.intersection(itemResults, deduplicated.items, schema, ctx) + : visitor.union(itemResults, deduplicated.items, schema, ctx); } // fallback - const result = visitor.unknown({ type: 'unknown' }, ctx); - return { - ...result, - default: result.default ?? baseResult.default, - readonly: result.readonly || baseResult.readonly, - }; + return visitor.unknown({ type: 'unknown' }, ctx); }; return walk; @@ -233,12 +173,12 @@ export function createSchemaWalker( /** * Dispatch to the appropriate visitor method based on schema type. */ -function visitTyped( +function visitTyped( schema: SchemaWithType, ctx: SchemaVisitorContext, - visitor: SchemaVisitor, - walk: Walker, -): SchemaResult { + visitor: SchemaVisitor, + walk: Walker, +): TResult { switch (schema.type) { case 'array': return visitor.array(schema as SchemaWithType<'array'>, ctx, walk);