diff --git a/src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs b/src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs
index faf03c3f0..ee57125dd 100644
--- a/src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs
+++ b/src/Microsoft.OpenApi.Hidi/Extensions/OpenApiExtensibleExtensions.cs
@@ -14,9 +14,9 @@ internal static class OpenApiExtensibleExtensions
/// A value matching the provided extensionKey. Return null when extensionKey is not found.
internal static string GetExtension(this IDictionary extensions, string extensionKey)
{
- if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiString castValue)
+ if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny castValue)
{
- return castValue.Value;
+ return castValue.Node.GetValue();
}
return string.Empty;
}
diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs
index 96d3cc17d..c2bbc97d0 100644
--- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs
+++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs
@@ -52,7 +52,8 @@ public override void Visit(OpenApiSchema schema)
public override void Visit(OpenApiPathItem pathItem)
{
- if (pathItem.Operations.TryGetValue(OperationType.Put, out var value))
+ if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) &&
+ value.OperationId != null)
{
var operationId = value.OperationId;
pathItem.Operations[OperationType.Put].OperationId = ResolvePutOperationId(operationId);
@@ -67,14 +68,14 @@ public override void Visit(OpenApiOperation operation)
throw new ArgumentException($"OperationId is required {PathString}", nameof(operation));
var operationId = operation.OperationId;
- var operationTypeExtension = operation.Extensions.GetExtension("x-ms-docs-operation-type");
+ var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type");
if (operationTypeExtension.IsEquals("function"))
- operation.Parameters = ResolveFunctionParameters(operation.Parameters);
+ operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List());
// Order matters. Resolve operationId.
operationId = RemoveHashSuffix(operationId);
if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function"))
- operationId = RemoveKeyTypeSegment(operationId, operation.Parameters);
+ operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List());
operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.'));
operationId = ResolveODataCastOperationId(operationId);
operationId = ResolveByRefOperationId(operationId);
@@ -165,10 +166,10 @@ private static IList ResolveFunctionParameters(IList ResolveFunctionParameters(IList
+
Exe
diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs
index d98508a13..c981639e9 100644
--- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs
+++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs
@@ -29,6 +29,7 @@
using Microsoft.OpenApi.Hidi.Utilities;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData;
+using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Writers;
@@ -38,6 +39,12 @@ namespace Microsoft.OpenApi.Hidi
{
internal static class OpenApiService
{
+ static OpenApiService()
+ {
+ OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
+ OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader());
+ }
+
///
/// Implementation of the transform command
///
@@ -52,7 +59,12 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
{
if (options.Output == null)
{
- var inputExtension = GetInputPathExtension(options.OpenApi, options.Csdl);
+#pragma warning disable CA1308 // Normalize strings to uppercase
+ var extension = options.OpenApiFormat?.GetDisplayName().ToLowerInvariant();
+ var inputExtension = !string.IsNullOrEmpty(extension) ? string.Concat(".", extension)
+ : GetInputPathExtension(options.OpenApi, options.Csdl);
+
+#pragma warning restore CA1308 // Normalize strings to uppercase
options.Output = new($"./output{inputExtension}");
};
@@ -67,7 +79,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
// Default to yaml and OpenApiVersion 3 during csdl to OpenApi conversion
var openApiFormat = options.OpenApiFormat ?? (!string.IsNullOrEmpty(options.OpenApi) ? GetOpenApiFormat(options.OpenApi, logger) : OpenApiFormat.Yaml);
- var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_0;
+ var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_1;
// If ApiManifest is provided, set the referenced OpenAPI document
var apiDependency = await FindApiDependencyAsync(options.FilterOptions.FilterByApiManifest, logger, cancellationToken).ConfigureAwait(false);
@@ -85,7 +97,8 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
}
// Load OpenAPI document
- var document = await GetOpenApiAsync(options, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
+ var format = OpenApiModelFactory.GetFormat(options.OpenApi);
+ var document = await GetOpenApiAsync(options, format, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
if (options.FilterOptions != null)
{
@@ -212,7 +225,7 @@ private static void WriteOpenApi(HidiOptions options, OpenApiFormat openApiForma
}
// Get OpenAPI document either from OpenAPI or CSDL
- private static async Task GetOpenApiAsync(HidiOptions options, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
+ private static async Task GetOpenApiAsync(HidiOptions options, string format, ILogger logger, string? metadataVersion = null, CancellationToken cancellationToken = default)
{
OpenApiDocument document;
Stream stream;
@@ -233,7 +246,7 @@ private static async Task GetOpenApiAsync(HidiOptions options,
await stream.DisposeAsync().ConfigureAwait(false);
}
- document = await ConvertCsdlToOpenApiAsync(filteredStream ?? stream, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false);
+ document = await ConvertCsdlToOpenApiAsync(filteredStream ?? stream, format, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false);
stopwatch.Stop();
logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths.Count);
}
@@ -375,14 +388,16 @@ private static async Task ParseOpenApiAsync(string openApiFile, bool
{
stopwatch.Start();
- result = await new OpenApiStreamReader(new()
- {
+ var settings = new OpenApiReaderSettings
+ {
LoadExternalRefs = inlineExternal,
BaseUrl = openApiFile.StartsWith("http", StringComparison.OrdinalIgnoreCase) ?
new(openApiFile) :
new Uri("file://" + new FileInfo(openApiFile).DirectoryName + Path.DirectorySeparatorChar)
- }
- ).ReadAsync(stream, cancellationToken).ConfigureAwait(false);
+ };
+
+ var format = OpenApiModelFactory.GetFormat(openApiFile);
+ result = await OpenApiDocument.LoadAsync(stream, format, settings, cancellationToken).ConfigureAwait(false);
logger.LogTrace("{Timestamp}ms: Completed parsing.", stopwatch.ElapsedMilliseconds);
@@ -398,7 +413,7 @@ private static async Task ParseOpenApiAsync(string openApiFile, bool
///
/// The CSDL stream.
/// An OpenAPI document.
- public static async Task ConvertCsdlToOpenApiAsync(Stream csdl, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
+ public static async Task ConvertCsdlToOpenApiAsync(Stream csdl, string format, string? metadataVersion = null, IConfiguration? settings = null, CancellationToken token = default)
{
using var reader = new StreamReader(csdl);
var csdlText = await reader.ReadToEndAsync(token).ConfigureAwait(false);
@@ -406,7 +421,7 @@ public static async Task ConvertCsdlToOpenApiAsync(Stream csdl,
settings ??= SettingsUtilities.GetConfiguration();
var document = edmModel.ConvertToOpenApi(SettingsUtilities.GetOpenApiConvertSettings(settings, metadataVersion));
- document = FixReferences(document);
+ document = FixReferences(document, format);
return document;
}
@@ -416,14 +431,15 @@ public static async Task ConvertCsdlToOpenApiAsync(Stream csdl,
///
/// The converted OpenApiDocument.
/// A valid OpenApiDocument instance.
- public static OpenApiDocument FixReferences(OpenApiDocument document)
+ public static OpenApiDocument FixReferences(OpenApiDocument document, string format)
{
// This method is only needed because the output of ConvertToOpenApi isn't quite a valid OpenApiDocument instance.
// So we write it out, and read it back in again to fix it up.
var sb = new StringBuilder();
document.SerializeAsV3(new OpenApiYamlWriter(new StringWriter(sb)));
- var doc = new OpenApiStringReader().Read(sb.ToString(), out _);
+
+ var doc = OpenApiDocument.Parse(sb.ToString(), format).OpenApiDocument;
return doc;
}
@@ -571,7 +587,8 @@ private static string GetInputPathExtension(string? openapi = null, string? csdl
throw new ArgumentException("Please input a file path or URL");
}
- var document = await GetOpenApiAsync(options, logger, null, cancellationToken).ConfigureAwait(false);
+ var format = OpenApiModelFactory.GetFormat(options.OpenApi);
+ var document = await GetOpenApiAsync(options, format, logger, null, cancellationToken).ConfigureAwait(false);
using (logger.BeginScope("Creating diagram"))
{
@@ -732,7 +749,8 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
}
// Load OpenAPI document
- var document = await GetOpenApiAsync(options, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
+ var format = OpenApiModelFactory.GetFormat(options.OpenApi);
+ var document = await GetOpenApiAsync(options, format, logger, options.MetadataVersion, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
@@ -750,7 +768,7 @@ internal static async Task PluginManifestAsync(HidiOptions options, ILogger logg
// Write OpenAPI to Output folder
options.Output = new(Path.Combine(options.OutputFolder, "openapi.json"));
options.TerseOutput = true;
- WriteOpenApi(options, OpenApiFormat.Json, OpenApiSpecVersion.OpenApi3_0, document, logger);
+ WriteOpenApi(options, OpenApiFormat.Json, OpenApiSpecVersion.OpenApi3_1, document, logger);
// Create OpenAIPluginManifest from ApiDependency and OpenAPI document
var manifest = new OpenAIPluginManifest
diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs b/src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs
index 234298481..222f7a8c6 100644
--- a/src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs
+++ b/src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT license.
using System;
-using System.Linq;
namespace Microsoft.OpenApi.Hidi
{
@@ -14,17 +13,30 @@ public static OpenApiSpecVersion TryParseOpenApiSpecVersion(string value)
{
throw new InvalidOperationException("Please provide a version");
}
- var res = value.Split('.', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
+ // Split the version string by the dot
+ var versionSegments = value.Split('.', StringSplitOptions.RemoveEmptyEntries);
- if (int.TryParse(res, out var result))
+ if (!int.TryParse(versionSegments[0], out var majorVersion)
+ || !int.TryParse(versionSegments[1], out var minorVersion))
{
- if (result is >= 2 and < 3)
- {
- return OpenApiSpecVersion.OpenApi2_0;
- }
+ throw new InvalidOperationException("Invalid version format. Please provide a valid OpenAPI version (e.g., 2.0, 3.0, 3.1).");
}
- return OpenApiSpecVersion.OpenApi3_0; // default
+ // Check for specific version matches
+ if (majorVersion == 2)
+ {
+ return OpenApiSpecVersion.OpenApi2_0;
+ }
+ else if (majorVersion == 3 && minorVersion == 0)
+ {
+ return OpenApiSpecVersion.OpenApi3_0;
+ }
+ else if (majorVersion == 3 && minorVersion == 1)
+ {
+ return OpenApiSpecVersion.OpenApi3_1;
+ }
+
+ return OpenApiSpecVersion.OpenApi3_1; // default
}
}
}
diff --git a/src/Microsoft.OpenApi.Hidi/Program.cs b/src/Microsoft.OpenApi.Hidi/Program.cs
index d5846dca9..ddbb96fe9 100644
--- a/src/Microsoft.OpenApi.Hidi/Program.cs
+++ b/src/Microsoft.OpenApi.Hidi/Program.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.CommandLine;
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs b/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs
deleted file mode 100644
index 8991c9b59..000000000
--- a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiReader.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Models;
-
-namespace Microsoft.OpenApi.Readers.Interface
-{
- ///
- /// Interface for Open API readers.
- ///
- /// The type of input to read from.
- /// The type of diagnostic for information from reading process.
- public interface IOpenApiReader where TDiagnostic : IDiagnostic
- {
- ///
- /// Reads the input and parses it into an Open API document.
- ///
- /// The input to read from.
- /// The diagnostic entity containing information from the reading process.
- /// The Open API document.
- OpenApiDocument Read(TInput input, out TDiagnostic diagnostic);
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
index ca868b9b6..68204d9c9 100644
--- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
+++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
@@ -1,9 +1,9 @@
-
+
netstandard2.0
latest
true
- 1.6.22
+ 2.0.0-preview1
OpenAPI.NET Readers for JSON and YAML documents
true
@@ -17,6 +17,12 @@
..\Microsoft.OpenApi.snk
+
+
+
+
+
+
@@ -25,6 +31,7 @@
+
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs
deleted file mode 100644
index c6c8add2f..000000000
--- a/src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Interface;
-
-namespace Microsoft.OpenApi.Readers
-{
- ///
- /// Service class for converting streams into OpenApiDocument instances
- ///
- public class OpenApiStreamReader : IOpenApiReader
- {
- private readonly OpenApiReaderSettings _settings;
-
- ///
- /// Create stream reader with custom settings if desired.
- ///
- ///
- public OpenApiStreamReader(OpenApiReaderSettings settings = null)
- {
- _settings = settings ?? new OpenApiReaderSettings();
-
- if((_settings.ReferenceResolution == ReferenceResolutionSetting.ResolveAllReferences || _settings.LoadExternalRefs)
- && _settings.BaseUrl == null)
- {
- throw new ArgumentException("BaseUrl must be provided to resolve external references.");
- }
- }
-
- ///
- /// Reads the stream input and parses it into an Open API document.
- ///
- /// Stream containing OpenAPI description to parse.
- /// Returns diagnostic object containing errors detected during parsing.
- /// Instance of newly created OpenApiDocument.
- public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
- {
- using var reader = new StreamReader(input, Encoding.UTF8, true, 4096, _settings.LeaveStreamOpen);
- return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
- }
-
- ///
- /// Reads the stream input and parses it into an Open API document.
- ///
- /// Stream containing OpenAPI description to parse.
- /// Cancellation token.
- /// Instance result containing newly created OpenApiDocument and diagnostics object from the process
- public async Task ReadAsync(Stream input, CancellationToken cancellationToken = default)
- {
- MemoryStream bufferedStream;
- int bufferSize = 4096;
- if (input is MemoryStream stream)
- {
- bufferedStream = stream;
- }
- else
- {
- // Buffer stream so that OpenApiTextReaderReader can process it synchronously
- // YamlDocument doesn't support async reading.
- bufferedStream = new();
- bufferSize = 81920;
- await input.CopyToAsync(bufferedStream, bufferSize, cancellationToken);
- bufferedStream.Position = 0;
- }
-
- using var reader = new StreamReader(bufferedStream, Encoding.UTF8, true, bufferSize, _settings.LeaveStreamOpen);
- return await new OpenApiTextReaderReader(_settings).ReadAsync(reader, cancellationToken);
- }
-
- ///
- /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
- ///
- /// Stream containing OpenAPI description to parse.
- /// Version of the OpenAPI specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created OpenApiDocument
- public T ReadFragment(Stream input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiReferenceable
- {
- using var reader = new StreamReader(input, Encoding.UTF8, true, 4096, _settings.LeaveStreamOpen);
- return new OpenApiTextReaderReader(_settings).ReadFragment(reader, version, out diagnostic);
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs
deleted file mode 100644
index 1a694f255..000000000
--- a/src/Microsoft.OpenApi.Readers/OpenApiStringReader.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.IO;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Interface;
-
-namespace Microsoft.OpenApi.Readers
-{
- ///
- /// Service class for converting strings into OpenApiDocument instances
- ///
- public class OpenApiStringReader : IOpenApiReader
- {
- private readonly OpenApiReaderSettings _settings;
-
- ///
- /// Constructor tha allows reader to use non-default settings
- ///
- ///
- public OpenApiStringReader(OpenApiReaderSettings settings = null)
- {
- _settings = settings ?? new OpenApiReaderSettings();
- }
-
- ///
- /// Reads the string input and parses it into an Open API document.
- ///
- public OpenApiDocument Read(string input, out OpenApiDiagnostic diagnostic)
- {
- using var reader = new StringReader(input);
- return new OpenApiTextReaderReader(_settings).Read(reader, out diagnostic);
- }
-
- ///
- /// Reads the string input and parses it into an Open API element.
- ///
- public T ReadFragment(string input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
- {
- using var reader = new StringReader(input);
- return new OpenApiTextReaderReader(_settings).ReadFragment(reader, version, out diagnostic);
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
deleted file mode 100644
index dff20fc7f..000000000
--- a/src/Microsoft.OpenApi.Readers/OpenApiTextReaderReader.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Interface;
-using SharpYaml;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers
-{
- ///
- /// Service class for converting contents of TextReader into OpenApiDocument instances
- ///
- public class OpenApiTextReaderReader : IOpenApiReader
- {
- private readonly OpenApiReaderSettings _settings;
-
- ///
- /// Create stream reader with custom settings if desired.
- ///
- ///
- public OpenApiTextReaderReader(OpenApiReaderSettings settings = null)
- {
- _settings = settings ?? new OpenApiReaderSettings();
- }
-
- ///
- /// Reads the stream input and parses it into an Open API document.
- ///
- /// TextReader containing OpenAPI description to parse.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created OpenApiDocument
- public OpenApiDocument Read(TextReader input, out OpenApiDiagnostic diagnostic)
- {
- YamlDocument yamlDocument;
-
- // Parse the YAML/JSON text in the TextReader into the YamlDocument
- try
- {
- yamlDocument = LoadYamlDocument(input);
- }
- catch (YamlException ex)
- {
- diagnostic = new();
- diagnostic.Errors.Add(new($"#line={ex.Start.Line}", ex.Message));
- return new();
- }
-
- return new OpenApiYamlDocumentReader(this._settings).Read(yamlDocument, out diagnostic);
- }
-
- ///
- /// Reads the content of the TextReader. If there are references to external documents then they will be read asynchronously.
- ///
- /// TextReader containing OpenAPI description to parse.
- /// Cancellation token.
- /// A ReadResult instance that contains the resulting OpenApiDocument and a diagnostics instance.
- public async Task ReadAsync(TextReader input, CancellationToken cancellationToken = default)
- {
- YamlDocument yamlDocument;
-
- // Parse the YAML/JSON text in the TextReader into the YamlDocument
- try
- {
- yamlDocument = LoadYamlDocument(input);
- }
- catch (YamlException ex)
- {
- var diagnostic = new OpenApiDiagnostic();
- diagnostic.Errors.Add(new($"#line={ex.Start.Line}", ex.Message));
- return new()
- {
- OpenApiDocument = null,
- OpenApiDiagnostic = diagnostic
- };
- }
-
- return await new OpenApiYamlDocumentReader(this._settings).ReadAsync(yamlDocument, cancellationToken);
- }
-
- ///
- /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
- ///
- /// TextReader containing OpenAPI description to parse.
- /// Version of the OpenAPI specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created OpenApiDocument
- public T ReadFragment(TextReader input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
- {
- YamlDocument yamlDocument;
-
- // Parse the YAML/JSON
- try
- {
- yamlDocument = LoadYamlDocument(input);
- }
- catch (YamlException ex)
- {
- diagnostic = new();
- diagnostic.Errors.Add(new($"#line={ex.Start.Line}", ex.Message));
- return default;
- }
-
- return new OpenApiYamlDocumentReader(this._settings).ReadFragment(yamlDocument, version, out diagnostic);
- }
-
- ///
- /// Helper method to turn streams into YamlDocument
- ///
- /// Stream containing YAML formatted text
- /// Instance of a YamlDocument
- static YamlDocument LoadYamlDocument(TextReader input)
- {
- var yamlStream = new YamlStream();
- yamlStream.Load(input);
- return yamlStream.Documents.First();
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs
deleted file mode 100644
index af9ebcad1..000000000
--- a/src/Microsoft.OpenApi.Readers/OpenApiYamlDocumentReader.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.OpenApi.Exceptions;
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Interface;
-using Microsoft.OpenApi.Readers.Services;
-using Microsoft.OpenApi.Services;
-using Microsoft.OpenApi.Validations;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers
-{
- ///
- /// Service class for converting contents of TextReader into OpenApiDocument instances
- ///
- internal class OpenApiYamlDocumentReader : IOpenApiReader
- {
- private readonly OpenApiReaderSettings _settings;
-
- ///
- /// Create stream reader with custom settings if desired.
- ///
- ///
- public OpenApiYamlDocumentReader(OpenApiReaderSettings settings = null)
- {
- _settings = settings ?? new OpenApiReaderSettings();
- }
-
- ///
- /// Reads the stream input and parses it into an Open API document.
- ///
- /// TextReader containing OpenAPI description to parse.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created OpenApiDocument
- public OpenApiDocument Read(YamlDocument input, out OpenApiDiagnostic diagnostic)
- {
- diagnostic = new();
- var context = new ParsingContext(diagnostic)
- {
- ExtensionParsers = _settings.ExtensionParsers,
- BaseUrl = _settings.BaseUrl,
- DefaultContentType = _settings.DefaultContentType
- };
-
- OpenApiDocument document = null;
- try
- {
- // Parse the OpenAPI Document
- document = context.Parse(input);
-
- if (_settings.LoadExternalRefs)
- {
- throw new InvalidOperationException("Cannot load external refs using the synchronous Read, use ReadAsync instead.");
- }
-
- ResolveReferences(diagnostic, document);
- }
- catch (OpenApiException ex)
- {
- diagnostic.Errors.Add(new(ex));
- }
-
- // Validate the document
- if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
- {
- var openApiErrors = document.Validate(_settings.RuleSet);
- foreach (var item in openApiErrors.OfType())
- {
- diagnostic.Errors.Add(item);
- }
- foreach (var item in openApiErrors.OfType())
- {
- diagnostic.Warnings.Add(item);
- }
- }
-
- return document;
- }
-
- public async Task ReadAsync(YamlDocument input, CancellationToken cancellationToken = default)
- {
- var diagnostic = new OpenApiDiagnostic();
- var context = new ParsingContext(diagnostic)
- {
- ExtensionParsers = _settings.ExtensionParsers,
- BaseUrl = _settings.BaseUrl
- };
-
- OpenApiDocument document = null;
- try
- {
- // Parse the OpenAPI Document
- document = context.Parse(input);
-
- if (_settings.LoadExternalRefs)
- {
- var diagnosticExternalRefs = await LoadExternalRefsAsync(document, cancellationToken);
- // Merge diagnostics of external reference
- if (diagnosticExternalRefs != null)
- {
- diagnostic.Errors.AddRange(diagnosticExternalRefs.Errors);
- diagnostic.Warnings.AddRange(diagnosticExternalRefs.Warnings);
- }
- }
-
- ResolveReferences(diagnostic, document);
- }
- catch (OpenApiException ex)
- {
- diagnostic.Errors.Add(new(ex));
- }
-
- // Validate the document
- if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
- {
- var openApiErrors = document.Validate(_settings.RuleSet);
- foreach (var item in openApiErrors.OfType())
- {
- diagnostic.Errors.Add(item);
- }
- foreach (var item in openApiErrors.OfType())
- {
- diagnostic.Warnings.Add(item);
- }
- }
-
- return new()
- {
- OpenApiDocument = document,
- OpenApiDiagnostic = diagnostic
- };
- }
-
- private Task LoadExternalRefsAsync(OpenApiDocument document, CancellationToken cancellationToken = default)
- {
- // Create workspace for all documents to live in.
- var openApiWorkSpace = new OpenApiWorkspace();
-
- // Load this root document into the workspace
- var streamLoader = new DefaultStreamLoader(_settings.BaseUrl);
- var workspaceLoader = new OpenApiWorkspaceLoader(openApiWorkSpace, _settings.CustomExternalLoader ?? streamLoader, _settings);
- return workspaceLoader.LoadAsync(new() { ExternalResource = "/" }, document, null, cancellationToken);
- }
-
- private void ResolveReferences(OpenApiDiagnostic diagnostic, OpenApiDocument document)
- {
- var errors = new List();
-
- // Resolve References if requested
- switch (_settings.ReferenceResolution)
- {
- case ReferenceResolutionSetting.ResolveAllReferences:
- throw new ArgumentException("Resolving external references is not supported");
- case ReferenceResolutionSetting.ResolveLocalReferences:
- errors.AddRange(document.ResolveReferences());
- break;
- case ReferenceResolutionSetting.DoNotResolveReferences:
- break;
- }
-
- foreach (var item in errors)
- {
- diagnostic.Errors.Add(item);
- }
- }
-
- ///
- /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
- ///
- /// TextReader containing OpenAPI description to parse.
- /// Version of the OpenAPI specification that the fragment conforms to.
- /// Returns diagnostic object containing errors detected during parsing
- /// Instance of newly created OpenApiDocument
- public T ReadFragment(YamlDocument input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic) where T : IOpenApiElement
- {
- diagnostic = new();
- var context = new ParsingContext(diagnostic)
- {
- ExtensionParsers = _settings.ExtensionParsers
- };
-
- IOpenApiElement element = null;
- try
- {
- // Parse the OpenAPI element
- element = context.ParseFragment(input, version);
- }
- catch (OpenApiException ex)
- {
- diagnostic.Errors.Add(new(ex));
- }
-
- // Validate the element
- if (_settings.RuleSet != null && _settings.RuleSet.Rules.Count > 0)
- {
- var errors = element.Validate(_settings.RuleSet);
- foreach (var item in errors)
- {
- diagnostic.Errors.Add(item);
- }
- }
-
- return (T)element;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs
new file mode 100644
index 000000000..cff6dd1da
--- /dev/null
+++ b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.IO;
+using System.Text.Json.Nodes;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Reader;
+using SharpYaml.Serialization;
+using System.Linq;
+using Microsoft.OpenApi.Models;
+
+namespace Microsoft.OpenApi.Readers
+{
+ ///
+ /// Reader for parsing YAML files into an OpenAPI document.
+ ///
+ public class OpenApiYamlReader : IOpenApiReader
+ {
+ ///
+ public async Task ReadAsync(TextReader input,
+ OpenApiReaderSettings settings = null,
+ CancellationToken cancellationToken = default)
+ {
+ JsonNode jsonNode;
+
+ // Parse the YAML text in the TextReader into a sequence of JsonNodes
+ try
+ {
+ jsonNode = LoadJsonNodesFromYamlDocument(input);
+ }
+ catch (JsonException ex)
+ {
+ var diagnostic = new OpenApiDiagnostic();
+ diagnostic.Errors.Add(new($"#line={ex.LineNumber}", ex.Message));
+ return new()
+ {
+ OpenApiDocument = null,
+ OpenApiDiagnostic = diagnostic
+ };
+ }
+
+ return await ReadAsync(jsonNode, settings, cancellationToken: cancellationToken);
+ }
+
+ ///
+ public T ReadFragment(TextReader input,
+ OpenApiSpecVersion version,
+ out OpenApiDiagnostic diagnostic,
+ OpenApiReaderSettings settings = null) where T : IOpenApiElement
+ {
+ JsonNode jsonNode;
+
+ // Parse the YAML
+ try
+ {
+ jsonNode = LoadJsonNodesFromYamlDocument(input);
+ }
+ catch (JsonException ex)
+ {
+ diagnostic = new();
+ diagnostic.Errors.Add(new($"#line={ex.LineNumber}", ex.Message));
+ return default;
+ }
+
+ return ReadFragment(jsonNode, version, out diagnostic);
+ }
+
+ ///
+ /// Helper method to turn streams into a sequence of JsonNodes
+ ///
+ /// Stream containing YAML formatted text
+ /// Instance of a YamlDocument
+ static JsonNode LoadJsonNodesFromYamlDocument(TextReader input)
+ {
+ var yamlStream = new YamlStream();
+ yamlStream.Load(input);
+ var yamlDocument = yamlStream.Documents.First();
+ return yamlDocument.ToJsonNode();
+ }
+
+ ///
+ public async Task ReadAsync(JsonNode jsonNode, OpenApiReaderSettings settings, string format = null, CancellationToken cancellationToken = default)
+ {
+ return await OpenApiReaderRegistry.DefaultReader.ReadAsync(jsonNode, settings, OpenApiConstants.Yaml, cancellationToken);
+ }
+
+ ///
+ public T ReadFragment(JsonNode input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement
+ {
+ return OpenApiReaderRegistry.DefaultReader.ReadFragment(input, version, out diagnostic);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs
deleted file mode 100644
index 412d6901b..000000000
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/JsonPointerExtensions.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers.ParseNodes
-{
- ///
- /// Extensions for JSON pointers.
- ///
- public static class JsonPointerExtensions
- {
- ///
- /// Finds the YAML node that corresponds to this JSON pointer based on the base YAML node.
- ///
- public static YamlNode Find(this JsonPointer currentPointer, YamlNode baseYamlNode)
- {
- if (currentPointer.Tokens.Length == 0)
- {
- return baseYamlNode;
- }
-
- try
- {
- var pointer = baseYamlNode;
- foreach (var token in currentPointer.Tokens)
- {
- if (pointer is YamlSequenceNode sequence)
- {
- pointer = sequence.Children[Convert.ToInt32(token)];
- }
- else
- {
- if (pointer is YamlMappingNode map)
- {
- if (!map.Children.TryGetValue(new YamlScalarNode(token), out pointer))
- {
- return null;
- }
- }
- }
- }
-
- return pointer;
- }
- catch (Exception)
- {
- return null;
- }
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs
deleted file mode 100644
index 61f609817..000000000
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/MapNode.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Exceptions;
-using SharpYaml.Schemas;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers.ParseNodes
-{
- ///
- /// Abstraction of a Map to isolate semantic parsing from details of
- ///
- internal class MapNode : ParseNode, IEnumerable
- {
- private readonly YamlMappingNode _node;
- private readonly List _nodes;
-
- public MapNode(ParsingContext context, string yamlString) :
- this(context, (YamlMappingNode)YamlHelper.ParseYamlString(yamlString))
- {
- }
-
- public MapNode(ParsingContext context, YamlNode node) : base(
- context)
- {
- if (node is not YamlMappingNode mapNode)
- {
- throw new OpenApiReaderException("Expected map.", Context);
- }
-
- this._node = mapNode;
-
- _nodes = this._node.Children
- .Select(kvp => new PropertyNode(Context, kvp.Key.GetScalarValue(), kvp.Value))
- .Cast()
- .ToList();
- }
-
- public PropertyNode this[string key]
- {
- get
- {
- if (this._node.Children.TryGetValue(new YamlScalarNode(key), out var node))
- {
- return new(Context, key, node);
- }
-
- return null;
- }
- }
-
- public override Dictionary CreateMap(Func map)
- {
- var yamlMap = _node;
- if (yamlMap == null)
- {
- throw new OpenApiReaderException($"Expected map while parsing {typeof(T).Name}", Context);
- }
-
- var nodes = yamlMap.Select(
- n =>
- {
- var key = n.Key.GetScalarValue();
- T value;
- try
- {
- Context.StartObject(key);
- value = n.Value as YamlMappingNode == null
- ? default
- : map(new(Context, n.Value as YamlMappingNode));
- }
- finally
- {
- Context.EndObject();
- }
- return new
- {
- key = key,
- value = value
- };
- });
-
- return nodes.ToDictionary(k => k.key, v => v.value);
- }
-
- public override Dictionary CreateMapWithReference(
- ReferenceType referenceType,
- Func map)
- {
- var yamlMap = _node;
- if (yamlMap == null)
- {
- throw new OpenApiReaderException($"Expected map while parsing {typeof(T).Name}", Context);
- }
-
- var nodes = yamlMap.Select(
- n =>
- {
- var key = n.Key.GetScalarValue();
- (string key, T value) entry;
- try
- {
- Context.StartObject(key);
- entry = (
- key: key,
- value: map(new(Context, (YamlMappingNode)n.Value))
- );
- if (entry.value == null)
- {
- return default; // Body Parameters shouldn't be converted to Parameters
- }
- // If the component isn't a reference to another component, then point it to itself.
- if (entry.value.Reference == null)
- {
- entry.value.Reference = new()
- {
- Type = referenceType,
- Id = entry.key
- };
- }
- }
- finally
- {
- Context.EndObject();
- }
- return entry;
- }
- );
- return nodes.Where(n => n != default).ToDictionary(k => k.key, v => v.value);
- }
-
- public override Dictionary CreateSimpleMap(Func map)
- {
- var yamlMap = _node;
- if (yamlMap == null)
- {
- throw new OpenApiReaderException($"Expected map while parsing {typeof(T).Name}", Context);
- }
-
- var nodes = yamlMap.Select(
- n =>
- {
- var key = n.Key.GetScalarValue();
- try
- {
- Context.StartObject(key);
- if (n.Value is not YamlScalarNode scalarNode)
- {
- throw new OpenApiReaderException($"Expected scalar while parsing {typeof(T).Name}", Context);
- }
- return (key, value: map(new(Context, (YamlScalarNode)n.Value)));
- } finally {
- Context.EndObject();
- }
- });
- return nodes.ToDictionary(k => k.key, v => v.value);
- }
-
- public IEnumerator GetEnumerator()
- {
- return _nodes.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return _nodes.GetEnumerator();
- }
-
- public override string GetRaw()
- {
- var x = new Serializer(new(new JsonSchema()) { EmitJsonComptible = true });
- return x.Serialize(_node);
- }
-
- public T GetReferencedObject(ReferenceType referenceType, string referenceId)
- where T : IOpenApiReferenceable, new()
- {
- return new()
- {
- UnresolvedReference = true,
- Reference = Context.VersionService.ConvertToOpenApiReference(referenceId, referenceType)
- };
- }
-
- public string GetReferencePointer()
- {
- if (!_node.Children.TryGetValue(new YamlScalarNode("$ref"), out var refNode))
- {
- return null;
- }
-
- return refNode.GetScalarValue();
- }
-
- public string GetScalarValue(ValueNode key)
- {
- if (_node.Children[new YamlScalarNode(key.GetScalarValue())] is not YamlScalarNode scalarNode)
- {
- throw new OpenApiReaderException($"Expected scalar at line {_node.Start.Line} for key {key.GetScalarValue()}", Context);
- }
-
- return scalarNode.Value;
- }
-
- ///
- /// Create a
- ///
- /// The created Any object.
- public override IOpenApiAny CreateAny()
- {
- var apiObject = new OpenApiObject();
- foreach (var node in this)
- {
- apiObject.Add(node.Name, node.Value.CreateAny());
- }
-
- return apiObject;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs
deleted file mode 100644
index 2c0a45379..000000000
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/OpenApiAnyConverter.cs
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Models;
-
-namespace Microsoft.OpenApi.Readers.ParseNodes
-{
- internal static class OpenApiAnyConverter
- {
- ///
- /// Converts the s in the given
- /// into the appropriate type based on the given .
- /// For those strings that the schema does not specify the type for, convert them into
- /// the most specific type based on the value.
- ///
- public static IOpenApiAny GetSpecificOpenApiAny(IOpenApiAny openApiAny, OpenApiSchema schema = null)
- {
- if (openApiAny is OpenApiArray openApiArray)
- {
- var newArray = new OpenApiArray();
- foreach (var element in openApiArray)
- {
- newArray.Add(GetSpecificOpenApiAny(element, schema?.Items));
- }
-
- return newArray;
- }
-
- if (openApiAny is OpenApiObject openApiObject)
- {
- var newObject = new OpenApiObject();
-
- foreach (var key in openApiObject.Keys.ToList())
- {
- if (schema?.Properties != null && schema.Properties.TryGetValue(key, out var property))
- {
- newObject[key] = GetSpecificOpenApiAny(openApiObject[key], property);
- }
- else
- {
- newObject[key] = GetSpecificOpenApiAny(openApiObject[key], schema?.AdditionalProperties);
- }
- }
-
- return newObject;
- }
-
- if (openApiAny is not OpenApiString apiString)
- {
- return openApiAny;
- }
-
- var value = apiString.Value;
- var type = schema?.Type;
- var format = schema?.Format;
-
- if (apiString.IsExplicit())
- {
- // More narrow type detection for explicit strings, only check types that are passed as strings
- if (schema == null)
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- // if the time component is exactly midnight(00:00:00) meaning no time has elapsed, return a date-only value
- return dateTimeValue.TimeOfDay == TimeSpan.Zero ? new OpenApiDate(dateTimeValue.Date)
- : new OpenApiDateTime(dateTimeValue);
- }
- }
- else if (type == "string")
- {
- if (format == "byte")
- {
- try
- {
- return new OpenApiByte(Convert.FromBase64String(value));
- }
- catch (FormatException)
- { }
- }
-
- if (format == "binary")
- {
- try
- {
- return new OpenApiBinary(Encoding.UTF8.GetBytes(value));
- }
- catch (EncoderFallbackException)
- { }
- }
-
- if (format == "date")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
- {
- return new OpenApiDate(dateValue.Date);
- }
- }
-
- if (format == "date-time")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new OpenApiDateTime(dateTimeValue);
- }
- }
-
- if (format == "password")
- {
- return new OpenApiPassword(value);
- }
- }
-
- return apiString;
- }
-
- if (value is null or "null")
- {
- return new OpenApiNull();
- }
-
- if (schema?.Type == null)
- {
- if (value == "true")
- {
- return new OpenApiBoolean(true);
- }
-
- if (value == "false")
- {
- return new OpenApiBoolean(false);
- }
-
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new OpenApiInteger(intValue);
- }
-
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
- {
- return new OpenApiLong(longValue);
- }
-
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new OpenApiDouble(doubleValue);
- }
-
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new OpenApiDateTime(dateTimeValue);
- }
- }
- else
- {
- if (type is "integer" or "number" && format == "int32")
- {
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new OpenApiInteger(intValue);
- }
- }
-
- if (type is "integer" or "number" && format == "int64")
- {
- if (long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longValue))
- {
- return new OpenApiLong(longValue);
- }
- }
-
- if (type == "integer")
- {
- if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
- {
- return new OpenApiInteger(intValue);
- }
- }
-
- if (type == "number" && format == "float")
- {
- if (float.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var floatValue))
- {
- return new OpenApiFloat(floatValue);
- }
- }
-
- if (type == "number" && format == "double")
- {
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new OpenApiDouble(doubleValue);
- }
- }
-
- if (type == "number")
- {
- if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
- {
- return new OpenApiDouble(doubleValue);
- }
- }
-
- if (type == "string" && format == "byte")
- {
- try
- {
- return new OpenApiByte(Convert.FromBase64String(value));
- }
- catch (FormatException)
- { }
- }
-
- // binary
- if (type == "string" && format == "binary")
- {
- try
- {
- return new OpenApiBinary(Encoding.UTF8.GetBytes(value));
- }
- catch (EncoderFallbackException)
- { }
- }
-
- if (type == "string" && format == "date")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
- {
- return new OpenApiDate(dateValue.Date);
- }
- }
-
- if (type == "string" && format == "date-time")
- {
- if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateTimeValue))
- {
- return new OpenApiDateTime(dateTimeValue);
- }
- }
-
- if (type == "string" && format == "password")
- {
- return new OpenApiPassword(value);
- }
-
- if (type == "string")
- {
- return apiString;
- }
-
- if (type == "boolean")
- {
- if (bool.TryParse(value, out var booleanValue))
- {
- return new OpenApiBoolean(booleanValue);
- }
- }
- }
-
- // If data conflicts with the given type, return a string.
- // This converter is used in the parser, so it does not perform any validations,
- // but the validator can be used to validate whether the data and given type conflicts.
- return apiString;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs
deleted file mode 100644
index f70b9ca99..000000000
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/RootNode.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers.ParseNodes
-{
- ///
- /// Wrapper class around YamlDocument to isolate semantic parsing from details of Yaml DOM.
- ///
- internal class RootNode : ParseNode
- {
- private readonly YamlDocument _yamlDocument;
-
- public RootNode(
- ParsingContext context,
- YamlDocument yamlDocument) : base(context)
- {
- _yamlDocument = yamlDocument;
- }
-
- public ParseNode Find(JsonPointer referencePointer)
- {
- var yamlNode = referencePointer.Find(_yamlDocument.RootNode);
- if (yamlNode == null)
- {
- return null;
- }
-
- return Create(Context, yamlNode);
- }
-
- public MapNode GetMap()
- {
- return new(Context, (YamlMappingNode)_yamlDocument.RootNode);
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs b/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs
deleted file mode 100644
index 1aeccb8e7..000000000
--- a/src/Microsoft.OpenApi.Readers/ParseNodes/ValueNode.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Readers.Exceptions;
-using SharpYaml;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers.ParseNodes
-{
- internal class ValueNode : ParseNode
- {
- private readonly YamlScalarNode _node;
-
- public ValueNode(ParsingContext context, YamlNode node) : base(
- context)
- {
- if (node is not YamlScalarNode scalarNode)
- {
- throw new OpenApiReaderException("Expected a value.", node);
- }
- _node = scalarNode;
- }
-
- public override string GetScalarValue()
- {
- return _node.Value;
- }
-
- ///
- /// Create a
- ///
- /// The created Any object.
- public override IOpenApiAny CreateAny()
- {
- var value = GetScalarValue();
- return new OpenApiString(value, this._node.Style is ScalarStyle.SingleQuoted or ScalarStyle.DoubleQuoted or ScalarStyle.Literal or ScalarStyle.Folded);
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/Properties/SRResource.Designer.cs b/src/Microsoft.OpenApi.Readers/Properties/SRResource.Designer.cs
index e8bbc567e..a35dab766 100644
--- a/src/Microsoft.OpenApi.Readers/Properties/SRResource.Designer.cs
+++ b/src/Microsoft.OpenApi.Readers/Properties/SRResource.Designer.cs
@@ -8,7 +8,7 @@
//
//------------------------------------------------------------------------------
-namespace Microsoft.OpenApi.Readers.Properties {
+namespace Microsoft.OpenApi.Reader.Properties {
using System;
@@ -19,7 +19,7 @@ namespace Microsoft.OpenApi.Readers.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class SRResource {
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs
deleted file mode 100644
index ff873f4a0..000000000
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiHeaderDeserializer.cs
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Globalization;
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.Exceptions;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V2
-{
- ///
- /// Class containing logic to deserialize Open API V2 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV2Deserializer
- {
- private static readonly FixedFieldMap _headerFixedFields = new()
- {
- {
- "description",
- (o, n) => o.Description = n.GetScalarValue()
- },
- {
- "type",
- (o, n) => GetOrCreateSchema(o).Type = n.GetScalarValue()
- },
- {
- "format",
- (o, n) => GetOrCreateSchema(o).Format = n.GetScalarValue()
- },
- {
- "items",
- (o, n) => GetOrCreateSchema(o).Items = LoadSchema(n)
- },
- {
- "collectionFormat",
- (o, n) => LoadStyle(o, n.GetScalarValue())
- },
- {
- "default",
- (o, n) => GetOrCreateSchema(o).Default = n.CreateAny()
- },
- {
- "maximum",
- (o, n) => GetOrCreateSchema(o).Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
- },
- {
- "exclusiveMaximum",
- (o, n) => GetOrCreateSchema(o).ExclusiveMaximum = bool.Parse(n.GetScalarValue())
- },
- {
- "minimum",
- (o, n) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
- },
- {
- "exclusiveMinimum",
- (o, n) => GetOrCreateSchema(o).ExclusiveMinimum = bool.Parse(n.GetScalarValue())
- },
- {
- "maxLength",
- (o, n) => GetOrCreateSchema(o).MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minLength",
- (o, n) => GetOrCreateSchema(o).MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "pattern",
- (o, n) => GetOrCreateSchema(o).Pattern = n.GetScalarValue()
- },
- {
- "maxItems",
- (o, n) => GetOrCreateSchema(o).MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minItems",
- (o, n) => GetOrCreateSchema(o).MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "uniqueItems",
- (o, n) => GetOrCreateSchema(o).UniqueItems = bool.Parse(n.GetScalarValue())
- },
- {
- "multipleOf",
- (o, n) => GetOrCreateSchema(o).MultipleOf = decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "enum",
- (o, n) => GetOrCreateSchema(o).Enum = n.CreateListOfAny()
- }
- };
-
- private static readonly PatternFieldMap _headerPatternFields = new()
- {
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p, n))}
- };
-
- private static readonly AnyFieldMap _headerAnyFields =
- new()
- {
- {
- OpenApiConstants.Default,
- new(
- p => p.Schema?.Default,
- (p, v) =>
- {
- if(p.Schema == null) return;
- p.Schema.Default = v;
- },
- p => p.Schema)
- }
- };
-
- private static readonly AnyListFieldMap _headerAnyListFields =
- new()
- {
- {
- OpenApiConstants.Enum,
- new(
- p => p.Schema?.Enum,
- (p, v) =>
- {
- if(p.Schema == null) return;
- p.Schema.Enum = v;
- },
- p => p.Schema)
- },
- };
-
- public static OpenApiHeader LoadHeader(ParseNode node)
- {
- var mapNode = node.CheckMapNode("header");
- var header = new OpenApiHeader();
- foreach (var property in mapNode)
- {
- property.ParseField(header, _headerFixedFields, _headerPatternFields);
- }
-
- var schema = node.Context.GetFromTempStorage("schema");
- if (schema != null)
- {
- header.Schema = schema;
- node.Context.SetTempStorage("schema", null);
- }
-
- ProcessAnyFields(mapNode, header, _headerAnyFields);
- ProcessAnyListFields(mapNode, header, _headerAnyListFields);
-
- return header;
- }
-
- private static void LoadStyle(OpenApiHeader header, string style)
- {
- switch (style)
- {
- case "csv":
- header.Style = ParameterStyle.Simple;
- return;
- case "ssv":
- header.Style = ParameterStyle.SpaceDelimited;
- return;
- case "pipes":
- header.Style = ParameterStyle.PipeDelimited;
- return;
- case "tsv":
- throw new NotSupportedException();
- default:
- throw new OpenApiReaderException("Unrecognized header style: " + style);
- }
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiSchemaDeserializer.cs
deleted file mode 100644
index dd884d574..000000000
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiSchemaDeserializer.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.Collections.Generic;
-using System.Globalization;
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V2
-{
- ///
- /// Class containing logic to deserialize Open API V2 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV2Deserializer
- {
- private static readonly FixedFieldMap _schemaFixedFields = new()
- {
- {
- "title",
- (o, n) => o.Title = n.GetScalarValue()
- },
- {
- "multipleOf",
- (o, n) => o.MultipleOf = decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)
- },
- {
- "maximum",
- (o, n) => o.Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
- },
- {
- "exclusiveMaximum",
- (o, n) => o.ExclusiveMaximum = bool.Parse(n.GetScalarValue())
- },
- {
- "minimum",
- (o, n) => o.Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
- },
- {
- "exclusiveMinimum",
- (o, n) => o.ExclusiveMinimum = bool.Parse(n.GetScalarValue())
- },
- {
- "maxLength",
- (o, n) => o.MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minLength",
- (o, n) => o.MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "pattern",
- (o, n) => o.Pattern = n.GetScalarValue()
- },
- {
- "maxItems",
- (o, n) => o.MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minItems",
- (o, n) => o.MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "uniqueItems",
- (o, n) => o.UniqueItems = bool.Parse(n.GetScalarValue())
- },
- {
- "maxProperties",
- (o, n) => o.MaxProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minProperties",
- (o, n) => o.MinProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "required",
- (o, n) => o.Required = new HashSet(n.CreateSimpleList(n2 => n2.GetScalarValue()))
- },
- {
- "enum",
- (o, n) => o.Enum = n.CreateListOfAny()
- },
-
- {
- "type",
- (o, n) => o.Type = n.GetScalarValue()
- },
- {
- "allOf",
- (o, n) => o.AllOf = n.CreateList(LoadSchema)
- },
- {
- "items",
- (o, n) => o.Items = LoadSchema(n)
- },
- {
- "properties",
- (o, n) => o.Properties = n.CreateMap(LoadSchema)
- },
- {
- "additionalProperties", (o, n) =>
- {
- if (n is ValueNode)
- {
- o.AdditionalPropertiesAllowed = bool.Parse(n.GetScalarValue());
- }
- else
- {
- o.AdditionalProperties = LoadSchema(n);
- }
- }
- },
- {
- "description",
- (o, n) => o.Description = n.GetScalarValue()
- },
- {
- "format",
- (o, n) => o.Format = n.GetScalarValue()
- },
- {
- "default",
- (o, n) => o.Default = n.CreateAny()
- },
- {
- "discriminator", (o, n) =>
- {
- o.Discriminator = new()
- {
- PropertyName = n.GetScalarValue()
- };
- }
- },
- {
- "readOnly",
- (o, n) => o.ReadOnly = bool.Parse(n.GetScalarValue())
- },
- {
- "xml",
- (o, n) => o.Xml = LoadXml(n)
- },
- {
- "externalDocs",
- (o, n) => o.ExternalDocs = LoadExternalDocs(n)
- },
- {
- "example",
- (o, n) => o.Example = n.CreateAny()
- },
- };
-
- private static readonly PatternFieldMap _schemaPatternFields = new()
- {
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p, n))}
- };
-
- private static readonly AnyFieldMap _schemaAnyFields = new()
- {
- {
- OpenApiConstants.Default,
- new(
- s => s.Default,
- (s, v) => s.Default = v,
- s => s)
- },
- {
- OpenApiConstants.Example,
- new(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s) }
- };
-
- private static readonly AnyListFieldMap _schemaAnyListFields = new()
- {
- {
- OpenApiConstants.Enum,
- new(
- s => s.Enum,
- (s, v) => s.Enum = v,
- s => s)
- }
- };
-
- public static OpenApiSchema LoadSchema(ParseNode node)
- {
- var mapNode = node.CheckMapNode("schema");
-
- var pointer = mapNode.GetReferencePointer();
- if (pointer != null)
- {
- return mapNode.GetReferencedObject(ReferenceType.Schema, pointer);
- }
-
- var schema = new OpenApiSchema();
-
- foreach (var propertyNode in mapNode)
- {
- propertyNode.ParseField(schema, _schemaFixedFields, _schemaPatternFields);
- }
-
- ProcessAnyFields(mapNode, schema, _schemaAnyFields);
- ProcessAnyListFields(mapNode, schema, _schemaAnyListFields);
-
- return schema;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs b/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs
deleted file mode 100644
index 790940759..000000000
--- a/src/Microsoft.OpenApi.Readers/V2/OpenApiV2Deserializer.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.OpenApi.Any;
-using Microsoft.OpenApi.Exceptions;
-using Microsoft.OpenApi.Interfaces;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V2
-{
- ///
- /// Class containing logic to deserialize Open API V2 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV2Deserializer
- {
- private static void ParseMap(
- MapNode mapNode,
- T domainObject,
- FixedFieldMap fixedFieldMap,
- PatternFieldMap patternFieldMap,
- List requiredFields = null)
- {
- if (mapNode == null)
- {
- return;
- }
-
- var allFields = fixedFieldMap.Keys.Union(mapNode.Select(static x => x.Name));
- foreach (var propertyNode in allFields)
- {
- mapNode[propertyNode]?.ParseField(domainObject, fixedFieldMap, patternFieldMap);
- requiredFields?.Remove(propertyNode);
- }
- }
-
- private static void ProcessAnyFields(
- MapNode mapNode,
- T domainObject,
- AnyFieldMap anyFieldMap)
- {
- foreach (var anyFieldName in anyFieldMap.Keys.ToList())
- {
- try
- {
- mapNode.Context.StartObject(anyFieldName);
-
- var convertedOpenApiAny = OpenApiAnyConverter.GetSpecificOpenApiAny(
- anyFieldMap[anyFieldName].PropertyGetter(domainObject),
- anyFieldMap[anyFieldName].SchemaGetter(domainObject));
-
- anyFieldMap[anyFieldName].PropertySetter(domainObject, convertedOpenApiAny);
- }
- catch (OpenApiException exception)
- {
- exception.Pointer = mapNode.Context.GetLocation();
- mapNode.Context.Diagnostic.Errors.Add(new(exception));
- }
- finally
- {
- mapNode.Context.EndObject();
- }
- }
- }
-
- private static void ProcessAnyListFields(
- MapNode mapNode,
- T domainObject,
- AnyListFieldMap anyListFieldMap)
- {
- foreach (var anyListFieldName in anyListFieldMap.Keys.ToList())
- {
- try
- {
- var newProperty = new List();
-
- mapNode.Context.StartObject(anyListFieldName);
- if (anyListFieldMap.TryGetValue(anyListFieldName, out var fieldName))
- {
- var list = fieldName.PropertyGetter(domainObject);
- if (list != null)
- {
- foreach (var propertyElement in list)
- {
- newProperty.Add(
- OpenApiAnyConverter.GetSpecificOpenApiAny(
- propertyElement,
- anyListFieldMap[anyListFieldName].SchemaGetter(domainObject)));
- }
- }
- }
-
- anyListFieldMap[anyListFieldName].PropertySetter(domainObject, newProperty);
- }
- catch (OpenApiException exception)
- {
- exception.Pointer = mapNode.Context.GetLocation();
- mapNode.Context.Diagnostic.Errors.Add(new(exception));
- }
- finally
- {
- mapNode.Context.EndObject();
- }
- }
- }
-
- public static IOpenApiAny LoadAny(ParseNode node)
- {
- return OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny());
- }
-
- private static IOpenApiExtension LoadExtension(string name, ParseNode node)
- {
- if (node.Context.ExtensionParsers.TryGetValue(name, out var parser) && parser(
- OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny()),
- OpenApiSpecVersion.OpenApi2_0) is { } result)
- {
- return result;
- }
- else
- {
- return OpenApiAnyConverter.GetSpecificOpenApiAny(node.CreateAny());
- }
- }
-
- private static string LoadString(ParseNode node)
- {
- return node.GetScalarValue();
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs
deleted file mode 100644
index 62ed95fda..000000000
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiComponentsDeserializer.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V3
-{
- ///
- /// Class containing logic to deserialize Open API V3 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV3Deserializer
- {
- private static FixedFieldMap _componentsFixedFields = new()
- {
- {
- "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)},
- {"requestBodies", (o, n) => o.RequestBodies = n.CreateMapWithReference(ReferenceType.RequestBody, LoadRequestBody)},
- {"headers", (o, n) => o.Headers = n.CreateMapWithReference(ReferenceType.Header, LoadHeader)},
- {"securitySchemes", (o, n) => o.SecuritySchemes = n.CreateMapWithReference(ReferenceType.SecurityScheme, LoadSecurityScheme)},
- {"links", (o, n) => o.Links = n.CreateMapWithReference(ReferenceType.Link, LoadLink)},
- {"callbacks", (o, n) => o.Callbacks = n.CreateMapWithReference(ReferenceType.Callback, LoadCallback)},
- };
-
- private static PatternFieldMap _componentsPatternFields =
- new()
- {
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p, n))}
- };
-
- public static OpenApiComponents LoadComponents(ParseNode node)
- {
- var mapNode = node.CheckMapNode("components");
- var components = new OpenApiComponents();
-
- ParseMap(mapNode, components, _componentsFixedFields, _componentsPatternFields);
-
- return components;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiDocumentDeserializer.cs
deleted file mode 100644
index edeca23ad..000000000
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiDocumentDeserializer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V3
-{
- ///
- /// Class containing logic to deserialize Open API V3 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV3Deserializer
- {
- private static FixedFieldMap _openApiFixedFields = new()
- {
- {
- "openapi", (_, _) =>
- {
- } /* Version is valid field but we already parsed it */
- },
- {"info", (o, n) => o.Info = LoadInfo(n)},
- {"servers", (o, n) => o.Servers = n.CreateList(LoadServer)},
- {"paths", (o, n) => o.Paths = LoadPaths(n)},
- {"components", (o, n) => o.Components = LoadComponents(n)},
- {"tags", (o, n) => {o.Tags = n.CreateList(LoadTag);
- foreach (var tag in o.Tags)
- {
- tag.Reference = new()
- {
- Id = tag.Name,
- Type = ReferenceType.Tag
- };
- }
- } },
- {"externalDocs", (o, n) => o.ExternalDocs = LoadExternalDocs(n)},
- {"security", (o, n) => o.SecurityRequirements = n.CreateList(LoadSecurityRequirement)}
- };
-
- private static PatternFieldMap _openApiPatternFields = new()
- {
- // We have no semantics to verify X- nodes, therefore treat them as just values.
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p, n))}
- };
-
- public static OpenApiDocument LoadOpenApi(RootNode rootNode)
- {
- var openApidoc = new OpenApiDocument();
-
- var openApiNode = rootNode.GetMap();
-
- ParseMap(openApiNode, openApidoc, _openApiFixedFields, _openApiPatternFields);
-
- return openApidoc;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiPathItemDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiPathItemDeserializer.cs
deleted file mode 100644
index f4ab2ad3b..000000000
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiPathItemDeserializer.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
-
-namespace Microsoft.OpenApi.Readers.V3
-{
- ///
- /// Class containing logic to deserialize Open API V3 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV3Deserializer
- {
- private static readonly FixedFieldMap _pathItemFixedFields = new()
- {
- {
- "$ref", (o,n) => {
- o.Reference = new() { ExternalResource = n.GetScalarValue() };
- o.UnresolvedReference =true;
- }
- },
- {
- "summary",
- (o, n) => o.Summary = n.GetScalarValue()
- },
- {
- "description",
- (o, n) => o.Description = n.GetScalarValue()
- },
- {"get", (o, n) => o.AddOperation(OperationType.Get, LoadOperation(n))},
- {"put", (o, n) => o.AddOperation(OperationType.Put, LoadOperation(n))},
- {"post", (o, n) => o.AddOperation(OperationType.Post, LoadOperation(n))},
- {"delete", (o, n) => o.AddOperation(OperationType.Delete, LoadOperation(n))},
- {"options", (o, n) => o.AddOperation(OperationType.Options, LoadOperation(n))},
- {"head", (o, n) => o.AddOperation(OperationType.Head, LoadOperation(n))},
- {"patch", (o, n) => o.AddOperation(OperationType.Patch, LoadOperation(n))},
- {"trace", (o, n) => o.AddOperation(OperationType.Trace, LoadOperation(n))},
- {"servers", (o, n) => o.Servers = n.CreateList(LoadServer)},
- {"parameters", (o, n) => o.Parameters = n.CreateList(LoadParameter)}
- };
-
- private static readonly PatternFieldMap _pathItemPatternFields =
- new()
- {
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p,n))}
- };
-
- public static OpenApiPathItem LoadPathItem(ParseNode node)
- {
- var mapNode = node.CheckMapNode("PathItem");
-
- var pointer = mapNode.GetReferencePointer();
- if (pointer != null)
- {
- var refObject = mapNode.GetReferencedObject(ReferenceType.Path, pointer);
- return refObject;
- }
-
- var pathItem = new OpenApiPathItem();
-
- ParseMap(mapNode, pathItem, _pathItemFixedFields, _pathItemPatternFields);
-
- return pathItem;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi.Readers/V3/OpenApiSchemaDeserializer.cs
deleted file mode 100644
index 1e386a33d..000000000
--- a/src/Microsoft.OpenApi.Readers/V3/OpenApiSchemaDeserializer.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Extensions;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
-using System.Collections.Generic;
-using System.Globalization;
-
-namespace Microsoft.OpenApi.Readers.V3
-{
- ///
- /// Class containing logic to deserialize Open API V3 document into
- /// runtime Open API object model.
- ///
- internal static partial class OpenApiV3Deserializer
- {
- private static readonly FixedFieldMap _schemaFixedFields = new()
- {
- {
- "title",
- (o, n) => o.Title = n.GetScalarValue()
- },
- {
- "multipleOf",
- (o, n) => o.MultipleOf = decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)
- },
- {
- "maximum",
- (o, n) => o.Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue)
- },
- {
- "exclusiveMaximum",
- (o, n) => o.ExclusiveMaximum = bool.Parse(n.GetScalarValue())
- },
- {
- "minimum",
- (o, n) => o.Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue)
- },
- {
- "exclusiveMinimum",
- (o, n) => o.ExclusiveMinimum = bool.Parse(n.GetScalarValue())
- },
- {
- "maxLength",
- (o, n) => o.MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minLength",
- (o, n) => o.MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "pattern",
- (o, n) => o.Pattern = n.GetScalarValue()
- },
- {
- "maxItems",
- (o, n) => o.MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minItems",
- (o, n) => o.MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "uniqueItems",
- (o, n) => o.UniqueItems = bool.Parse(n.GetScalarValue())
- },
- {
- "maxProperties",
- (o, n) => o.MaxProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "minProperties",
- (o, n) => o.MinProperties = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)
- },
- {
- "required",
- (o, n) => o.Required = new HashSet(n.CreateSimpleList(n2 => n2.GetScalarValue()))
- },
- {
- "enum",
- (o, n) => o.Enum = n.CreateListOfAny()
- },
- {
- "type",
- (o, n) => o.Type = n.GetScalarValue()
- },
- {
- "allOf",
- (o, n) => o.AllOf = n.CreateList(LoadSchema)
- },
- {
- "oneOf",
- (o, n) => o.OneOf = n.CreateList(LoadSchema)
- },
- {
- "anyOf",
- (o, n) => o.AnyOf = n.CreateList(LoadSchema)
- },
- {
- "not",
- (o, n) => o.Not = LoadSchema(n)
- },
- {
- "items",
- (o, n) => o.Items = LoadSchema(n)
- },
- {
- "properties",
- (o, n) => o.Properties = n.CreateMap(LoadSchema)
- },
- {
- "additionalProperties", (o, n) =>
- {
- if (n is ValueNode)
- {
- o.AdditionalPropertiesAllowed = bool.Parse(n.GetScalarValue());
- }
- else
- {
- o.AdditionalProperties = LoadSchema(n);
- }
- }
- },
- {
- "description",
- (o, n) => o.Description = n.GetScalarValue()
- },
- {
- "format",
- (o, n) => o.Format = n.GetScalarValue()
- },
- {
- "default",
- (o, n) => o.Default = n.CreateAny()
- },
- {
- "nullable",
- (o, n) => o.Nullable = bool.Parse(n.GetScalarValue())
- },
- {
- "discriminator",
- (o, n) => o.Discriminator = LoadDiscriminator(n)
- },
- {
- "readOnly",
- (o, n) => o.ReadOnly = bool.Parse(n.GetScalarValue())
- },
- {
- "writeOnly",
- (o, n) => o.WriteOnly = bool.Parse(n.GetScalarValue())
- },
- {
- "xml",
- (o, n) => o.Xml = LoadXml(n)
- },
- {
- "externalDocs",
- (o, n) => o.ExternalDocs = LoadExternalDocs(n)
- },
- {
- "example",
- (o, n) => o.Example = n.CreateAny()
- },
- {
- "deprecated",
- (o, n) => o.Deprecated = bool.Parse(n.GetScalarValue())
- },
- };
-
- private static readonly PatternFieldMap _schemaPatternFields = new()
- {
- {s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p,n))}
- };
-
- private static readonly AnyFieldMap _schemaAnyFields = new()
- {
- {
- OpenApiConstants.Default,
- new(
- s => s.Default,
- (s, v) => s.Default = v,
- s => s)
- },
- {
- OpenApiConstants.Example,
- new(
- s => s.Example,
- (s, v) => s.Example = v,
- s => s)
- }
- };
-
- private static readonly AnyListFieldMap _schemaAnyListFields = new()
- {
- {
- OpenApiConstants.Enum,
- new(
- s => s.Enum,
- (s, v) => s.Enum = v,
- s => s)
- }
- };
-
- public static OpenApiSchema LoadSchema(ParseNode node)
- {
- var mapNode = node.CheckMapNode(OpenApiConstants.Schema);
-
- var pointer = mapNode.GetReferencePointer();
-
- if (pointer != null)
- {
- return new()
- {
- UnresolvedReference = true,
- Reference = node.Context.VersionService.ConvertToOpenApiReference(pointer, ReferenceType.Schema)
- };
- }
-
- var schema = new OpenApiSchema();
-
- foreach (var propertyNode in mapNode)
- {
- propertyNode.ParseField(schema, _schemaFixedFields, _schemaPatternFields);
- }
-
- ProcessAnyFields(mapNode, schema, _schemaAnyFields);
- ProcessAnyListFields(mapNode, schema, _schemaAnyListFields);
-
- return schema;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/YamlConverter.cs b/src/Microsoft.OpenApi.Readers/YamlConverter.cs
new file mode 100644
index 000000000..7d338ffa1
--- /dev/null
+++ b/src/Microsoft.OpenApi.Readers/YamlConverter.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.Json.Nodes;
+using SharpYaml;
+using SharpYaml.Serialization;
+
+namespace Microsoft.OpenApi.Reader
+{
+ ///
+ /// 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
+ {
+ JsonObject obj => obj.ToYamlMapping(),
+ JsonArray arr => arr.ToYamlSequence(),
+ JsonValue val => val.ToYamlScalar(),
+ _ => throw new NotSupportedException("This isn't a supported JsonNode")
+ };
+ }
+
+ ///
+ /// Converts a to a .
+ ///
+ ///
+ ///
+ public 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()));
+ }
+
+ ///
+ /// Converts a to a .
+ ///
+ ///
+ ///
+ public 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, NumberStyles.Float, CultureInfo.InvariantCulture, 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 new YamlScalarNode(val.ToJsonString());
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi.Readers/YamlHelper.cs b/src/Microsoft.OpenApi.Readers/YamlHelper.cs
deleted file mode 100644
index 7ce58d481..000000000
--- a/src/Microsoft.OpenApi.Readers/YamlHelper.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.IO;
-using System.Linq;
-using Microsoft.OpenApi.Exceptions;
-using SharpYaml.Serialization;
-
-namespace Microsoft.OpenApi.Readers
-{
- internal static class YamlHelper
- {
- public static string GetScalarValue(this YamlNode node)
- {
- if (node is not YamlScalarNode scalarNode)
- {
- throw new OpenApiException($"Expected scalar at line {node.Start.Line}");
- }
-
- return scalarNode.Value;
- }
-
- public static YamlNode ParseYamlString(string yamlString)
- {
- var reader = new StringReader(yamlString);
- var yamlStream = new YamlStream();
- yamlStream.Load(reader);
-
- var yamlDocument = yamlStream.Documents.First();
- return yamlDocument.RootNode;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Workbench/MainModel.cs b/src/Microsoft.OpenApi.Workbench/MainModel.cs
index 7068a61e8..d518645a5 100644
--- a/src/Microsoft.OpenApi.Workbench/MainModel.cs
+++ b/src/Microsoft.OpenApi.Workbench/MainModel.cs
@@ -10,6 +10,7 @@
using System.Threading.Tasks;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
+using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Validations;
@@ -158,6 +159,7 @@ public OpenApiSpecVersion Version
_version = value;
OnPropertyChanged(nameof(IsV2_0));
OnPropertyChanged(nameof(IsV3_0));
+ OnPropertyChanged(nameof(IsV3_1));
}
}
@@ -185,6 +187,12 @@ public bool IsV3_0
set => Version = OpenApiSpecVersion.OpenApi3_0;
}
+ public bool IsV3_1
+ {
+ get => Version == OpenApiSpecVersion.OpenApi3_1;
+ set => Version = OpenApiSpecVersion.OpenApi3_1;
+ }
+
///
/// Handling method when the property with given name has changed.
///
@@ -203,6 +211,9 @@ protected void OnPropertyChanged(string propertyName)
///
internal async Task ParseDocumentAsync()
{
+ OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
+ OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yml, new OpenApiYamlReader());
+
Stream stream = null;
try
{
@@ -245,8 +256,9 @@ internal async Task ParseDocumentAsync()
settings.BaseUrl = new("file://" + Path.GetDirectoryName(_inputFile) + "/");
}
}
- var readResult = await new OpenApiStreamReader(settings
- ).ReadAsync(stream);
+
+ var format = OpenApiModelFactory.GetFormat(_inputFile);
+ var readResult = await OpenApiDocument.LoadAsync(stream, format);
var document = readResult.OpenApiDocument;
var context = readResult.OpenApiDiagnostic;
@@ -287,7 +299,8 @@ internal async Task ParseDocumentAsync()
Output = string.Empty;
Errors = "Failed to parse input: " + ex.Message;
}
- finally {
+ finally
+ {
if (stream != null)
{
stream.Close();
diff --git a/src/Microsoft.OpenApi.Workbench/MainWindow.xaml b/src/Microsoft.OpenApi.Workbench/MainWindow.xaml
index 41a4f2543..a3696f1e7 100644
--- a/src/Microsoft.OpenApi.Workbench/MainWindow.xaml
+++ b/src/Microsoft.OpenApi.Workbench/MainWindow.xaml
@@ -40,6 +40,7 @@
+
diff --git a/src/Microsoft.OpenApi.Workbench/MainWindow.xaml.cs b/src/Microsoft.OpenApi.Workbench/MainWindow.xaml.cs
index f9f1773c7..3c02c254d 100644
--- a/src/Microsoft.OpenApi.Workbench/MainWindow.xaml.cs
+++ b/src/Microsoft.OpenApi.Workbench/MainWindow.xaml.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;
diff --git a/src/Microsoft.OpenApi/Any/AnyType.cs b/src/Microsoft.OpenApi/Any/AnyType.cs
deleted file mode 100644
index 3ac617e8a..000000000
--- a/src/Microsoft.OpenApi/Any/AnyType.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Type of an
- ///
- public enum AnyType
- {
- ///
- /// Primitive.
- ///
- Primitive,
-
- ///
- /// Null.
- ///
- Null,
-
- ///
- /// Array.
- ///
- Array,
-
- ///
- /// Object.
- ///
- Object
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/IOpenApiAny.cs b/src/Microsoft.OpenApi/Any/IOpenApiAny.cs
deleted file mode 100644
index ece675508..000000000
--- a/src/Microsoft.OpenApi/Any/IOpenApiAny.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Interfaces;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Base interface for all the types that represent Open API Any.
- ///
- public interface IOpenApiAny : IOpenApiElement, IOpenApiExtension
- {
- ///
- /// Type of an .
- ///
- AnyType AnyType { get; }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/IOpenApiPrimitive.cs b/src/Microsoft.OpenApi/Any/IOpenApiPrimitive.cs
deleted file mode 100644
index 039782852..000000000
--- a/src/Microsoft.OpenApi/Any/IOpenApiPrimitive.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Primitive type.
- ///
- public enum PrimitiveType
- {
- ///
- /// Integer
- ///
- Integer,
-
- ///
- /// Long
- ///
- Long,
-
- ///
- /// Float
- ///
- Float,
-
- ///
- /// Double
- ///
- Double,
-
- ///
- /// String
- ///
- String,
-
- ///
- /// Byte
- ///
- Byte,
-
- ///
- /// Binary
- ///
- Binary,
-
- ///
- /// Boolean
- ///
- Boolean,
-
- ///
- /// Date
- ///
- Date,
-
- ///
- /// DateTime
- ///
- DateTime,
-
- ///
- /// Password
- ///
- Password
- }
-
- ///
- /// Base interface for the Primitive type.
- ///
- public interface IOpenApiPrimitive : IOpenApiAny
- {
- ///
- /// Primitive type.
- ///
- PrimitiveType PrimitiveType { get; }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiAny.cs b/src/Microsoft.OpenApi/Any/OpenApiAny.cs
new file mode 100644
index 000000000..54bddf326
--- /dev/null
+++ b/src/Microsoft.OpenApi/Any/OpenApiAny.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Text.Json.Nodes;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.Any
+{
+ ///
+ /// A wrapper class for JsonNode
+ ///
+ public class OpenApiAny : IOpenApiElement, IOpenApiExtension
+ {
+ private readonly JsonNode jsonNode;
+
+ ///
+ /// Initializes the class.
+ ///
+ ///
+ public OpenApiAny(JsonNode jsonNode)
+ {
+ this.jsonNode = jsonNode;
+ }
+
+ ///
+ /// Gets the underlying JsonNode.
+ ///
+ public JsonNode Node { get { return jsonNode; } }
+
+ ///
+ /// Writes out the OpenApiAny type.
+ ///
+ ///
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ writer.WriteAny(Node);
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiAnyCloneHelper.cs b/src/Microsoft.OpenApi/Any/OpenApiAnyCloneHelper.cs
deleted file mode 100644
index eaa1dac31..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiAnyCloneHelper.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Contains logic for cloning objects through copy constructors.
- ///
- public class OpenApiAnyCloneHelper
- {
- ///
- /// Clones an instance of object from the copy constructor
- ///
- /// The object instance.
- /// A clone copy or the object itself.
- [Obsolete("Use native AoT-friendly generic overload of CloneFromCopyConstructor instead.")]
- [RequiresUnreferencedCode("CloneFromCopyConstructor is not trim-compatible. Recommended to use native AoT-friendly type-specific overloads of CloneFromCopyConstructor instead.")]
- public static IOpenApiAny CloneFromCopyConstructor(IOpenApiAny obj)
- {
- if (obj != null)
- {
- var t = obj.GetType();
- foreach (var ci in t.GetConstructors())
- {
- var pi = ci.GetParameters();
- if (pi.Length == 1 && pi[0].ParameterType == t)
- {
- return (IOpenApiAny)ci.Invoke(new object[] { obj });
- }
- }
- }
-
- return obj;
- }
-
- ///
- /// Clones an instance of object from the copy constructor
- ///
- /// The object instance.
- /// A clone copy or the object itself.
- public static T CloneFromCopyConstructor<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(T obj) where T : IOpenApiAny
- {
- if (obj != null)
- {
- foreach (var ci in typeof(T).GetConstructors())
- {
- var pi = ci.GetParameters();
- if (pi.Length == 1 && pi[0].ParameterType == typeof(T))
- {
- return (T)ci.Invoke([obj]);
- }
- }
- }
-
- return obj;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiArray.cs b/src/Microsoft.OpenApi/Any/OpenApiArray.cs
deleted file mode 100644
index 5a9af0fff..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiArray.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Writers;
-using System.Collections.Generic;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API array.
- ///
- public class OpenApiArray : List, IOpenApiAny
- {
- ///
- /// The type of
- ///
- public AnyType AnyType { get; } = AnyType.Array;
-
- ///
- /// Parameterless constructor
- ///
- public OpenApiArray() { }
-
- ///
- /// Initializes a copy of object
- ///
- public OpenApiArray(OpenApiArray array)
- {
- AnyType = array.AnyType;
- foreach (var item in array)
- {
- Add(OpenApiAnyCloneHelper.CloneFromCopyConstructor(item));
- }
- }
-
- ///
- /// Write out contents of OpenApiArray to passed writer
- ///
- /// Instance of JSON or YAML writer.
- /// Version of the OpenAPI specification that that will be output.
- public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
- {
- writer.WriteStartArray();
-
- foreach (var item in this)
- {
- writer.WriteAny(item);
- }
-
- writer.WriteEndArray();
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiBinary.cs b/src/Microsoft.OpenApi/Any/OpenApiBinary.cs
deleted file mode 100644
index 23fdbe4d6..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiBinary.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API binary.
- ///
- public class OpenApiBinary : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- ///
- public OpenApiBinary(byte[] value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Binary;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiBoolean.cs b/src/Microsoft.OpenApi/Any/OpenApiBoolean.cs
deleted file mode 100644
index aef1a42f8..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiBoolean.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API boolean.
- ///
- public class OpenApiBoolean : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- ///
- public OpenApiBoolean(bool value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Boolean;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiByte.cs b/src/Microsoft.OpenApi/Any/OpenApiByte.cs
deleted file mode 100644
index f28a50175..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiByte.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Byte
- ///
- public class OpenApiByte : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiByte(byte value)
- : this(new[] { value })
- {
- }
-
- ///
- /// Initializes the class.
- ///
- public OpenApiByte(byte[] value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Byte;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiDate.cs b/src/Microsoft.OpenApi/Any/OpenApiDate.cs
deleted file mode 100644
index 4552ddfc8..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiDate.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Date
- ///
- public class OpenApiDate : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiDate(DateTime value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Date;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiDateTime.cs b/src/Microsoft.OpenApi/Any/OpenApiDateTime.cs
deleted file mode 100644
index c812aa50c..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiDateTime.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Datetime
- ///
- public class OpenApiDateTime : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiDateTime(DateTimeOffset value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.DateTime;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiDouble.cs b/src/Microsoft.OpenApi/Any/OpenApiDouble.cs
deleted file mode 100644
index 3a913873c..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiDouble.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Double
- ///
- public class OpenApiDouble : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiDouble(double value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Double;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiFloat.cs b/src/Microsoft.OpenApi/Any/OpenApiFloat.cs
deleted file mode 100644
index 5e90a4106..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiFloat.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Float
- ///
- public class OpenApiFloat : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiFloat(float value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Float;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiInteger.cs b/src/Microsoft.OpenApi/Any/OpenApiInteger.cs
deleted file mode 100644
index fa47b4f48..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiInteger.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API Integer
- ///
- public class OpenApiInteger : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiInteger(int value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Integer;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiLong.cs b/src/Microsoft.OpenApi/Any/OpenApiLong.cs
deleted file mode 100644
index f54b20084..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiLong.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API long.
- ///
- public class OpenApiLong : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiLong(long value)
- : base(value)
- {
- }
-
- ///
- /// Primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Long;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiNull.cs b/src/Microsoft.OpenApi/Any/OpenApiNull.cs
deleted file mode 100644
index b606d98e1..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiNull.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Writers;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API null.
- ///
- public class OpenApiNull : IOpenApiAny
- {
- ///
- /// The type of
- ///
- public AnyType AnyType { get; } = AnyType.Null;
-
- ///
- /// Parameterless constructor
- ///
- public OpenApiNull() { }
-
- ///
- /// Initializes a copy of object
- ///
- public OpenApiNull(OpenApiNull openApiNull)
- {
- AnyType = openApiNull.AnyType;
- }
-
- ///
- /// Write out null representation
- ///
- ///
- /// Version of the OpenAPI specification that that will be output.
- public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
- {
- writer.WriteAny(this);
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiObject.cs b/src/Microsoft.OpenApi/Any/OpenApiObject.cs
deleted file mode 100644
index 95783cc23..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiObject.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System.Collections.Generic;
-using Microsoft.OpenApi.Writers;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API object.
- ///
- public class OpenApiObject : Dictionary, IOpenApiAny
- {
- ///
- /// Type of .
- ///
- public AnyType AnyType { get; } = AnyType.Object;
-
- ///
- /// Parameterless constructor
- ///
- public OpenApiObject() { }
-
- ///
- /// Initializes a copy of object
- ///
- public OpenApiObject(OpenApiObject obj)
- {
- AnyType = obj.AnyType;
- foreach (var key in obj.Keys)
- {
- this[key] = OpenApiAnyCloneHelper.CloneFromCopyConstructor(obj[key]);
- }
- }
-
- ///
- /// Serialize OpenApiObject to writer
- ///
- ///
- /// Version of the OpenAPI specification that that will be output.
- public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
- {
- writer.WriteStartObject();
-
- foreach (var item in this)
- {
- writer.WritePropertyName(item.Key);
- writer.WriteAny(item.Value);
- }
-
- writer.WriteEndObject();
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiPassword.cs b/src/Microsoft.OpenApi/Any/OpenApiPassword.cs
deleted file mode 100644
index f9e68bf66..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiPassword.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API password.
- ///
- public class OpenApiPassword : OpenApiPrimitive
- {
- ///
- /// Initializes the class.
- ///
- public OpenApiPassword(string value)
- : base(value)
- {
- }
-
- ///
- /// The primitive type this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.Password;
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiPrimitive.cs b/src/Microsoft.OpenApi/Any/OpenApiPrimitive.cs
deleted file mode 100644
index 3ac1b0082..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiPrimitive.cs
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using System;
-using System.Globalization;
-using System.Text;
-using Microsoft.OpenApi.Exceptions;
-using Microsoft.OpenApi.Properties;
-using Microsoft.OpenApi.Writers;
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API primitive class.
- ///
- ///
- public abstract class OpenApiPrimitive : IOpenApiPrimitive
- {
- ///
- /// Initializes the class with the given value.
- ///
- ///
- public OpenApiPrimitive(T value)
- {
- Value = value;
- }
-
- ///
- /// Initializes a copy of an object
- ///
- ///
- public OpenApiPrimitive(OpenApiPrimitive openApiPrimitive)
- {
- Value = openApiPrimitive.Value;
- }
-
- ///
- /// The kind of .
- ///
- public AnyType AnyType => AnyType.Primitive;
-
- ///
- /// The primitive class this object represents.
- ///
- public abstract PrimitiveType PrimitiveType { get; }
-
- ///
- /// Value of this
- ///
- public T Value { get; }
-
- ///
- /// Write out content of primitive element
- ///
- ///
- ///
- public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
- {
- switch (this.PrimitiveType)
- {
- case PrimitiveType.Integer:
- var intValue = (OpenApiInteger)(IOpenApiPrimitive)this;
- writer.WriteValue(intValue.Value);
- break;
-
- case PrimitiveType.Long:
- var longValue = (OpenApiLong)(IOpenApiPrimitive)this;
- writer.WriteValue(longValue.Value);
- break;
-
- case PrimitiveType.Float:
- var floatValue = (OpenApiFloat)(IOpenApiPrimitive)this;
- writer.WriteValue(floatValue.Value);
- break;
-
- case PrimitiveType.Double:
- var doubleValue = (OpenApiDouble)(IOpenApiPrimitive)this;
- var actualValue = doubleValue.Value;
- if (actualValue.Equals(double.NaN)
- || actualValue.Equals(double.NegativeInfinity)
- || actualValue.Equals(double.PositiveInfinity))
- {
- // Write out NaN, -Infinity, Infinity as strings
- writer.WriteValue(actualValue.ToString(CultureInfo.InvariantCulture));
- break;
- }
- else
- {
- writer.WriteValue(actualValue);
- }
- break;
-
- case PrimitiveType.String:
- var stringValue = (OpenApiString)(IOpenApiPrimitive)this;
- if (stringValue.IsRawString())
- writer.WriteRaw(stringValue.Value);
- else
- writer.WriteValue(stringValue.Value);
- break;
-
- case PrimitiveType.Byte:
- var byteValue = (OpenApiByte)(IOpenApiPrimitive)this;
- if (byteValue.Value == null)
- {
- writer.WriteNull();
- }
- else
- {
- writer.WriteValue(Convert.ToBase64String(byteValue.Value));
- }
-
- break;
-
- case PrimitiveType.Binary:
- var binaryValue = (OpenApiBinary)(IOpenApiPrimitive)this;
- if (binaryValue.Value == null)
- {
- writer.WriteNull();
- }
- else
- {
- writer.WriteValue(Encoding.UTF8.GetString(binaryValue.Value));
- }
-
- break;
-
- case PrimitiveType.Boolean:
- var boolValue = (OpenApiBoolean)(IOpenApiPrimitive)this;
- writer.WriteValue(boolValue.Value);
- break;
-
- case PrimitiveType.Date:
- var dateValue = (OpenApiDate)(IOpenApiPrimitive)this;
- writer.WriteValue(dateValue.Value.ToString("o").Substring(0, 10));
- break;
-
- case PrimitiveType.DateTime:
- var dateTimeValue = (OpenApiDateTime)(IOpenApiPrimitive)this;
- writer.WriteValue(dateTimeValue.Value);
- break;
-
- case PrimitiveType.Password:
- var passwordValue = (OpenApiPassword)(IOpenApiPrimitive)this;
- writer.WriteValue(passwordValue.Value);
- break;
-
- default:
- throw new OpenApiWriterException(
- string.Format(
- SRResource.PrimitiveTypeNotSupported,
- this.PrimitiveType));
- }
- }
- }
-}
diff --git a/src/Microsoft.OpenApi/Any/OpenApiString.cs b/src/Microsoft.OpenApi/Any/OpenApiString.cs
deleted file mode 100644
index fa1b799ee..000000000
--- a/src/Microsoft.OpenApi/Any/OpenApiString.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-namespace Microsoft.OpenApi.Any
-{
- ///
- /// Open API string type.
- ///
- public class OpenApiString : OpenApiPrimitive
- {
- private bool isExplicit;
- private bool isRawString;
-
- ///
- /// Initializes the class.
- ///
- ///
- public OpenApiString(string value)
- : this(value, false)
- {
- }
-
- ///
- /// Initializes the class.
- ///
- ///
- /// Used to indicate if a string is quoted.
- public OpenApiString(string value, bool isExplicit)
- : base(value)
- {
- this.isExplicit = isExplicit;
- }
-
- ///
- /// Initializes the class.
- ///
- ///
- /// Used to indicate if a string is quoted.
- /// Used to indicate to the writer that the value should be written without encoding.
- public OpenApiString(string value, bool isExplicit, bool isRawString)
- : base(value)
- {
- this.isExplicit = isExplicit;
- this.isRawString = isRawString;
- }
-
- ///
- /// The primitive class this object represents.
- ///
- public override PrimitiveType PrimitiveType => PrimitiveType.String;
-
- ///
- /// True if string was specified explicitly by the means of double quotes, single quotes, or literal or folded style.
- ///
- public bool IsExplicit()
- {
- return this.isExplicit;
- }
-
- ///
- /// True if the writer should process the value as supplied without encoding.
- ///
- public bool IsRawString()
- {
- return this.isRawString;
- }
- }
-}
diff --git a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs b/src/Microsoft.OpenApi/Exceptions/OpenApiReaderException.cs
similarity index 87%
rename from src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs
rename to src/Microsoft.OpenApi/Exceptions/OpenApiReaderException.cs
index 53ae62d50..257b0e9a4 100644
--- a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs
+++ b/src/Microsoft.OpenApi/Exceptions/OpenApiReaderException.cs
@@ -1,11 +1,11 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
-using Microsoft.OpenApi.Exceptions;
-using SharpYaml.Serialization;
+using System.Text.Json.Nodes;
+using Microsoft.OpenApi.Reader;
-namespace Microsoft.OpenApi.Readers.Exceptions
+namespace Microsoft.OpenApi.Exceptions
{
///
/// Defines an exception indicating OpenAPI Reader encountered an issue while reading.
@@ -29,7 +29,8 @@ public OpenApiReaderException(string message) : base(message) { }
///
/// Plain text error message for this exception.
/// Context of current parsing process.
- public OpenApiReaderException(string message, ParsingContext context) : base(message) {
+ public OpenApiReaderException(string message, ParsingContext context) : base(message)
+ {
Pointer = context.GetLocation();
}
@@ -38,11 +39,10 @@ public OpenApiReaderException(string message, ParsingContext context) : base(mes
///
/// Plain text error message for this exception.
/// Parsing node where error occured
- public OpenApiReaderException(string message, YamlNode node) : base(message)
+ public OpenApiReaderException(string message, JsonNode node) : base(message)
{
// This only includes line because using a char range causes tests to break due to CR/LF & LF differences
// See https://tools.ietf.org/html/rfc5147 for syntax
- Pointer = $"#line={node.Start.Line}";
}
///
diff --git a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs b/src/Microsoft.OpenApi/Exceptions/OpenApiUnsupportedSpecVersionException.cs
similarity index 97%
rename from src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs
rename to src/Microsoft.OpenApi/Exceptions/OpenApiUnsupportedSpecVersionException.cs
index 2d125c259..f9be8bd63 100644
--- a/src/Microsoft.OpenApi.Readers/Exceptions/OpenApiUnsupportedSpecVersionException.cs
+++ b/src/Microsoft.OpenApi/Exceptions/OpenApiUnsupportedSpecVersionException.cs
@@ -4,7 +4,7 @@
using System;
using System.Globalization;
-namespace Microsoft.OpenApi.Readers.Exceptions
+namespace Microsoft.OpenApi.Exceptions
{
///
/// Defines an exception indicating OpenAPI Reader encountered an unsupported specification version while reading.
diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiElementExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiElementExtensions.cs
index 38a53ecec..d0b0d9c35 100644
--- a/src/Microsoft.OpenApi/Extensions/OpenApiElementExtensions.cs
+++ b/src/Microsoft.OpenApi/Extensions/OpenApiElementExtensions.cs
@@ -24,6 +24,12 @@ public static class OpenApiElementExtensions
public static IEnumerable Validate(this IOpenApiElement element, ValidationRuleSet ruleSet)
{
var validator = new OpenApiValidator(ruleSet);
+
+ if (element is OpenApiDocument doc)
+ {
+ validator.HostDocument = doc;
+ }
+
var walker = new OpenApiWalker(validator);
walker.Walk(element);
return validator.Errors.Cast().Union(validator.Warnings);
diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
index 5fb1190eb..aca76f979 100644
--- a/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
+++ b/src/Microsoft.OpenApi/Extensions/OpenApiReferencableExtensions.cs
@@ -59,8 +59,6 @@ private static IOpenApiReferenceable ResolveReferenceOnHeaderElement(
{
switch (propertyName)
{
- case OpenApiConstants.Schema:
- return headerElement.Schema;
case OpenApiConstants.Examples when mapKey != null:
return headerElement.Examples[mapKey];
default:
@@ -76,8 +74,6 @@ private static IOpenApiReferenceable ResolveReferenceOnParameterElement(
{
switch (propertyName)
{
- case OpenApiConstants.Schema:
- return parameterElement.Schema;
case OpenApiConstants.Examples when mapKey != null:
return parameterElement.Examples[mapKey];
default:
diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs b/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs
index 845f6ce65..5d59a8de2 100755
--- a/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs
+++ b/src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.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.Globalization;
@@ -106,6 +106,10 @@ public static void Serialize(this T element, IOpenApiWriter writer, OpenApiSp
switch (specVersion)
{
+ case OpenApiSpecVersion.OpenApi3_1:
+ element.SerializeAsV31(writer);
+ break;
+
case OpenApiSpecVersion.OpenApi3_0:
element.SerializeAsV3(writer);
break;
diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs
index 6b7801541..e6dadd44d 100644
--- a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs
+++ b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
namespace Microsoft.OpenApi.Extensions
@@ -12,40 +13,81 @@ namespace Microsoft.OpenApi.Extensions
///
public static class OpenApiTypeMapper
{
+ ///
+ /// Maps a JsonSchema data type to an identifier.
+ ///
+ ///
+ ///
+ public static string ToIdentifier(this JsonSchemaType? schemaType)
+ {
+ return schemaType switch
+ {
+ JsonSchemaType.Null => "null",
+ JsonSchemaType.Boolean => "boolean",
+ JsonSchemaType.Integer => "integer",
+ JsonSchemaType.Number => "number",
+ JsonSchemaType.String => "string",
+ JsonSchemaType.Array => "array",
+ JsonSchemaType.Object => "object",
+ _ => null,
+ };
+ }
+
+ ///
+ /// Converts a schema type's identifier into the enum equivalent
+ ///
+ ///
+ ///
+ public static JsonSchemaType ToJsonSchemaType(this string identifier)
+ {
+ return identifier switch
+ {
+ "null" => JsonSchemaType.Null,
+ "boolean" => JsonSchemaType.Boolean,
+ "integer" or "int" => JsonSchemaType.Integer,
+ "number" or "double" or "float" or "decimal"=> JsonSchemaType.Number,
+ "string" => JsonSchemaType.String,
+ "array" => JsonSchemaType.Array,
+ "object" => JsonSchemaType.Object,
+ "file" => JsonSchemaType.String, // File is treated as string
+ _ => throw new OpenApiException(string.Format("Invalid schema type identifier: {0}", identifier))
+ };
+ }
+
private static readonly Dictionary> _simpleTypeToOpenApiSchema = new()
{
- [typeof(bool)] = () => new() { Type = "boolean" },
- [typeof(byte)] = () => new() { Type = "string", Format = "byte" },
- [typeof(int)] = () => new() { Type = "number", Format = "int32" },
- [typeof(uint)] = () => new() { Type = "number", Format = "int32" },
- [typeof(long)] = () => new() { Type = "number", Format = "int64" },
- [typeof(ulong)] = () => new() { Type = "number", Format = "int64" },
- [typeof(float)] = () => new() { Type = "number", Format = "float" },
- [typeof(double)] = () => new() { Type = "number", Format = "double" },
- [typeof(decimal)] = () => new() { Type = "number", Format = "double" },
- [typeof(DateTime)] = () => new() { Type = "string", Format = "date-time" },
- [typeof(DateTimeOffset)] = () => new() { Type = "string", Format = "date-time" },
- [typeof(Guid)] = () => new() { Type = "string", Format = "uuid" },
- [typeof(char)] = () => new() { Type = "string" },
+ [typeof(bool)] = () => new() { Type = JsonSchemaType.Boolean },
+ [typeof(byte)] = () => new() { Type = JsonSchemaType.String, Format = "byte" },
+ [typeof(int)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32" },
+ [typeof(uint)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32" },
+ [typeof(long)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64" },
+ [typeof(ulong)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64" },
+ [typeof(float)] = () => new() { Type = JsonSchemaType.Number, Format = "float" },
+ [typeof(double)] = () => new() { Type = JsonSchemaType.Number, Format = "double" },
+ [typeof(decimal)] = () => new() { Type = JsonSchemaType.Number, Format = "double" },
+ [typeof(DateTime)] = () => new() { Type = JsonSchemaType.String, Format = "date-time" },
+ [typeof(DateTimeOffset)] = () => new() { Type = JsonSchemaType.String, Format = "date-time" },
+ [typeof(Guid)] = () => new() { Type = JsonSchemaType.String, Format = "uuid" },
+ [typeof(char)] = () => new() { Type = JsonSchemaType.String },
// Nullable types
- [typeof(bool?)] = () => new() { Type = "boolean", Nullable = true },
- [typeof(byte?)] = () => new() { Type = "string", Format = "byte", Nullable = true },
- [typeof(int?)] = () => new() { Type = "number", Format = "int32", Nullable = true },
- [typeof(uint?)] = () => new() { Type = "number", Format = "int32", Nullable = true },
- [typeof(long?)] = () => new() { Type = "number", Format = "int64", Nullable = true },
- [typeof(ulong?)] = () => new() { Type = "number", Format = "int64", Nullable = true },
- [typeof(float?)] = () => new() { Type = "number", Format = "float", Nullable = true },
- [typeof(double?)] = () => new() { Type = "number", Format = "double", Nullable = true },
- [typeof(decimal?)] = () => new() { Type = "number", Format = "double", Nullable = true },
- [typeof(DateTime?)] = () => new() { Type = "string", Format = "date-time", Nullable = true },
- [typeof(DateTimeOffset?)] = () => new() { Type = "string", Format = "date-time", Nullable = true },
- [typeof(Guid?)] = () => new() { Type = "string", Format = "uuid", Nullable = true },
- [typeof(char?)] = () => new() { Type = "string", Nullable = true },
+ [typeof(bool?)] = () => new() { Type = JsonSchemaType.Boolean, Nullable = true },
+ [typeof(byte?)] = () => new() { Type = JsonSchemaType.String, Format = "byte", Nullable = true },
+ [typeof(int?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true },
+ [typeof(uint?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true },
+ [typeof(long?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true },
+ [typeof(ulong?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true },
+ [typeof(float?)] = () => new() { Type = JsonSchemaType.Number, Format = "float", Nullable = true },
+ [typeof(double?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true },
+ [typeof(decimal?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true },
+ [typeof(DateTime?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true },
+ [typeof(DateTimeOffset?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true },
+ [typeof(Guid?)] = () => new() { Type = JsonSchemaType.String, Format = "uuid", Nullable = true },
+ [typeof(char?)] = () => new() { Type = JsonSchemaType.String, Nullable = true },
- [typeof(Uri)] = () => new() { Type = "string", Format = "uri"}, // Uri is treated as simple string
- [typeof(string)] = () => new() { Type = "string" },
- [typeof(object)] = () => new() { Type = "object" }
+ [typeof(Uri)] = () => new() { Type = JsonSchemaType.String, Format = "uri" }, // Uri is treated as simple string
+ [typeof(string)] = () => new() { Type = JsonSchemaType.String },
+ [typeof(object)] = () => new() { Type = JsonSchemaType.Object }
};
///
@@ -79,11 +121,11 @@ public static OpenApiSchema MapTypeToOpenApiPrimitiveType(this Type type)
return _simpleTypeToOpenApiSchema.TryGetValue(type, out var result)
? result()
- : new() { Type = "string" };
+ : new() { Type = JsonSchemaType.String };
}
///
- /// Maps an OpenAPI data type and format to a simple type.
+ /// Maps an JsonSchema data type and format to a simple type.
///
/// The OpenApi data type
/// The simple type
@@ -95,13 +137,13 @@ public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema
throw new ArgumentNullException(nameof(schema));
}
- var type = (schema.Type?.ToLowerInvariant(), schema.Format?.ToLowerInvariant(), schema.Nullable) switch
+ var type = (schema.Type.ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Nullable) switch
{
("boolean", null, false) => typeof(bool),
// integer is technically not valid with format, but we must provide some compatibility
("integer" or "number", "int32", false) => typeof(int),
("integer" or "number", "int64", false) => typeof(long),
- ("integer", null, false) => typeof(int),
+ ("integer", null, false) => typeof(long),
("number", "float", false) => typeof(float),
("number", "double", false) => typeof(double),
("number", "decimal", false) => typeof(decimal),
@@ -116,7 +158,7 @@ public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema
("string", "uri", false) => typeof(Uri),
("integer" or "number", "int32", true) => typeof(int?),
("integer" or "number", "int64", true) => typeof(long?),
- ("integer", null, true) => typeof(int?),
+ ("integer", null, true) => typeof(long?),
("number", "float", true) => typeof(float?),
("number", "double", true) => typeof(double?),
("number", null, true) => typeof(double?),
diff --git a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs
new file mode 100644
index 000000000..d6e9cb9df
--- /dev/null
+++ b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+using Microsoft.OpenApi.Any;
+
+namespace Microsoft.OpenApi.Helpers
+{
+ internal static class JsonNodeCloneHelper
+ {
+ private static readonly JsonSerializerOptions options = new()
+ {
+ ReferenceHandler = ReferenceHandler.IgnoreCycles
+ };
+
+ internal static JsonNode Clone(JsonNode value)
+ {
+ var jsonString = Serialize(value);
+ if (string.IsNullOrEmpty(jsonString))
+ {
+ return null;
+ }
+
+ var result = JsonSerializer.Deserialize(jsonString, options);
+ return result;
+ }
+
+ private static string Serialize(object obj)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+ var result = JsonSerializer.Serialize(obj, options);
+ return result;
+ }
+ }
+}
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs b/src/Microsoft.OpenApi/Interfaces/IDiagnostic.cs
similarity index 85%
rename from src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs
rename to src/Microsoft.OpenApi/Interfaces/IDiagnostic.cs
index 65511ce11..74376de02 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IDiagnostic.cs
+++ b/src/Microsoft.OpenApi/Interfaces/IDiagnostic.cs
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-namespace Microsoft.OpenApi.Readers.Interface
+namespace Microsoft.OpenApi.Interfaces
{
///
/// Interface for the entity containing diagnostic information from the reading process.
diff --git a/src/Microsoft.OpenApi/Interfaces/IEffective.cs b/src/Microsoft.OpenApi/Interfaces/IEffective.cs
deleted file mode 100644
index b3ac0a37b..000000000
--- a/src/Microsoft.OpenApi/Interfaces/IEffective.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license.
-
-using Microsoft.OpenApi.Models;
-
-namespace Microsoft.OpenApi.Interfaces
-{
- ///
- /// OpenApiElements that implement IEffective indicate that their description is not self-contained.
- /// External elements affect the effective description.
- ///
- /// Currently this will only be used for accessing external references.
- /// In the next major version, this will be the approach accessing all referenced elements.
- /// This will enable us to support merging properties that are peers of the $ref
- /// Type of OpenApi Element that is being referenced.
- public interface IEffective where T : class,IOpenApiElement
- {
- ///
- /// Returns a calculated and cloned version of the element.
- ///
- T GetEffective(OpenApiDocument document);
- }
-}
diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs
new file mode 100644
index 000000000..5f8b1cb22
--- /dev/null
+++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System.IO;
+using System.Text.Json.Nodes;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.OpenApi.Reader;
+
+namespace Microsoft.OpenApi.Interfaces
+{
+ ///
+ /// Interface for Open API readers.
+ ///
+ public interface IOpenApiReader
+ {
+ ///
+ /// Reads the TextReader input and parses it into an Open API document.
+ ///
+ /// The TextReader input.
+ /// The OpenApi reader settings.
+ /// Propagates notification that an operation should be cancelled.
+ ///
+ Task ReadAsync(TextReader input, OpenApiReaderSettings settings = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Parses the JsonNode input into an Open API document.
+ ///
+ /// The JsonNode input.
+ /// The Reader settings to be used during parsing.
+ /// Propagates notifications that operations should be cancelled.
+ /// The OpenAPI format.
+ ///
+ Task ReadAsync(JsonNode jsonNode, OpenApiReaderSettings settings, string format = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Reads the TextReader input and parses the fragment of an OpenAPI description into an Open API Element.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Version of the OpenAPI specification that the fragment conforms to.
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// The OpenApiReader settings.
+ /// Instance of newly created IOpenApiElement.
+ T ReadFragment(TextReader input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement;
+
+ ///
+ /// Reads the JsonNode input and parses the fragment of an OpenAPI description into an Open API Element.
+ ///
+ /// TextReader containing OpenAPI description to parse.
+ /// Version of the OpenAPI specification that the fragment conforms to.
+ /// Returns diagnostic object containing errors detected during parsing.
+ /// The OpenApiReader settings.
+ /// Instance of newly created IOpenApiElement.
+ T ReadFragment(JsonNode input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement;
+ }
+}
diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs
index 39d345319..0920fb1ef 100644
--- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs
+++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs
@@ -20,16 +20,5 @@ public interface IOpenApiReferenceable : IOpenApiSerializable
/// Reference object.
///
OpenApiReference Reference { get; set; }
-
- ///
- /// Serialize to OpenAPI V3 document without using reference.
- ///
- void SerializeAsV3WithoutReference(IOpenApiWriter writer);
-
- ///
- /// Serialize to OpenAPI V2 document without using reference.
- ///
- void SerializeAsV2WithoutReference(IOpenApiWriter writer);
-
}
}
diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiSerializable.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiSerializable.cs
index a3b22bd08..081545b14 100644
--- a/src/Microsoft.OpenApi/Interfaces/IOpenApiSerializable.cs
+++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiSerializable.cs
@@ -10,6 +10,12 @@ namespace Microsoft.OpenApi.Interfaces
///
public interface IOpenApiSerializable : IOpenApiElement
{
+ ///
+ /// Serialize OpenAPI element into v3.1
+ ///
+ ///
+ void SerializeAsV31(IOpenApiWriter writer);
+
///
/// Serialize Open API element to v3.0.
///
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs
similarity index 58%
rename from src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs
rename to src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs
index d70766132..97d1d3c9b 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IOpenApiVersionService.cs
+++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs
@@ -1,11 +1,10 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers.ParseNodes;
+using Microsoft.OpenApi.Reader.ParseNodes;
-namespace Microsoft.OpenApi.Readers.Interface
+namespace Microsoft.OpenApi.Interfaces
{
///
/// Interface to a version specific parsing implementations.
@@ -17,16 +16,19 @@ internal interface IOpenApiVersionService
///
/// The reference string.
/// The type of the reference.
+ /// The summary of the reference.
+ /// A reference description
/// The object or null.
- OpenApiReference ConvertToOpenApiReference(string reference, ReferenceType? type);
+ OpenApiReference ConvertToOpenApiReference(string reference, ReferenceType? type, string summary = null, string description = null);
///
/// Loads an OpenAPI Element from a document fragment
///
/// Type of element to load
/// document fragment node
+ /// A host document instance.
/// Instance of OpenAPIElement
- T LoadElement(ParseNode node) where T : IOpenApiElement;
+ T LoadElement(ParseNode node, OpenApiDocument doc = null) where T : IOpenApiElement;
///
/// Converts a generic RootNode instance into a strongly typed OpenApiDocument
@@ -34,5 +36,13 @@ internal interface IOpenApiVersionService
/// RootNode containing the information to be converted into an OpenAPI Document
/// Instance of OpenApiDocument populated with data from rootNode
OpenApiDocument LoadDocument(RootNode rootNode);
+
+ ///
+ /// Gets the description and summary scalar values in a reference object for V3.1 support
+ ///
+ /// A YamlMappingNode.
+ /// The scalar value we're parsing.
+ /// The resulting node value.
+ string GetReferenceScalarValues(MapNode mapNode, string scalarValue);
}
}
diff --git a/src/Microsoft.OpenApi.Readers/Interface/IStreamLoader.cs b/src/Microsoft.OpenApi/Interfaces/IStreamLoader.cs
similarity index 95%
rename from src/Microsoft.OpenApi.Readers/Interface/IStreamLoader.cs
rename to src/Microsoft.OpenApi/Interfaces/IStreamLoader.cs
index 1c5471238..c3edebe1b 100644
--- a/src/Microsoft.OpenApi.Readers/Interface/IStreamLoader.cs
+++ b/src/Microsoft.OpenApi/Interfaces/IStreamLoader.cs
@@ -7,7 +7,7 @@
using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
-namespace Microsoft.OpenApi.Readers.Interface
+namespace Microsoft.OpenApi.Interfaces
{
///
/// Interface for service that translates a URI into a stream that can be loaded by a Reader
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index eb0ee6b12..6ddac0ec9 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -3,7 +3,7 @@
netstandard2.0
Latest
true
- 1.6.22
+ 2.0.0-preview1
.NET models with JSON and YAML writers for OpenAPI specification
true
@@ -17,6 +17,14 @@
..\Microsoft.OpenApi.snk
+
+
+ true
+
+
+
+
+
True
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs
index 683082e2c..a5bae9fa9 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs
@@ -8,6 +8,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
+using System.Text.Json.Nodes;
namespace Microsoft.OpenApi.MicrosoftExtensions;
@@ -71,23 +72,23 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
}
}
///
- /// Parses the to .
+ /// Parses the to .
///
/// The source object.
/// The .
/// When the source element is not an object
- public static OpenApiDeprecationExtension Parse(IOpenApiAny source)
+ public static OpenApiDeprecationExtension Parse(JsonNode source)
{
- if (source is not OpenApiObject rawObject) return null;
+ if (source is not JsonObject rawObject) return null;
var extension = new OpenApiDeprecationExtension();
- if (rawObject.TryGetValue(nameof(RemovalDate).ToFirstCharacterLowerCase(), out var removalDate) && removalDate is OpenApiDateTime removalDateValue)
- extension.RemovalDate = removalDateValue.Value;
- if (rawObject.TryGetValue(nameof(Date).ToFirstCharacterLowerCase(), out var date) && date is OpenApiDateTime dateValue)
- extension.Date = dateValue.Value;
- if (rawObject.TryGetValue(nameof(Version).ToFirstCharacterLowerCase(), out var version) && version is OpenApiString versionValue)
- extension.Version = versionValue.Value;
- if (rawObject.TryGetValue(nameof(Description).ToFirstCharacterLowerCase(), out var description) && description is OpenApiString descriptionValue)
- extension.Description = descriptionValue.Value;
+ if (rawObject.TryGetPropertyValue(nameof(RemovalDate).ToFirstCharacterLowerCase(), out var removalDate) && removalDate is JsonNode removalDateValue)
+ extension.RemovalDate = removalDateValue.GetValue();
+ if (rawObject.TryGetPropertyValue(nameof(Date).ToFirstCharacterLowerCase(), out var date) && date is JsonNode dateValue)
+ extension.Date = dateValue.GetValue();
+ if (rawObject.TryGetPropertyValue(nameof(Version).ToFirstCharacterLowerCase(), out var version) && version is JsonNode versionValue)
+ extension.Version = versionValue.GetValue();
+ if (rawObject.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var description) && description is JsonNode descriptionValue)
+ extension.Description = descriptionValue.GetValue();
return extension;
}
}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs
index 946537478..9cbae6350 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs
@@ -8,6 +8,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
+using System.Text.Json.Nodes;
namespace Microsoft.OpenApi.MicrosoftExtensions;
@@ -38,18 +39,18 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
writer.WriteEndObject();
}
///
- /// Parse the extension from the raw IOpenApiAny object.
+ /// Parse the extension from the raw OpenApiAny object.
///
/// The source element to parse.
/// The .
/// When the source element is not an object
- public static OpenApiEnumFlagsExtension Parse(IOpenApiAny source)
+ public static OpenApiEnumFlagsExtension Parse(JsonNode source)
{
- if (source is not OpenApiObject rawObject) return null;
+ if (source is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
var extension = new OpenApiEnumFlagsExtension();
- if (rawObject.TryGetValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is OpenApiBoolean isFlags)
+ if (rawObject.TryGetPropertyValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is JsonNode isFlags)
{
- extension.IsFlags = isFlags.Value;
+ extension.IsFlags = isFlags.GetValue();
}
return extension;
}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs
index 272f4b313..1235e68b0 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs
@@ -10,6 +10,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
+using System.Text.Json.Nodes;
namespace Microsoft.OpenApi.MicrosoftExtensions;
@@ -62,14 +63,14 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
/// The source element to parse.
/// The .
/// When the source element is not an object
- public static OpenApiEnumValuesDescriptionExtension Parse(IOpenApiAny source)
+ public static OpenApiEnumValuesDescriptionExtension Parse(JsonNode source)
{
- if (source is not OpenApiObject rawObject) return null;
+ if (source is not JsonObject rawObject) return null;
var extension = new OpenApiEnumValuesDescriptionExtension();
- if (rawObject.TryGetValue("values", out var values) && values is OpenApiArray valuesArray)
+ if (rawObject.TryGetPropertyValue("values", out var values) && values is JsonArray valuesArray)
{
extension.ValuesDescriptions.AddRange(valuesArray
- .OfType()
+ .OfType()
.Select(x => new EnumDescription(x)));
}
return extension;
@@ -92,15 +93,15 @@ public EnumDescription()
/// Constructor from a raw OpenApiObject
///
/// The source object
- public EnumDescription(OpenApiObject source)
+ public EnumDescription(JsonObject source)
{
if (source is null) throw new ArgumentNullException(nameof(source));
- if (source.TryGetValue(nameof(Value).ToFirstCharacterLowerCase(), out var rawValue) && rawValue is OpenApiString value)
- Value = value.Value;
- if (source.TryGetValue(nameof(Description).ToFirstCharacterLowerCase(), out var rawDescription) && rawDescription is OpenApiString description)
- Description = description.Value;
- if (source.TryGetValue(nameof(Name).ToFirstCharacterLowerCase(), out var rawName) && rawName is OpenApiString name)
- Name = name.Value;
+ if (source.TryGetPropertyValue(nameof(Value).ToFirstCharacterLowerCase(), out var rawValue) && rawValue is JsonNode value)
+ Value = value.GetValue();
+ if (source.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var rawDescription) && rawDescription is JsonNode description)
+ Description = description.GetValue();
+ if (source.TryGetPropertyValue(nameof(Name).ToFirstCharacterLowerCase(), out var rawName) && rawName is JsonNode name)
+ Name = name.GetValue();
}
///
/// The description for the enum symbol
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs
index 9b81e2561..f64eebf3f 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs
@@ -8,6 +8,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
+using System.Text.Json.Nodes;
namespace Microsoft.OpenApi.MicrosoftExtensions;
@@ -71,23 +72,23 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
/// The source element to parse.
/// The .
/// When the source element is not an object
- public static OpenApiPagingExtension Parse(IOpenApiAny source)
+ public static OpenApiPagingExtension Parse(JsonNode source)
{
- if (source is not OpenApiObject rawObject) return null;
+ if (source is not JsonObject rawObject) return null;
var extension = new OpenApiPagingExtension();
- if (rawObject.TryGetValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is OpenApiString nextLinkNameStr)
+ if (rawObject.TryGetPropertyValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is JsonNode nextLinkNameStr)
{
- extension.NextLinkName = nextLinkNameStr.Value;
+ extension.NextLinkName = nextLinkNameStr.GetValue();
}
- if (rawObject.TryGetValue(nameof(OperationName).ToFirstCharacterLowerCase(), out var opName) && opName is OpenApiString opNameStr)
+ if (rawObject.TryGetPropertyValue(nameof(OperationName).ToFirstCharacterLowerCase(), out var opName) && opName is JsonNode opNameStr)
{
- extension.OperationName = opNameStr.Value;
+ extension.OperationName = opNameStr.GetValue();
}
- if (rawObject.TryGetValue(nameof(ItemName).ToFirstCharacterLowerCase(), out var itemName) && itemName is OpenApiString itemNameStr)
+ if (rawObject.TryGetPropertyValue(nameof(ItemName).ToFirstCharacterLowerCase(), out var itemName) && itemName is JsonNode itemNameStr)
{
- extension.ItemName = itemNameStr.Value;
+ extension.ItemName = itemNameStr.GetValue();
}
return extension;
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs
index 0250af758..ad47db39b 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs
@@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System;
+using System.Text.Json.Nodes;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
@@ -33,16 +34,16 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
public bool IsPrimaryErrorMessage { get; set; }
///
- /// Parses the to .
+ /// Parses the to .
///
/// The source object.
/// The .
- public static OpenApiPrimaryErrorMessageExtension Parse(IOpenApiAny source)
+ public static OpenApiPrimaryErrorMessageExtension Parse(JsonNode source)
{
- if (source is not OpenApiBoolean rawObject) return null;
+ if (source is not JsonNode rawObject) return null;
return new()
{
- IsPrimaryErrorMessage = rawObject.Value
+ IsPrimaryErrorMessage = rawObject.GetValue()
};
}
}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs
index e45d9e7e9..2d3a8c117 100644
--- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs
@@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System;
+using System.Text.Json.Nodes;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
@@ -34,17 +35,17 @@ public bool? IsReserved
get; set;
}
///
- /// Parses the to .
+ /// Parses the to .
///
/// The source object.
/// The .
///
- public static OpenApiReservedParameterExtension Parse(IOpenApiAny source)
+ public static OpenApiReservedParameterExtension Parse(JsonNode source)
{
- if (source is not OpenApiBoolean rawBoolean) return null;
+ if (source is not JsonNode rawBoolean) return null;
return new()
{
- IsReserved = rawBoolean.Value
+ IsReserved = rawBoolean.GetValue()
};
}
}
diff --git a/src/Microsoft.OpenApi/Models/JsonSchemaType.cs b/src/Microsoft.OpenApi/Models/JsonSchemaType.cs
new file mode 100644
index 000000000..6024aa21b
--- /dev/null
+++ b/src/Microsoft.OpenApi/Models/JsonSchemaType.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+using System;
+
+namespace Microsoft.OpenApi.Models
+{
+ ///
+ /// Represents the type of a JSON schema.
+ ///
+ [Flags]
+ public enum JsonSchemaType
+ {
+ ///
+ /// Represents a null type.
+ ///
+ Null = 1,
+
+ ///
+ /// Represents a boolean type.
+ ///
+ Boolean = 2,
+
+ ///
+ /// Represents an integer type.
+ ///
+ Integer = 4,
+
+ ///
+ /// Represents a number type.
+ ///
+ Number = 8,
+
+ ///
+ /// Represents a string type.
+ ///
+ String = 16,
+
+ ///
+ /// Represents an object type.
+ ///
+ Object = 32,
+
+ ///
+ /// Represents an array type.
+ ///
+ Array = 64,
+ }
+}
diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
index 98799c9c6..f538d90c0 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using System;
using System.Collections.Generic;
using Microsoft.OpenApi.Expressions;
using Microsoft.OpenApi.Interfaces;
@@ -11,18 +12,18 @@ namespace Microsoft.OpenApi.Models
///
/// Callback Object: A map of possible out-of band callbacks related to the parent operation.
///
- public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IEffective
+ public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible
{
///
/// A Path Item Object used to define a callback request and expected responses.
///
- public Dictionary PathItems { get; set; }
+ public virtual Dictionary PathItems { get; set; }
= new();
///
/// Indicates if object is populated with data or is just a reference to the data
///
- public bool UnresolvedReference { get; set; }
+ public virtual bool UnresolvedReference { get; set; }
///
/// Reference pointer.
@@ -32,7 +33,7 @@ public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IEffec
///
/// This object MAY be extended with Specification Extensions.
///
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public virtual IDictionary Extensions { get; set; } = new Dictionary();
///
/// Parameter-less constructor
@@ -60,71 +61,44 @@ public void AddPathItem(RuntimeExpression expression, OpenApiPathItem pathItem)
Utils.CheckArgumentNull(expression);
Utils.CheckArgumentNull(pathItem);
- if (PathItems == null)
- {
- PathItems = new();
- }
+ PathItems ??= new();
PathItems.Add(expression, pathItem);
}
///
- /// Serialize to Open Api v3.0
+ /// Serialize to Open Api v3.1
///
- public void SerializeAsV3(IOpenApiWriter writer)
+ ///
+ ///
+ public virtual void SerializeAsV31(IOpenApiWriter writer)
{
- Utils.CheckArgumentNull(writer);
-
- var target = this;
-
- if (Reference != null)
- {
- if (!writer.GetSettings().ShouldInlineReference(Reference))
- {
- Reference.SerializeAsV3(writer);
- return;
- }
- else
- {
- target = GetEffective(Reference.HostDocument);
- }
- }
- target.SerializeAsV3WithoutReference(writer);
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer));
}
///
- /// Returns an effective OpenApiCallback object based on the presence of a $ref
+ /// Serialize to Open Api v3.0
///
- /// The host OpenApiDocument that contains the reference.
- /// OpenApiCallback
- public OpenApiCallback GetEffective(OpenApiDocument doc)
+ public virtual void SerializeAsV3(IOpenApiWriter writer)
{
- if (this.Reference != null)
- {
- return doc.ResolveReferenceTo(this.Reference);
- }
- else
- {
- return this;
- }
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer));
}
- ///
- /// Serialize to OpenAPI V3 document without using reference.
- ///
-
- public void SerializeAsV3WithoutReference(IOpenApiWriter writer)
+ internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
+ Action callback)
{
+ Utils.CheckArgumentNull(writer);
+
writer.WriteStartObject();
// path items
foreach (var item in PathItems)
{
- writer.WriteRequiredObject(item.Key.Expression, item.Value, (w, p) => p.SerializeAsV3(w));
+ writer.WriteRequiredObject(item.Key.Expression, item.Value, callback);
}
// extensions
- writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_0);
+ writer.WriteExtensions(Extensions, version);
writer.WriteEndObject();
}
@@ -136,14 +110,5 @@ public void SerializeAsV2(IOpenApiWriter writer)
{
// Callback object does not exist in V2.
}
-
- ///
- /// Serialize to OpenAPI V2 document without using reference.
- ///
-
- public void SerializeAsV2WithoutReference(IOpenApiWriter writer)
- {
- // Callback object does not exist in V2.
- }
}
}
diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
index 52e8cac14..f672b7dd1 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs
@@ -1,11 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
+using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Models.References;
using Microsoft.OpenApi.Writers;
+#nullable enable
+
namespace Microsoft.OpenApi.Models
{
///
@@ -16,55 +20,60 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible
///
/// An object to hold reusable Objects.
///
- public IDictionary Schemas { get; set; } = new Dictionary();
+ public IDictionary? Schemas { get; set; } = new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Responses { get; set; } = new Dictionary();
+ public virtual IDictionary? Responses { get; set; } = new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Parameters { get; set; } =
+ public virtual IDictionary? Parameters { get; set; } =
new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Examples { get; set; } = new Dictionary();
+ public virtual IDictionary? Examples { get; set; } = new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary RequestBodies { get; set; } =
+ public virtual IDictionary? RequestBodies { get; set; } =
new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Headers { get; set; } = new Dictionary();
+ public virtual IDictionary? Headers { get; set; } = new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary SecuritySchemes { get; set; } =
+ public virtual IDictionary? SecuritySchemes { get; set; } =
new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Links { get; set; } = new Dictionary();
+ public virtual IDictionary? Links { get; set; } = new Dictionary();
///
/// An object to hold reusable Objects.
///
- public IDictionary Callbacks { get; set; } = new Dictionary();
+ public virtual IDictionary? Callbacks { get; set; } = new Dictionary();
+
+ ///
+ /// An object to hold reusable Object.
+ ///
+ public virtual IDictionary? PathItems { get; set; } = new Dictionary();
///
/// This object MAY be extended with Specification Extensions.
///
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public virtual IDictionary? Extensions { get; set; } = new Dictionary();
///
/// Parameter-less constructor
@@ -74,7 +83,7 @@ public OpenApiComponents() { }
///
/// Initializes a copy of an object
///
- public OpenApiComponents(OpenApiComponents components)
+ public OpenApiComponents(OpenApiComponents? components)
{
Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null;
Responses = components?.Responses != null ? new Dictionary(components.Responses) : null;
@@ -85,13 +94,15 @@ public OpenApiComponents(OpenApiComponents components)
SecuritySchemes = components?.SecuritySchemes != null ? new Dictionary(components.SecuritySchemes) : null;
Links = components?.Links != null ? new Dictionary(components.Links) : null;
Callbacks = components?.Callbacks != null ? new Dictionary(components.Callbacks) : null;
+ PathItems = components?.PathItems != null ? new Dictionary(components.PathItems) : null;
Extensions = components?.Extensions != null ? new Dictionary(components.Extensions) : null;
}
///
- /// Serialize to Open Api v3.0.
+ /// Serialize to Open API v3.1.
///
- public void SerializeAsV3(IOpenApiWriter writer)
+ ///
+ public void SerializeAsV31(IOpenApiWriter writer)
{
Utils.CheckArgumentNull(writer);
@@ -99,24 +110,59 @@ public void SerializeAsV3(IOpenApiWriter writer)
// however if they have cycles, then we will need a component rendered
if (writer.GetSettings().InlineLocalReferences)
{
- var loops = writer.GetSettings().LoopDetector.Loops;
- writer.WriteStartObject();
- if (loops.TryGetValue(typeof(OpenApiSchema), out var schemas))
- {
- var openApiSchemas = schemas.Cast().Distinct().ToList()
- .ToDictionary(k => k.Reference.Id);
+ RenderComponents(writer, (writer, element) => element.SerializeAsV31(writer));
+ return;
+ }
+
+ writer.WriteStartObject();
- writer.WriteOptionalMap(
- OpenApiConstants.Schemas,
- Schemas,
- (w, _, component) => component.SerializeAsV3WithoutReference(w));
+ // pathItems - only present in v3.1
+ writer.WriteOptionalMap(
+ OpenApiConstants.PathItems,
+ PathItems,
+ (w, key, component) =>
+ {
+ if (component is OpenApiPathItemReference reference)
+ {
+ reference.SerializeAsV31(w);
+ }
+ else
+ {
+ component.SerializeAsV31(w);
}
- writer.WriteEndObject();
+ });
+
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer),
+ (writer, referenceElement) => referenceElement.SerializeAsV31(writer));
+ }
+
+ ///
+ /// Serialize to v3.0
+ ///
+ ///
+ public void SerializeAsV3(IOpenApiWriter writer)
+ {
+ Utils.CheckArgumentNull(writer);
+
+ // If references have been inlined we don't need the to render the components section
+ // however if they have cycles, then we will need a component rendered
+ if (writer.GetSettings().InlineLocalReferences)
+ {
+ RenderComponents(writer, (writer, element) => element.SerializeAsV3(writer));
return;
}
writer.WriteStartObject();
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer),
+ (writer, referenceElement) => referenceElement.SerializeAsV3(writer));
+ }
+ ///
+ /// Serialize .
+ ///
+ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
+ Action callback, Action action)
+ {
// Serialize each referenceable object as full object without reference if the reference in the object points to itself.
// If the reference exists but points to other objects, the object is serialized to just that reference.
@@ -126,14 +172,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Schemas,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Schema} &&
- component.Reference.Id == key)
+ if (component is OpenApiSchemaReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -143,14 +188,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Responses,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Response} &&
- component.Reference.Id == key)
+ if (component is OpenApiResponseReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -160,14 +204,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Parameters,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Parameter} &&
- component.Reference.Id == key)
+ if (component is OpenApiParameterReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -177,14 +220,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Examples,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Example} &&
- component.Reference.Id == key)
+ if (component is OpenApiExampleReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -194,14 +236,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
RequestBodies,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.RequestBody} &&
- component.Reference.Id == key)
+ if (component is OpenApiRequestBodyReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -211,14 +252,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Headers,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Header} &&
- component.Reference.Id == key)
+ if (component is OpenApiHeaderReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -228,14 +268,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
SecuritySchemes,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.SecurityScheme} &&
- component.Reference.Id == key)
+ if (component is OpenApiSecuritySchemeReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -245,14 +284,13 @@ public void SerializeAsV3(IOpenApiWriter writer)
Links,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Link} &&
- component.Reference.Id == key)
+ if (component is OpenApiLinkReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
@@ -262,20 +300,29 @@ public void SerializeAsV3(IOpenApiWriter writer)
Callbacks,
(w, key, component) =>
{
- if (component.Reference is {Type: ReferenceType.Callback} &&
- component.Reference.Id == key)
+ if (component is OpenApiCallbackReference reference)
{
- component.SerializeAsV3WithoutReference(w);
+ action(w, reference);
}
else
{
- component.SerializeAsV3(w);
+ callback(w, component);
}
});
// extensions
- writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_0);
+ writer.WriteExtensions(Extensions, version);
+ writer.WriteEndObject();
+ }
+ private void RenderComponents(IOpenApiWriter writer, Action callback)
+ {
+ var loops = writer.GetSettings().LoopDetector.Loops;
+ writer.WriteStartObject();
+ if (loops.TryGetValue(typeof(OpenApiSchema), out List
public const string OpenApi = "openapi";
+ ///
+ /// Field: Json
+ ///
+ public const string Json = "json";
+
+ ///
+ /// Field: Yaml
+ ///
+ public const string Yaml = "yaml";
+
+ ///
+ /// Field: Yml
+ ///
+ public const string Yml = "yml";
+
///
/// Field: Info
///
public const string Info = "info";
+ ///
+ /// Field: JsonSchemaDialect
+ ///
+ public const string JsonSchemaDialect = "jsonSchemaDialect";
+
+ ///
+ /// Field: Webhooks
+ ///
+ public const string Webhooks = "webhooks";
+
///
/// Field: Title
///
@@ -35,6 +60,66 @@ public static class OpenApiConstants
///
public const string Format = "format";
+ ///
+ /// Field: Schema
+ ///
+ public const string DollarSchema = "$schema";
+
+ ///
+ /// Field: Id
+ ///
+ public const string Id = "$id";
+
+ ///
+ /// Field: Comment
+ ///
+ public const string Comment = "$comment";
+
+ ///
+ /// Field: Vocabulary
+ ///
+ public const string Vocabulary = "$vocabulary";
+
+ ///
+ /// Field: DynamicRef
+ ///
+ public const string DynamicRef = "$dynamicRef";
+
+ ///
+ /// Field: DynamicAnchor
+ ///
+ public const string DynamicAnchor = "$dynamicAnchor";
+
+ ///
+ /// Field: RecursiveRef
+ ///
+ public const string RecursiveRef = "$recursiveRef";
+
+ ///
+ /// Field: RecursiveAnchor
+ ///
+ public const string RecursiveAnchor = "$recursiveAnchor";
+
+ ///
+ /// Field: Definitions
+ ///
+ public const string Defs = "$defs";
+
+ ///
+ /// Field: V31ExclusiveMaximum
+ ///
+ public const string V31ExclusiveMaximum = "exclusiveMaximum";
+
+ ///
+ /// Field: V31ExclusiveMinimum
+ ///
+ public const string V31ExclusiveMinimum = "exclusiveMinimum";
+
+ ///
+ /// Field: UnevaluatedProperties
+ ///
+ public const string UnevaluatedProperties = "unevaluatedProperties";
+
///
/// Field: Version
///
@@ -75,6 +160,11 @@ public static class OpenApiConstants
///
public const string Components = "components";
+ ///
+ /// Field: PathItems
+ ///
+ public const string PathItems = "pathItems";
+
///
/// Field: Security
///
@@ -120,6 +210,11 @@ public static class OpenApiConstants
///
public const string Name = "name";
+ ///
+ /// Field: Identifier
+ ///
+ public const string Identifier = "identifier";
+
///
/// Field: Namespace
///
@@ -380,6 +475,11 @@ public static class OpenApiConstants
///
public const string Properties = "properties";
+ ///
+ /// Field: Pattern Properties
+ ///
+ public const string PatternProperties = "patternProperties";
+
///
/// Field: AdditionalProperties
///
@@ -580,6 +680,36 @@ public static class OpenApiConstants
///
public static readonly Uri defaultUrl = new("http://localhost/");
+ ///
+ /// Field: V3 JsonSchema Reference Uri
+ ///
+ public const string V3ReferenceUri = "https://registry/components/schemas/";
+
+ ///
+ /// Field: V2 JsonSchema Reference Uri
+ ///
+ public const string V2ReferenceUri = "https://registry/definitions/";
+
+ ///
+ /// The default registry uri for OpenApi documents and workspaces
+ ///
+ public const string BaseRegistryUri = "https://openapi.net/";
+
+ ///
+ /// The components path segment in a $ref value.
+ ///
+ public const string ComponentsSegment = "/components/";
+
+ ///
+ /// Field: Null
+ ///
+ public const string Null = "null";
+
+ ///
+ /// Field: Nullable extension
+ ///
+ public const string NullableExtension = "x-nullable";
+
#region V2.0
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiContact.cs b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
index 365b96807..15d67cc76 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiContact.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiContact.cs
@@ -50,6 +50,15 @@ public OpenApiContact(OpenApiContact contact)
Extensions = contact?.Extensions != null ? new Dictionary(contact.Extensions) : null;
}
+ ///
+ /// Serialize to Open Api v3.1
+ ///
+ ///
+ public void SerializeAsV31(IOpenApiWriter writer)
+ {
+ WriteInternal(writer, OpenApiSpecVersion.OpenApi3_1);
+ }
+
///
/// Serialize to Open Api v3.0
///
@@ -68,6 +77,8 @@ public void SerializeAsV2(IOpenApiWriter writer)
private void WriteInternal(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
{
+ Utils.CheckArgumentNull(writer);
+
writer.WriteStartObject();
// name
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
index bb98be623..342025f9f 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiDiscriminator.cs
@@ -10,7 +10,7 @@ namespace Microsoft.OpenApi.Models
///
/// Discriminator object.
///
- public class OpenApiDiscriminator : IOpenApiSerializable
+ public class OpenApiDiscriminator : IOpenApiSerializable, IOpenApiExtensible
{
///
/// REQUIRED. The name of the property in the payload that will hold the discriminator value.
@@ -22,6 +22,11 @@ public class OpenApiDiscriminator : IOpenApiSerializable
///
public IDictionary Mapping { get; set; } = new Dictionary();
+ ///
+ /// This object MAY be extended with Specification Extensions.
+ ///
+ public IDictionary Extensions { get; set; } = new Dictionary();
+
///
/// Parameter-less constructor
///
@@ -34,12 +39,38 @@ public OpenApiDiscriminator(OpenApiDiscriminator discriminator)
{
PropertyName = discriminator?.PropertyName ?? PropertyName;
Mapping = discriminator?.Mapping != null ? new Dictionary(discriminator.Mapping) : null;
+ Extensions = discriminator?.Extensions != null ? new Dictionary(discriminator.Extensions) : null;
+ }
+
+ ///
+ /// Serialize to Open Api v3.1
+ ///
+ ///
+ public void SerializeAsV31(IOpenApiWriter writer)
+ {
+ SerializeInternal(writer);
+
+ // extensions
+ writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_1);
+
+ writer.WriteEndObject();
}
///
/// Serialize to Open Api v3.0
///
public void SerializeAsV3(IOpenApiWriter writer)
+ {
+ SerializeInternal(writer);
+
+ writer.WriteEndObject();
+ }
+
+ ///
+ /// Serialize to Open Api v3.0
+ ///
+ ///
+ private void SerializeInternal(IOpenApiWriter writer)
{
Utils.CheckArgumentNull(writer);
@@ -50,8 +81,6 @@ public void SerializeAsV3(IOpenApiWriter writer)
// mapping
writer.WriteOptionalMap(OpenApiConstants.Mapping, Mapping, (w, s) => w.WriteValue(s));
-
- writer.WriteEndObject();
}
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
index 1a7035793..0baf31e68 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs
@@ -7,12 +7,17 @@
using System.Linq;
using System.Security.Cryptography;
using System.Text;
-using Microsoft.OpenApi.Exceptions;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Models.References;
+using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.Services;
using Microsoft.OpenApi.Writers;
+#nullable enable
+
namespace Microsoft.OpenApi.Models
{
///
@@ -21,49 +26,62 @@ namespace Microsoft.OpenApi.Models
public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenApiAnnotatable
{
///
- /// Related workspace containing OpenApiDocuments that are referenced in this document
+ /// Related workspace containing components that are referenced in a document
///
- public OpenApiWorkspace Workspace { get; set; }
+ public OpenApiWorkspace? Workspace { get; set; }
///
/// REQUIRED. Provides metadata about the API. The metadata MAY be used by tooling as required.
///
public OpenApiInfo Info { get; set; }
+ ///
+ /// The default value for the $schema keyword within Schema Objects contained within this OAS document. This MUST be in the form of a URI.
+ ///
+ public string? JsonSchemaDialect { get; set; }
+
///
/// An array of Server Objects, which provide connectivity information to a target server.
///
- public IList Servers { get; set; } = new List();
+ public IList? Servers { get; set; } = new List();
///
/// REQUIRED. The available paths and operations for the API.
///
public OpenApiPaths Paths { get; set; }
+ ///
+ /// The incoming webhooks that MAY be received as part of this API and that the API consumer MAY choose to implement.
+ /// A map of requests initiated other than by an API call, for example by an out of band registration.
+ /// The key name is a unique string to refer to each webhook, while the (optionally referenced) Path Item Object describes a request that may be initiated by the API provider and the expected responses
+ ///
+ public IDictionary? Webhooks { get; set; } = new Dictionary();
+
///
/// An element to hold various schemas for the specification.
///
- public OpenApiComponents Components { get; set; }
+ public OpenApiComponents? Components { get; set; }
///
/// A declaration of which security mechanisms can be used across the API.
///
- public IList SecurityRequirements { get; set; } = new List();
+ public IList? SecurityRequirements { get; set; } =
+ new List();
///
/// A list of tags used by the specification with additional metadata.
///
- public IList Tags { get; set; } = new List();
+ public IList? Tags { get; set; } = new List();
///
/// Additional external documentation.
///
- public OpenApiExternalDocs ExternalDocs { get; set; }
+ public OpenApiExternalDocs? ExternalDocs { get; set; }
///
/// This object MAY be extended with Specification Extensions.
///
- public IDictionary Extensions { get; set; } = new Dictionary();
+ public IDictionary? Extensions { get; set; } = new Dictionary();
///
/// The unique hash code of the generated OpenAPI document
@@ -71,28 +89,79 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IOpenAp
public string HashCode => GenerateHashValue(this);
///
- public IDictionary Annotations { get; set; }
+ public IDictionary? Annotations { get; set; }
///
- /// Parameter-less constructor
+ /// Implements IBaseDocument
///
- public OpenApiDocument() {}
+ public Uri BaseUri { get; }
+ ///
+ /// Parameter-less constructor
+ ///
+ public OpenApiDocument()
+ {
+ Workspace = new OpenApiWorkspace();
+ BaseUri = new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid());
+ Info = new OpenApiInfo();
+ Paths = new OpenApiPaths();
+ }
+
///
/// Initializes a copy of an an object
///
- public OpenApiDocument(OpenApiDocument document)
+ public OpenApiDocument(OpenApiDocument? document)
{
Workspace = document?.Workspace != null ? new(document?.Workspace) : null;
- Info = document?.Info != null ? new(document?.Info) : null;
+ Info = document?.Info != null ? new(document?.Info) : new OpenApiInfo();
+ JsonSchemaDialect = document?.JsonSchemaDialect ?? JsonSchemaDialect;
Servers = document?.Servers != null ? new List(document.Servers) : null;
- Paths = document?.Paths != null ? new(document?.Paths) : null;
+ Paths = document?.Paths != null ? new(document?.Paths) : new OpenApiPaths();
+ Webhooks = document?.Webhooks != null ? new Dictionary(document.Webhooks) : null;
Components = document?.Components != null ? new(document?.Components) : null;
SecurityRequirements = document?.SecurityRequirements != null ? new List(document.SecurityRequirements) : null;
Tags = document?.Tags != null ? new List(document.Tags) : null;
ExternalDocs = document?.ExternalDocs != null ? new(document?.ExternalDocs) : null;
Extensions = document?.Extensions != null ? new Dictionary(document.Extensions) : null;
Annotations = document?.Annotations != null ? new Dictionary(document.Annotations) : null;
+ BaseUri = document?.BaseUri != null ? document.BaseUri : new(OpenApiConstants.BaseRegistryUri + Guid.NewGuid());
+ }
+
+ ///
+ /// Serialize to Open API v3.1 document.
+ ///
+ ///
+ public void SerializeAsV31(IOpenApiWriter writer)
+ {
+ Utils.CheckArgumentNull(writer);
+
+ writer.WriteStartObject();
+
+ // openApi;
+ writer.WriteProperty(OpenApiConstants.OpenApi, "3.1.0");
+
+ // jsonSchemaDialect
+ writer.WriteProperty(OpenApiConstants.JsonSchemaDialect, JsonSchemaDialect);
+
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (w, element) => element.SerializeAsV31(w));
+
+ // webhooks
+ writer.WriteOptionalMap(
+ OpenApiConstants.Webhooks,
+ Webhooks,
+ (w, key, component) =>
+ {
+ if (component is OpenApiPathItemReference reference)
+ {
+ reference.SerializeAsV31(w);
+ }
+ else
+ {
+ component.SerializeAsV31(w);
+ }
+ });
+
+ writer.WriteEndObject();
}
///
@@ -106,35 +175,45 @@ public void SerializeAsV3(IOpenApiWriter writer)
// openapi
writer.WriteProperty(OpenApiConstants.OpenApi, "3.0.1");
+ SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (w, element) => element.SerializeAsV3(w));
+ writer.WriteEndObject();
+ }
+ ///
+ /// Serialize
+ ///
+ ///
+ ///
+ ///
+ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
+ Action callback)
+ {
// info
- writer.WriteRequiredObject(OpenApiConstants.Info, Info, (w, i) => i.SerializeAsV3(w));
+ writer.WriteRequiredObject(OpenApiConstants.Info, Info, callback);
// servers
- writer.WriteOptionalCollection(OpenApiConstants.Servers, Servers, (w, s) => s.SerializeAsV3(w));
+ writer.WriteOptionalCollection(OpenApiConstants.Servers, Servers, callback);
- // paths
- writer.WriteRequiredObject(OpenApiConstants.Paths, Paths, (w, p) => p.SerializeAsV3(w));
+ // paths
+ writer.WriteRequiredObject(OpenApiConstants.Paths, Paths, callback);
// components
- writer.WriteOptionalObject(OpenApiConstants.Components, Components, (w, c) => c.SerializeAsV3(w));
+ writer.WriteOptionalObject(OpenApiConstants.Components, Components, callback);
// security
writer.WriteOptionalCollection(
OpenApiConstants.Security,
SecurityRequirements,
- (w, s) => s.SerializeAsV3(w));
+ callback);
// tags
- writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.SerializeAsV3WithoutReference(w));
+ writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => callback(w, t));
// external docs
- writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, e) => e.SerializeAsV3(w));
+ writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, callback);
// extensions
- writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_0);
-
- writer.WriteEndObject();
+ writer.WriteExtensions(Extensions, version);
}
///
@@ -164,10 +243,10 @@ public void SerializeAsV2(IOpenApiWriter writer)
{
var loops = writer.GetSettings().LoopDetector.Loops;
- if (loops.TryGetValue(typeof(OpenApiSchema), out var schemas))
+ if (loops.TryGetValue(typeof(OpenApiSchema), out List