From 6b7f37b2ccc31e6e3ec94c1e8197cd2120cd532d Mon Sep 17 00:00:00 2001 From: alexrjones Date: Tue, 3 Feb 2026 11:49:34 +0800 Subject: [PATCH 1/2] Transform 3.0 schema with allOf + nullable into oneOf --- helpers/schema_compiler.go | 20 ++++++ helpers/schema_compiler_test.go | 120 ++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/helpers/schema_compiler.go b/helpers/schema_compiler.go index 62189120..9fc6cec6 100644 --- a/helpers/schema_compiler.go +++ b/helpers/schema_compiler.go @@ -187,6 +187,26 @@ func transformNullableSchema(schema map[string]interface{}) map[string]interface } } } + allOf, hasAllOf := schema["allOf"] + if hasAllOf { + delete(schema, "allOf") + oneOfAdditions := []interface{}{ + map[string]interface{}{ + "allOf": allOf, + }, + map[string]interface{}{ + "type": "null", + }, + } + var oneOfSlice []interface{} + oneOf, hasOneOf := schema["oneOf"] + if hasOneOf { + oneOfSlice, _ = oneOf.([]interface{}) + } + oneOfSlice = append(oneOfSlice, oneOfAdditions...) + schema["oneOf"] = oneOfSlice + } + return schema } diff --git a/helpers/schema_compiler_test.go b/helpers/schema_compiler_test.go index 0cfc1030..979650b9 100644 --- a/helpers/schema_compiler_test.go +++ b/helpers/schema_compiler_test.go @@ -456,6 +456,126 @@ func TestTransformNullableSchema_ArrayTypeWithNull(t *testing.T) { assert.False(t, hasNullable) } +func TestTransformNullableSchema_NullableAllOf(t *testing.T) { + schema := map[string]interface{}{ + "type": []interface{}{"object"}, + "allOf": []interface{}{ + map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + }}, + }, + }, + "nullable": true, + } + + result := transformNullableSchema(schema) + + schemaType, ok := result["type"] + require.True(t, ok) + + typeArray, ok := schemaType.([]interface{}) + require.True(t, ok) + assert.Contains(t, typeArray, "object") + assert.Contains(t, typeArray, "null") + + oneOf, ok := result["oneOf"] + require.True(t, ok) + + oneOfSlice, ok := oneOf.([]interface{}) + require.True(t, ok) + + assert.Len(t, oneOfSlice, 2) + assert.Contains(t, oneOfSlice, map[string]interface{}{ + "allOf": []interface{}{ + map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + }}, + }, + }, + }) + assert.Contains(t, oneOfSlice, map[string]interface{}{ + "type": "null", + }) + + _, hasNullable := result["nullable"] + assert.False(t, hasNullable) +} + +func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) { + schema := map[string]interface{}{ + "type": []interface{}{"object"}, + "allOf": []interface{}{ + map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + }}, + }, + }, + "oneOf": []interface{}{ + map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + "const": []any{"val"}, + }}, + }, + }, + "nullable": true, + } + + result := transformNullableSchema(schema) + + schemaType, ok := result["type"] + require.True(t, ok) + + typeArray, ok := schemaType.([]interface{}) + require.True(t, ok) + assert.Contains(t, typeArray, "object") + assert.Contains(t, typeArray, "null") + + oneOf, ok := result["oneOf"] + require.True(t, ok) + + oneOfSlice, ok := oneOf.([]interface{}) + require.True(t, ok) + + assert.Len(t, oneOfSlice, 3) + assert.Contains(t, oneOfSlice, map[string]interface{}{ + "allOf": []interface{}{ + map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + }}, + }, + }, + }) + assert.Contains(t, oneOfSlice, map[string]interface{}{ + "type": "null", + }) + assert.Contains(t, oneOfSlice, map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{ + "type": "string", + "const": []any{"val"}, + }}, + }) + + _, hasNullable := result["nullable"] + assert.False(t, hasNullable) +} + func TestTransformSchemaForCoercion_ValidJSON(t *testing.T) { input := []byte(`{ "type": "boolean" From 33d377dd6c7b18f56fb0efcaf63b5bd27261b12f Mon Sep 17 00:00:00 2001 From: alexrjones Date: Tue, 3 Feb 2026 12:01:21 +0800 Subject: [PATCH 2/2] gofumpt --- helpers/schema_compiler_test.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/helpers/schema_compiler_test.go b/helpers/schema_compiler_test.go index 979650b9..c5965b37 100644 --- a/helpers/schema_compiler_test.go +++ b/helpers/schema_compiler_test.go @@ -465,7 +465,8 @@ func TestTransformNullableSchema_NullableAllOf(t *testing.T) { "properties": map[string]interface{}{ "id": map[string]interface{}{ "type": "string", - }}, + }, + }, }, }, "nullable": true, @@ -495,7 +496,8 @@ func TestTransformNullableSchema_NullableAllOf(t *testing.T) { "properties": map[string]interface{}{ "id": map[string]interface{}{ "type": "string", - }}, + }, + }, }, }, }) @@ -516,7 +518,8 @@ func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) { "properties": map[string]interface{}{ "id": map[string]interface{}{ "type": "string", - }}, + }, + }, }, }, "oneOf": []interface{}{ @@ -526,7 +529,8 @@ func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) { "id": map[string]interface{}{ "type": "string", "const": []any{"val"}, - }}, + }, + }, }, }, "nullable": true, @@ -556,7 +560,8 @@ func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) { "properties": map[string]interface{}{ "id": map[string]interface{}{ "type": "string", - }}, + }, + }, }, }, }) @@ -569,7 +574,8 @@ func TestTransformNullableSchema_NullableAllOfWithExistingOneOf(t *testing.T) { "id": map[string]interface{}{ "type": "string", "const": []any{"val"}, - }}, + }, + }, }) _, hasNullable := result["nullable"]