From 3e1259e9d939ae92bfcf495ca615d5091bf04340 Mon Sep 17 00:00:00 2001 From: Alex Wichmann Date: Wed, 2 Aug 2023 00:41:53 +0200 Subject: [PATCH 1/2] add missing properties --- .../V2/AsyncApiSchemaDeserializer.cs | 33 +++++++- src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs | 3 + src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs | 34 +++++++- .../Models/JsonSchema/FalseApiSchema.cs | 10 +++ .../JsonSchema/NoAdditionalProperties.cs | 12 --- .../Models/AsyncApiSchema_Should.cs | 81 ++++++++++++++++++- 6 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs delete mode 100644 src/LEGO.AsyncAPI/Models/JsonSchema/NoAdditionalProperties.cs diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs index 582016eb..2131eb7e 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs @@ -130,7 +130,7 @@ public class JsonSchemaDeserializer { if (n is ValueNode && n.GetBooleanValueOrDefault(null) == false) { - a.AdditionalProperties = new NoAdditionalProperties(); + a.AdditionalProperties = new FalseApiSchema(); } else { @@ -139,7 +139,36 @@ public class JsonSchemaDeserializer } }, { - "items", (a, n) => { a.Items = LoadSchema(n); } + "items", (a, n) => + { + if (n is ValueNode && n.GetBooleanValueOrDefault(null) == false) + { + a.Items = new FalseApiSchema(); + } + else + { + a.Items = LoadSchema(n); + } + } + }, + { + "additionalItems", (a, n) => + { + if (n is ValueNode && n.GetBooleanValueOrDefault(null) == false) + { + a.AdditionalItems = new FalseApiSchema(); + } + else + { + a.AdditionalItems = LoadSchema(n); + } + } + }, + { + "patternProperties", (a, n) => { a.PatternProperties = n.CreateMap(LoadSchema); } + }, + { + "propertyNames", (a, n) => { a.PropertyNames = LoadSchema(n); } }, { "contains", (a, n) => { a.Contains = LoadSchema(n); } diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs b/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs index 2d3ae13c..37b1b45d 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs @@ -138,5 +138,8 @@ public static class AsyncApiConstants public const string MaxMessageBytes = "max.message.bytes"; public const string TopicConfiguration = "topicConfiguration"; public const string GeoReplication = "geo-replication"; + public const string AdditionalItems = "additionalItems"; + public const string PropertyNames = "propertyNames"; + public const string PatternProperties = "patternProperties"; } } diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs b/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs index 1de5542b..85fcc13c 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs @@ -159,6 +159,13 @@ public class AsyncApiSchema : IAsyncApiReferenceable, IAsyncApiExtensible, IAsyn /// public AsyncApiSchema Items { get; set; } + /// + /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html + /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object + /// and not a standard JSON Schema. items MUST be present if the type is array. + /// + public AsyncApiSchema AdditionalItems { get; set; } + /// /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. /// @@ -197,6 +204,8 @@ public class AsyncApiSchema : IAsyncApiReferenceable, IAsyncApiExtensible, IAsyn /// public AsyncApiSchema AdditionalProperties { get; set; } + public IDictionary PatternProperties { get; set; } = new Dictionary(); + /// /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. /// @@ -335,7 +344,24 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer) writer.WriteOptionalCollection(AsyncApiConstants.Required, this.Required, (w, s) => w.WriteValue(s)); // items - writer.WriteOptionalObject(AsyncApiConstants.Items, this.Items, (w, s) => s.SerializeV2(w)); + if (this.Items is FalseApiSchema) + { + writer.WriteOptionalProperty(AsyncApiConstants.Items, false); + } + else + { + writer.WriteOptionalObject(AsyncApiConstants.Items, this.Items, (w, s) => s.SerializeV2(w)); + } + + // additionalItems + if (this.AdditionalItems is FalseApiSchema) + { + writer.WriteOptionalProperty(AsyncApiConstants.AdditionalItems, false); + } + else + { + writer.WriteOptionalObject(AsyncApiConstants.AdditionalItems, this.AdditionalItems, (w, s) => s.SerializeV2(w)); + } // maxItems writer.WriteOptionalProperty(AsyncApiConstants.MaxItems, this.MaxItems); @@ -356,7 +382,7 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer) writer.WriteOptionalProperty(AsyncApiConstants.MinProperties, this.MinProperties); // additionalProperties - if (this.AdditionalProperties is NoAdditionalProperties) + if (this.AdditionalProperties is FalseApiSchema) { writer.WriteOptionalProperty(AsyncApiConstants.AdditionalProperties, false); } @@ -365,6 +391,10 @@ public void SerializeV2WithoutReference(IAsyncApiWriter writer) writer.WriteOptionalObject(AsyncApiConstants.AdditionalProperties, this.AdditionalProperties, (w, s) => s.SerializeV2(w)); } + writer.WriteOptionalMap(AsyncApiConstants.PatternProperties, this.PatternProperties, (w, s) => s.SerializeV2(w)); + + writer.WriteOptionalObject(AsyncApiConstants.PropertyNames, this.PropertyNames, (w, s) => s.SerializeV2(w)); + // discriminator writer.WriteOptionalProperty(AsyncApiConstants.Discriminator, this.Discriminator); diff --git a/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs b/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs new file mode 100644 index 00000000..40746fb3 --- /dev/null +++ b/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs @@ -0,0 +1,10 @@ +namespace LEGO.AsyncAPI.Models +{ + /// + /// An object representing 'false' for properties of AsyncApiSchema that can be false OR a schema. + /// + /// + public class FalseApiSchema : AsyncApiSchema + { + } +} diff --git a/src/LEGO.AsyncAPI/Models/JsonSchema/NoAdditionalProperties.cs b/src/LEGO.AsyncAPI/Models/JsonSchema/NoAdditionalProperties.cs deleted file mode 100644 index 700d3351..00000000 --- a/src/LEGO.AsyncAPI/Models/JsonSchema/NoAdditionalProperties.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) The LEGO Group. All rights reserved. - -namespace LEGO.AsyncAPI.Models -{ - /// - /// An object representing 'false' for the 'additionalProperties' property of AsyncApiSchema. - /// - /// - public class NoAdditionalProperties : AsyncApiSchema - { - } -} diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs index 4b99a465..eeb61dbb 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs @@ -71,7 +71,9 @@ public class AsyncApiSchema_Should MaxLength = 15, }, }, - AdditionalProperties = new NoAdditionalProperties(), + AdditionalProperties = new FalseApiSchema(), + Items = new FalseApiSchema(), + AdditionalItems = new FalseApiSchema(), }, ["property4"] = new AsyncApiSchema { @@ -93,6 +95,26 @@ public class AsyncApiSchema_Should MinLength = 2, }, }, + PatternProperties = new Dictionary() + { + { + "^S_", + new AsyncApiSchema() + { + Type = SchemaType.String, + } + }, + { + "^I_", new AsyncApiSchema() + { + Type = SchemaType.Integer, + } + }, + }, + PropertyNames = new AsyncApiSchema() + { + Pattern = "^[A-Za-z_][A-Za-z0-9_]*$", + }, AdditionalProperties = new AsyncApiSchema { Properties = new Dictionary @@ -103,8 +125,28 @@ public class AsyncApiSchema_Should }, }, }, + Items = new AsyncApiSchema + { + Properties = new Dictionary + { + ["Property9"] = new AsyncApiSchema + { + Type = SchemaType.String | SchemaType.Null, + }, + }, + }, + AdditionalItems = new AsyncApiSchema + { + Properties = new Dictionary + { + ["Property10"] = new AsyncApiSchema + { + Type = SchemaType.String | SchemaType.Null, + }, + }, + }, }, - ["property9"] = new AsyncApiSchema + ["property11"] = new AsyncApiSchema { Const = new AsyncApiString("aSpecialConstant"), }, @@ -387,6 +429,8 @@ public void SerializeAsJson_WithAdvancedSchemaObject_V2Works() ""title"": ""title1"", ""properties"": { ""property1"": { + ""items"": false, + ""additionalItems"": false, ""properties"": { ""property2"": { ""type"": ""integer"" @@ -399,6 +443,26 @@ public void SerializeAsJson_WithAdvancedSchemaObject_V2Works() ""additionalProperties"": false }, ""property4"": { + ""items"": { + ""properties"": { + ""Property9"": { + ""type"": [ + ""null"", + ""string"" + ] + } + } + }, + ""additionalItems"": { + ""properties"": { + ""Property10"": { + ""type"": [ + ""null"", + ""string"" + ] + } + } + }, ""properties"": { ""property5"": { ""properties"": { @@ -421,9 +485,20 @@ public void SerializeAsJson_WithAdvancedSchemaObject_V2Works() ] } } + }, + ""patternProperties"": { + ""^S_"": { + ""type"": ""string"" + }, + ""^I_"": { + ""type"": ""integer"" + } + }, + ""propertyNames"": { + ""pattern"": ""^[A-Za-z_][A-Za-z0-9_]*$"" } }, - ""property9"": { + ""property11"": { ""const"": ""aSpecialConstant"" } }, From 995f2fb201cb92cd725819938cb05f447c175626 Mon Sep 17 00:00:00 2001 From: Alex Wichmann Date: Wed, 2 Aug 2023 00:48:53 +0200 Subject: [PATCH 2/2] fix other test --- .../Models/AsyncApiSchema_Should.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs index eeb61dbb..31647d3e 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs @@ -518,13 +518,15 @@ public void SerializeAsJson_WithAdvancedSchemaObject_V2Works() } [Test] - public void Deserialize_WithAdditionalProperties_Works() + public void Deserialize_WithAdvancedSchema_Works() { // Arrange var json = @"{ ""title"": ""title1"", ""properties"": { ""property1"": { + ""items"": false, + ""additionalItems"": false, ""properties"": { ""property2"": { ""type"": ""integer"" @@ -537,6 +539,26 @@ public void Deserialize_WithAdditionalProperties_Works() ""additionalProperties"": false }, ""property4"": { + ""items"": { + ""properties"": { + ""Property9"": { + ""type"": [ + ""null"", + ""string"" + ] + } + } + }, + ""additionalItems"": { + ""properties"": { + ""Property10"": { + ""type"": [ + ""null"", + ""string"" + ] + } + } + }, ""properties"": { ""property5"": { ""properties"": { @@ -559,9 +581,20 @@ public void Deserialize_WithAdditionalProperties_Works() ] } } + }, + ""patternProperties"": { + ""^S_"": { + ""type"": ""string"" + }, + ""^I_"": { + ""type"": ""integer"" + } + }, + ""propertyNames"": { + ""pattern"": ""^[A-Za-z_][A-Za-z0-9_]*$"" } }, - ""property9"": { + ""property11"": { ""const"": ""aSpecialConstant"" } },