Skip to content

Latest commit

 

History

History
42 lines (34 loc) · 19.4 KB

File metadata and controls

42 lines (34 loc) · 19.4 KB

Zod 4 Support Matrix

This document tracks the Zod 4 surface that next-openapi-gen currently validates in code and fixtures.

The generator still relies primarily on static AST analysis, but it now uses a selective runtime-assisted Zod 4 export path for a small set of features where input/output-aware JSON Schema adds useful fidelity without replacing the existing AST converter.

Verified Coverage

Zod 4 construct Expected emitted shape OpenAPI targets Regression coverage Notes
z.email() type: "string", format: "email" 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Same parity as z.string().email()
z.url() type: "string", format: "uri" 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Same parity as z.string().url()
z.uuid() type: "string", format: "uuid" 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Closes issue #92
z.iso.datetime() type: "string", format: "date-time" 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Nested namespace helper support
z.guid() / z.ipv4() / z.ipv6() / z.iso.duration() String formats are preserved in emitted schemas 3.0, 3.1, 3.2 tests/unit/schema/zod/node-helpers.test.ts, tests/unit/schema/zod/zod-converter.test.ts Added to the AST converter parity path
nullable() / nullish() on base schemas and named schema references nullable: true in 3.0; type: [..., "null"] in 3.1+ for primitive types. For named schema references (producing a $ref), emits anyOf: [{ $ref }, { type: "null" }]; the version processor downgrades to { allOf: [{ $ref }], nullable: true } for 3.0. 3.0, 3.1, 3.2 tests/integration/generator/zod4-support.test.ts, tests/integration/validation/openapi-validation.test.ts, tests/integration/regressions/zod-nullability.test.ts Closes issue #142; version finalization rewrites nullable semantics
pipe() into a stronger schema Preserves strongest representable base schema 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts Used for patterns like z.string().pipe(z.email())
Runtime-assisted coerce / pipe variants Request-side schemas can keep input shapes while responses keep output constraints when the runtime export can prove the difference 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts Falls back to AST behavior when runtime export is unavailable
transform() / refine() / superRefine() / brand() Preserve the underlying JSON-schema-compatible base shape 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Runtime-only semantics are not serialized
.describe("text") / .meta({ description }) — OpenAPI description Maps to description in emitted schema. .describe() and .meta({ description }) are equivalent. @deprecated prefix sets deprecated: true. 3.0, 3.1, 3.2 tests/unit/schema/zod/features/modifiers.test.ts Idiomatic Zod-native alternative to @description JSDoc
.meta({...}) — OpenAPI annotations (Zod v4) Copies all representable keys into emitted schema: description, examples, example, deprecated, title, custom x-* extensions. The id field is treated specially: it overrides the generated component name instead of being emitted as a schema property (see Component Naming). Example: z.number().int().positive().meta({ description: "PIM ID", examples: [42, 1337] }){ type: "integer", exclusiveMinimum: 0, description: "PIM ID", examples: [42, 1337] } 3.0, 3.1, 3.2 tests/unit/schema/zod/features/modifiers.test.ts, tests/unit/schema/zod/zod-converter.test.ts, tests/unit/schema/zod/runtime-exporter.test.ts Runtime-assisted path via z.toJSONSchema() when .meta() is outermost call; AST path for mid-chain usage
z.literal() with numeric values Integer values emit type: "integer"; float values emit type: "number". A z.union([z.literal(1), z.literal(2)]) composed entirely of integer literals collapses to { type: "integer", enum: [...] }. Mixed integer/float unions fall through to separate anyOf items. 3.0, 3.1, 3.2 tests/unit/schema/zod/features/unions-and-intersections.test.ts, tests/unit/schema/zod/features/primitives.test.ts, tests/unit/schema/zod/node-helpers.test.ts Closes issue #143
z.tuple([...]) Emits tuple-aware arrays with prefixItems, items: false, and fixed item counts 3.1, 3.2 tests/unit/schema/zod/node-helpers.test.ts, tests/unit/schema/zod/zod-converter-helpers.test.ts 3.0 downgrades happen in version finalization
Shared imported query schemas Per-parameter schemas retain $ref / allOf detail 3.0, 3.1, 3.2 tests/unit/schema/typescript/schema-content.test.ts, tests/integration/generator/zod4-support.test.ts Closes issue #93
Required fields in @queryParams object schemas Per-parameter required: true matches parent schema required list 3.0, 3.1, 3.2 tests/unit/schema/typescript/schema-content.test.ts, tests/integration/generator/zod4-support.test.ts Closes issue #94
Exported z.infer<typeof Schema> aliases in pure-Zod mode No duplicate component unless alias is explicitly referenced 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts Closes issue #96
import { z } from "zod/v4" Parsed the same as zod import path when the local binding is z 3.0, 3.1, 3.2 tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts, tests/integration/generator/zod4-support.test.ts Also covered in a Pages Router fixture
z.discriminatedUnion() with spread base shapes Member schemas that spread a shared base shape (e.g. z.object({ ...baseShape, type: z.literal('dog') }).meta({ id: 'Dog' })) emit correct component schemas containing all spread properties, not only the discriminator field. 3.0, 3.1, 3.2 tests/unit/regressions/zod-issue-141-discriminated-union-spread.test.ts Closes issue #141

Checked-In Fixtures

Fixture Purpose
tests/fixtures/projects/next/app-router/zod-only-coverage App Router Zod-first coverage for top-level helpers, transformed query params, nullable helper output, and pure-Zod alias behavior
tests/fixtures/projects/next/pages-router/zod-flow Pages Router coverage for zod/v4 imports and Zod-generated response schemas

Known Boundaries

  • The generator preserves the strongest OpenAPI-representable base schema for transforms and refinements, but it does not serialize arbitrary runtime predicates.
  • The runtime-assisted Zod 4 export path is intentionally selective. It currently targets features such as coerce, pipe, templateLiteral, stringbool, and static .meta(...) payloads, while the broader converter still runs through AST analysis.
  • @auth metadata currently emits alternative security requirements for comma-separated values. Combined requirements and advanced scheme fields should still be modeled in templates or reusable OpenAPI fragments.
  • Response inference is selective and best-effort. It supports named response types, inline object responses, multiple return paths, and 204 responses, but explicit @response tags remain the most deterministic option when stable component names matter.