diff --git a/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs index 86dc74ef..3a2e6a35 100644 --- a/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/AMQP/AMQPOperationBinding.cs @@ -5,7 +5,6 @@ namespace LEGO.AsyncAPI.Bindings.AMQP using System; using System.Collections.Generic; using LEGO.AsyncAPI.Models; - using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; using LEGO.AsyncAPI.Writers; diff --git a/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs index 7a5731ef..912e7fe1 100644 --- a/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Http/HttpMessageBinding.cs @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.Http { using System; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; @@ -16,7 +17,7 @@ public class HttpMessageBinding : MessageBinding /// /// A Schema object containing the definitions for HTTP-specific headers. This schema MUST be of type object and have a properties key. /// - public AsyncApiSchema Headers { get; set; } + public JsonSchema Headers { get; set; } /// /// Serialize to AsyncAPI V2 document without using reference. diff --git a/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs index f70858c2..a0cb4b16 100644 --- a/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Http/HttpOperationBinding.cs @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.Http { using System; + using Json.Schema; using LEGO.AsyncAPI.Attributes; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; @@ -36,7 +37,7 @@ public enum HttpOperationType /// /// A Schema object containing the definitions for each query parameter. This schema MUST be of type object and have a properties key. /// - public AsyncApiSchema Query { get; set; } + public JsonSchema Query { get; set; } /// /// Serialize to AsyncAPI V2 document without using reference. diff --git a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs index 2f665560..1d866886 100644 --- a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaMessageBinding.cs @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.Kafka { using System; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; @@ -16,7 +17,7 @@ public class KafkaMessageBinding : MessageBinding /// /// The message key. NOTE: You can also use the reference object way. /// - public AsyncApiSchema Key { get; set; } + public JsonSchema Key { get; set; } /// /// If a Schema Registry is used when performing this operation, tells where the id of schema is stored (e.g. header or payload). diff --git a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs index 53db7ae0..adae9663 100644 --- a/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/Kafka/KafkaOperationBinding.cs @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.Kafka { using System; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; @@ -16,12 +17,12 @@ public class KafkaOperationBinding : OperationBinding /// /// Id of the consumer group. /// - public AsyncApiSchema GroupId { get; set; } + public JsonSchema GroupId { get; set; } /// /// Id of the consumer inside a consumer group. /// - public AsyncApiSchema ClientId { get; set; } + public JsonSchema ClientId { get; set; } public override string BindingKey => "kafka"; diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs index b48e5ae9..ebaa3eb4 100644 --- a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.MQTT { using System; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; @@ -22,7 +23,7 @@ public class MQTTMessageBinding : MessageBinding /// /// Correlation Data is used to identify the request the response message is for. /// - public AsyncApiSchema CorrelationData { get; set; } + public JsonSchema CorrelationData { get; set; } /// /// String describing the content type of the message payload. diff --git a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs index d3155ecd..f58eede9 100644 --- a/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/MQTT/MQTTOperationBinding.cs @@ -3,9 +3,6 @@ namespace LEGO.AsyncAPI.Bindings.MQTT { using System; - using System.Collections.Generic; - using LEGO.AsyncAPI.Models; - using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Readers.ParseNodes; using LEGO.AsyncAPI.Writers; diff --git a/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs b/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs index c87393bb..9abcfce4 100644 --- a/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs +++ b/src/LEGO.AsyncAPI.Bindings/WebSockets/WebSocketsChannelBinding.cs @@ -18,12 +18,12 @@ public class WebSocketsChannelBinding : ChannelBinding /// /// A Schema object containing the definitions for each query parameter. This schema MUST be of type 'object' and have a 'properties' key. /// - public AsyncApiSchema Query { get; set; } + public JsonSchema Query { get; set; } /// /// A Schema object containing the definitions of the HTTP headers to use when establishing the connection. This schma MUST be of type 'object' and have a 'properties' key. /// - public AsyncApiSchema Headers { get; set; } + public JsonSchema Headers { get; set; } public override string BindingKey => "websockets"; diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs index aca50c17..3cd5c1f3 100644 --- a/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs +++ b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs @@ -8,7 +8,6 @@ namespace LEGO.AsyncAPI.Readers using System.Threading; using System.Threading.Tasks; using LEGO.AsyncAPI.Exceptions; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Readers.Interface; diff --git a/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs b/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs index 5744985d..f6803930 100644 --- a/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/BindingDeserializer.cs @@ -2,7 +2,7 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; + using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj b/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj index c47530c0..54684a4d 100644 --- a/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj +++ b/src/LEGO.AsyncAPI.Readers/LEGO.AsyncAPI.Readers.csproj @@ -17,6 +17,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs index 76e9008a..ac6db9e6 100644 --- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs +++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyFieldMapParameter.cs @@ -10,7 +10,7 @@ internal class AnyFieldMapParameter public AnyFieldMapParameter( Func propertyGetter, Action propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -21,6 +21,6 @@ public AnyFieldMapParameter( public Action PropertySetter { get; } - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs index ee1af993..05da57d2 100644 --- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs +++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyListFieldMapParameter{T}.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models; internal class AnyListFieldMapParameter @@ -11,7 +12,7 @@ internal class AnyListFieldMapParameter public AnyListFieldMapParameter( Func> propertyGetter, Action> propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -22,6 +23,6 @@ public AnyListFieldMapParameter( public Action> PropertySetter { get; } - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs index 2399fe31..b9a423d0 100644 --- a/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs +++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/AnyMapFieldMapParameter{T,U}.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Readers.ParseNodes { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models; internal class AnyMapFieldMapParameter @@ -12,7 +13,7 @@ public AnyMapFieldMapParameter( Func> propertyMapGetter, Func propertyGetter, Action propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyMapGetter = propertyMapGetter; this.PropertyGetter = propertyGetter; @@ -26,6 +27,6 @@ public AnyMapFieldMapParameter( public Action PropertySetter { get; } - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Readers/ParseNodes/ValueNode.cs b/src/LEGO.AsyncAPI.Readers/ParseNodes/ValueNode.cs index e580afe6..d517fb32 100644 --- a/src/LEGO.AsyncAPI.Readers/ParseNodes/ValueNode.cs +++ b/src/LEGO.AsyncAPI.Readers/ParseNodes/ValueNode.cs @@ -10,6 +10,7 @@ public class ValueNode : ParseNode { private readonly JsonNode node; private string cachedScalarValue; + public ValueNode(ParsingContext context, JsonNode node) : base( context) diff --git a/src/LEGO.AsyncAPI.Readers/SchemaTypeConverter.cs b/src/LEGO.AsyncAPI.Readers/SchemaTypeConverter.cs new file mode 100644 index 00000000..8a9464b2 --- /dev/null +++ b/src/LEGO.AsyncAPI.Readers/SchemaTypeConverter.cs @@ -0,0 +1,25 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Readers +{ + using System; + using Json.Schema; + + public static class SchemaTypeConverter + { + public static SchemaValueType ConvertToSchemaValueType(string value) + { + return value.ToLowerInvariant() switch + { + "string" => SchemaValueType.String, + "number" or "double" => SchemaValueType.Number, + "integer" => SchemaValueType.Integer, + "boolean" => SchemaValueType.Boolean, + "array" => SchemaValueType.Array, + "object" => SchemaValueType.Object, + "null" => SchemaValueType.Null, + _ => throw new NotSupportedException(), + }; + } + } +} diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiChannelDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiChannelDeserializer.cs index cc74e0c0..d4b5fd7a 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiChannelDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiChannelDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiComponentsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiComponentsDeserializer.cs index 3b63db28..3590cd4c 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiComponentsDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiComponentsDeserializer.cs @@ -2,15 +2,16 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; + using System; internal static partial class AsyncApiV2Deserializer { private static FixedFieldMap componentsFixedFields = new() { - { "schemas", (a, n) => a.Schemas = n.CreateMapWithReference(ReferenceType.Schema, JsonSchemaDeserializer.LoadSchema) }, + { "schemas", (a, n) => a.Schemas = n.CreateMap(JsonSchemaDeserializer.LoadSchema) }, { "servers", (a, n) => a.Servers = n.CreateMapWithReference(ReferenceType.Server, LoadServer) }, { "channels", (a, n) => a.Channels = n.CreateMapWithReference(ReferenceType.Channel, LoadChannel) }, { "messages", (a, n) => a.Messages = n.CreateMapWithReference(ReferenceType.Message, LoadMessage) }, @@ -37,7 +38,11 @@ public static AsyncApiComponents LoadComponents(ParseNode node) var components = new AsyncApiComponents(); ParseMap(mapNode, components, componentsFixedFields, componentsPatternFields); - + foreach (var schema in components.Schemas) + { + var refUri = new Uri(AsyncApiConstants.V2ReferenceUri + schema.Key); + SchemaRegistry.Global.Register(refUri, schema.Value); + } return components; } } diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiContactDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiContactDeserializer.cs index 1a02ffaa..362a705b 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiContactDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiContactDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiCorrelationIdDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiCorrelationIdDeserializer.cs index 0b8e88f0..250bfacb 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiCorrelationIdDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiCorrelationIdDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiDocumentDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiDocumentDeserializer.cs index e7f0289e..53d64bcc 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiDocumentDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiDocumentDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExampleDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExampleDeserializer.cs index 46667a4b..0cb6fb4c 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExampleDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExampleDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExternalDocsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExternalDocsDeserializer.cs index 2c5e07b6..b295973c 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExternalDocsDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiExternalDocsDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiInfoDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiInfoDeserializer.cs index 60a359f5..361d1504 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiInfoDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiInfoDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiLicenseDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiLicenseDeserializer.cs index 630d2efc..d2e8164d 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiLicenseDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiLicenseDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs index 4c16bf22..90629826 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using LEGO.AsyncAPI.Exceptions; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; using System.Collections.Generic; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageTraitDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageTraitDeserializer.cs index eca8af64..dc732717 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageTraitDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiMessageTraitDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowDeserializer.cs index cddb8126..01c5cb50 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowsDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowsDeserializer.cs index dba5ab09..56f3481e 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowsDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOAuthFlowsDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationDeserializer.cs index 8a9a0505..3af5af61 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System.Collections.Generic; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationTraitDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationTraitDeserializer.cs index 561456e9..6992019d 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationTraitDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiOperationTraitDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiParameterDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiParameterDeserializer.cs index bff810f1..3ad03102 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiParameterDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiParameterDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs deleted file mode 100644 index 04c51f52..00000000 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSchemaDeserializer.cs +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) The LEGO Group. All rights reserved. - -namespace LEGO.AsyncAPI.Readers -{ - using System.Collections.Generic; - using System.Globalization; - using LEGO.AsyncAPI.Extensions; - using LEGO.AsyncAPI.Models; - using LEGO.AsyncAPI.Readers.ParseNodes; - using LEGO.AsyncAPI.Writers; - - public class JsonSchemaDeserializer - { - private static readonly FixedFieldMap schemaFixedFields = new() - { - { - "title", (a, n) => { a.Title = n.GetScalarValue(); } - }, - { - "type", (a, n) => - { - if (n.GetType() == typeof(ValueNode)) - { - a.Type = n.GetScalarValue().GetEnumFromDisplayName(); - } - - if (n.GetType() == typeof(ListNode)) - { - SchemaType? initialValue = null; - foreach (var node in n as ListNode) - { - if (initialValue == null) - { - initialValue = node.GetScalarValue().GetEnumFromDisplayName(); - continue; - } - - initialValue |= node.GetScalarValue().GetEnumFromDisplayName(); - } - - a.Type = initialValue; - } - } - }, - { - "required", - (a, n) => { a.Required = new HashSet(n.CreateSimpleList(n2 => n2.GetScalarValue())); } - }, - { - "multipleOf", - (a, n) => - { - a.MultipleOf = double.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture); - } - }, - { - "maximum", - (a, n) => - { - a.Maximum = double.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture); - } - }, - { - "exclusiveMaximum", (a, n) => { a.ExclusiveMaximum = bool.Parse(n.GetScalarValue()); } - }, - { - "minimum", - (a, n) => - { - a.Minimum = double.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture); - } - }, - { - "exclusiveMinimum", (a, n) => { a.ExclusiveMinimum = bool.Parse(n.GetScalarValue()); } - }, - { - "maxLength", (a, n) => { a.MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "minLength", (a, n) => { a.MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "pattern", (a, n) => { a.Pattern = n.GetScalarValue(); } - }, - { - "maxItems", (a, n) => { a.MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "minItems", (a, n) => { a.MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "uniqueItems", (a, n) => { a.UniqueItems = bool.Parse(n.GetScalarValue()); } - }, - { - "maxProperties", - (a, n) => { a.MaxProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "minProperties", - (a, n) => { a.MinProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture); } - }, - { - "enum", (a, n) => { a.Enum = n.CreateListOfAny(); } - }, - { - "const", (a, n) => { a.Const = n.CreateAny(); } - }, - { - "examples", (a, n) => { a.Examples = n.CreateListOfAny(); } - }, - { - "if", (a, n) => { a.If = LoadSchema(n); } - }, - { - "then", (a, n) => { a.Then = LoadSchema(n); } - }, - { - "else", (a, n) => { a.Else = LoadSchema(n); } - }, - { - "readOnly", (a, n) => { a.ReadOnly = bool.Parse(n.GetScalarValue()); } - }, - { - "writeOnly", (a, n) => { a.WriteOnly = bool.Parse(n.GetScalarValue()); } - }, - { - "properties", (a, n) => { a.Properties = n.CreateMap(LoadSchema); } - }, - { - "additionalProperties", (a, n) => - { - if (n is ValueNode && n.GetBooleanValueOrDefault(null) == false) - { - a.AdditionalProperties = new FalseApiSchema(); - } - else - { - a.AdditionalProperties = 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); } - }, - { - "allOf", (a, n) => { a.AllOf = n.CreateList(LoadSchema); } - }, - { - "oneOf", (a, n) => { a.OneOf = n.CreateList(LoadSchema); } - }, - { - "anyOf", (a, n) => { a.AnyOf = n.CreateList(LoadSchema); } - }, - { - "not", (a, n) => { a.Not = LoadSchema(n); } - }, - { - "description", (a, n) => { a.Description = n.GetScalarValue(); } - }, - { - "format", (a, n) => { a.Format = n.GetScalarValue(); } - }, - { - "default", (a, n) => { a.Default = n.CreateAny(); } - }, - { - "discriminator", (a, n) => { a.Discriminator = n.GetScalarValue(); } - }, - { - "externalDocs", (a, n) => { a.ExternalDocs = AsyncApiV2Deserializer.LoadExternalDocs(n); } - }, - { - "deprecated", (a, n) => { a.Deprecated = bool.Parse(n.GetScalarValue()); } - }, - { - "nullable", (a, n) => { a.Nullable = n.GetBooleanValue(); } - }, - }; - - private static readonly PatternFieldMap schemaPatternFields = - new() - { - { s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, AsyncApiV2Deserializer.LoadExtension(p, n)) }, - }; - - private static readonly AnyFieldMap schemaAnyFields = new() - { - { - AsyncApiConstants.Default, - new AnyFieldMapParameter( - s => s.Default, - (s, v) => s.Default = v, - s => s) - }, - }; - - private static readonly AnyListFieldMap schemaAnyListFields = new() - { - { - AsyncApiConstants.Enum, - new AnyListFieldMapParameter( - s => s.Enum, - (s, v) => s.Enum = v, - s => s) - }, - }; - - public static AsyncApiSchema LoadSchema(ParseNode node) - { - var mapNode = node.CheckMapNode(AsyncApiConstants.Schema); - - var pointer = mapNode.GetReferencePointer(); - - if (pointer != null) - { - return new AsyncApiSchema - { - UnresolvedReference = true, - Reference = node.Context.VersionService.ConvertToAsyncApiReference(pointer, ReferenceType.Schema), - }; - } - - var schema = new AsyncApiSchema(); - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(schema, schemaFixedFields, schemaPatternFields); - } - - AsyncApiV2Deserializer.ProcessAnyFields(mapNode, schema, schemaAnyFields); - AsyncApiV2Deserializer.ProcessAnyListFields(mapNode, schema, schemaAnyListFields); - - return schema; - } - } -} \ No newline at end of file diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSecuritySchemeDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSecuritySchemeDeserializer.cs index 92708116..82a1246e 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSecuritySchemeDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiSecuritySchemeDeserializer.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using System; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; using LEGO.AsyncAPI.Writers; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerDeserializer.cs index 6eae00af..0e41ec22 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerVariableDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerVariableDeserializer.cs index b773d255..7d0a1545 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerVariableDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiServerVariableDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiTagDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiTagDeserializer.cs index cc589fa2..f8eea039 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiTagDeserializer.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiTagDeserializer.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Readers { - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs index 10edd3ba..92c89d62 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Readers.V2 { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Exceptions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; @@ -35,7 +36,7 @@ public AsyncApiV2VersionService(AsyncApiDiagnostic diagnostic) [typeof(AsyncApiOAuthFlows)] = AsyncApiV2Deserializer.LoadOAuthFlows, [typeof(AsyncApiOperation)] = AsyncApiV2Deserializer.LoadOperation, [typeof(AsyncApiParameter)] = AsyncApiV2Deserializer.LoadParameter, - [typeof(AsyncApiSchema)] = JsonSchemaDeserializer.LoadSchema, + [typeof(JsonSchema)] = JsonSchemaDeserializer.LoadSchema, [typeof(AsyncApiSecurityRequirement)] = AsyncApiV2Deserializer.LoadSecurityRequirement, [typeof(AsyncApiSecurityScheme)] = AsyncApiV2Deserializer.LoadSecurityScheme, [typeof(AsyncApiServer)] = AsyncApiV2Deserializer.LoadServer, diff --git a/src/LEGO.AsyncAPI.Readers/V2/ExtensionHelpers.cs b/src/LEGO.AsyncAPI.Readers/V2/ExtensionHelpers.cs index 60689b31..3f7276a3 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/ExtensionHelpers.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/ExtensionHelpers.cs @@ -3,7 +3,6 @@ namespace LEGO.AsyncAPI.Readers { using LEGO.AsyncAPI.Exceptions; - using LEGO.AsyncAPI.Extensions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Readers.ParseNodes; diff --git a/src/LEGO.AsyncAPI.Readers/V2/JsonSchemaDeserializer.cs b/src/LEGO.AsyncAPI.Readers/V2/JsonSchemaDeserializer.cs new file mode 100644 index 00000000..e32cfb83 --- /dev/null +++ b/src/LEGO.AsyncAPI.Readers/V2/JsonSchemaDeserializer.cs @@ -0,0 +1,229 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Readers +{ + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using Json.Schema; + using LEGO.AsyncAPI.Models; + using LEGO.AsyncAPI.Models.Interfaces; + using LEGO.AsyncAPI.Readers.ParseNodes; + + public class JsonSchemaDeserializer + { + private static readonly FixedFieldMap schemaFixedFields = new() + { + { + "title", (a, n) => { a.Title(n.GetScalarValue()); } + }, + { + "type", (a, n) => + { + if(n is ListNode) + { + a.Type(n.CreateSimpleList(s => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); + } + else + { + a.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); + } + } + }, + { + "required", + (a, n) => { a.Required(new HashSet(n.CreateSimpleList(n2 => n2.GetScalarValue()))); } + }, + { + "multipleOf", + (a, n) => + { + a.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); + } + }, + { + "maximum", + (a, n) => + { + a.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); + } + }, + { + "exclusiveMaximum", (a, n) => { a.ExclusiveMaximum(decimal.Parse(n.GetScalarValue())); } + }, + { + "minimum", + (a, n) => + { + a.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); + } + }, + { + "exclusiveMinimum", (a, n) => { a.ExclusiveMinimum(decimal.Parse(n.GetScalarValue())); } + }, + { + "maxLength", (a, n) => { a.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "minLength", (a, n) => { a.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "pattern", (a, n) => { a.Pattern(n.GetScalarValue()); } + }, + { + "maxItems", (a, n) => { a.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "minItems", (a, n) => { a.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "uniqueItems", (a, n) => { a.UniqueItems(bool.Parse(n.GetScalarValue())); } + }, + { + "maxProperties", + (a, n) => { a.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "minProperties", + (a, n) => { a.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); } + }, + { + "enum", (a, n) => { a.Enum(n.CreateListOfAny().Select(a => a.GetNode())); } + }, + { + "const", (a, n) => { a.Const(n.CreateAny().GetNode()); } + }, + { + "examples", (a, n) => { a.Examples(n.CreateListOfAny().Select(a => a.GetNode())); } + }, + { + "if", (a, n) => { a.If(LoadSchema(n)); } + }, + { + "then", (a, n) => { a.Then(LoadSchema(n)); } + }, + { + "else", (a, n) => { a.Else(LoadSchema(n)); } + }, + { + "readOnly", (a, n) => { a.ReadOnly(bool.Parse(n.GetScalarValue())); } + }, + { + "writeOnly", (a, n) => { a.WriteOnly(bool.Parse(n.GetScalarValue())); } + }, + { + "properties", (a, n) => { a.Properties(n.CreateMap(LoadSchema)); } + }, + { + "additionalProperties", (a, n) => + { + if (n is ValueNode) + { + a.AdditionalProperties(bool.Parse(n.GetScalarValue())); + } + else + { + a.AdditionalProperties(LoadSchema(n)); + } + } + }, + { + "items", (a, n) => + { + a.Items(LoadSchema(n)); + } + }, + { + "additionalItems", (a, n) => + { + if (n is ValueNode) + { + a.AdditionalProperties(bool.Parse(n.GetScalarValue())); + } + else + { + a.AdditionalProperties(LoadSchema(n)); + } + } + }, + { + "patternProperties", (a, n) => { a.PatternProperties(n.CreateMap(LoadSchema)); } + }, + { + "propertyNames", (a, n) => { a.PropertyNames(LoadSchema(n)); } + }, + { + "contains", (a, n) => { a.Contains(LoadSchema(n)); } + }, + { + "allOf", (a, n) => { a.AllOf(n.CreateList(LoadSchema)); } + }, + { + "oneOf", (a, n) => { a.OneOf(n.CreateList(LoadSchema)); } + }, + { + "anyOf", (a, n) => { a.AnyOf(n.CreateList(LoadSchema)); } + }, + { + "not", (a, n) => { a.Not(LoadSchema(n)); } + }, + { + "description", (a, n) => { a.Description(n.GetScalarValue()); } + }, + { + "format", (a, n) => { a.Format(n.GetScalarValue()); } + }, + { + "default", (a, n) => { a.Default(n.CreateAny().GetNode()); } + }, + { + "discriminator", (a, n) => { a.Discriminator(n.GetScalarValue()); } + }, + { + "externalDocs", (a, n) => { a.ExternalDocs(AsyncApiV2Deserializer.LoadExternalDocs(n)); } + }, + { + "deprecated", (a, n) => { a.Deprecated(bool.Parse(n.GetScalarValue())); } + }, + { + "nullable", (a, n) => { a.Nullable(n.GetBooleanValue()); } + }, + }; + + private static Dictionary LoadExtensions(string value, IAsyncApiExtension extension) + { + var extensions = new Dictionary + { + { value, extension }, + }; + return extensions; + } + + private static readonly PatternFieldMap schemaPatternFields = + new() + { + { s => s.StartsWith("x-"), (o, p, n) => o.Extensions(LoadExtensions(p, AsyncApiV2Deserializer.LoadExtension(p, n))) }, + }; + + public static JsonSchema LoadSchema(ParseNode node) + { + var mapNode = node.CheckMapNode(AsyncApiConstants.Schema); + var schemaBuilder = new JsonSchemaBuilder(); + + // check for a $ref and if present, add it to the builder as a Ref keyword + var pointer = mapNode.GetReferencePointer(); + if (pointer != null) + { + return schemaBuilder.Ref(pointer); + } + + foreach (var propertyNode in mapNode) + { + propertyNode.ParseField(schemaBuilder, schemaFixedFields, schemaPatternFields); + } + + var schema = schemaBuilder.Build(); + return schema; + } + } +} \ No newline at end of file diff --git a/src/LEGO.AsyncAPI/Extensions/AsyncApiElementExtensions.cs b/src/LEGO.AsyncAPI/Extensions/AsyncApiElementExtensions.cs index 1215b86b..10b7b78b 100644 --- a/src/LEGO.AsyncAPI/Extensions/AsyncApiElementExtensions.cs +++ b/src/LEGO.AsyncAPI/Extensions/AsyncApiElementExtensions.cs @@ -1,10 +1,9 @@ // Copyright (c) The LEGO Group. All rights reserved. -namespace LEGO.AsyncAPI.Extensions +namespace LEGO.AsyncAPI.Models { using System.Collections.Generic; using System.Linq; - using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Services; using LEGO.AsyncAPI.Validations; diff --git a/src/LEGO.AsyncAPI/Extensions/AsyncApiExtensibleExtensions.cs b/src/LEGO.AsyncAPI/Extensions/AsyncApiExtensibleExtensions.cs index 8fdb50e5..5ae9ffa4 100644 --- a/src/LEGO.AsyncAPI/Extensions/AsyncApiExtensibleExtensions.cs +++ b/src/LEGO.AsyncAPI/Extensions/AsyncApiExtensibleExtensions.cs @@ -1,10 +1,9 @@ // Copyright (c) The LEGO Group. All rights reserved. -namespace LEGO.AsyncAPI.Extensions +namespace LEGO.AsyncAPI.Models { using System.Collections.Generic; using LEGO.AsyncAPI.Exceptions; - using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; /// diff --git a/src/LEGO.AsyncAPI/Extensions/JsonSchemaBuilderExtensions.cs b/src/LEGO.AsyncAPI/Extensions/JsonSchemaBuilderExtensions.cs new file mode 100644 index 00000000..29a22bdd --- /dev/null +++ b/src/LEGO.AsyncAPI/Extensions/JsonSchemaBuilderExtensions.cs @@ -0,0 +1,203 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Models +{ + using System; + using System.Collections.Generic; + using Json.Schema; + using LEGO.AsyncAPI.Models.Interfaces; + + public static class JsonSchemaBuilderExtensions + { + /// + /// Custom extensions in the schema + /// + /// + /// + /// + public static JsonSchemaBuilder Extensions(this JsonSchemaBuilder builder, IDictionary extensions) + { + builder.Add(new ExtensionsKeyword(extensions)); + return builder; + } + + /// + /// Allows sending a null value for the defined schema. Default value is false. + /// + /// + /// + /// + public static JsonSchemaBuilder Nullable(this JsonSchemaBuilder builder, bool value) + { + builder.Add(new NullableKeyword(value)); + return builder; + } + + /// + /// Additional external documentation for this schema. + /// + /// + /// + /// + public static JsonSchemaBuilder ExternalDocs(this JsonSchemaBuilder builder, AsyncApiExternalDocumentation value) + { + builder.Add(new ExternalDocsKeyword(value)); + return builder; + } + + /// + /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate + /// between other schemas which may satisfy the payload description. + /// + /// + /// + /// + public static JsonSchemaBuilder Discriminator(this JsonSchemaBuilder builder, string discriminator) + { + builder.Add(new DiscriminatorKeyword(discriminator)); + return builder; + } + } + + /// + /// The nullable keyword + /// + [SchemaKeyword(Name)] + public class NullableKeyword : IJsonSchemaKeyword + { + public const string Name = "nullable"; + + public bool Value { get; } + + public NullableKeyword(bool value) + { + Value = value; + } + + public void Evaluate(EvaluationContext context) + { + throw new NotImplementedException(); + } + + public KeywordConstraint GetConstraint(SchemaConstraint schemaConstraint, IReadOnlyList localConstraints, EvaluationContext context) + { + throw new NotImplementedException(); + } + } + + /// + /// The extensions keyword + /// + [SchemaKeyword(Name)] + public class ExternalDocsKeyword : IJsonSchemaKeyword + { + /// + /// The schema keyword name + /// + public const string Name = "externalDocs"; + + internal AsyncApiExternalDocumentation ExternalDocs { get; } + + internal ExternalDocsKeyword(AsyncApiExternalDocumentation externalDocs) + { + ExternalDocs = externalDocs; + } + + public void Evaluate(EvaluationContext context) + { + throw new NotImplementedException(); + } + + public KeywordConstraint GetConstraint(SchemaConstraint schemaConstraint, IReadOnlyList localConstraints, EvaluationContext context) + { + throw new NotImplementedException(); + } + } + + /// + /// The extensions keyword. + /// + [SchemaKeyword(Name)] + public class ExtensionsKeyword : IJsonSchemaKeyword + { + /// + /// The schema keyword name + /// + public const string Name = "extensions"; + + internal IDictionary Extensions { get; } + + internal ExtensionsKeyword(IDictionary extensions) + { + Extensions = extensions; + } + + public void Evaluate(EvaluationContext context) + { + throw new NotImplementedException(); + } + + public KeywordConstraint GetConstraint(SchemaConstraint schemaConstraint, IReadOnlyList localConstraints, EvaluationContext context) + { + throw new NotImplementedException(); + } + } + + /// + /// The AdditionalPropertiesAllowed Keyword. + /// + [SchemaKeyword(Name)] + public class AdditionalPropertiesAllowedKeyword : IJsonSchemaKeyword + { + /// + /// The schema keyword name + /// + public const string Name = "additionalPropertiesAllowed"; + + internal bool AdditionalPropertiesAllowed { get; } + + internal AdditionalPropertiesAllowedKeyword(bool additionalPropertiesAllowed) + { + AdditionalPropertiesAllowed = additionalPropertiesAllowed; + } + + public void Evaluate(EvaluationContext context) + { + throw new NotImplementedException(); + } + + public KeywordConstraint GetConstraint(SchemaConstraint schemaConstraint, IReadOnlyList localConstraints, EvaluationContext context) + { + throw new NotImplementedException(); + } + } + + /// + /// The Discriminator Keyword + /// + [SchemaKeyword(Name)] + public class DiscriminatorKeyword : IJsonSchemaKeyword + { + /// + /// The schema keyword name + /// + public const string Name = "discriminator"; + + internal string Descriminator { get; } + + public DiscriminatorKeyword(string descriminator) + { + this.Descriminator = descriminator; + } + + public void Evaluate(EvaluationContext context) + { + throw new NotImplementedException(); + } + + public KeywordConstraint GetConstraint(SchemaConstraint schemaConstraint, IReadOnlyList localConstraints, EvaluationContext context) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/LEGO.AsyncAPI/Extensions/JsonSchemaExtensions.cs b/src/LEGO.AsyncAPI/Extensions/JsonSchemaExtensions.cs new file mode 100644 index 00000000..7a06ff6a --- /dev/null +++ b/src/LEGO.AsyncAPI/Extensions/JsonSchemaExtensions.cs @@ -0,0 +1,250 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Models +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Json.Schema; + using LEGO.AsyncAPI.Models.Interfaces; + using LEGO.AsyncAPI.Models; + using LEGO.AsyncAPI.Writers; + using System.Text.RegularExpressions; + + public static class JsonSchemaExtensions + { + public static void SerializeV2WithoutReference(this JsonSchema schema, IAsyncApiWriter writer) + { + writer.WriteStartObject(); + + // title + writer.WriteOptionalProperty(AsyncApiConstants.Title, schema.GetTitle()); + + // type + if (schema.GetJsonType() != null) + { + var types = EnumExtensions.GetFlags(schema.GetJsonType()); + if (types.Count() == 1) + { + writer.WriteOptionalProperty(AsyncApiConstants.Type, types.First().GetDisplayName()); + } + else + { + writer.WriteOptionalCollection(AsyncApiConstants.Type, types.Select(t => t.GetDisplayName()), (w, s) => w.WriteValue(s)); + } + } + + // format + writer.WriteOptionalProperty(AsyncApiConstants.Format, schema.GetFormat()?.Key); + + // description + writer.WriteOptionalProperty(AsyncApiConstants.Description, schema.GetDescription()); + + // maximum + writer.WriteOptionalProperty(AsyncApiConstants.Maximum, schema.GetMaximum()); + + // exclusiveMaximum + writer.WriteOptionalProperty(AsyncApiConstants.ExclusiveMaximum, schema.GetExclusiveMaximum()); + + // minimum + writer.WriteOptionalProperty(AsyncApiConstants.Minimum, schema.GetMinimum()); + + // exclusiveMinimum + writer.WriteOptionalProperty(AsyncApiConstants.ExclusiveMinimum, schema.GetExclusiveMinimum()); + + // maxLength + writer.WriteOptionalProperty(AsyncApiConstants.MaxLength, schema.GetMaxLength()); + + // minLength + writer.WriteOptionalProperty(AsyncApiConstants.MinLength, schema.GetMinLength()); + + // pattern + writer.WriteOptionalProperty(AsyncApiConstants.Pattern, schema.GetPattern().ToString()); + + // multipleOf + writer.WriteOptionalProperty(AsyncApiConstants.MultipleOf, schema.GetMultipleOf()); + + // default + writer.WriteOptionalObject(AsyncApiConstants.Default, schema.GetDefault(), (w, d) => w.WriteAny(d)); + + // readOnly + writer.WriteOptionalProperty(AsyncApiConstants.ReadOnly, schema.GetReadOnly(), false); + + // writeOnly + writer.WriteOptionalProperty(AsyncApiConstants.WriteOnly, schema.GetWriteOnly(), false); + + // allOf + writer.WriteOptionalCollection(AsyncApiConstants.AllOf, schema.GetAllOf(), (w, s) => s.SerializeV2(w)); + + // oneOf + writer.WriteOptionalCollection(AsyncApiConstants.OneOf, schema.GetOneOf(), (w, s) => s.SerializeV2(w)); + + // anyOf + writer.WriteOptionalCollection(AsyncApiConstants.AnyOf, schema.GetAnyOf(), (w, s) => s.SerializeV2(w)); + + // not + writer.WriteOptionalObject(AsyncApiConstants.Not, schema.GetNot(), (w, s) => s.SerializeV2(w)); + + // contains + writer.WriteOptionalObject(AsyncApiConstants.Contains, schema.GetContains(), (w, s) => s.SerializeV2(w)); + + // anyOf + writer.WriteOptionalObject(AsyncApiConstants.If, schema.GetIf(), (w, s) => s.SerializeV2(w)); + + // then + writer.WriteOptionalObject(AsyncApiConstants.Then, schema.GetThen(), (w, s) => s.SerializeV2(w)); + + // else + writer.WriteOptionalObject(AsyncApiConstants.Else, schema.GetElse(), (w, s) => s.SerializeV2(w)); + + // required + writer.WriteOptionalCollection(AsyncApiConstants.Required, schema.GetRequired(), (w, s) => w.WriteValue(s)); + + // items + writer.WriteOptionalObject(AsyncApiConstants.Items, schema.GetItems(), (w, s) => s.SerializeV2(w)); + + // additionalItems + writer.WriteOptionalObject(AsyncApiConstants.AdditionalItems, schema.GetAdditionalItems(), (w, s) => s.SerializeV2(w)); + + // maxItems + writer.WriteOptionalProperty(AsyncApiConstants.MaxItems, schema.GetMaxItems()); + + // minItems + writer.WriteOptionalProperty(AsyncApiConstants.MinItems, schema.GetMinItems()); + + // uniqueItems + writer.WriteOptionalProperty(AsyncApiConstants.UniqueItems, schema.GetUniqueItems()); + + // properties + writer.WriteOptionalMap(AsyncApiConstants.Properties, (IDictionary)schema.GetProperties(), (w, key, s) => s.SerializeV2(w)); + + // maxProperties + writer.WriteOptionalProperty(AsyncApiConstants.MaxProperties, schema.GetMaxProperties()); + + // minProperties + writer.WriteOptionalProperty(AsyncApiConstants.MinProperties, schema.GetMinProperties()); + + // additionalProperties + writer.WriteOptionalObject(AsyncApiConstants.AdditionalProperties, schema.GetAdditionalProperties(), (w, s) => s.SerializeV2(w)); + + writer.WriteOptionalMap(AsyncApiConstants.PatternProperties, schema.GetPatternProperties().ToDictionary(d => d.Key.ToString(), d => d.Value), (w, key, s) => s.SerializeV2(w)); + + writer.WriteOptionalObject(AsyncApiConstants.PropertyNames, schema.GetPropertyNames(), (w, s) => s.SerializeV2(w)); + + // discriminator + writer.WriteOptionalProperty(AsyncApiConstants.Discriminator, schema.GetDiscriminator()); + + // enum + writer.WriteOptionalCollection(AsyncApiConstants.Enum, schema.GetEnum(), (w, s) => w.WriteAny(s)); + + // example + writer.WriteOptionalCollection(AsyncApiConstants.Examples, schema.GetExamples(), (w, e) => w.WriteAny(e)); + + writer.WriteOptionalObject(AsyncApiConstants.Const, schema.GetConst(), (w, s) => w.WriteAny(s)); + + // nullable + writer.WriteOptionalProperty(AsyncApiConstants.Nullable, schema.GetNullable(), false); + + // externalDocs + writer.WriteOptionalObject(AsyncApiConstants.ExternalDocs, schema.GetExternalDocs(), (w, s) => s.SerializeV2(w)); + + // deprecated + writer.WriteOptionalProperty(AsyncApiConstants.Deprecated, schema.GetDeprecated(), false); + + // extensions + writer.WriteExtensions(schema.GetExtensions()); + + writer.WriteEndObject(); + } + + public static void WriteJsonSchemaReference(this IAsyncApiWriter writer, Uri reference) + { + writer.WriteStartObject(); + writer.WriteRequiredProperty(AsyncApiConstants.DollarRef, reference.OriginalString); + writer.WriteEndObject(); + } + + public static void SerializeV2(this JsonSchema schema, IAsyncApiWriter writer) + { + if (schema == null) + { + return; + } + + var reference = schema.GetRef(); + var settings = writer.GetSettings(); + if (reference != null) + { + if (!settings.InlineReferences) + { + writer.WriteJsonSchemaReference(reference); + return; + } + else + { + if (!settings.LoopDetector.PushLoop(schema)) + { + settings.LoopDetector.SaveLoop(schema); + writer.WriteJsonSchemaReference(reference); + return; + } + } + } + + schema.SerializeV2WithoutReference(writer); + + if (reference != null) + { + settings.LoopDetector.PopLoop(); + } + } + + /// + /// Gets the `discriminator` keyword if it exists. + /// + public static string GetDiscriminator(this JsonSchema schema) + { + return schema.TryGetKeyword(DiscriminatorKeyword.Name, out var k) ? k.Descriminator! : null; + } + + /// + /// Gets the `ExternalDocs` keyword if it exists. + /// + /// The schema. + /// + public static AsyncApiExternalDocumentation GetExternalDocs(this JsonSchema schema) + { + return schema.TryGetKeyword(ExternalDocsKeyword.Name, out var k) ? k.ExternalDocs! : null; + } + + /// + /// Gets the nullable value if it exists + /// + /// + /// + public static bool? GetNullable(this JsonSchema schema) + { + return schema.TryGetKeyword(NullableKeyword.Name, out var k) ? k.Value! : null; + } + + /// + /// Gets the additional properties value if it exists + /// + /// + /// + public static bool? GetAdditionalPropertiesAllowed(this JsonSchema schema) + { + return schema.TryGetKeyword(AdditionalPropertiesAllowedKeyword.Name, out var k) ? k.AdditionalPropertiesAllowed! : null; + } + + /// + /// Gets the custom extensions if it exists + /// + /// + /// + public static IDictionary GetExtensions(this JsonSchema schema) + { + return schema.TryGetKeyword(ExtensionsKeyword.Name, out var k) ? k.Extensions! : null; + } + } +} diff --git a/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj b/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj index c26d0242..c5514084 100644 --- a/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj +++ b/src/LEGO.AsyncAPI/LEGO.AsyncAPI.csproj @@ -15,6 +15,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -51,5 +52,9 @@ Resource.Designer.cs + + + + diff --git a/src/LEGO.AsyncAPI/Models/Any/AsyncApiAny.cs b/src/LEGO.AsyncAPI/Models/Any/AsyncApiAny.cs index 5c5f2b31..45b764b3 100644 --- a/src/LEGO.AsyncAPI/Models/Any/AsyncApiAny.cs +++ b/src/LEGO.AsyncAPI/Models/Any/AsyncApiAny.cs @@ -2,7 +2,6 @@ namespace LEGO.AsyncAPI.Models { - using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Nodes; using LEGO.AsyncAPI.Models.Interfaces; diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiComponents.cs b/src/LEGO.AsyncAPI/Models/AsyncApiComponents.cs index 6c8a2a4c..b11394cb 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiComponents.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiComponents.cs @@ -5,6 +5,7 @@ namespace LEGO.AsyncAPI.Models using System; using System.Collections.Generic; using System.Linq; + using Json.Schema; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Writers; @@ -19,7 +20,7 @@ public class AsyncApiComponents : IAsyncApiExtensible, IAsyncApiSerializable /// /// An object to hold reusable Schema Objects. /// - public IDictionary Schemas { get; set; } = new Dictionary(); + public IDictionary Schemas { get; set; } = new Dictionary(); /// /// An object to hold reusable Server Objects. @@ -101,11 +102,8 @@ public void SerializeV2(IAsyncApiWriter writer) { var loops = writer.GetSettings().LoopDetector.Loops; writer.WriteStartObject(); - if (loops.TryGetValue(typeof(AsyncApiSchema), out List schemas)) + if (loops.TryGetValue(typeof(JsonSchema), out List schemas)) { - var asyncApiSchemas = schemas.Cast().Distinct().ToList() - .ToDictionary(k => k.Reference.Id); - writer.WriteOptionalMap( AsyncApiConstants.Schemas, this.Schemas, @@ -130,9 +128,9 @@ public void SerializeV2(IAsyncApiWriter writer) this.Schemas, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Schema && - component.Reference.Id == key) + var reference = component.GetRef(); + if (reference != null && + reference.OriginalString.Split('/').Last().Equals(key)) { component.SerializeV2WithoutReference(w); } diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs b/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs index 5806e8f9..9f1e973a 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiConstants.cs @@ -145,5 +145,6 @@ public static class AsyncApiConstants public const string AdditionalItems = "additionalItems"; public const string PropertyNames = "propertyNames"; public const string PatternProperties = "patternProperties"; + public const string V2ReferenceUri = "https://registry/components/schemas/"; } } diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs index 5be55202..09d5d39d 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs @@ -172,8 +172,6 @@ internal IAsyncApiReferenceable ResolveReference(AsyncApiReference reference) { switch (reference.Type) { - case ReferenceType.Schema: - return this.Components.Schemas[reference.Id]; case ReferenceType.Server: return this.Components.Servers[reference.Id]; case ReferenceType.Channel: diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiMessage.cs b/src/LEGO.AsyncAPI/Models/AsyncApiMessage.cs index 2c627541..f69635e9 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiMessage.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiMessage.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Models { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Writers; @@ -20,12 +21,12 @@ public class AsyncApiMessage : IAsyncApiExtensible, IAsyncApiReferenceable, IAsy /// /// schema definition of the application headers. Schema MUST be of type "object". /// - public AsyncApiSchema Headers { get; set; } + public JsonSchema Headers { get; set; } /// /// definition of the message payload. It can be of any type but defaults to Schema object. It must match the schema format, including encoding type - e.g Avro should be inlined as either a YAML or JSON object NOT a string to be parsed as YAML or JSON. /// - public AsyncApiSchema Payload { get; set; } + public JsonSchema Payload { get; set; } /// /// definition of the correlation ID used for message tracing or matching. diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiMessageTrait.cs b/src/LEGO.AsyncAPI/Models/AsyncApiMessageTrait.cs index 856fb7cd..c95de4dd 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiMessageTrait.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiMessageTrait.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Models { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Writers; @@ -20,7 +21,7 @@ public class AsyncApiMessageTrait : IAsyncApiExtensible, IAsyncApiReferenceable, /// /// schema definition of the application headers. Schema MUST be of type "object". /// - public AsyncApiSchema Headers { get; set; } + public JsonSchema Headers { get; set; } /// /// definition of the correlation ID used for message tracing or matching. diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiParameter.cs b/src/LEGO.AsyncAPI/Models/AsyncApiParameter.cs index fd925c7b..3cbf56d2 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiParameter.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiParameter.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Models { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Writers; @@ -20,7 +21,7 @@ public class AsyncApiParameter : IAsyncApiReferenceable, IAsyncApiExtensible, IA /// /// Gets or sets definition of the parameter. /// - public AsyncApiSchema Schema { get; set; } + public JsonSchema Schema { get; set; } /// /// Gets or sets a runtime expression that specifies the location of the parameter value. diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs b/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs deleted file mode 100644 index 3244017b..00000000 --- a/src/LEGO.AsyncAPI/Models/AsyncApiSchema.cs +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright (c) The LEGO Group. All rights reserved. - -namespace LEGO.AsyncAPI.Models -{ - using System; - using System.Collections.Generic; - using System.Linq; - using LEGO.AsyncAPI.Models.Interfaces; - using LEGO.AsyncAPI.Writers; - - /// - /// The Schema Object allows the definition of input and output data types. - /// - public class AsyncApiSchema : IAsyncApiReferenceable, IAsyncApiExtensible, IAsyncApiSerializable - { - /// - /// follow JSON Schema definition. Short text providing information about the data. - /// - public string Title { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public SchemaType? Type { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public string Format { get; set; } - - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// CommonMark syntax MAY be used for rich text representation. - /// - public string Description { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public double? Maximum { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public bool? ExclusiveMaximum { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public double? Minimum { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public bool? ExclusiveMinimum { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public int? MaxLength { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public int? MinLength { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect. - /// - public string Pattern { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public double? MultipleOf { get; set; } - - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// The default value represents what would be assumed by the consumer of the input as the value of the schema if one is not provided. - /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. - /// For example, if type is string, then default can be "foo" but cannot be 1. - /// - public AsyncApiAny Default { get; set; } - - /// - /// a value indicating whether relevant only for Schema "properties" definitions. Declares the property as "read only". - /// This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request. - /// If the property is marked as readOnly being true and is in the required list, - /// the required will take effect on the response only. - /// A property MUST NOT be marked as both readOnly and writeOnly being true. - /// Default value is false. - /// - public bool ReadOnly { get; set; } - - /// - /// a value indicating whether relevant only for Schema "properties" definitions. Declares the property as "write only". - /// Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response. - /// If the property is marked as writeOnly being true and is in the required list, - /// the required will take effect on the request only. - /// A property MUST NOT be marked as both readOnly and writeOnly being true. - /// Default value is false. - /// - public bool WriteOnly { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public IList AllOf { get; set; } = new List(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public IList OneOf { get; set; } = new List(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public IList AnyOf { get; set; } = new List(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. - /// - public AsyncApiSchema Not { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public AsyncApiSchema Contains { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public AsyncApiSchema If { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public AsyncApiSchema Then { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public AsyncApiSchema Else { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public ISet Required { get; set; } = new HashSet(); - - /// - /// 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 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. - /// - public int? MaxItems { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public int? MinItems { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public bool? UniqueItems { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced). - /// - public IDictionary Properties { get; set; } = new Dictionary(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public int? MaxProperties { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public int? MinProperties { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html - /// Value can be boolean or object. Inline or referenced schema - /// MUST be of a Schema Object and not a standard JSON Schema. - /// - 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. - /// - public AsyncApiSchema PropertyNames { get; set; } - - /// - /// adds support for polymorphism. - /// The discriminator is the schema property name that is used to differentiate between other schema that inherit this schema. - /// - public string Discriminator { get; set; } - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public IList Enum { get; set; } = new List(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public IList Examples { get; set; } = new List(); - - /// - /// follow JSON Schema definition: https://json-schema.org/draft-07/json-schema-release-notes.html. - /// - public AsyncApiAny Const { get; set; } - - /// - /// a value indicating whether allows sending a null value for the defined schema. Default value is false. - /// - public bool Nullable { get; set; } - - /// - /// additional external documentation for this schema. - /// - public AsyncApiExternalDocumentation ExternalDocs { get; set; } - - /// - /// a value indicating whether specifies that a schema is deprecated and SHOULD be transitioned out of usage. - /// Default value is false. - /// - public bool Deprecated { get; set; } - - /// - public bool UnresolvedReference { get; set; } - - /// - public AsyncApiReference Reference { get; set; } - - public IDictionary Extensions { get; set; } = new Dictionary(); - - public void SerializeV2WithoutReference(IAsyncApiWriter writer) - { - writer.WriteStartObject(); - - // title - writer.WriteOptionalProperty(AsyncApiConstants.Title, this.Title); - - // type - if (this.Type != null) - { - var types = EnumExtensions.GetFlags(this.Type.Value); - if (types.Count() == 1) - { - writer.WriteOptionalProperty(AsyncApiConstants.Type, types.First().GetDisplayName()); - } - else - { - writer.WriteOptionalCollection(AsyncApiConstants.Type, types.Select(t => t.GetDisplayName()), (w, s) => w.WriteValue(s)); - } - } - - // format - writer.WriteOptionalProperty(AsyncApiConstants.Format, this.Format); - - // description - writer.WriteOptionalProperty(AsyncApiConstants.Description, this.Description); - - // maximum - writer.WriteOptionalProperty(AsyncApiConstants.Maximum, this.Maximum); - - // exclusiveMaximum - writer.WriteOptionalProperty(AsyncApiConstants.ExclusiveMaximum, this.ExclusiveMaximum); - - // minimum - writer.WriteOptionalProperty(AsyncApiConstants.Minimum, this.Minimum); - - // exclusiveMinimum - writer.WriteOptionalProperty(AsyncApiConstants.ExclusiveMinimum, this.ExclusiveMinimum); - - // maxLength - writer.WriteOptionalProperty(AsyncApiConstants.MaxLength, this.MaxLength); - - // minLength - writer.WriteOptionalProperty(AsyncApiConstants.MinLength, this.MinLength); - - // pattern - writer.WriteOptionalProperty(AsyncApiConstants.Pattern, this.Pattern); - - // multipleOf - writer.WriteOptionalProperty(AsyncApiConstants.MultipleOf, this.MultipleOf); - - // default - writer.WriteOptionalObject(AsyncApiConstants.Default, this.Default, (w, d) => w.WriteAny(d)); - - // readOnly - writer.WriteOptionalProperty(AsyncApiConstants.ReadOnly, this.ReadOnly, false); - - // writeOnly - writer.WriteOptionalProperty(AsyncApiConstants.WriteOnly, this.WriteOnly, false); - - // allOf - writer.WriteOptionalCollection(AsyncApiConstants.AllOf, this.AllOf, (w, s) => s.SerializeV2(w)); - - // oneOf - writer.WriteOptionalCollection(AsyncApiConstants.OneOf, this.OneOf, (w, s) => s.SerializeV2(w)); - - // anyOf - writer.WriteOptionalCollection(AsyncApiConstants.AnyOf, this.AnyOf, (w, s) => s.SerializeV2(w)); - - // not - writer.WriteOptionalObject(AsyncApiConstants.Not, this.Not, (w, s) => s.SerializeV2(w)); - - // contains - writer.WriteOptionalObject(AsyncApiConstants.Contains, this.Contains, (w, s) => s.SerializeV2(w)); - - // anyOf - writer.WriteOptionalObject(AsyncApiConstants.If, this.If, (w, s) => s.SerializeV2(w)); - - // then - writer.WriteOptionalObject(AsyncApiConstants.Then, this.Then, (w, s) => s.SerializeV2(w)); - - // else - writer.WriteOptionalObject(AsyncApiConstants.Else, this.Else, (w, s) => s.SerializeV2(w)); - - // required - writer.WriteOptionalCollection(AsyncApiConstants.Required, this.Required, (w, s) => w.WriteValue(s)); - - // items - 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); - - // minItems - writer.WriteOptionalProperty(AsyncApiConstants.MinItems, this.MinItems); - - // uniqueItems - writer.WriteOptionalProperty(AsyncApiConstants.UniqueItems, this.UniqueItems); - - // properties - writer.WriteOptionalMap(AsyncApiConstants.Properties, this.Properties, (w, s) => s.SerializeV2(w)); - - // maxProperties - writer.WriteOptionalProperty(AsyncApiConstants.MaxProperties, this.MaxProperties); - - // minProperties - writer.WriteOptionalProperty(AsyncApiConstants.MinProperties, this.MinProperties); - - // additionalProperties - if (this.AdditionalProperties is FalseApiSchema) - { - writer.WriteOptionalProperty(AsyncApiConstants.AdditionalProperties, false); - } - else - { - 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); - - // enum - writer.WriteOptionalCollection(AsyncApiConstants.Enum, this.Enum, (nodeWriter, s) => nodeWriter.WriteAny(s)); - - // example - writer.WriteOptionalCollection(AsyncApiConstants.Examples, this.Examples, (w, e) => w.WriteAny(e)); - - writer.WriteOptionalObject(AsyncApiConstants.Const, this.Const, (w, s) => w.WriteAny(s)); - - // nullable - writer.WriteOptionalProperty(AsyncApiConstants.Nullable, this.Nullable, false); - - // externalDocs - writer.WriteOptionalObject(AsyncApiConstants.ExternalDocs, this.ExternalDocs, (w, s) => s.SerializeV2(w)); - - // deprecated - writer.WriteOptionalProperty(AsyncApiConstants.Deprecated, this.Deprecated, false); - - // extensions - writer.WriteExtensions(this.Extensions); - - writer.WriteEndObject(); - } - - public void SerializeV2(IAsyncApiWriter writer) - { - if (writer is null) - { - throw new ArgumentNullException(nameof(writer)); - } - - var target = this; - - var settings = writer.GetSettings(); - - if (this.Reference != null) - { - if (!settings.ShouldInlineReference(this.Reference)) - { - this.Reference.SerializeV2(writer); - return; - } - - // If Loop is detected then just Serialize as a reference. - if (!settings.LoopDetector.PushLoop(this)) - { - settings.LoopDetector.SaveLoop(this); - this.Reference.SerializeV2(writer); - return; - } - - target = this.GetReferenced(this.Reference.HostDocument); - } - - target.SerializeV2WithoutReference(writer); - - if (this.Reference != null) - { - settings.LoopDetector.PopLoop(); - } - } - - public AsyncApiSchema GetReferenced(AsyncApiDocument document) - { - if (this.Reference != null && document != null) - { - return document.ResolveReference(this.Reference); - } - else - { - return this; - } - } - } -} \ No newline at end of file diff --git a/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs b/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs deleted file mode 100644 index 01f313e5..00000000 --- a/src/LEGO.AsyncAPI/Models/JsonSchema/FalseApiSchema.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) The LEGO Group. All rights reserved. - -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/ReferenceType.cs b/src/LEGO.AsyncAPI/Models/ReferenceType.cs index 8903dd73..6270a7e8 100644 --- a/src/LEGO.AsyncAPI/Models/ReferenceType.cs +++ b/src/LEGO.AsyncAPI/Models/ReferenceType.cs @@ -8,11 +8,6 @@ public enum ReferenceType { None, - /// - /// Schema item. - /// - [Display("schemas")] Schema, - /// /// Servers item. /// diff --git a/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs b/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs index da6195c6..4b6d8382 100644 --- a/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs +++ b/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs @@ -5,6 +5,7 @@ namespace LEGO.AsyncAPI.Services using System; using System.Collections.Generic; using System.Linq; + using Json.Schema; using LEGO.AsyncAPI.Exceptions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; @@ -70,7 +71,7 @@ public override void Visit(AsyncApiChannel channel) public override void Visit(AsyncApiMessageTrait trait) { this.ResolveObject(trait.CorrelationId, r => trait.CorrelationId = r); - this.ResolveObject(trait.Headers, r => trait.Headers = r); + this.ResolveJsonSchema(trait.Headers, r => trait.Headers = r); } /// @@ -85,8 +86,8 @@ public override void Visit(AsyncApiOperation operation) public override void Visit(AsyncApiMessage message) { - this.ResolveObject(message.Headers, r => message.Headers = r); - this.ResolveObject(message.Payload, r => message.Payload = r); + this.ResolveJsonSchema(message.Headers, r => message.Headers = r); + this.ResolveJsonSchema(message.Payload, r => message.Payload = r); this.ResolveList(message.Traits); this.ResolveObject(message.CorrelationId, r => message.CorrelationId = r); this.ResolveObject(message.Bindings, r => message.Bindings = r); @@ -131,27 +132,64 @@ public override void Visit(IList parameters) /// public override void Visit(AsyncApiParameter parameter) { - this.ResolveObject(parameter.Schema, r => parameter.Schema = r); + this.ResolveJsonSchema(parameter.Schema, r => parameter.Schema = r); } /// /// Resolve all references used in a schema. /// - public override void Visit(AsyncApiSchema schema) - { - this.ResolveObject(schema.Items, r => schema.Items = r); - this.ResolveList(schema.OneOf); - this.ResolveList(schema.AllOf); - this.ResolveList(schema.AnyOf); - this.ResolveObject(schema.Contains, r => schema.Contains = r); - this.ResolveObject(schema.Else, r => schema.Else = r); - this.ResolveObject(schema.If, r => schema.If = r); - this.ResolveObject(schema.Items, r => schema.Items = r); - this.ResolveObject(schema.Not, r => schema.Not = r); - this.ResolveObject(schema.Then, r => schema.Then = r); - this.ResolveObject(schema.PropertyNames, r => schema.PropertyNames = r); - this.ResolveObject(schema.AdditionalProperties, r => schema.AdditionalProperties = r); - this.ResolveMap(schema.Properties); + public override void Visit(ref JsonSchema schema) + { + var reference = schema.GetRef(); + + if (reference != null) + { + schema = this.ResolveJsonSchemaReference(reference); + } + + var builder = new JsonSchemaBuilder(); + foreach (var keyword in schema.Keywords) + { + builder.Add(keyword); + } + + schema = builder.Build(); + } + + private void ResolveJsonSchema(JsonSchema schema, Action assign) + { + if (schema == null) + { + return; + } + + var reference = schema.GetRef(); + if (reference != null) + { + assign(this.ResolveJsonSchemaReference(reference)); + } + } + + public JsonSchema ResolveJsonSchemaReference(Uri reference) + { + var refUri = $"https://registry{reference.OriginalString.Split('#').LastOrDefault()}"; + var resolvedSchema = (JsonSchema)SchemaRegistry.Global.Get(new Uri(refUri)); + + if (resolvedSchema != null) + { + var resolvedSchemaBuilder = new JsonSchemaBuilder(); + + foreach (var keyword in resolvedSchema.Keywords) + { + resolvedSchemaBuilder.Add(keyword); + } + + return resolvedSchemaBuilder.Build(); + } + else + { + return null; + } } private void ResolveObject(T entity, Action assign) @@ -204,6 +242,15 @@ private void ResolveMap(IDictionary map) } } + private void ResolveMap(IDictionary map) + { + foreach (var schema in map) + { + var schemaValue = schema.Value; + this.Visit(ref schemaValue); + } + } + private T ResolveReference(AsyncApiReference reference) where T : class, IAsyncApiReferenceable, new() { diff --git a/src/LEGO.AsyncAPI/Services/AsyncApiVisitorBase.cs b/src/LEGO.AsyncAPI/Services/AsyncApiVisitorBase.cs index 8e3dc241..3a52ad6c 100644 --- a/src/LEGO.AsyncAPI/Services/AsyncApiVisitorBase.cs +++ b/src/LEGO.AsyncAPI/Services/AsyncApiVisitorBase.cs @@ -5,6 +5,7 @@ namespace LEGO.AsyncAPI.Services using System; using System.Collections.Generic; using System.Linq; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; @@ -145,9 +146,9 @@ public virtual void Visit(AsyncApiExternalDocumentation externalDocs) } /// - /// Visits . + /// Visits . /// - public virtual void Visit(AsyncApiSchema schema) + public virtual void Visit(ref JsonSchema schema) { } diff --git a/src/LEGO.AsyncAPI/Services/AsyncApiWalker.cs b/src/LEGO.AsyncAPI/Services/AsyncApiWalker.cs index fc5c5186..c45dfb69 100644 --- a/src/LEGO.AsyncAPI/Services/AsyncApiWalker.cs +++ b/src/LEGO.AsyncAPI/Services/AsyncApiWalker.cs @@ -4,13 +4,14 @@ namespace LEGO.AsyncAPI.Services { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; public class AsyncApiWalker { private readonly AsyncApiVisitorBase visitor; - private readonly Stack schemaLoop = new(); + private readonly Stack schemaLoop = new(); public AsyncApiWalker(AsyncApiVisitorBase visitor) { @@ -293,7 +294,7 @@ internal void Walk(AsyncApiParameter parameter, bool isComponent = false) this.Walk(parameter as IAsyncApiExtensible); } - internal void Walk(AsyncApiSchema schema, bool isComponent = false) + internal void Walk(JsonSchema schema, bool isComponent = false) { if (schema == null || this.ProcessAsReference(schema, isComponent)) { @@ -309,121 +310,121 @@ internal void Walk(AsyncApiSchema schema, bool isComponent = false) this.schemaLoop.Push(schema); } - this.visitor.Visit(schema); + this.visitor.Visit(ref schema); - if (schema.Items != null) + if (schema.GetItems() != null) { - this.Walk("items", () => this.Walk(schema.Items)); + this.Walk("items", () => this.Walk(schema.GetItems())); } - if (schema.Default != null) + if (schema.GetDefault() != null) { - this.Walk(AsyncApiConstants.Default, () => this.Walk(schema.Default)); + this.Walk(AsyncApiConstants.Default, () => this.Walk(new AsyncApiAny(schema.GetDefault()))); } - if (schema.AllOf != null) + if (schema.GetAllOf() != null) { - foreach (var item in schema.AllOf) + foreach (var item in schema.GetAllOf()) { this.Walk("allOf", () => this.Walk(item)); } } - if (schema.AnyOf != null) + if (schema.GetAnyOf() != null) { - foreach (var item in schema.AnyOf) + foreach (var item in schema.GetAnyOf()) { this.Walk("anyOf", () => this.Walk(item)); } } - if (schema.Not != null) + if (schema.GetNot() != null) { - this.Walk("not", () => this.Walk(schema.Not)); + this.Walk("not", () => this.Walk(schema.GetNot())); } - if (schema.Contains != null) + if (schema.GetContains() != null) { - this.Walk("contains", () => this.Walk(schema.Contains)); + this.Walk("contains", () => this.Walk(schema.GetContains())); } - if (schema.If != null) + if (schema.GetIf() != null) { - this.Walk("if", () => this.Walk(schema.If)); + this.Walk("if", () => this.Walk(schema.GetIf())); } - if (schema.Then != null) + if (schema.GetThen() != null) { - this.Walk("then", () => this.Walk(schema.Then)); + this.Walk("then", () => this.Walk(schema.GetThen())); } - if (schema.Else != null) + if (schema.GetElse() != null) { - this.Walk("else", () => this.Walk(schema.Else)); + this.Walk("else", () => this.Walk(schema.GetElse())); } - if (schema.OneOf != null) + if (schema.GetOneOf() != null) { - foreach (var item in schema.OneOf) + foreach (var item in schema.GetOneOf()) { this.Walk("oneOf", () => this.Walk(item)); } } - if (schema.Properties != null) + if (schema.GetProperties() != null) { this.Walk("properties", () => { - foreach (var item in schema.Properties) + foreach (var item in schema.GetProperties()) { this.Walk(item.Key, () => this.Walk(item.Value)); } }); } - if (schema.AdditionalProperties != null) + if (schema.GetAdditionalProperties() != null) { - this.Walk("additionalProperties", () => this.Walk(schema.AdditionalProperties)); + this.Walk("additionalProperties", () => this.Walk(schema.GetAdditionalProperties())); } - if (schema.PatternProperties != null) + if (schema.GetPatternProperties() != null) { this.Walk("patternProperties", () => { - foreach (var item in schema.PatternProperties) + foreach (var item in schema.GetPatternProperties()) { - this.Walk(item.Key, () => this.Walk(item.Value)); + this.Walk(item.Key.ToString(), () => this.Walk(item.Value)); } }); } - if (schema.PropertyNames != null) + if (schema.GetPropertyNames() != null) { - this.Walk("propertyNames", () => this.Walk(schema.PropertyNames)); + this.Walk("propertyNames", () => this.Walk(schema.GetPropertyNames())); } - if (schema.Enum != null) + if (schema.GetEnum() != null) { - foreach (var item in schema.Enum) + foreach (var item in schema.GetEnum()) { - this.Walk("enum", () => this.Walk(item)); + this.Walk("enum", () => this.Walk(new AsyncApiAny(item))); } } - if (schema.Examples != null) + if (schema.GetExamples() != null) { - foreach (var item in schema.Examples) + foreach (var item in schema.GetExamples()) { - this.Walk("examples", () => this.Walk(item)); + this.Walk("examples", () => this.Walk(new AsyncApiAny(item))); } } - if (schema.Const != null) + if (schema.GetConst() != null) { - this.Walk("const", () => this.Walk(schema.Const)); + this.Walk("const", () => this.Walk(new AsyncApiAny(schema.GetConst()))); } - this.Walk(AsyncApiConstants.ExternalDocs, () => this.Walk(schema.ExternalDocs)); + this.Walk(AsyncApiConstants.ExternalDocs, () => this.Walk(schema.GetExternalDocs())); this.Walk(schema as IAsyncApiExtensible); @@ -903,6 +904,17 @@ private bool ProcessAsReference(IAsyncApiReferenceable referenceable, bool isCom return isReference; } + private bool ProcessAsReference(JsonSchema jsonSchema, bool isComponent = false) + { + var isReference = jsonSchema.GetRef() != null && !isComponent; + if (isReference) + { + this.Walk(jsonSchema); + } + + return isReference; + } + internal void Walk(IAsyncApiReferenceable referenceable) { this.visitor.Visit(referenceable); @@ -933,7 +945,7 @@ public void Walk(IAsyncApiElement element) case AsyncApiOAuthFlow e: this.Walk(e); break; case AsyncApiOperation e: this.Walk(e); break; case AsyncApiParameter e: this.Walk(e); break; - case AsyncApiSchema e: this.Walk(e); break; + case JsonSchema e: this.Walk(e); break; case AsyncApiSecurityRequirement e: this.Walk(e); break; case AsyncApiSecurityScheme e: this.Walk(e); break; case AsyncApiServer e: this.Walk(e); break; diff --git a/src/LEGO.AsyncAPI/Validation/AsyncApiValidator.cs b/src/LEGO.AsyncAPI/Validation/AsyncApiValidator.cs index 4ce96627..0161c169 100644 --- a/src/LEGO.AsyncAPI/Validation/AsyncApiValidator.cs +++ b/src/LEGO.AsyncAPI/Validation/AsyncApiValidator.cs @@ -4,6 +4,7 @@ namespace LEGO.AsyncAPI.Validations { using System; using System.Collections.Generic; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using LEGO.AsyncAPI.Services; @@ -125,10 +126,10 @@ public void AddWarning(AsyncApiValidatorWarning warning) public override void Visit(AsyncApiParameter item) => this.Validate(item); /// - /// Execute validation rules against an . + /// Execute validation rules against an . /// /// The object to be validated. - public override void Visit(AsyncApiSchema item) => this.Validate(item); + public override void Visit(ref JsonSchema item) => this.Validate(item); /// /// Execute validation rules against an . diff --git a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterAnyExtensions.cs b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterAnyExtensions.cs index 9a317cd1..e276b519 100644 --- a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterAnyExtensions.cs +++ b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterAnyExtensions.cs @@ -41,6 +41,11 @@ public static void WriteExtensions(this IAsyncApiWriter writer, IDictionary /// Write the value. /// diff --git a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs index 67c4737a..d510b104 100644 --- a/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs +++ b/src/LEGO.AsyncAPI/Writers/AsyncApiWriterExtensions.cs @@ -6,6 +6,7 @@ namespace LEGO.AsyncAPI.Writers using System.Collections; using System.Collections.Generic; using System.Linq; + using Json.Schema; using LEGO.AsyncAPI.Models.Interfaces; public static class AsyncApiWriterExtensions @@ -156,6 +157,30 @@ public static void WriteOptionalObject( } } + public static void WriteOptionalObject( + this IAsyncApiWriter writer, + string name, + JsonSchema value, + Action action) + { + if (value != null) + { + if (value is IAsyncApiReferenceable refer && refer.Reference != null) + { + writer.WriteRequiredObject(name, value, action); + return; + } + + var values = value as IEnumerable; + if (values != null && !values.GetEnumerator().MoveNext()) + { + return; // Don't render optional empty collections + } + + writer.WriteRequiredObject(name, value, action); + } + } + /// /// Write the required AsyncApi object/element. /// @@ -185,6 +210,26 @@ public static void WriteRequiredObject( } } + public static void WriteRequiredObject( + this IAsyncApiWriter writer, + string name, + JsonSchema value, + Action action) + { + CheckArguments(writer, name, action); + + writer.WritePropertyName(name); + if (value != null) + { + action(writer, value); + } + else + { + writer.WriteStartObject(); + writer.WriteEndObject(); + } + } + /// /// Write the optional of collection string. /// @@ -204,6 +249,18 @@ public static void WriteOptionalCollection( } } + public static void WriteOptionalCollection( + this IAsyncApiWriter writer, + string name, + IEnumerable elements, + Action action) + { + if (elements != null && elements.Any()) + { + writer.WriteCollectionInternal(name, elements, action); + } + } + /// /// Write the optional AsyncApi object/element collection. /// @@ -262,6 +319,18 @@ public static void WriteOptionalMap( } } + public static void WriteOptionalMap( + this IAsyncApiWriter writer, + string name, + IDictionary elements, + Action action) + { + if (elements != null && elements.Any()) + { + writer.WriteMapInternal(name, elements, action); + } + } + /// /// Write the required AsyncApi element map (string to string mapping). /// diff --git a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs index 3f2ee429..14cc642a 100644 --- a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs +++ b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentBuilder.cs @@ -2,6 +2,7 @@ namespace LEGO.AsyncAPI.Tests { + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; using System; @@ -46,7 +47,7 @@ public AsyncApiDocumentBuilder WithChannel(string key, AsyncApiChannel channel) return this; } - public AsyncApiDocumentBuilder WithComponent(string key, AsyncApiSchema schema) + public AsyncApiDocumentBuilder WithComponent(string key, JsonSchema schema) { if (this.document.Components == null) { diff --git a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs index d73125fb..1b7dbb8f 100644 --- a/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs +++ b/test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs @@ -490,7 +490,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }, - Payload = new AsyncApiSchema() + Payload = new JsonSchema() { Reference = new AsyncApiReference() { @@ -515,7 +515,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }, - Payload = new AsyncApiSchema() + Payload = new JsonSchema() { Reference = new AsyncApiReference() { @@ -540,7 +540,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }, - Payload = new AsyncApiSchema() + Payload = new JsonSchema() { Reference = new AsyncApiReference() { @@ -549,13 +549,13 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }) - .WithComponent("lightMeasuredPayload", new AsyncApiSchema() + .WithComponent("lightMeasuredPayload", new JsonSchema() { Type = SchemaType.Object, - Properties = new Dictionary() + Properties = new Dictionary() { { - "lumens", new AsyncApiSchema() + "lumens", new JsonSchema() { Type = SchemaType.Integer, Minimum = 0, @@ -563,7 +563,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() } }, { - "sentAt", new AsyncApiSchema() + "sentAt", new JsonSchema() { Reference = new AsyncApiReference() { @@ -574,13 +574,13 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }) - .WithComponent("turnOnOffPayload", new AsyncApiSchema() + .WithComponent("turnOnOffPayload", new JsonSchema() { Type = SchemaType.Object, - Properties = new Dictionary() + Properties = new Dictionary() { { - "command", new AsyncApiSchema() + "command", new JsonSchema() { Type = SchemaType.String, Enum = new List @@ -592,7 +592,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() } }, { - "sentAt", new AsyncApiSchema() + "sentAt", new JsonSchema() { Reference = new AsyncApiReference() { @@ -603,13 +603,13 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }) - .WithComponent("dimLightPayload", new AsyncApiSchema() + .WithComponent("dimLightPayload", new JsonSchema() { Type = SchemaType.Object, - Properties = new Dictionary() + Properties = new Dictionary() { { - "percentage", new AsyncApiSchema() + "percentage", new JsonSchema() { Type = SchemaType.Integer, Description = "Percentage to which the light should be dimmed to.", @@ -618,7 +618,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() } }, { - "sentAt", new AsyncApiSchema() + "sentAt", new JsonSchema() { Reference = new AsyncApiReference() { @@ -629,7 +629,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() }, }, }) - .WithComponent("sentAt", new AsyncApiSchema() + .WithComponent("sentAt", new JsonSchema() { Type = SchemaType.String, Format = "date-time", @@ -648,20 +648,20 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() .WithComponent("streetlightId", new AsyncApiParameter() { Description = "The ID of the streetlight.", - Schema = new AsyncApiSchema() + Schema = new JsonSchema() { Type = SchemaType.String, }, }) .WithComponent("commonHeaders", new AsyncApiMessageTrait() { - Headers = new AsyncApiSchema() + Headers = new JsonSchema() { Type = SchemaType.Object, - Properties = new Dictionary() + Properties = new Dictionary() { { - "my-app-header", new AsyncApiSchema() + "my-app-header", new JsonSchema() { Type = SchemaType.Integer, Minimum = 0, @@ -678,7 +678,7 @@ public void AsyncApiDocument_WithStreetLightsExample_SerializesAndDeserializes() { "kafka", new KafkaOperationBinding() { - ClientId = new AsyncApiSchema() + ClientId = new JsonSchema() { Type = SchemaType.String, Enum = new List @@ -1014,7 +1014,7 @@ public void SerializeV2_WithFullSpec_Serializes() { Name = traitName, Title = traitTitle, - Headers = new AsyncApiSchema + Headers = new JsonSchema { Title = schemaTitle, WriteOnly = true, @@ -1283,7 +1283,7 @@ public void Serializev2_WithBindings_Serializes() { new HttpMessageBinding { - Headers = new AsyncApiSchema + Headers = new JsonSchema { Description = "this mah binding", }, @@ -1292,7 +1292,7 @@ public void Serializev2_WithBindings_Serializes() { new KafkaMessageBinding { - Key = new AsyncApiSchema + Key = new JsonSchema { Description = "this mah other binding", }, diff --git a/test/LEGO.AsyncAPI.Tests/AsyncApiReaderTests.cs b/test/LEGO.AsyncAPI.Tests/AsyncApiReaderTests.cs index 40a2ddbb..4b8019c5 100644 --- a/test/LEGO.AsyncAPI.Tests/AsyncApiReaderTests.cs +++ b/test/LEGO.AsyncAPI.Tests/AsyncApiReaderTests.cs @@ -5,7 +5,6 @@ namespace LEGO.AsyncAPI.Tests using System; using System.Collections.Generic; using System.Linq; - using System.Text.Json.Nodes; using LEGO.AsyncAPI.Exceptions; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Models.Interfaces; diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/Http/HttpBindings_Should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/Http/HttpBindings_Should.cs index b207dcd8..812e5697 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/Http/HttpBindings_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/Http/HttpBindings_Should.cs @@ -25,7 +25,7 @@ public void HttpMessageBinding_FilledObject_SerializesAndDeserializes() message.Bindings.Add(new HttpMessageBinding { - Headers = new AsyncApiSchema + Headers = new JsonSchema { Description = "this mah binding", }, @@ -62,7 +62,7 @@ public void HttpOperationBinding_FilledObject_SerializesAndDeserializes() { Type = HttpOperationBinding.HttpOperationType.Request, Method = "POST", - Query = new AsyncApiSchema + Query = new JsonSchema { Description = "this mah query", }, diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/Kafka/KafkaBindings_Should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/Kafka/KafkaBindings_Should.cs index 842f3c1d..1d87c06a 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/Kafka/KafkaBindings_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/Kafka/KafkaBindings_Should.cs @@ -124,7 +124,7 @@ public void KafkaMessageBinding_WithFilledObject_SerializesAndDeserializes() message.Bindings.Add(new KafkaMessageBinding { - Key = new AsyncApiSchema + Key = new JsonSchema { Description = "this mah other binding", }, @@ -162,11 +162,11 @@ public void KafkaOperationBinding_WithFilledObject_SerializesAndDeserializes() operation.Bindings.Add(new KafkaOperationBinding { - GroupId = new AsyncApiSchema + GroupId = new JsonSchema { Description = "this mah groupId", }, - ClientId = new AsyncApiSchema + ClientId = new JsonSchema { Description = "this mah clientId", }, diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/StringOrStringList_Should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/StringOrStringList_Should.cs index 21b64f5e..4f3ed131 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/StringOrStringList_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/StringOrStringList_Should.cs @@ -4,7 +4,6 @@ namespace LEGO.AsyncAPI.Tests.Bindings { using System; using System.Collections.Generic; - using System.Linq; using FluentAssertions; using LEGO.AsyncAPI.Bindings; using LEGO.AsyncAPI.Models; diff --git a/test/LEGO.AsyncAPI.Tests/Bindings/WebSockets/WebSocketBindings_Should.cs b/test/LEGO.AsyncAPI.Tests/Bindings/WebSockets/WebSocketBindings_Should.cs index 0e9c5344..65b806ff 100644 --- a/test/LEGO.AsyncAPI.Tests/Bindings/WebSockets/WebSocketBindings_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Bindings/WebSockets/WebSocketBindings_Should.cs @@ -28,11 +28,11 @@ public void WebSocketChannelBinding_WithFilledObject_SerializesAndDeserializes() channel.Bindings.Add(new WebSocketsChannelBinding { Method = "POST", - Query = new AsyncApiSchema + Query = new JsonSchema { Description = "this mah query", }, - Headers = new AsyncApiSchema + Headers = new JsonSchema { Description = "this mah binding", }, diff --git a/test/LEGO.AsyncAPI.Tests/MQTT/MQTTBindings_Should.cs b/test/LEGO.AsyncAPI.Tests/MQTT/MQTTBindings_Should.cs index 3ee233d3..cf325fc8 100644 --- a/test/LEGO.AsyncAPI.Tests/MQTT/MQTTBindings_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/MQTT/MQTTBindings_Should.cs @@ -115,7 +115,7 @@ public void MQTTMessageBinding_WithFilledObject_SerializesAndDeserializes() message.Bindings.Add(new MQTTMessageBinding { ContentType = "application/json", - CorrelationData = new AsyncApiSchema + CorrelationData = new JsonSchema { Type = SchemaType.String, Format = "uuid", diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiAnyTests.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiAnyTests.cs index 6c93e483..8fde22f0 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiAnyTests.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiAnyTests.cs @@ -2,7 +2,6 @@ using LEGO.AsyncAPI.Models; using NUnit.Framework; -using System; using System.Collections.Generic; using System.Linq; diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiChannel_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiChannel_Should.cs index 18e6b4fd..45454873 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiChannel_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiChannel_Should.cs @@ -35,24 +35,24 @@ public void AsyncApiChannel_WithWebSocketsBinding_Serializes() new WebSocketsChannelBinding() { Method = "POST", - Query = new AsyncApiSchema() + Query = new JsonSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { { - "index", new AsyncApiSchema() + "index", new JsonSchema() { Description = "the index", } }, }, }, - Headers = new AsyncApiSchema() + Headers = new JsonSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { { - "x-correlation-id", new AsyncApiSchema() + "x-correlation-id", new JsonSchema() { Description = "the correlationid", } diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs index 67156b1d..f4560c84 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiMessage_Should.cs @@ -96,12 +96,12 @@ public void AsyncApiMessage_WithNoSchemaFormat_DoesNotSerializeSchemaFormat() - string"; var message = new AsyncApiMessage(); - message.Payload = new AsyncApiSchema() + message.Payload = new JsonSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { { - "propertyA", new AsyncApiSchema() + "propertyA", new JsonSchema() { Type = SchemaType.String | SchemaType.Null, } @@ -137,12 +137,12 @@ public void AsyncApiMessage_WithSchemaFormat_Serializes() var message = new AsyncApiMessage(); message.SchemaFormat = "application/vnd.aai.asyncapi+json;version=2.6.0"; - message.Payload = new AsyncApiSchema() + message.Payload = new JsonSchema() { - Properties = new Dictionary() + Properties = new Dictionary() { { - "propertyA", new AsyncApiSchema() + "propertyA", new JsonSchema() { Type = SchemaType.String | SchemaType.Null, } @@ -236,7 +236,7 @@ public void AsyncApiMessage_WithFilledObject_Serializes() var message = new AsyncApiMessage { - Headers = new AsyncApiSchema + Headers = new JsonSchema { Title = "HeaderTitle", WriteOnly = true, @@ -249,18 +249,18 @@ public void AsyncApiMessage_WithFilledObject_Serializes() }), }, }, - Payload = new AsyncApiSchema() + Payload = new JsonSchema() { - Properties = new Dictionary + Properties = new Dictionary { { - "propA", new AsyncApiSchema() + "propA", new JsonSchema() { Type = SchemaType.String, } }, { - "propB", new AsyncApiSchema() + "propB", new JsonSchema() { Type = SchemaType.String, } @@ -299,7 +299,7 @@ public void AsyncApiMessage_WithFilledObject_Serializes() { "http", new HttpMessageBinding { - Headers = new AsyncApiSchema + Headers = new JsonSchema { Title = "SchemaTitle", WriteOnly = true, @@ -333,7 +333,7 @@ public void AsyncApiMessage_WithFilledObject_Serializes() { Name = "MessageTraitName", Title = "MessageTraitTitle", - Headers = new AsyncApiSchema + Headers = new JsonSchema { Title = "SchemaTitle", WriteOnly = true, diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiOperation_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiOperation_Should.cs index 8d8bd4f5..12e45fc4 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiOperation_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiOperation_Should.cs @@ -99,7 +99,7 @@ public void AsyncApiOperation_WithBindings_Serializes() { Type = HttpOperationBinding.HttpOperationType.Request, Method = "PUT", - Query = new AsyncApiSchema + Query = new JsonSchema { Description = "some query", }, @@ -108,11 +108,11 @@ public void AsyncApiOperation_WithBindings_Serializes() { new KafkaOperationBinding { - GroupId = new AsyncApiSchema + GroupId = new JsonSchema { Description = "some Id", }, - ClientId = new AsyncApiSchema + ClientId = new JsonSchema { Description = "some Id", }, diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs index e7d7725e..41bf0bdd 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiSchema_Should.cs @@ -7,16 +7,17 @@ namespace LEGO.AsyncAPI.Tests.Models using System.Globalization; using System.IO; using FluentAssertions; + using Json.Schema; using LEGO.AsyncAPI.Models; using LEGO.AsyncAPI.Readers; using LEGO.AsyncAPI.Writers; using NUnit.Framework; - public class AsyncApiSchema_Should + public class JsonSchema_Should { - public static AsyncApiSchema BasicSchema = new AsyncApiSchema(); + public static JsonSchema BasicSchema = new JsonSchema(); - public static AsyncApiSchema AdvancedSchemaNumber = new AsyncApiSchema + public static JsonSchema AdvancedSchemaNumber = new JsonSchema { Title = "title1", MultipleOf = 3, @@ -32,7 +33,7 @@ public class AsyncApiSchema_Should }, }; - public static AsyncApiSchema AdvancedSchemaBigNumbers = new AsyncApiSchema + public static JsonSchema AdvancedSchemaBigNumbers = new JsonSchema { Title = "title1", MultipleOf = 3, @@ -48,20 +49,20 @@ public class AsyncApiSchema_Should }, }; - public static AsyncApiSchema AdvancedSchemaObject = new AsyncApiSchema + public static JsonSchema AdvancedSchemaObject = new JsonSchema { Title = "title1", - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new AsyncApiSchema + ["property1"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new AsyncApiSchema + ["property2"] = new JsonSchema { Type = SchemaType.Integer, }, - ["property3"] = new AsyncApiSchema + ["property3"] = new JsonSchema { Type = SchemaType.String, MaxLength = 15, @@ -71,78 +72,78 @@ public class AsyncApiSchema_Should Items = new FalseApiSchema(), AdditionalItems = new FalseApiSchema(), }, - ["property4"] = new AsyncApiSchema + ["property4"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property5"] = new AsyncApiSchema + ["property5"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property6"] = new AsyncApiSchema + ["property6"] = new JsonSchema { Type = SchemaType.Boolean, }, }, }, - ["property7"] = new AsyncApiSchema + ["property7"] = new JsonSchema { Type = SchemaType.String, MinLength = 2, }, }, - PatternProperties = new Dictionary() + PatternProperties = new Dictionary() { { "^S_", - new AsyncApiSchema() + new JsonSchema() { Type = SchemaType.String, } }, { - "^I_", new AsyncApiSchema() + "^I_", new JsonSchema() { Type = SchemaType.Integer, } }, }, - PropertyNames = new AsyncApiSchema() + PropertyNames = new JsonSchema() { Pattern = "^[A-Za-z_][A-Za-z0-9_]*$", }, - AdditionalProperties = new AsyncApiSchema + AdditionalProperties = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["Property8"] = new AsyncApiSchema + ["Property8"] = new JsonSchema { Type = SchemaType.String | SchemaType.Null, }, }, }, - Items = new AsyncApiSchema + Items = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["Property9"] = new AsyncApiSchema + ["Property9"] = new JsonSchema { Type = SchemaType.String | SchemaType.Null, }, }, }, - AdditionalItems = new AsyncApiSchema + AdditionalItems = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["Property10"] = new AsyncApiSchema + ["Property10"] = new JsonSchema { Type = SchemaType.String | SchemaType.Null, }, }, }, }, - ["property11"] = new AsyncApiSchema + ["property11"] = new JsonSchema { Const = new AsyncApiAny("aSpecialConstant"), }, @@ -154,43 +155,43 @@ public class AsyncApiSchema_Should }, }; - public static AsyncApiSchema AdvancedSchemaWithAllOf = new AsyncApiSchema + public static JsonSchema AdvancedSchemaWithAllOf = new JsonSchema { Title = "title1", - AllOf = new List + AllOf = new List { - new AsyncApiSchema + new JsonSchema { Title = "title2", - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new AsyncApiSchema + ["property1"] = new JsonSchema { Type = SchemaType.Integer, }, - ["property2"] = new AsyncApiSchema + ["property2"] = new JsonSchema { Type = SchemaType.String, MaxLength = 15, }, }, }, - new AsyncApiSchema + new JsonSchema { Title = "title3", - Properties = new Dictionary + Properties = new Dictionary { - ["property3"] = new AsyncApiSchema + ["property3"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property4"] = new AsyncApiSchema + ["property4"] = new JsonSchema { Type = SchemaType.Boolean , }, }, }, - ["property5"] = new AsyncApiSchema + ["property5"] = new JsonSchema { Type = SchemaType.String, MinLength = 2, @@ -206,7 +207,7 @@ public class AsyncApiSchema_Should }, }; - public static AsyncApiSchema ReferencedSchema = new AsyncApiSchema + public static JsonSchema ReferencedSchema = new JsonSchema { Title = "title1", MultipleOf = 3, @@ -229,22 +230,22 @@ public class AsyncApiSchema_Should }, }; - public static AsyncApiSchema AdvancedSchemaWithRequiredPropertiesObject = new AsyncApiSchema + public static JsonSchema AdvancedSchemaWithRequiredPropertiesObject = new JsonSchema { Title = "title1", Required = new HashSet() { "property1" }, - Properties = new Dictionary + Properties = new Dictionary { - ["property1"] = new AsyncApiSchema + ["property1"] = new JsonSchema { Required = new HashSet() { "property3" }, - Properties = new Dictionary + Properties = new Dictionary { - ["property2"] = new AsyncApiSchema + ["property2"] = new JsonSchema { Type = SchemaType.Integer, }, - ["property3"] = new AsyncApiSchema + ["property3"] = new JsonSchema { Type = SchemaType.String, MaxLength = 15, @@ -253,21 +254,21 @@ public class AsyncApiSchema_Should }, ReadOnly = true, }, - ["property4"] = new AsyncApiSchema + ["property4"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property5"] = new AsyncApiSchema + ["property5"] = new JsonSchema { - Properties = new Dictionary + Properties = new Dictionary { - ["property6"] = new AsyncApiSchema + ["property6"] = new JsonSchema { Type = SchemaType.Boolean, }, }, }, - ["property7"] = new AsyncApiSchema + ["property7"] = new JsonSchema { Type = SchemaType.String, MinLength = 2, @@ -602,7 +603,7 @@ public void Deserialize_WithAdvancedSchema_Works() var expected = AdvancedSchemaObject; // Act - var actual = new AsyncApiStringReader().ReadFragment(json, AsyncApiVersion.AsyncApi2_0, out var _diagnostics); + var actual = new AsyncApiStringReader().ReadFragment(json, AsyncApiVersion.AsyncApi2_0, out var _diagnostics); // Assert actual.Should().BeEquivalentTo(expected); @@ -686,30 +687,30 @@ public void Serialize_WithInliningOptions_ShouldInlineAccordingly(bool shouldInl { new AsyncApiMessage { - Payload = new AsyncApiSchema + Payload = new JsonSchema { Type = SchemaType.Object, Required = new HashSet { "testB" }, - Properties = new Dictionary + Properties = new Dictionary { - { "testC", new AsyncApiSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testC" } } }, - { "testB", new AsyncApiSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testB" } } }, + { "testC", new JsonSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testC" } } }, + { "testB", new JsonSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testB" } } }, }, }, }, }, }, }) - .WithComponent("testD", new AsyncApiSchema() { Type = SchemaType.String, Format = "uuid" }) - .WithComponent("testC", new AsyncApiSchema() + .WithComponent("testD", new JsonSchema() { Type = SchemaType.String, Format = "uuid" }) + .WithComponent("testC", new JsonSchema() { Type = SchemaType.Object, - Properties = new Dictionary + Properties = new Dictionary { - { "testD", new AsyncApiSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testD" } } }, + { "testD", new JsonSchema { Reference = new AsyncApiReference { Type = ReferenceType.Schema, Id = "testD" } } }, }, }) - .WithComponent("testB", new AsyncApiSchema() { Description = "test", Type = SchemaType.Boolean }) + .WithComponent("testB", new JsonSchema() { Description = "test", Type = SchemaType.Boolean }) .Build(); var outputString = new StringWriter(CultureInfo.InvariantCulture); @@ -756,10 +757,10 @@ public void SerializeV2_WithNullWriter_Throws() [Test] public void Serialize_WithOneOf_DoesNotWriteThen() { - var mainSchema = new AsyncApiSchema(); - var subSchema = new AsyncApiSchema(); - subSchema.Properties.Add("title", new AsyncApiSchema() { Type = SchemaType.String }); - mainSchema.OneOf = new List() { subSchema }; + var mainSchema = new JsonSchema(); + var subSchema = new JsonSchema(); + subSchema.Properties.Add("title", new JsonSchema() { Type = SchemaType.String }); + mainSchema.OneOf = new List() { subSchema }; var yaml = mainSchema.Serialize(AsyncApiVersion.AsyncApi2_0, AsyncApiFormat.Yaml); @@ -774,10 +775,10 @@ public void Serialize_WithOneOf_DoesNotWriteThen() [Test] public void Serialize_WithAnyOf_DoesNotWriteIf() { - var mainSchema = new AsyncApiSchema(); - var subSchema = new AsyncApiSchema(); - subSchema.Properties.Add("title", new AsyncApiSchema() { Type = SchemaType.String }); - mainSchema.AnyOf = new List() { subSchema }; + var mainSchema = new JsonSchema(); + var subSchema = new JsonSchema(); + subSchema.Properties.Add("title", new JsonSchema() { Type = SchemaType.String }); + mainSchema.AnyOf = new List() { subSchema }; var yaml = mainSchema.Serialize(AsyncApiVersion.AsyncApi2_0, AsyncApiFormat.Yaml); @@ -791,9 +792,9 @@ public void Serialize_WithAnyOf_DoesNotWriteIf() [Test] public void Serialize_WithNot_DoesNotWriteElse() { - var mainSchema = new AsyncApiSchema(); - var subSchema = new AsyncApiSchema(); - subSchema.Properties.Add("title", new AsyncApiSchema() { Type = SchemaType.String }); + var mainSchema = new JsonSchema(); + var subSchema = new JsonSchema(); + subSchema.Properties.Add("title", new JsonSchema() { Type = SchemaType.String }); mainSchema.Not = subSchema; var yaml = mainSchema.Serialize(AsyncApiVersion.AsyncApi2_0, AsyncApiFormat.Yaml);