Repository navigation
Commit 8a0d645
fix(downgrader): make a nullable allOf a oneOf when any member rejects null (#202)
<!-- claude-projects-attribution: {"github_login":"dinwwwh"} -->
_Requested by **dinwwwh** · [project
thread](https://claude.ai/code/project/chan_01UcKMz91tMarPV1kWLVgLYE?thread=cmsg_01UcKMz91tMarPV1kWLVgLYEJyw1s6rAadV1YjLbH5F8Fh)_
## What
`mergeNullable` makes an `anyOf` null pair a `oneOf` when the other
branch rejects null (#126). For an `allOf` branch it looked only at
`allOf[0]`, and only when that was a `$ref`. So these stayed an `anyOf`
in 3.0:
- oRPC's `z.intersection(B, T).nullable()` with `T` registered, which
writes `anyOf [{ allOf [B, $ref T] }, { type: "null" }]` (the `$ref`
second).
- an intersection of two inline objects, `anyOf [{ allOf [object,
object] }, { type: "null" }]`.
NSwag reads that `anyOf` as an empty class (checked with NSwag 14 C#:
the `anyOf` gives an empty `V`, the `oneOf` gives `V : T` holding `B`),
which is the reason #126 makes the pair a `oneOf`.
## Fix
An `allOf` rejects null when any member does, so every member is
checked, following a member's `$ref`. That is exact: null fails the
`allOf`, so it matches only the null branch. An `allOf` whose members
all admit null stays an `anyOf`.
The README row for the `anyOf` null pair now says the pair also becomes
a `oneOf` for "an `allOf` with such a member in any place, as Zod writes
a nullable intersection".
## Tests
New test: the `$ref`-second intersection becomes a `oneOf`, two inline
objects become a `oneOf`, and an `allOf` of an untyped member and a
`$ref` to a schema that admits null stays an `anyOf`. The test fails on
main. `pnpm run check` and `pnpm test` pass (363 tests), and coverage
stays at 100%.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VVaw7RdCF4usMbdkSRvsKh)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 8e11ec5 commit 8a0d645
3 files changed
Lines changed: 76 additions & 38 deletions
0 commit comments