diff --git a/src/Confix.Tool/src/Confix.Tool/Entities/Project/DefaultValueVisitor.cs b/src/Confix.Tool/src/Confix.Tool/Entities/Project/DefaultValueVisitor.cs index 19784bb1..25b4566a 100644 --- a/src/Confix.Tool/src/Confix.Tool/Entities/Project/DefaultValueVisitor.cs +++ b/src/Confix.Tool/src/Confix.Tool/Entities/Project/DefaultValueVisitor.cs @@ -42,12 +42,16 @@ protected override JsonNode Rewrite(JsonObject obj, DefaultValueVisitorContext c continue; } + var possiblePropertySchemas = propertySchema + .GetPossibleSchemas(context.ReferenceResolver) + .ToArray(); + context.Schemas.Push(propertySchema); // when the field is null and we have a default value, set it if (!obj.ContainsKey(field)) { - if (propertySchema.GetDefault() is { } defaultValue) + if (possiblePropertySchemas.GetDefaultValue() is { } defaultValue) { obj[field] = defaultValue; } @@ -55,8 +59,7 @@ protected override JsonNode Rewrite(JsonObject obj, DefaultValueVisitorContext c { obj[field] = propertySchema.IsArray() ? new JsonArray() - : propertySchema - .GetPossibleSchemas(context.ReferenceResolver) + : possiblePropertySchemas .Where(x => x.GetProperties() is { Count: > 0 }) .SingleOrNone() is not null ? new JsonObject() @@ -67,8 +70,7 @@ protected override JsonNode Rewrite(JsonObject obj, DefaultValueVisitorContext c // when the field is null and we have a required field, initialize it if (obj.ContainsKey(field) && obj[field] is null) { - var hasSchemaOrDefaults = propertySchema - .GetPossibleSchemas(context.ReferenceResolver) + var hasSchemaOrDefaults = possiblePropertySchemas .Where(x => x.GetRequired() is { Count: > 0 }) .SingleOrNone() is not null; @@ -163,6 +165,12 @@ public static IEnumerable GetPossibleSchemas( } } + public static JsonNode? GetDefaultValue(this IEnumerable schemas) + => schemas + .Select(x => x.GetDefault()) + .OfType() + .SingleOrNone(); + public static JsonObject AddRequiredFields(this JsonObject value, JsonSchema schema) { var properties = schema.GetProperties() ?? ImmutableDictionary.Empty; diff --git a/src/Confix.Tool/test/Confix.Tool.Tests/ProjectComposerTests.cs b/src/Confix.Tool/test/Confix.Tool.Tests/DefaultValueVisitorTests.cs similarity index 93% rename from src/Confix.Tool/test/Confix.Tool.Tests/ProjectComposerTests.cs rename to src/Confix.Tool/test/Confix.Tool.Tests/DefaultValueVisitorTests.cs index 7788f80d..69d13461 100644 --- a/src/Confix.Tool/test/Confix.Tool.Tests/ProjectComposerTests.cs +++ b/src/Confix.Tool/test/Confix.Tool.Tests/DefaultValueVisitorTests.cs @@ -587,7 +587,7 @@ type Nested { var result = DefaultValueVisitor.ApplyDefaults(schema, value!); // assert - result.MatchInline(""" + result.MatchInline(""" { "nested": "should-still-exists" } @@ -868,6 +868,62 @@ type Deeper { Match(result); } + [Fact] + public void Should_InitializeComplexObjectArrays_When_InComponent() + { + // arrange + + var jsonSchema = Create( + new Definition("HealthChecks", + """ + type Configuration { + Endpoints: [Endpoint!]! @defaultValue(value: [ + { + Path: "/_health/live", + TagsPredicate: [ + "liveness" + ] + }, + { + Path: "/_health/ready", + TagsPredicate: [ + "readyness" + ] + } + ]) + } + + type Endpoint { + Path: String! + TagsPredicate: [String]! + } + """)); + // act + var result = DefaultValueVisitor.ApplyDefaults(jsonSchema, JsonNode.Parse("{}")!); + + // assert + result.MatchInline(""" + { + "HealthChecks": { + "Endpoints": [ + { + "Path": "/_health/live", + "TagsPredicate": [ + "liveness" + ] + }, + { + "Path": "/_health/ready", + "TagsPredicate": [ + "readyness" + ] + } + ] + } + } + """); + } + private static void Match(JsonNode result) { result.ToJsonString(new JsonSerializerOptions { WriteIndented = true }).MatchSnapshot();