diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
index 47c2eb4c5..0f9564c2a 100644
--- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
+++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
@@ -35,8 +35,6 @@
-
-
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
index f4e81dee9..315813864 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
+using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
@@ -50,7 +51,12 @@ public OpenApiDocument Read(TextReader input, out OpenApiDiagnostic diagnostic)
return new OpenApiDocument();
}
- return new OpenApiYamlDocumentReader(this._settings).Read(yamlDocument, out diagnostic);
+ var asJsonNode = yamlDocument.ToJsonNode();
+
+ diagnostic = null; // TBD
+ return asJsonNode.Deserialize();
+
+ //return new OpenApiYamlDocumentReader(this._settings).Read(yamlDocument, out diagnostic);
}
///
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiDocumentDeserializer.cs
index 02e868412..67193176b 100644
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiDocumentDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiDocumentDeserializer.cs
@@ -63,9 +63,9 @@ internal static partial class OpenApiV2Deserializer
o.Components = new OpenApiComponents();
}
- o.Components.Schemas = n.CreateMapWithReference(
- ReferenceType.Schema,
- LoadSchema);
+ //o.Components.Schemas = n.CreateMapWithReference(
+ // ReferenceType.Schema,
+ // LoadSchema);
}
},
{
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs
index 5d6cc2ff3..b4c92b526 100644
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
@@ -136,33 +136,33 @@ internal static partial class OpenApiV2Deserializer
private static readonly AnyFieldMap _headerAnyFields =
new AnyFieldMap
{
- {
- OpenApiConstants.Default,
- new AnyFieldMapParameter(
- p => p.Schema?.Default,
- (p, v) =>
- {
- if(p.Schema == null) return;
- p.Schema.Default = v;
- },
- p => p.Schema)
- }
+ //{
+ // OpenApiConstants.Default,
+ // new AnyFieldMapParameter(
+ // p => p.Schema?.Default,
+ // (p, v) =>
+ // {
+ // if(p.Schema == null) return;
+ // p.Schema.Default = v;
+ // },
+ // p => p.Schema)
+ //}
};
private static readonly AnyListFieldMap _headerAnyListFields =
new AnyListFieldMap
{
- {
- OpenApiConstants.Enum,
- new AnyListFieldMapParameter(
- p => p.Schema?.Enum,
- (p, v) =>
- {
- if(p.Schema == null) return;
- p.Schema.Enum = v;
- },
- p => p.Schema)
- },
+ //{
+ // OpenApiConstants.Enum,
+ // new AnyListFieldMapParameter(
+ // p => p.Schema?.Enum,
+ // (p, v) =>
+ // {
+ // if(p.Schema == null) return;
+ // p.Schema.Enum = v;
+ // },
+ // p => p.Schema)
+ //},
};
public static OpenApiHeader LoadHeader(ParseNode node)
@@ -177,7 +177,7 @@ public static OpenApiHeader LoadHeader(ParseNode node)
var schema = node.Context.GetFromTempStorage("schema");
if (schema != null)
{
- header.Schema = schema;
+ //header.Schema = schema;
node.Context.SetTempStorage("schema", null);
}
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs
index 1cf5b7ae8..e6475a1cc 100644
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiOperationDeserializer.cs
@@ -163,19 +163,19 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List k.Name,
- v =>
- {
- var schema = v.Schema;
- schema.Description = v.Description;
- schema.Extensions = v.Extensions;
- return schema;
- }),
- Required = new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name))
- }
+ //Schema = new OpenApiSchema
+ //{
+ // Properties = formParameters.ToDictionary(
+ // k => k.Name,
+ // v =>
+ // {
+ // var schema = v.Schema;
+ // schema.Description = v.Description;
+ // schema.Extensions = v.Extensions;
+ // return schema;
+ // }),
+ // Required = new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name))
+ //}
};
var consumes = context.GetFromTempStorage>(TempStorageKeys.OperationConsumes) ??
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiParameterDeserializer.cs
index 5be08c71e..22a2ddbed 100644
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiParameterDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiParameterDeserializer.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using Json.Schema;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers.ParseNodes;
@@ -130,7 +131,7 @@ internal static partial class OpenApiV2Deserializer
{
"schema", (o, n) =>
{
- o.Schema = LoadSchema(n);
+ //o.Schema = LoadSchema(n);
}
},
};
@@ -144,35 +145,35 @@ internal static partial class OpenApiV2Deserializer
private static readonly AnyFieldMap _parameterAnyFields =
new AnyFieldMap
{
- {
- OpenApiConstants.Default,
- new AnyFieldMapParameter(
- p => p.Schema?.Default,
- (p, v) => {
- if (p.Schema != null || v != null)
- {
- GetOrCreateSchema(p).Default = v;
- }
- },
- p => p.Schema)
- }
+ //{
+ // OpenApiConstants.Default,
+ // new AnyFieldMapParameter(
+ // p => p.Schema?.Default,
+ // (p, v) => {
+ // if (p.Schema != null || v != null)
+ // {
+ // GetOrCreateSchema(p).Default = v;
+ // }
+ // },
+ // p => p.Schema)
+ //}
};
private static readonly AnyListFieldMap _parameterAnyListFields =
new AnyListFieldMap
{
- {
- OpenApiConstants.Enum,
- new AnyListFieldMapParameter(
- p => p.Schema?.Enum,
- (p, v) => {
- if (p.Schema != null || v != null && v.Count > 0)
- {
- GetOrCreateSchema(p).Enum = v;
- }
- },
- p => p.Schema)
- },
+ //{
+ // OpenApiConstants.Enum,
+ // new AnyListFieldMapParameter(
+ // p => p.Schema?.Enum,
+ // (p, v) => {
+ // if (p.Schema != null || v != null && v.Count > 0)
+ // {
+ // GetOrCreateSchema(p).Enum = v;
+ // }
+ // },
+ // p => p.Schema)
+ //},
};
private static void LoadStyle(OpenApiParameter p, string v)
@@ -208,20 +209,20 @@ private static OpenApiSchema GetOrCreateSchema(OpenApiParameter p)
{
if (p.Schema == null)
{
- p.Schema = new OpenApiSchema();
+ p.Schema = JsonSchema.Empty;
}
- return p.Schema;
+ return new OpenApiSchema();
}
private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p)
{
if (p.Schema == null)
{
- p.Schema = new OpenApiSchema();
+ p.Schema = JsonSchema.Empty;
}
- return p.Schema;
+ return new OpenApiSchema();
}
private static void ProcessIn(OpenApiParameter o, ParseNode n)
@@ -284,7 +285,7 @@ public static OpenApiParameter LoadParameter(ParseNode node, bool loadRequestBod
var schema = node.Context.GetFromTempStorage("schema");
if (schema != null)
{
- parameter.Schema = schema;
+ //parameter.Schema = schema;
node.Context.SetTempStorage("schema", null);
}
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiResponseDeserializer.cs
index 343dcd2ce..51c666506 100644
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiResponseDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V2/OpenApiResponseDeserializer.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using System.Collections.Generic;
+using Json.Schema;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers.ParseNodes;
@@ -51,13 +52,13 @@ internal static partial class OpenApiV2Deserializer
private static readonly AnyFieldMap _mediaTypeAnyFields =
new AnyFieldMap
{
- {
- OpenApiConstants.Example,
- new AnyFieldMapParameter(
- m => m.Example,
- (m, v) => m.Example = v,
- m => m.Schema)
- }
+ //{
+ // OpenApiConstants.Example,
+ // new AnyFieldMapParameter(
+ // m => m.Example,
+ // (m, v) => m.Example = v,
+ // m => m.Schema)
+ //}
};
private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, ParsingContext context)
@@ -78,7 +79,7 @@ private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, P
{
foreach (var produce in produces)
{
- var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response);
+ var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response);
if (response.Content.ContainsKey(produce) && response.Content[produce] != null)
{
@@ -131,7 +132,7 @@ private static void LoadExample(OpenApiResponse response, string mediaType, Pars
{
mediaTypeObject = new OpenApiMediaType
{
- Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response)
+ Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response)
};
response.Content.Add(mediaType, mediaTypeObject);
}
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs
index f48c57093..0545d7a74 100644
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs
@@ -17,7 +17,7 @@ internal static partial class OpenApiV3Deserializer
{
private static FixedFieldMap _componentsFixedFields = new FixedFieldMap
{
- {"schemas", (o, n) => o.Schemas = n.CreateMapWithReference(ReferenceType.Schema, LoadSchema)},
+ //{"schemas", (o, n) => o.Schemas = n.CreateMapWithReference(ReferenceType.Schema, LoadSchema)},
{"responses", (o, n) => o.Responses = n.CreateMapWithReference(ReferenceType.Response, LoadResponse)},
{"parameters", (o, n) => o.Parameters = n.CreateMapWithReference(ReferenceType.Parameter, LoadParameter)},
{"examples", (o, n) => o.Examples = n.CreateMapWithReference(ReferenceType.Example, LoadExample)},
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiHeaderDeserializer.cs
index 91b149db0..94aeea148 100644
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiHeaderDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiHeaderDeserializer.cs
@@ -61,7 +61,7 @@ internal static partial class OpenApiV3Deserializer
{
"schema", (o, n) =>
{
- o.Schema = LoadSchema(n);
+ //o.Schema = LoadSchema(n);
}
},
{
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiMediaTypeDeserializer.cs
index 12f693ead..efaebd8ee 100644
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiMediaTypeDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiMediaTypeDeserializer.cs
@@ -23,7 +23,7 @@ internal static partial class OpenApiV3Deserializer
{
OpenApiConstants.Schema, (o, n) =>
{
- o.Schema = LoadSchema(n);
+ //o.Schema = LoadSchema(n);
}
},
{
@@ -54,27 +54,27 @@ internal static partial class OpenApiV3Deserializer
private static readonly AnyFieldMap _mediaTypeAnyFields = new AnyFieldMap
{
- {
- OpenApiConstants.Example,
- new AnyFieldMapParameter(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s.Schema)
- }
+ //{
+ // OpenApiConstants.Example,
+ // new AnyFieldMapParameter(
+ // s => s.Example,
+ // (s, v) => s.Example = v,
+ // s => s.Schema)
+ //}
};
private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields =
new AnyMapFieldMap
{
- {
- OpenApiConstants.Examples,
- new AnyMapFieldMapParameter(
- m => m.Examples,
- e => e.Value,
- (e, v) => e.Value = v,
- m => m.Schema)
- }
+ //{
+ // OpenApiConstants.Examples,
+ // new AnyMapFieldMapParameter(
+ // m => m.Examples,
+ // e => e.Value,
+ // (e, v) => e.Value = v,
+ // m => m.Schema)
+ //}
};
public static OpenApiMediaType LoadMediaType(ParseNode node)
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiParameterDeserializer.cs
index 2dd7ac1f4..2068ad15a 100644
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiParameterDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V3/OpenApiParameterDeserializer.cs
@@ -86,7 +86,7 @@ internal static partial class OpenApiV3Deserializer
{
"schema", (o, n) =>
{
- o.Schema = LoadSchema(n);
+ //o.Schema = LoadSchema(n);
}
},
{
@@ -117,26 +117,26 @@ internal static partial class OpenApiV3Deserializer
private static readonly AnyFieldMap _parameterAnyFields = new AnyFieldMap
{
- {
- OpenApiConstants.Example,
- new AnyFieldMapParameter(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s.Schema)
- }
+ //{
+ // OpenApiConstants.Example,
+ // new AnyFieldMapParameter(
+ // s => s.Example,
+ // (s, v) => s.Example = v,
+ // s => s.Schema)
+ //}
};
private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields =
new AnyMapFieldMap
{
- {
- OpenApiConstants.Examples,
- new AnyMapFieldMapParameter(
- m => m.Examples,
- e => e.Value,
- (e, v) => e.Value = v,
- m => m.Schema)
- }
+ //{
+ // OpenApiConstants.Examples,
+ // new AnyMapFieldMapParameter(
+ // m => m.Examples,
+ // e => e.Value,
+ // (e, v) => e.Value = v,
+ // m => m.Schema)
+ //}
};
public static OpenApiParameter LoadParameter(ParseNode node)
diff --git a/src/Microsoft.OpenApi.Readers/V31/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi.Readers/V31/OpenApiHeaderDeserializer.cs
index f42e148f8..ddb062db1 100644
--- a/src/Microsoft.OpenApi.Readers/V31/OpenApiHeaderDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V31/OpenApiHeaderDeserializer.cs
@@ -61,7 +61,7 @@ internal static partial class OpenApiV31Deserializer
{
"schema", (o, n) =>
{
- o.Schema31 = LoadSchema(n);
+ //o.Schema31 = LoadSchema(n);
}
},
{
diff --git a/src/Microsoft.OpenApi.Readers/V31/OpenApiMediaTypeDeserializer.cs b/src/Microsoft.OpenApi.Readers/V31/OpenApiMediaTypeDeserializer.cs
index e10bbd9ed..3fb790995 100644
--- a/src/Microsoft.OpenApi.Readers/V31/OpenApiMediaTypeDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V31/OpenApiMediaTypeDeserializer.cs
@@ -19,7 +19,7 @@ internal static partial class OpenApiV31Deserializer
{
OpenApiConstants.Schema, (o, n) =>
{
- o.Schema31 = LoadSchema(n);
+ //o.Schema31 = LoadSchema(n);
}
},
{
@@ -50,27 +50,27 @@ internal static partial class OpenApiV31Deserializer
private static readonly AnyFieldMap _mediaTypeAnyFields = new AnyFieldMap
{
- {
- OpenApiConstants.Example,
- new AnyFieldMapParameter(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s.Schema)
- }
+ //{
+ // OpenApiConstants.Example,
+ // new AnyFieldMapParameter(
+ // s => s.Example,
+ // (s, v) => s.Example = v,
+ // s => s.Schema)
+ //}
};
private static readonly AnyMapFieldMap _mediaTypeAnyMapOpenApiExampleFields =
new AnyMapFieldMap
{
- {
- OpenApiConstants.Examples,
- new AnyMapFieldMapParameter(
- m => m.Examples,
- e => e.Value,
- (e, v) => e.Value = v,
- m => m.Schema)
- }
+ //{
+ // OpenApiConstants.Examples,
+ // new AnyMapFieldMapParameter(
+ // m => m.Examples,
+ // e => e.Value,
+ // (e, v) => e.Value = v,
+ // m => m.Schema)
+ //}
};
public static OpenApiMediaType LoadMediaType(ParseNode node)
diff --git a/src/Microsoft.OpenApi.Readers/V31/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi.Readers/V31/OpenApiParameterDeserializer.cs
index 6ab221293..4abc4d976 100644
--- a/src/Microsoft.OpenApi.Readers/V31/OpenApiParameterDeserializer.cs
+++ b/src/Microsoft.OpenApi.Readers/V31/OpenApiParameterDeserializer.cs
@@ -85,7 +85,7 @@ internal static partial class OpenApiV31Deserializer
{
"schema", (o, n) =>
{
- o.Schema31 = LoadSchema(n);
+ //o.Schema31 = LoadSchema(n);
}
},
{
@@ -116,26 +116,26 @@ internal static partial class OpenApiV31Deserializer
private static readonly AnyFieldMap _parameterAnyFields = new AnyFieldMap
{
- {
- OpenApiConstants.Example,
- new AnyFieldMapParameter(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s.Schema)
- }
+ //{
+ // OpenApiConstants.Example,
+ // new AnyFieldMapParameter(
+ // s => s.Example,
+ // (s, v) => s.Example = v,
+ // s => s.Schema)
+ //}
};
private static readonly AnyMapFieldMap _parameterAnyMapOpenApiExampleFields =
new AnyMapFieldMap
{
- {
- OpenApiConstants.Examples,
- new AnyMapFieldMapParameter(
- m => m.Examples,
- e => e.Value,
- (e, v) => e.Value = v,
- m => m.Schema)
- }
+ //{
+ // OpenApiConstants.Examples,
+ // new AnyMapFieldMapParameter(
+ // m => m.Examples,
+ // e => e.Value,
+ // (e, v) => e.Value = v,
+ // m => m.Schema)
+ //}
};
public static OpenApiParameter LoadParameter(ParseNode node)
diff --git a/src/Microsoft.OpenApi.Readers/YamlConverter.cs b/src/Microsoft.OpenApi.Readers/YamlConverter.cs
new file mode 100644
index 000000000..f46dc45f4
--- /dev/null
+++ b/src/Microsoft.OpenApi.Readers/YamlConverter.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Nodes;
+using Json.More;
+using SharpYaml;
+using SharpYaml.Serialization;
+
+namespace Microsoft.OpenApi.Readers
+{
+ ///
+ /// Provides extensions to convert YAML models to JSON models.
+ ///
+ public static class YamlConverter
+ {
+ ///
+ /// Converts all of the documents in a YAML stream to s.
+ ///
+ /// The YAML stream.
+ /// A collection of nodes representing the YAML documents in the stream.
+ public static IEnumerable ToJsonNode(this YamlStream yaml)
+ {
+ return yaml.Documents.Select(x => x.ToJsonNode());
+ }
+
+ ///
+ /// Converts a single YAML document to a .
+ ///
+ /// The YAML document.
+ /// A `JsonNode` representative of the YAML document.
+ public static JsonNode ToJsonNode(this YamlDocument yaml)
+ {
+ return yaml.RootNode.ToJsonNode();
+ }
+
+ ///
+ /// Converts a single YAML node to a .
+ ///
+ /// The YAML node.
+ /// A `JsonNode` representative of the YAML node.
+ /// Thrown for YAML that is not compatible with JSON.
+ public static JsonNode ToJsonNode(this YamlNode yaml)
+ {
+ return yaml switch
+ {
+ YamlMappingNode map => map.ToJsonObject(),
+ YamlSequenceNode seq => seq.ToJsonArray(),
+ YamlScalarNode scalar => scalar.ToJsonValue(),
+ _ => throw new NotSupportedException("This yaml isn't convertible to JSON")
+ };
+ }
+
+ ///
+ /// Converts a single JSON node to a .
+ ///
+ ///
+ ///
+ ///
+ public static YamlNode ToYamlNode(this JsonNode json)
+ {
+ return json switch
+ {
+ null => null,
+ JsonObject obj => obj.ToYamlMapping(),
+ JsonArray arr => arr.ToYamlSequence(),
+ JsonValue val => val.ToYamlScalar(),
+ _ => throw new NotSupportedException("This isn't a supported JsonNode")
+ };
+ }
+
+ private static JsonObject ToJsonObject(this YamlMappingNode yaml)
+ {
+ var node = new JsonObject();
+ foreach (var keyValuePair in yaml)
+ {
+ var key = ((YamlScalarNode)keyValuePair.Key).Value!;
+ node[key] = keyValuePair.Value.ToJsonNode();
+ }
+
+ return node;
+ }
+
+ private static YamlMappingNode ToYamlMapping(this JsonObject obj)
+ {
+ return new YamlMappingNode(obj.ToDictionary(x => (YamlNode)new YamlScalarNode(x.Key),
+ x => x.Value!.ToYamlNode()));
+ }
+
+ private static JsonArray ToJsonArray(this YamlSequenceNode yaml)
+ {
+ var node = new JsonArray();
+ foreach (var value in yaml)
+ {
+ node.Add(value.ToJsonNode());
+ }
+
+ return node;
+ }
+
+ private static YamlSequenceNode ToYamlSequence(this JsonArray arr)
+ {
+ return new YamlSequenceNode(arr.Select(x => x!.ToYamlNode()));
+ }
+
+ private static JsonValue ToJsonValue(this YamlScalarNode yaml)
+ {
+ switch (yaml.Style)
+ {
+ case ScalarStyle.Plain:
+ return decimal.TryParse(yaml.Value, out var d)
+ ? JsonValue.Create(d)
+ : bool.TryParse(yaml.Value, out var b)
+ ? JsonValue.Create(b)
+ : JsonValue.Create(yaml.Value)!;
+ case ScalarStyle.SingleQuoted:
+ case ScalarStyle.DoubleQuoted:
+ case ScalarStyle.Literal:
+ case ScalarStyle.Folded:
+ case ScalarStyle.Any:
+ return JsonValue.Create(yaml.Value)!;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ private static YamlScalarNode ToYamlScalar(this JsonValue val)
+ {
+ return val.TryGetValue(out string s)
+ ? new YamlScalarNode(s)
+ : new YamlScalarNode(val.AsJsonString());
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMaximumKeyword.cs b/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMaximumKeyword.cs
new file mode 100644
index 000000000..a6718acab
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMaximumKeyword.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using Json.Schema;
+using Json.More;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ [SchemaKeyword(Name)]
+ [SchemaSpecVersion(Draft4SupportData.Draft4Version)]
+ [SchemaSpecVersion(SpecVersion.Draft202012)]
+ [JsonConverter(typeof(Draft4ExclusiveMaximumKeywordJsonConverter))]
+ internal class Draft4ExclusiveMaximumKeyword : IJsonSchemaKeyword, IEquatable
+ {
+ public const string Name = "exclusiveMaximum";
+
+ private readonly ExclusiveMaximumKeyword _numberSupport;
+
+ ///
+ /// The ID.
+ ///
+ public bool? BoolValue { get; }
+
+ public decimal? NumberValue => _numberSupport?.Value;
+
+ ///
+ /// Creates a new .
+ ///
+ /// Whether the `minimum` value should be considered exclusive.
+ public Draft4ExclusiveMaximumKeyword(bool value)
+ {
+ BoolValue = value;
+ }
+
+ public Draft4ExclusiveMaximumKeyword(decimal value)
+ {
+ _numberSupport = new ExclusiveMaximumKeyword(value);
+ }
+
+ public void Evaluate(EvaluationContext context)
+ {
+ // TODO: do we need to validate that the right version of the keyword is being used?
+ if (BoolValue.HasValue)
+ {
+ context.EnterKeyword(Name);
+ if (!BoolValue.Value)
+ {
+ context.NotApplicable(() => "exclusiveMinimum is false; minimum validation is sufficient");
+ return;
+ }
+
+ var limit = context.LocalSchema.GetMinimum();
+ if (!limit.HasValue)
+ {
+ context.NotApplicable(() => "minimum not present");
+ return;
+ }
+
+ var schemaValueType = context.LocalInstance.GetSchemaValueType();
+ if (schemaValueType is not (SchemaValueType.Number or SchemaValueType.Integer))
+ {
+ context.WrongValueKind(schemaValueType);
+ return;
+ }
+
+ var number = context.LocalInstance!.AsValue().GetNumber();
+
+ if (limit == number)
+ context.LocalResult.Fail(Name, ErrorMessages.ExclusiveMaximum, ("received", number), ("limit", BoolValue));
+ context.ExitKeyword(Name, context.LocalResult.IsValid);
+ }
+ else
+ {
+ _numberSupport.Evaluate(context);
+ }
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(Draft4ExclusiveMaximumKeyword other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(BoolValue, other.BoolValue);
+ }
+
+ /// Determines whether the specified object is equal to the current object.
+ /// The object to compare with the current object.
+ /// true if the specified object is equal to the current object; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Draft4ExclusiveMaximumKeyword);
+ }
+
+ /// Serves as the default hash function.
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return BoolValue.GetHashCode();
+ }
+ }
+
+ internal class Draft4ExclusiveMaximumKeywordJsonConverter : JsonConverter
+ {
+ public override Draft4ExclusiveMaximumKeyword Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.TokenType switch
+ {
+ JsonTokenType.True or JsonTokenType.False => new Draft4ExclusiveMaximumKeyword(reader.GetBoolean()),
+ JsonTokenType.Number => new Draft4ExclusiveMaximumKeyword(reader.GetDecimal()),
+ _ => throw new JsonException("Expected boolean or number")
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, Draft4ExclusiveMaximumKeyword value, JsonSerializerOptions options)
+ {
+ if (value.BoolValue.HasValue)
+ {
+ writer.WriteBoolean(Draft4ExclusiveMaximumKeyword.Name, value.BoolValue.Value);
+ }
+ else
+ {
+ writer.WriteNumber(Draft4ExclusiveMaximumKeyword.Name, value.NumberValue.Value);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMinimumKeyword.cs b/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMinimumKeyword.cs
new file mode 100644
index 000000000..148953380
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/Draft4ExclusiveMinimumKeyword.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using Json.Schema;
+using Json.More;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ [SchemaKeyword(Name)]
+ [SchemaSpecVersion(Draft4SupportData.Draft4Version)]
+ [SchemaSpecVersion(SpecVersion.Draft202012)]
+ [JsonConverter(typeof(Draft4ExclusiveMinimumKeywordJsonConverter))]
+ internal class Draft4ExclusiveMinimumKeyword : IJsonSchemaKeyword, IEquatable
+ {
+ public const string Name = "exclusiveMinimum";
+
+ private readonly ExclusiveMinimumKeyword _numberSupport;
+
+ ///
+ /// The ID.
+ ///
+ public bool? BoolValue { get; }
+
+ public decimal? NumberValue => _numberSupport?.Value;
+
+ ///
+ /// Creates a new .
+ ///
+ /// Whether the `minimum` value should be considered exclusive.
+ public Draft4ExclusiveMinimumKeyword(bool value)
+ {
+ BoolValue = value;
+ }
+
+ public Draft4ExclusiveMinimumKeyword(decimal value)
+ {
+ _numberSupport = new ExclusiveMinimumKeyword(value);
+ }
+
+ public void Evaluate(EvaluationContext context)
+ {
+ // TODO: do we need to validate that the right version of the keyword is being used?
+ if (BoolValue.HasValue)
+ {
+ context.EnterKeyword(Name);
+ if (!BoolValue.Value)
+ {
+ context.NotApplicable(() => "exclusiveMinimum is false; minimum validation is sufficient");
+ return;
+ }
+
+ var limit = context.LocalSchema.GetMinimum();
+ if (!limit.HasValue)
+ {
+ context.NotApplicable(() => "minimum not present");
+ return;
+ }
+
+ var schemaValueType = context.LocalInstance.GetSchemaValueType();
+ if (schemaValueType is not (SchemaValueType.Number or SchemaValueType.Integer))
+ {
+ context.WrongValueKind(schemaValueType);
+ return;
+ }
+
+ var number = context.LocalInstance!.AsValue().GetNumber();
+
+ if (limit == number)
+ context.LocalResult.Fail(Name, ErrorMessages.ExclusiveMaximum, ("received", number), ("limit", BoolValue));
+ context.ExitKeyword(Name, context.LocalResult.IsValid);
+ }
+ else
+ {
+ _numberSupport.Evaluate(context);
+ }
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(Draft4ExclusiveMinimumKeyword other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(BoolValue, other.BoolValue);
+ }
+
+ /// Determines whether the specified object is equal to the current object.
+ /// The object to compare with the current object.
+ /// true if the specified object is equal to the current object; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Draft4ExclusiveMinimumKeyword);
+ }
+
+ /// Serves as the default hash function.
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return BoolValue.GetHashCode();
+ }
+ }
+
+ internal class Draft4ExclusiveMinimumKeywordJsonConverter : JsonConverter
+ {
+ public override Draft4ExclusiveMinimumKeyword Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.TokenType switch
+ {
+ JsonTokenType.True or JsonTokenType.False => new Draft4ExclusiveMinimumKeyword(reader.GetBoolean()),
+ JsonTokenType.Number => new Draft4ExclusiveMinimumKeyword(reader.GetDecimal()),
+ _ => throw new JsonException("Expected boolean or number")
+ };
+ }
+
+ public override void Write(Utf8JsonWriter writer, Draft4ExclusiveMinimumKeyword value, JsonSerializerOptions options)
+ {
+ if (value.BoolValue.HasValue)
+ writer.WriteBoolean(Draft4ExclusiveMinimumKeyword.Name, value.BoolValue.Value);
+ else
+ writer.WriteNumber(Draft4ExclusiveMinimumKeyword.Name, value.NumberValue.Value);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/Draft4IdKeyword.cs b/src/Microsoft.OpenApi/Draft4Support/Draft4IdKeyword.cs
new file mode 100644
index 000000000..53dfdad4e
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/Draft4IdKeyword.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using Json.Schema;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ [SchemaKeyword(Name)]
+ [SchemaPriority(int.MinValue + 1)]
+ [SchemaSpecVersion(Draft4SupportData.Draft4Version)]
+ [JsonConverter(typeof(Draft4IdKeywordJsonConverter))]
+ internal class Draft4IdKeyword : IIdKeyword, IEquatable
+ {
+ public const string Name = "id";
+
+ ///
+ /// The ID.
+ ///
+ public Uri Id { get; }
+
+ ///
+ /// Creates a new .
+ ///
+ /// The ID.
+ public Draft4IdKeyword(Uri id)
+ {
+ Id = id ?? throw new ArgumentNullException(nameof(id));
+ }
+
+ public void Evaluate(EvaluationContext context)
+ {
+ context.EnterKeyword(Name);
+ context.Log(() => "Nothing to do");
+ context.ExitKeyword(Name, true);
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(Draft4IdKeyword other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(Id, other.Id);
+ }
+
+ /// Determines whether the specified object is equal to the current object.
+ /// The object to compare with the current object.
+ /// true if the specified object is equal to the current object; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Draft4IdKeyword);
+ }
+
+ /// Serves as the default hash function.
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
+ }
+ }
+
+ internal class Draft4IdKeywordJsonConverter : JsonConverter
+ {
+ public override Draft4IdKeyword Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType != JsonTokenType.String)
+ throw new JsonException("Expected string");
+
+ var uriString = reader.GetString();
+ if (!Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out var uri))
+ throw new JsonException("Expected URI");
+
+ return new Draft4IdKeyword(uri);
+ }
+
+ public override void Write(Utf8JsonWriter writer, Draft4IdKeyword value, JsonSerializerOptions options)
+ {
+ writer.WriteString(Draft4IdKeyword.Name, value.Id.OriginalString);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/Draft4SupportData.cs b/src/Microsoft.OpenApi/Draft4Support/Draft4SupportData.cs
new file mode 100644
index 000000000..9c599ac29
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/Draft4SupportData.cs
@@ -0,0 +1,147 @@
+using System.Collections.Generic;
+using System.Text.Json.Nodes;
+using Json.Schema;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ internal static class Draft4SupportData
+ {
+ // This is kind of a hack since SpecVersion is an enum.
+ // Maybe it should be defined as string constants.
+ public const SpecVersion Draft4Version = (SpecVersion)(-1);
+ public const SchemaValueType FileDataType = (SchemaValueType)(-1);
+
+ public static readonly JsonSchema Draft4MetaSchema =
+ new JsonSchemaBuilder()
+ .OasId("http://json-schema.org/draft-04/schema#")
+ .Schema("http://json-schema.org/draft-04/schema#")
+ .Description("Core schema meta-schema")
+ .Definitions(
+ ("schemaArray", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Array)
+ .MinItems(1)
+ .Items(JsonSchemaBuilder.RefRoot())
+ ),
+ ("positiveInteger", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Integer)
+ .Minimum(0)
+ ),
+ ("positiveIntegerDefault0", new JsonSchemaBuilder().Ref("#/definitions/positiveInteger")),
+ ("simpleTypes", new JsonSchemaBuilder()
+ .Enum("array", "boolean", "integer", "null", "number", "object", "string")),
+ ("stringArray", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Array)
+ .Items(new JsonSchemaBuilder().Type(SchemaValueType.String))
+ .MinItems(1)
+ .UniqueItems(true)
+ )
+ )
+ .Type(SchemaValueType.Object)
+ .Properties(
+ ("id", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("$schema", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("title", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("description", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("default", JsonSchema.Empty),
+ ("multipleOf", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Number)
+ .Minimum(0)
+ .ExclusiveMinimum(true)
+ ),
+ ("maximum", new JsonSchemaBuilder().Type(SchemaValueType.Number)),
+ ("exclusiveMaximum", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Boolean)
+ .Default(false)
+ ),
+ ("minimum", new JsonSchemaBuilder().Type(SchemaValueType.Number)),
+ ("exclusiveMinimum", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Boolean)
+ .Default(false)
+ ),
+ ("maxLength", new JsonSchemaBuilder().Ref("#/definitions/positiveInteger")),
+ ("minLength", new JsonSchemaBuilder().Ref("#/definitions/positiveIntegerDefault0")),
+ ("pattern", new JsonSchemaBuilder()
+ .Type(SchemaValueType.String)
+ .Format(Formats.Regex)
+ ),
+ ("additionalItems", new JsonSchemaBuilder()
+ .AnyOf(
+ new JsonSchemaBuilder().Type(SchemaValueType.Boolean),
+ JsonSchemaBuilder.RefRoot()
+ )
+ .Default(new JsonObject())
+ ),
+ ("items", new JsonSchemaBuilder()
+ .AnyOf(
+ JsonSchemaBuilder.RefRoot(),
+ new JsonSchemaBuilder().Ref("#/definitions/schemaArray")
+ )
+ ),
+ ("maxItems", new JsonSchemaBuilder().Ref("#/definitions/positiveInteger")),
+ ("minItems", new JsonSchemaBuilder().Ref("#/definitions/positiveIntegerDefault0")),
+ ("uniqueItems", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Boolean)
+ .Default(false)
+ ),
+ ("maxProperties", new JsonSchemaBuilder().Ref("#/definitions/positiveInteger")),
+ ("minProperties", new JsonSchemaBuilder().Ref("#/definitions/positiveIntegerDefault0")),
+ ("required", new JsonSchemaBuilder().Ref("#/definitions/stringArray")),
+ ("additionalProperties", new JsonSchemaBuilder()
+ .AnyOf(
+ new JsonSchemaBuilder().Type(SchemaValueType.Boolean),
+ JsonSchemaBuilder.RefRoot()
+ )
+ .Default(new JsonObject())
+ ),
+ ("definitions", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Object)
+ .AdditionalProperties(JsonSchemaBuilder.RefRoot())
+ .Default(new JsonObject())
+ ),
+ ("properties", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Object)
+ .AdditionalProperties(JsonSchemaBuilder.RefRoot())
+ .Default(new JsonObject())
+ ),
+ ("patternProperties", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Object)
+ .AdditionalProperties(JsonSchemaBuilder.RefRoot())
+ .Default(new JsonObject())
+ ),
+ ("dependencies", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Object)
+ .AdditionalProperties(new JsonSchemaBuilder()
+ .AnyOf(
+ JsonSchemaBuilder.RefRoot(),
+ new JsonSchemaBuilder().Ref("#/definitions/stringArray")
+ )
+ )
+ ),
+ ("enum", new JsonSchemaBuilder()
+ .Type(SchemaValueType.Array)
+ .MinItems(1)
+ .UniqueItems(true)
+ ),
+ ("type", new JsonSchemaBuilder()
+ .AnyOf(
+ new JsonSchemaBuilder().Ref("#/definitions/simpleTypes"),
+ new JsonSchemaBuilder()
+ .Type(SchemaValueType.Array)
+ .Items(new JsonSchemaBuilder().Ref("#/definitions/simpleTypes"))
+ .MinItems(1)
+ .UniqueItems(true)
+ )
+ ),
+ ("format", new JsonSchemaBuilder().Type(SchemaValueType.String)),
+ ("allOf", new JsonSchemaBuilder().Ref("#/definitions/schemaArray")),
+ ("anyOf", new JsonSchemaBuilder().Ref("#/definitions/schemaArray")),
+ ("oneOf", new JsonSchemaBuilder().Ref("#/definitions/schemaArray")),
+ ("not", JsonSchemaBuilder.RefRoot())
+ )
+ .Dependencies(
+ ("exclusiveMaximum", new SchemaOrPropertyList(new List { "maximum" })),
+ ("exclusiveMinimum", new SchemaOrPropertyList(new List { "minimum" }))
+ )
+ .Default(new JsonObject());
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/Draft4TypeKeyword.cs b/src/Microsoft.OpenApi/Draft4Support/Draft4TypeKeyword.cs
new file mode 100644
index 000000000..4e66837a9
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/Draft4TypeKeyword.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using Json.Schema;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ [SchemaKeyword(Name)]
+ [SchemaSpecVersion(Draft4SupportData.Draft4Version)]
+ [SchemaSpecVersion(SpecVersion.Draft202012)]
+ [JsonConverter(typeof(Draft4TypeKeywordConverter))]
+ internal class Draft4TypeKeyword : IJsonSchemaKeyword, IEquatable
+ {
+ public const string Name = "type";
+
+ private readonly TypeKeyword _basicSupport;
+ private readonly TypeKeyword _draft4Support;
+
+ ///
+ /// The ID.
+ ///
+ public SchemaValueType Type => _basicSupport.Type;
+
+ ///
+ /// Creates a new .
+ ///
+ /// The instance type that is allowed.
+ public Draft4TypeKeyword(SchemaValueType type)
+ {
+ _basicSupport = new TypeKeyword(type);
+ _draft4Support = new TypeKeyword(type | SchemaValueType.Null);
+ }
+
+ public void Evaluate(EvaluationContext context)
+ {
+ if (context.Options.EvaluateAs == Draft4SupportData.Draft4Version)
+ {
+ _draft4Support.Evaluate(context);
+ }
+ else
+ {
+ _basicSupport.Evaluate(context);
+ }
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(Draft4TypeKeyword other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(Type, other.Type);
+ }
+
+ /// Determines whether the specified object is equal to the current object.
+ /// The object to compare with the current object.
+ /// true if the specified object is equal to the current object; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Draft4TypeKeyword);
+ }
+
+ /// Serves as the default hash function.
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return Type.GetHashCode();
+ }
+ }
+
+ internal class Draft4TypeKeywordConverter : JsonConverter
+ {
+ public override Draft4TypeKeyword Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var type = JsonSerializer.Deserialize(ref reader, options);
+
+ return new Draft4TypeKeyword(type);
+ }
+ public override void Write(Utf8JsonWriter writer, Draft4TypeKeyword value, JsonSerializerOptions options)
+ {
+ writer.WritePropertyName(Draft4TypeKeyword.Name);
+ JsonSerializer.Serialize(writer, value.Type, options);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/JsonSchemaKeywordExtensions.cs b/src/Microsoft.OpenApi/Draft4Support/JsonSchemaKeywordExtensions.cs
new file mode 100644
index 000000000..80ca6f891
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/JsonSchemaKeywordExtensions.cs
@@ -0,0 +1,44 @@
+using System;
+using Json.Schema;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ public static class JsonSchemaKeywordExtensions
+ {
+ public static JsonSchemaBuilder ExclusiveMaximum(this JsonSchemaBuilder builder, bool value)
+ {
+ builder.Add(new Draft4ExclusiveMaximumKeyword(value));
+ return builder;
+ }
+
+ public static JsonSchemaBuilder ExclusiveMinimum(this JsonSchemaBuilder builder, bool value)
+ {
+ builder.Add(new Draft4ExclusiveMinimumKeyword(value));
+ return builder;
+ }
+
+ public static JsonSchemaBuilder OasId(this JsonSchemaBuilder builder, Uri id)
+ {
+ builder.Add(new Draft4IdKeyword(id));
+ return builder;
+ }
+
+ public static JsonSchemaBuilder OasId(this JsonSchemaBuilder builder, string id)
+ {
+ builder.Add(new Draft4IdKeyword(new Uri(id, UriKind.RelativeOrAbsolute)));
+ return builder;
+ }
+
+ public static JsonSchemaBuilder OasType(this JsonSchemaBuilder builder, SchemaValueType type)
+ {
+ builder.Add(new Draft4TypeKeyword(type));
+ return builder;
+ }
+
+ public static JsonSchemaBuilder Nullable(this JsonSchemaBuilder builder, bool value)
+ {
+ builder.Add(new NullableKeyword(value));
+ return builder;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Draft4Support/NullableKeyword.cs b/src/Microsoft.OpenApi/Draft4Support/NullableKeyword.cs
new file mode 100644
index 000000000..fb6de9966
--- /dev/null
+++ b/src/Microsoft.OpenApi/Draft4Support/NullableKeyword.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Text.Json.Serialization;
+using System.Text.Json;
+using Json.Schema;
+
+namespace Microsoft.OpenApi.Draft4Support
+{
+ [SchemaKeyword(Name)]
+ [SchemaSpecVersion(Draft4SupportData.Draft4Version)]
+ [JsonConverter(typeof(NullableKeywordJsonConverter))]
+ internal class NullableKeyword : IJsonSchemaKeyword, IEquatable
+ {
+ public const string Name = "nullable";
+
+ ///
+ /// The ID.
+ ///
+ public bool Value { get; }
+
+ ///
+ /// Creates a new .
+ ///
+ /// Whether the `minimum` value should be considered exclusive.
+ public NullableKeyword(bool value)
+ {
+ Value = value;
+ }
+
+ public void Evaluate(EvaluationContext context)
+ {
+ context.EnterKeyword(Name);
+ var schemaValueType = context.LocalInstance.GetSchemaValueType();
+ if (schemaValueType == SchemaValueType.Null && !Value)
+ {
+ context.LocalResult.Fail(Name, "nulls are not allowed"); // TODO: localize error message
+ }
+ context.ExitKeyword(Name, context.LocalResult.IsValid);
+ }
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(NullableKeyword other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Equals(Value, other.Value);
+ }
+
+ /// Determines whether the specified object is equal to the current object.
+ /// The object to compare with the current object.
+ /// true if the specified object is equal to the current object; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as NullableKeyword);
+ }
+
+ /// Serves as the default hash function.
+ /// A hash code for the current object.
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+ }
+
+ internal class NullableKeywordJsonConverter : JsonConverter
+ {
+ public override NullableKeyword Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType is not (JsonTokenType.True or JsonTokenType.False))
+ {
+ throw new JsonException("Expected boolean");
+ }
+
+ return new NullableKeyword(reader.GetBoolean());
+ }
+
+ public override void Write(Utf8JsonWriter writer, NullableKeyword value, JsonSerializerOptions options)
+ {
+ writer.WriteBoolean(NullableKeyword.Name, value.Value);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
index 11fcd7e9e..637b9d6d5 100644
--- a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
+++ b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
@@ -59,8 +59,8 @@ private static IOpenApiReferenceable ResolveReferenceOnHeaderElement(
{
switch (propertyName)
{
- case OpenApiConstants.Schema:
- return headerElement.Schema;
+ //case OpenApiConstants.Schema:
+ // return headerElement.Schema;
case OpenApiConstants.Examples when mapKey != null:
return headerElement.Examples[mapKey];
default:
@@ -76,8 +76,8 @@ private static IOpenApiReferenceable ResolveReferenceOnParameterElement(
{
switch (propertyName)
{
- case OpenApiConstants.Schema:
- return parameterElement.Schema;
+ //case OpenApiConstants.Schema:
+ // return parameterElement.Schema;
case OpenApiConstants.Examples when mapKey != null:
return parameterElement.Examples[mapKey];
default:
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index 6637ce2f4..b6bdc0958 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -34,7 +34,8 @@
true
-
+
+
diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
index 09f1b6256..367c646cd 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
@@ -19,7 +19,6 @@ public class OpenApiCallback : IOpenApiSerializable, IOpenApiReferenceable, IOpe
/// A Path Item Object used to define a callback request and expected responses.
///
public Dictionary PathItems { get; set; }
- = new Dictionary();
///
/// Indicates if object is populated with data or is just a reference to the data
@@ -34,7 +33,7 @@ public class OpenApiCallback : IOpenApiSerializable, IOpenApiReferenceable, IOpe
///
/// This object MAY be extended with Specification Extensions.
///
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public IDictionary Extensions { get; set; }
///
/// Parameter-less constructor
diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
index 550248210..5cccddfe7 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Json.Schema;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
using static Microsoft.OpenApi.Extensions.OpenApiSerializableExtensions;
@@ -18,60 +19,57 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible
///
/// An object to hold reusable Objects.
///
- public IDictionary Schemas { get; set; } = new Dictionary();
+ public IDictionary Schemas { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Responses { get; set; } = new Dictionary();
+ public IDictionary Responses { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Parameters { get; set; } =
- new Dictionary();
+ public IDictionary Parameters { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Examples { get; set; } = new Dictionary();
+ public IDictionary Examples { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary RequestBodies { get; set; } =
- new Dictionary();
+ public IDictionary RequestBodies { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Headers { get; set; } = new Dictionary();
+ public IDictionary Headers { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary SecuritySchemes { get; set; } =
- new Dictionary();
+ public IDictionary SecuritySchemes { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Links { get; set; } = new Dictionary();
+ public IDictionary Links { get; set; }
///
/// An object to hold reusable Objects.
///
- public IDictionary Callbacks { get; set; } = new Dictionary();
+ public IDictionary Callbacks { get; set; }
///
/// An object to hold reusable Object.
///
- public IDictionary PathItems { get; set; } = new Dictionary();
+ public IDictionary PathItems { get; set; }
///
/// This object MAY be extended with Specification Extensions.
///
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public IDictionary Extensions { get; set; }
///
/// Parameter-less constructor
@@ -83,7 +81,7 @@ public OpenApiComponents() { }
///
public OpenApiComponents(OpenApiComponents components)
{
- Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null;
+ Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null;
Responses = components?.Responses != null ? new Dictionary(components.Responses) : null;
Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null;
Examples = components?.Examples != null ? new Dictionary(components.Examples) : null;
@@ -167,22 +165,22 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
// If the reference exists but points to other objects, the object is serialized to just that reference.
// schemas
- writer.WriteOptionalMap(
- OpenApiConstants.Schemas,
- Schemas,
- (w, key, component) =>
- {
- if (component.Reference != null &&
- component.Reference.Type == ReferenceType.Schema &&
- string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase))
- {
- action(w, component);
- }
- else
- {
- callback(w, component);
- }
- });
+ //writer.WriteOptionalMap(
+ // OpenApiConstants.Schemas,
+ // Schemas,
+ // (w, key, component) =>
+ // {
+ // if (component.Reference != null &&
+ // component.Reference.Type == ReferenceType.Schema &&
+ // string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase))
+ // {
+ // action(w, component);
+ // }
+ // else
+ // {
+ // callback(w, component);
+ // }
+ // });
// responses
writer.WriteOptionalMap(
@@ -338,16 +336,16 @@ private void RenderComponents(IOpenApiWriter writer)
{
var loops = writer.GetSettings().LoopDetector.Loops;
writer.WriteStartObject();
- if (loops.TryGetValue(typeof(OpenApiSchema), out List