Skip to content

fix: preserve nested nullable schema semantics - #158

Merged
adamcavendish merged 2 commits into
mainfrom
adamcavendish/preserve-nested-nullable-schemas
Oct 19, 2026
Merged

adamcavendish merged 2 commits into
mainfrom
adamcavendish/preserve-nested-nullable-schemas

Conversation

@adamcavendish

@adamcavendish adamcavendish commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Preserve nested nullability across OpenAPI 3.0, 3.1, and 3.2, with output coverage for all nine generators and real HTTP decoding coverage for all three Rust backends.

Rust generated-client tests now live in standalone consumer projects. They use ordinary Rust test files and unmodified generated path dependencies, rather than having generator tests assemble test programs and recursively invoke Cargo.

Problem

Nested lowering could lose nullability from map values, array items, promoted inline items, and array aliases. OpenAPI 3.1/3.2 named maps also bypassed the supported nullable oneOf/anyOf pattern. TypeScript nullable multidimensional arrays could produce invalid readonly readonly string[][] syntax, and nullable element unions needed parentheses.

The previous Rust runtime harness mixed generator testing with client build orchestration, rebuilt temporary crates per test, and injected an unused server helper that failed under CI's -Dwarnings. The entire Rust harness is migrated here, not just the newly added nullable cases.

Behavior

Situation Guaranteed behavior
Nullable map values Map(Nullable(T)), distinct from a nullable container
Nullable array items Array(Nullable(T)), distinct from a nullable container
Nullable array container Nullable(Array(T)), including aliases and promoted items
Two-member nullable union Existing pattern works at nested map/array nodes
TypeScript nullable arrays Semantic unions preserve precedence and named imports
Invalid Rust response payloads HTTP errors retain status, headers, and original bytes
Generated Rust client testing Separate consumer projects and an explicit CI matrix

Test organization

  • tests/generated-clients/rust/{reqwest,ureq,aioduct} are independent Cargo projects with checked-in manifests, lockfiles, and test source.
  • just golden-rust::prepare <backend> generates the three fixtures through the public CLI into ignored, disposable directories. Generated manifests and source are not patched.
  • just golden-rust::test runs one Cargo test invocation per backend, with persistent target directories. Tests contain no subprocess orchestration or dynamically assembled test programs.
  • Existing reqwest/ureq HTTP assertions, propagation checks, aioduct layout checks, and composite-payload compilation are retained. Each backend also runs the seven shared nullable HTTP cases.
  • Generator workspace tests and coverage no longer recursively build client crates. CI runs the consumer projects separately with inherited warning flags. JVM runtime tests are unchanged.

Boundaries

Shared schema semantics are fixed in lowering, not Rust-specific workarounds. Requiredness remains independent of nullability, and strict controls remain strict. Existing unspecified-type fallbacks and unrelated enum, union, and reference policies are unchanged.

No release-version or production dependency changes. The new consumer projects declare and lock their own test dependencies. Existing golden files are unchanged; the new nullable fixture adds output for every registered generator.

- Retain container, item, and map-value nullability across OpenAPI 3.0, 3.1,
  and 3.2 lowering, including promoted items and nullable array aliases.
- Render TypeScript nullable arrays with semantic unions that preserve
  precedence and named-type imports.
- Pin all nine generators with nested nullable goldens and verify Rust HTTP
  decoding preserves strict controls, error metadata, and original bodies.
- Replace the recursive Cargo harness with standalone consumer projects for
  reqwest, ureq, and aioduct while preserving existing runtime assertions.
- Generate unmodified client dependencies through the public CLI and run each
  backend's ordinary test files with checked-in manifests and lockfiles.
- Keep client builds out of generator tests and coverage, and run them in an
  explicit CI matrix with reusable build caches and inherited warning flags.
@codecov

codecov Bot commented Oct 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.36364% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/ir/lower/v31.rs 93.75% 3 Missing ⚠️
src/ir/lower/v32.rs 93.75% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@adamcavendish
adamcavendish merged commit 4067574 into main Oct 19, 2026
28 checks passed
@adamcavendish
adamcavendish deleted the adamcavendish/preserve-nested-nullable-schemas branch October 19, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant