From 2b7989cecd11ddf8bee6f104b0a295d995cfd306 Mon Sep 17 00:00:00 2001 From: Tristan Cartledge Date: Thu, 11 Sep 2025 01:04:36 +0000 Subject: [PATCH] fix: fixes handling of empty objects during marshaller sync that was impacting docs upgrading with nullable only schemas --- marshaller/syncer.go | 10 +++++++ .../expected_minimal_nullable_upgraded.json | 27 +++++++++++++++++++ .../testdata/upgrade/minimal_nullable.json | 20 ++++++++++++++ openapi/upgrade.go | 2 +- openapi/upgrade_test.go | 7 +++++ 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 openapi/testdata/upgrade/expected_minimal_nullable_upgraded.json create mode 100644 openapi/testdata/upgrade/minimal_nullable.json diff --git a/marshaller/syncer.go b/marshaller/syncer.go index 969bcce..adfda1c 100644 --- a/marshaller/syncer.go +++ b/marshaller/syncer.go @@ -249,6 +249,16 @@ func syncChanges(ctx context.Context, source any, target any, valueNode *yaml.No } } + // Ensure we have a valid YAML node even for empty structs + if valueNode == nil { + // Create an empty mapping node for empty structs + valueNode = &yaml.Node{ + Kind: yaml.MappingNode, + Tag: "!!map", + Style: yaml.FlowStyle, + } + } + // Populate the RootNode of the target with the result if coreModel, ok := t.Addr().Interface().(CoreModeler); ok { coreModel.SetRootNode(valueNode) diff --git a/openapi/testdata/upgrade/expected_minimal_nullable_upgraded.json b/openapi/testdata/upgrade/expected_minimal_nullable_upgraded.json new file mode 100644 index 0000000..036b083 --- /dev/null +++ b/openapi/testdata/upgrade/expected_minimal_nullable_upgraded.json @@ -0,0 +1,27 @@ +{ + "openapi": "3.1.1", + "info": { + "title": "Test API", + "version": "1.0.0" + }, + "paths": {}, + "components": { + "schemas": { + "TestSchema": { + "type": "object", + "properties": { + "parent": { + "oneOf": [ + {}, + { + "type": [ + "null" + ] + } + ] + } + } + } + } + } +} diff --git a/openapi/testdata/upgrade/minimal_nullable.json b/openapi/testdata/upgrade/minimal_nullable.json new file mode 100644 index 0000000..e2a11dd --- /dev/null +++ b/openapi/testdata/upgrade/minimal_nullable.json @@ -0,0 +1,20 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Test API", + "version": "1.0.0" + }, + "paths": {}, + "components": { + "schemas": { + "TestSchema": { + "type": "object", + "properties": { + "parent": { + "nullable": true + } + } + } + } + } +} diff --git a/openapi/upgrade.go b/openapi/upgrade.go index 99f9e99..7bdae7a 100644 --- a/openapi/upgrade.go +++ b/openapi/upgrade.go @@ -135,7 +135,7 @@ func upgradeNullableSchema(schema *oas3.Schema) { nullSchema := createNullSchema() clone := *schema newSchema := oas3.Schema{} - newSchema.OneOf = []*oas3.JSONSchema[oas3.Referenceable]{nullSchema, oas3.NewJSONSchemaFromSchema[oas3.Referenceable](&clone)} + newSchema.OneOf = []*oas3.JSONSchema[oas3.Referenceable]{oas3.NewJSONSchemaFromSchema[oas3.Referenceable](&clone), nullSchema} *schema = newSchema } } diff --git a/openapi/upgrade_test.go b/openapi/upgrade_test.go index 0bea443..5352690 100644 --- a/openapi/upgrade_test.go +++ b/openapi/upgrade_test.go @@ -51,6 +51,13 @@ func TestUpgrade_Success(t *testing.T) { options: []openapi.Option[openapi.UpgradeOptions]{openapi.WithUpgradeSamePatchVersion()}, description: "3.1.0 should upgrade with WithUpgradeSamePatchVersion option", }, + { + name: "upgrade_nullable_schema", + inputFile: "testdata/upgrade/minimal_nullable.json", + expectedFile: "testdata/upgrade/expected_minimal_nullable_upgraded.json", + options: nil, + description: "nullable schema should upgrade to oneOf without panic", + }, } for _, tt := range tests {