diff --git a/packages/downgrader/README.md b/packages/downgrader/README.md index 9cd9bf3..8dd600b 100644 --- a/packages/downgrader/README.md +++ b/packages/downgrader/README.md @@ -282,7 +282,7 @@ Accepts the default OAS dialect, which adds `discriminator`, `xml`, `externalDoc - aiopenapi3 fails to load a 3.0 document that holds the `"null"` branch: it takes `null` out of a nullable `enum` and builds an empty `Literal` from what is left. aiopenapi3 reads 3.1 too, which keeps `{ type: "null" }`. - oapi-codegen 2.8 rejects, and the OpenAPI Generator C# client breaks on, a string enum with a `format` such as `uuid`, which a `const` with a `format` becomes, as ArkType writes for `string.uuid`. oapi-codegen also stops on a `oneOf` that holds the `"null"` branch beside a `discriminator` with a `mapping`, as typia writes a nullable tagged union, since it wants every branch other than `{ type: "null" }` there to be a `$ref`. It reads 3.1 too, which keeps `{ type: "null" }` there. - Validators that coerce a value to each branch's `type`, as Prism, express-openapi-validator and openapi-backend do for parameters, and Fastify and Ruby's committee (through openapi_parser) by default for bodies too, match a value such as `1` or `"1"` to two branches of the `oneOf` a union of scalar types becomes, and reject it. So a query flag that takes `"true"`, `"false"`, `"0"`, `"1"` or a boolean, as GrowthBook writes, rejects `?flag=true`, since `"true"` matches the string and, coerced, the boolean. Fastify by default also wraps a value in an array, so it rejects a single value, and an array of one item, against the `oneOf` a union of a scalar type and an array becomes, as for `string | string[]`. It also coerces in place, so a branch of a `oneOf` can change the value that later branches and the handler see. A number in Effect's `Schema.Number`, a `oneOf` of a number and a string enum, arrives as a string, and null in a nullable enum, a nullable `$ref` to an enum, or a nullable union of literals becomes a value such as `""`, which the `"null"` branch rejects where 3.1's `{ type: "null" }` turns it back into null. Prism, express-openapi-validator, openapi-backend and fastify-openapi-glue read 3.1 too, which keeps the `type` list or the `anyOf`. -- kin-openapi's request validation (`openapi3filter`, which oapi-codegen's validator middleware wraps) decodes a query or path value with each branch of a `oneOf` and keeps the value of the last branch that decodes it. The `"null"` branch decodes any value as a string, so where it comes last, as Zod writes it, a parameter whose other branches take no string rejects every value, such as `?prio=5` against the `oneOf` that a nullable `$ref` to a number or integer schema or a number enum becomes, as for Zod's `.nullable()` on such a schema with its own id, or a nullable union of a number and a boolean. kin-openapi reads 3.1 too, which keeps the `anyOf`, where the first branch that decodes the value wins. +- kin-openapi's request validation (`openapi3filter`, which oapi-codegen's validator middleware wraps) decodes a parameter value (query, path, header or cookie) or a field of a form-encoded body with each branch of a `oneOf` and keeps the value of the last branch that decodes it. The `"null"` branch decodes any value as a string, so where it comes last, as Zod writes it, a parameter or field whose other branches take no string rejects every value, such as `?prio=5` against the `oneOf` that a nullable `$ref` to a number or integer schema or a number enum becomes, as for Zod's `.nullable()` on such a schema with its own id, or a nullable union of a number and a boolean. kin-openapi reads 3.1 too, which keeps the `anyOf`, where the first branch that decodes the value wins. In a `multipart/form-data` body it reads a text part whose schema has no `type` as null, so a part whose schema is a `type` list without `"null"`, such as `["string", "integer"]`, which becomes a `oneOf` in 3.0, rejects every value (with `"null"` in the list, the null branch takes that null). - Kiota reads the `"null"` branch's `type: "string"` as a real type, so array items that may be null, and a union of several types with null, come out as strings. It also skips a `oneOf` or `anyOf` branch that is an `allOf` holding a `$ref`, as a `$ref` with siblings becomes, other than one with only annotations beside a `discriminator` or to a schema with one, so a nullable `$ref` with a `description`, such as Zod's `.describe()` on a schema with its own id before `.nullable()`, comes out as an enum holding only Kiota's null sentinel, and a union of such branches as `UntypedNode` or as its other branches alone. Its TypeScript client reads every value of a `oneOf` of objects with the first branch, so it drops the tag of a value from any other branch, since `const` becomes a one-value `enum` that the first branch rejects, as for Zod's `z.discriminatedUnion()`. It also reads an array of `format: byte` strings, which an array of `contentEncoding: base64` strings such as `z.array(z.base64())` becomes, as one byte array, so it drops the array, and its C# client throws on it. Kiota reads 3.1 too, which keeps their types and the `$ref` beside its siblings, and reads `const` and `contentEncoding` strings as plain strings. - Speakeasy, like Kiota, reads the `"null"` branch's `type: "string"` as a string, so a nullable `$ref` or enum also takes any string, and a nullable union of scalars with a string becomes `any`, since it then holds two strings. It also fails on a recursive component, reached from another schema, with a property of `type: "null"` alone, such as Zod's `z.null()`. Speakeasy reads 3.1 too, which keeps their types. - `@nahkies/openapi-code-generator` 0.26, like Speakeasy, drops the `null` from the `"null"` branch's `enum` and keeps its `type: "string"`, so a nullable `$ref`, enum or union, such as Zod's `z.enum(["a", "b"]).nullable()`, also takes any string, both in its types and in the Zod schemas that its servers check request bodies with. It reads 3.1 too, which keeps `{ type: "null" }`.