agent_patch
runs/2026-02-27__21-30-28__gpt-5-4/flux-pr-5156/flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/agent-logs/agent.patch
6223 bytes
diff --git a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
index ec6267c..0d00c39 100644
--- a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
+++ b/app/packages/zod/src/v4/classic/tests/to-json-schema.test.ts
@@ -565,6 +565,28 @@ describe("toJSONSchema", () => {
const schema = z.union([z.string(), z.null()]);
expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
{
+ "anyOf": [
+ {
+ "type": "string",
+ },
+ {
+ "enum": [
+ null,
+ ],
+ "nullable": true,
+ "type": "string",
+ },
+ ],
+ }
+ `);
+ });
+
+ test("null openapi", () => {
+ expect(z.toJSONSchema(z.null(), { target: "openapi-3.0" })).toMatchInlineSnapshot(`
+ {
+ "enum": [
+ null,
+ ],
"nullable": true,
"type": "string",
}
@@ -737,6 +759,31 @@ describe("toJSONSchema", () => {
`);
});
+ test("tuple with null openapi", () => {
+ const schema = z.tuple([z.string(), z.null()]);
+ expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
+ {
+ "items": {
+ "anyOf": [
+ {
+ "type": "string",
+ },
+ {
+ "enum": [
+ null,
+ ],
+ "nullable": true,
+ "type": "string",
+ },
+ ],
+ },
+ "maxItems": 2,
+ "minItems": 2,
+ "type": "array",
+ }
+ `);
+ });
+
test("tuple with rest openapi", () => {
const schema = z.tuple([z.string(), z.number()]).rest(z.boolean());
expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
diff --git a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/core/to-json-schema.ts b/app/packages/zod/src/v4/core/to-json-schema.ts
index 0f5e400..01ead57 100644
--- a/tmp/agent-patch-flux-pr-5156.1-of-1.2026-02-27__21-30-28__gpt-5-4/app/packages/zod/src/v4/core/to-json-schema.ts
+++ b/app/packages/zod/src/v4/core/to-json-schema.ts
@@ -4,6 +4,12 @@ import { $ZodRegistry, globalRegistry } from "./registries.js";
import type * as schemas from "./schemas.js";
import { getEnumValues } from "./util.js";
+function setOpenAPINullSchema(json: JSONSchema.BaseSchema) {
+ json.type = "string";
+ json.nullable = true;
+ json.enum = [null];
+}
+
interface JSONSchemaGeneratorParams {
/** A registry used to look up metadata for each schema. Any schema with an `id` property will be extracted as a $def.
* @default globalRegistry */
@@ -236,7 +242,11 @@ export class JSONSchemaGenerator {
break;
}
case "null": {
- _json.type = "null";
+ if (this.target === "openapi-3.0") {
+ _json.type = "string";
+ _json.nullable = true;
+ _json.enum = [null];
+ } else _json.type = "null";
break;
}
case "any": {
@@ -332,18 +342,7 @@ export class JSONSchemaGenerator {
path: [...params.path, "anyOf", i],
})
);
- if (this.target === "openapi-3.0") {
- const nonNull = options.filter((x) => (x as any).type !== "null");
- const hasNull = nonNull.length !== options.length;
- if (nonNull.length === 1) {
- Object.assign(json, nonNull[0]!);
- } else {
- json.anyOf = nonNull;
- }
- if (hasNull) (json as any).nullable = true;
- } else {
- json.anyOf = options;
- }
+ json.anyOf = options;
break;
}
case "intersection": {
@@ -478,17 +477,27 @@ export class JSONSchemaGenerator {
// do nothing (an undefined literal was stripped)
} else if (vals.length === 1) {
const val = vals[0]!;
- json.type = val === null ? ("null" as const) : (typeof val as any);
- if (this.target === "draft-4" || this.target === "openapi-3.0") {
- json.enum = [val];
+ if (val === null && this.target === "openapi-3.0") {
+ setOpenAPINullSchema(json);
} else {
- json.const = val;
+ json.type = val === null ? ("null" as const) : (typeof val as any);
+ if (this.target === "draft-4" || this.target === "openapi-3.0") {
+ json.enum = [val];
+ } else {
+ json.const = val;
+ }
}
} else {
if (vals.every((v) => typeof v === "number")) json.type = "number";
if (vals.every((v) => typeof v === "string")) json.type = "string";
if (vals.every((v) => typeof v === "boolean")) json.type = "string";
- if (vals.every((v) => v === null)) json.type = "null";
+ if (vals.every((v) => v === null)) {
+ if (this.target === "openapi-3.0") {
+ setOpenAPINullSchema(json);
+ break;
+ }
+ json.type = "null";
+ }
json.enum = vals;
}
break;
@@ -532,12 +541,12 @@ export class JSONSchemaGenerator {
}
case "nullable": {
- const inner = this.process(def.innerType, params);
if (this.target === "openapi-3.0") {
- Object.assign(_json, inner);
- (_json as any).nullable = true;
+ this.process(def.innerType, params);
result.ref = def.innerType;
+ (_json as any).nullable = true;
} else {
+ const inner = this.process(def.innerType, params);
_json.anyOf = [inner, { type: "null" }];
}
break;