diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
index dd617aef8..fd0d9325e 100644
--- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
+++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
@@ -15,7 +15,7 @@
Microsoft.OpenApi.Hidi
hidi
./../../artifacts
- 1.2.8
+ 1.2.9
OpenAPI.NET CLI tool for slicing OpenAPI documents
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
@@ -43,8 +43,8 @@
-
-
+
+
diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
index 2671664c1..4f6b336f9 100644
--- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
+++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
@@ -11,7 +11,7 @@
Microsoft
Microsoft.OpenApi.Readers
Microsoft.OpenApi.Readers
- 1.6.7
+ 1.6.8
OpenAPI.NET Readers for JSON and YAML documents
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
diff --git a/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs b/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
index 12ccdb681..56001e295 100644
--- a/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
+++ b/src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
@@ -3,6 +3,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.MicrosoftExtensions;
using Microsoft.OpenApi.Readers.Interface;
using Microsoft.OpenApi.Validations;
using System;
@@ -74,5 +75,31 @@ public class OpenApiReaderSettings
/// from an object.
///
public bool LeaveStreamOpen { get; set; }
+
+ ///
+ /// Adds parsers for Microsoft OpenAPI extensions:
+ /// -
+ /// -
+ /// -
+ /// -
+ /// -
+ /// -
+ /// NOTE: The list of extensions is subject to change.
+ ///
+ public void AddMicrosoftExtensionParsers()
+ {
+ if (!ExtensionParsers.ContainsKey(OpenApiPagingExtension.Name))
+ ExtensionParsers.Add(OpenApiPagingExtension.Name, static (i, _) => OpenApiPagingExtension.Parse(i));
+ if (!ExtensionParsers.ContainsKey(OpenApiEnumValuesDescriptionExtension.Name))
+ ExtensionParsers.Add(OpenApiEnumValuesDescriptionExtension.Name, static (i, _ ) => OpenApiEnumValuesDescriptionExtension.Parse(i));
+ if (!ExtensionParsers.ContainsKey(OpenApiPrimaryErrorMessageExtension.Name))
+ ExtensionParsers.Add(OpenApiPrimaryErrorMessageExtension.Name, static (i, _ ) => OpenApiPrimaryErrorMessageExtension.Parse(i));
+ if (!ExtensionParsers.ContainsKey(OpenApiDeprecationExtension.Name))
+ ExtensionParsers.Add(OpenApiDeprecationExtension.Name, static (i, _ ) => OpenApiDeprecationExtension.Parse(i));
+ if (!ExtensionParsers.ContainsKey(OpenApiReservedParameterExtension.Name))
+ ExtensionParsers.Add(OpenApiReservedParameterExtension.Name, static (i, _ ) => OpenApiReservedParameterExtension.Parse(i));
+ if (!ExtensionParsers.ContainsKey(OpenApiEnumFlagsExtension.Name))
+ ExtensionParsers.Add(OpenApiEnumFlagsExtension.Name, static (i, _ ) => OpenApiEnumFlagsExtension.Parse(i));
+ }
}
}
diff --git a/src/Microsoft.OpenApi/Extensions/StringExtensions.cs b/src/Microsoft.OpenApi/Extensions/StringExtensions.cs
index 18d559c1b..51ce37365 100644
--- a/src/Microsoft.OpenApi/Extensions/StringExtensions.cs
+++ b/src/Microsoft.OpenApi/Extensions/StringExtensions.cs
@@ -37,5 +37,7 @@ public static T GetEnumFromDisplayName(this string displayName)
return default;
}
+ internal static string ToFirstCharacterLowerCase(this string input)
+ => string.IsNullOrEmpty(input) ? string.Empty : char.ToLowerInvariant(input[0]) + input.Substring(1);
}
}
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index bc638c883..d7220bf6f 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -11,7 +11,7 @@
Microsoft
Microsoft.OpenApi
Microsoft.OpenApi
- 1.6.7
+ 1.6.8
.NET models with JSON and YAML writers for OpenAPI specification
© Microsoft Corporation. All rights reserved.
OpenAPI .NET
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs
new file mode 100644
index 000000000..25a3b56a5
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs
@@ -0,0 +1,93 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add deprecation information. x-ms-deprecation
+///
+public class OpenApiDeprecationExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-deprecation";
+ ///
+ /// The date at which the element has been/will be removed entirely from the service.
+ ///
+ public DateTimeOffset? RemovalDate
+ {
+ get; set;
+ }
+ ///
+ /// The date at which the element has been/will be deprecated.
+ ///
+ public DateTimeOffset? Date
+ {
+ get; set;
+ }
+ ///
+ /// The version this revision was introduced.
+ ///
+ public string Version
+ {
+ get; set;
+ } = string.Empty;
+ ///
+ /// The description of the revision.
+ ///
+ public string Description
+ {
+ get; set;
+ } = string.Empty;
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+
+ if (RemovalDate.HasValue || Date.HasValue || !string.IsNullOrEmpty(Version) || !string.IsNullOrEmpty(Description))
+ {
+ writer.WriteStartObject();
+
+ if (RemovalDate.HasValue)
+ writer.WriteProperty(nameof(RemovalDate).ToFirstCharacterLowerCase(), RemovalDate.Value);
+ if (Date.HasValue)
+ writer.WriteProperty(nameof(Date).ToFirstCharacterLowerCase(), Date.Value);
+ if (!string.IsNullOrEmpty(Version))
+ writer.WriteProperty(nameof(Version).ToFirstCharacterLowerCase(), Version);
+ if (!string.IsNullOrEmpty(Description))
+ writer.WriteProperty(nameof(Description).ToFirstCharacterLowerCase(), Description);
+
+ writer.WriteEndObject();
+ }
+ }
+ ///
+ /// Parses the to .
+ ///
+ /// The source object.
+ /// The .
+ /// When the source element is not an object
+ public static OpenApiDeprecationExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
+ 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;
+ return extension;
+ }
+}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs
new file mode 100644
index 000000000..e7dcf88f8
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs
@@ -0,0 +1,56 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add deprecation information. x-ms-enum-flags
+///
+public class OpenApiEnumFlagsExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-enum-flags";
+ ///
+ /// Whether the enum is a flagged enum.
+ ///
+ public bool IsFlags
+ {
+ get; set;
+ }
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if (writer == null)
+ throw new ArgumentNullException(nameof(writer));
+
+ writer.WriteStartObject();
+ writer.WriteProperty(nameof(IsFlags).ToFirstCharacterLowerCase(), IsFlags);
+ writer.WriteEndObject();
+ }
+ ///
+ /// Parse the extension from the raw IOpenApiAny object.
+ ///
+ /// The source element to parse.
+ /// The .
+ /// When the source element is not an object
+ public static OpenApiEnumFlagsExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
+ var extension = new OpenApiEnumFlagsExtension();
+ if (rawObject.TryGetValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is OpenApiBoolean isFlags)
+ {
+ extension.IsFlags = isFlags.Value;
+ }
+ return extension;
+ }
+}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs
new file mode 100644
index 000000000..b3db2b437
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs
@@ -0,0 +1,117 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add enum values descriptions.
+/// Based of the AutoRest specification https://github.com/Azure/autorest/blob/main/docs/extensions/readme.md#x-ms-enum
+///
+public class OpenApiEnumValuesDescriptionExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-enum";
+
+ ///
+ /// The of the enum.
+ ///
+ public string EnumName { get; set; } = string.Empty;
+
+ ///
+ /// Descriptions for the enum symbols, where the value MUST match the enum symbols in the main description
+ ///
+ public List ValuesDescriptions { get; set; } = new();
+
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if (writer is null) throw new ArgumentNullException(nameof(writer));
+ if ((specVersion == OpenApiSpecVersion.OpenApi2_0 || specVersion == OpenApiSpecVersion.OpenApi3_0) &&
+ !string.IsNullOrEmpty(EnumName) &&
+ ValuesDescriptions.Any())
+ { // when we upgrade to 3.1, we don't need to write this extension as JSON schema will support writing enum values
+ writer.WriteStartObject();
+ writer.WriteProperty(nameof(Name).ToFirstCharacterLowerCase(), EnumName);
+ writer.WriteProperty("modelAsString", false);
+ writer.WriteRequiredCollection("values", ValuesDescriptions, (w, x) =>
+ {
+ w.WriteStartObject();
+ w.WriteProperty(nameof(x.Value).ToFirstCharacterLowerCase(), x.Value);
+ w.WriteProperty(nameof(x.Description).ToFirstCharacterLowerCase(), x.Description);
+ w.WriteProperty(nameof(x.Name).ToFirstCharacterLowerCase(), x.Name);
+ w.WriteEndObject();
+ });
+ writer.WriteEndObject();
+ }
+ }
+ ///
+ /// Parse the extension from the raw IOpenApiAny object.
+ ///
+ /// The source element to parse.
+ /// The .
+ /// When the source element is not an object
+ public static OpenApiEnumValuesDescriptionExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
+ var extension = new OpenApiEnumValuesDescriptionExtension();
+ if (rawObject.TryGetValue("values", out var values) && values is OpenApiArray valuesArray)
+ {
+ extension.ValuesDescriptions.AddRange(valuesArray
+ .OfType()
+ .Select(x => new EnumDescription(x)));
+ }
+ return extension;
+ }
+}
+
+///
+/// Description of an enum symbol
+///
+public class EnumDescription : IOpenApiElement
+{
+ ///
+ /// Default constructor
+ ///
+ public EnumDescription()
+ {
+
+ }
+ ///
+ /// Constructor from a raw OpenApiObject
+ ///
+ /// The source object
+ public EnumDescription(OpenApiObject 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;
+ }
+ ///
+ /// The description for the enum symbol
+ ///
+ public string Description { get; set; } = string.Empty;
+ ///
+ /// The symbol for the enum symbol to use for code-generation
+ ///
+ public string Name { get; set; } = string.Empty;
+ ///
+ /// The symbol as described in the main enum schema.
+ ///
+ public string Value { get; set; } = string.Empty;
+}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs
new file mode 100644
index 000000000..a73ecf005
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs
@@ -0,0 +1,95 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Extensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add pageable information.
+/// Based of the AutoRest specification https://github.com/Azure/autorest/blob/main/docs/extensions/readme.md#x-ms-pageable
+///
+public class OpenApiPagingExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-pageable";
+
+ ///
+ /// The name of the property that provides the collection of pageable items.
+ ///
+ public string ItemName
+ {
+ get; set;
+ } = "value";
+
+ ///
+ /// The name of the property that provides the next link (common: nextLink)
+ ///
+ public string NextLinkName
+ {
+ get; set;
+ } = "nextLink";
+
+ ///
+ /// The name (operationId) of the operation for retrieving the next page.
+ ///
+ public string OperationName
+ {
+ get; set;
+ } = string.Empty;
+
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if (writer is null) throw new ArgumentNullException(nameof(writer));
+ writer.WriteStartObject();
+ if (!string.IsNullOrEmpty(NextLinkName))
+ {
+ writer.WriteProperty(nameof(NextLinkName).ToFirstCharacterLowerCase(), NextLinkName);
+ }
+
+ if (!string.IsNullOrEmpty(OperationName))
+ {
+ writer.WriteProperty(nameof(OperationName).ToFirstCharacterLowerCase(), OperationName);
+ }
+
+ writer.WriteProperty(nameof(ItemName).ToFirstCharacterLowerCase(), ItemName);
+
+ writer.WriteEndObject();
+ }
+ ///
+ /// Parse the extension from the raw IOpenApiAny object.
+ ///
+ /// The source element to parse.
+ /// The .
+ /// When the source element is not an object
+ public static OpenApiPagingExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
+ var extension = new OpenApiPagingExtension();
+ if (rawObject.TryGetValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is OpenApiString nextLinkNameStr)
+ {
+ extension.NextLinkName = nextLinkNameStr.Value;
+ }
+
+ if (rawObject.TryGetValue(nameof(OperationName).ToFirstCharacterLowerCase(), out var opName) && opName is OpenApiString opNameStr)
+ {
+ extension.OperationName = opNameStr.Value;
+ }
+
+ if (rawObject.TryGetValue(nameof(ItemName).ToFirstCharacterLowerCase(), out var itemName) && itemName is OpenApiString itemNameStr)
+ {
+ extension.ItemName = itemNameStr.Value;
+ }
+
+ return extension;
+ }
+}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs
new file mode 100644
index 000000000..adcaa85dd
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs
@@ -0,0 +1,44 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add tag the primary error message to use on error types. x-ms-primary-error-message
+///
+public class OpenApiPrimaryErrorMessageExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-primary-error-message";
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if(writer is null) throw new ArgumentNullException(nameof(writer));
+ writer.WriteValue(IsPrimaryErrorMessage);
+ }
+ ///
+ /// Whether this property is the primary error message to use on error types.
+ ///
+ public bool IsPrimaryErrorMessage { get; set; }
+ ///
+ /// Parses the to .
+ ///
+ /// The source object.
+ /// The .
+ public static OpenApiPrimaryErrorMessageExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiBoolean rawObject) throw new ArgumentOutOfRangeException(nameof(source));
+ return new OpenApiPrimaryErrorMessageExtension() {
+ IsPrimaryErrorMessage = rawObject.Value
+ };
+ }
+}
diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs
new file mode 100644
index 000000000..5cfa54082
--- /dev/null
+++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs
@@ -0,0 +1,50 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Interfaces;
+using Microsoft.OpenApi.Writers;
+
+namespace Microsoft.OpenApi.MicrosoftExtensions;
+
+///
+/// Extension element for OpenAPI to add reserved parameters. x-ms-reserved-parameters
+///
+public class OpenApiReservedParameterExtension : IOpenApiExtension
+{
+ ///
+ /// Name of the extension as used in the description.
+ ///
+ public static string Name => "x-ms-reserved-parameter";
+ ///
+ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
+ {
+ if (writer is null) throw new ArgumentNullException(nameof(writer));
+ if (IsReserved.HasValue)
+ writer.WriteValue(IsReserved.Value);
+ }
+ ///
+ /// Whether the associated parameter is reserved or not.
+ ///
+ public bool? IsReserved
+ {
+ get; set;
+ }
+ ///
+ /// Parses the to .
+ ///
+ /// The source object.
+ /// The .
+ ///
+ public static OpenApiReservedParameterExtension Parse(IOpenApiAny source)
+ {
+ if (source is not OpenApiBoolean rawBoolean) throw new ArgumentOutOfRangeException(nameof(source));
+ return new OpenApiReservedParameterExtension
+ {
+ IsReserved = rawBoolean.Value
+ };
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs
new file mode 100644
index 000000000..9fabaf85f
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs
@@ -0,0 +1,107 @@
+using System;
+using System.IO;
+using Microsoft.OpenApi.MicrosoftExtensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Writers;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.MicrosoftExtensions;
+
+public class OpenApiDeprecationExtensionTests
+{
+ [Fact]
+ public void ExtensionNameMatchesExpected()
+ {
+ // Act
+ string name = OpenApiDeprecationExtension.Name;
+ string expectedName = "x-ms-deprecation";
+
+ // Assert
+ Assert.Equal(expectedName, name);
+ }
+
+ [Fact]
+ public void WritesNothingWhenNoValues()
+ {
+ // Arrange
+ OpenApiDeprecationExtension extension = new();
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.Null(extension.Date);
+ Assert.Null(extension.RemovalDate);
+ Assert.Empty(extension.Version);
+ Assert.Empty(extension.Description);
+ Assert.Empty(result);
+ }
+
+ [Fact]
+ public void WritesAllValues()
+ {
+ // Arrange
+ OpenApiDeprecationExtension extension = new() {
+ Date = new DateTime(2020, 1, 1),
+ RemovalDate = new DateTime(2021, 1, 1),
+ Version = "1.0.0",
+ Description = "This is a test"
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.NotNull(extension.Date);
+ Assert.NotNull(extension.RemovalDate);
+ Assert.NotNull(extension.Version);
+ Assert.NotNull(extension.Description);
+ Assert.Contains("2021-01-01T00:00:00.000000", result);
+ Assert.Contains("removalDate", result);
+ Assert.Contains("version", result);
+ Assert.Contains("1.0.0", result);
+ Assert.Contains("description", result);
+ Assert.Contains("This is a test", result);
+ }
+ [Fact]
+ public void Parses()
+ {
+ var oaiValue = new OpenApiObject
+ {
+ { "date", new OpenApiDateTime(new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)))},
+ { "removalDate", new OpenApiDateTime(new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)))},
+ { "version", new OpenApiString("v1.0")},
+ { "description", new OpenApiString("removing")}
+ };
+ var value = OpenApiDeprecationExtension.Parse(oaiValue);
+ Assert.NotNull(value);
+ Assert.Equal("v1.0", value.Version);
+ Assert.Equal("removing", value.Description);
+ Assert.Equal(new DateTimeOffset(2023, 05, 04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)), value.Date);
+ Assert.Equal(new DateTimeOffset(2023, 05, 04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)), value.RemovalDate);
+ }
+ [Fact]
+ public void Serializes()
+ {
+ var value = new OpenApiDeprecationExtension
+ {
+ Date = new DateTimeOffset(2023, 05, 04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)),
+ RemovalDate = new DateTimeOffset(2023, 05, 04, 16, 0, 0, 0, 0, new TimeSpan(4, 0, 0)),
+ Version = "v1.0",
+ Description = "removing"
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+
+ value.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ var result = sWriter.ToString();
+ Assert.Equal("{\n \"removalDate\": \"2023-05-04T16:00:00.0000000+04:00\",\n \"date\": \"2023-05-04T16:00:00.0000000+04:00\",\n \"version\": \"v1.0\",\n \"description\": \"removing\"\n}", result);
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumFlagsExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumFlagsExtensionTests.cs
new file mode 100644
index 000000000..9c05a8e18
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumFlagsExtensionTests.cs
@@ -0,0 +1,81 @@
+using System.IO;
+using Microsoft.OpenApi.MicrosoftExtensions;
+
+using Microsoft.OpenApi.Writers;
+
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.MicrosoftExtensions;
+
+public class OpenApiEnumFlagsExtensionTests
+{
+ [Fact]
+ public void ExtensionNameMatchesExpected()
+ {
+ // Act
+ string name = OpenApiEnumFlagsExtension.Name;
+ string expectedName = "x-ms-enum-flags";
+
+ // Assert
+ Assert.Equal(expectedName, name);
+ }
+
+ [Fact]
+ public void WritesDefaultValues()
+ {
+ // Arrange
+ OpenApiEnumFlagsExtension extension = new();
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.Contains("\"isFlags\": false", result);
+ Assert.DoesNotContain("\"style\"", result);
+ Assert.False(extension.IsFlags);
+ }
+
+ [Fact]
+ public void WritesAllDefaultValues()
+ {
+ // Arrange
+ OpenApiEnumFlagsExtension extension = new()
+ {
+ IsFlags = true
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.Contains("\"isFlags\": true", result);
+ Assert.True(extension.IsFlags);
+ }
+
+ [Fact]
+ public void WritesAllValues()
+ {
+ // Arrange
+ OpenApiEnumFlagsExtension extension = new()
+ {
+ IsFlags = true
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.True(extension.IsFlags);
+ Assert.Contains("\"isFlags\": true", result);
+ }
+}
+
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtensionTests.cs
new file mode 100644
index 000000000..571c28461
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtensionTests.cs
@@ -0,0 +1,71 @@
+using System.Collections.Generic;
+using System.IO;
+using Microsoft.OpenApi.MicrosoftExtensions;
+using Microsoft.OpenApi.Writers;
+using Moq;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.MicrosoftExtensions;
+
+public class OpenApiEnumValuesDescriptionExtensionTests
+{
+ [Fact]
+ public void ExtensionNameMatchesExpected()
+ {
+ // Act
+ string name = OpenApiEnumValuesDescriptionExtension.Name;
+ string expectedName = "x-ms-enum";
+
+ // Assert
+ Assert.Equal(expectedName, name);
+ }
+ [Fact]
+ public void WritesNothingWhenNoValues()
+ {
+ // Arrange
+ OpenApiEnumValuesDescriptionExtension extension = new();
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.Empty(extension.EnumName);
+ Assert.Empty(extension.ValuesDescriptions);
+ Assert.Empty(result);
+ }
+ [Fact]
+ public void WritesEnumDescription()
+ {
+ // Arrange
+ OpenApiEnumValuesDescriptionExtension extension = new()
+ {
+ EnumName = "TestEnum",
+ ValuesDescriptions = new()
+ {
+ new() {
+ Description = "TestDescription",
+ Value = "TestValue",
+ Name = "TestName"
+ }
+ }
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.Contains("values", result);
+ Assert.Contains("modelAsString\": false", result);
+ Assert.Contains("name\": \"TestEnum", result);
+ Assert.Contains("description\": \"TestDescription", result);
+ Assert.Contains("value\": \"TestValue", result);
+ Assert.Contains("name\": \"TestName", result);
+ }
+}
+
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs
new file mode 100644
index 000000000..cfbbf0a17
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs
@@ -0,0 +1,92 @@
+using System;
+using System.IO;
+using Microsoft.OpenApi.MicrosoftExtensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Writers;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.MicrosoftExtensions;
+
+public class OpenApiPagingExtensionsTests
+{
+ [Fact]
+ public void ExtensionNameMatchesExpected()
+ {
+ // Act
+ string name = OpenApiPagingExtension.Name;
+ var expectedName = "x-ms-pageable";
+
+ // Assert
+ Assert.Equal(expectedName, name);
+ }
+
+ [Fact]
+ public void ThrowsOnMissingWriter()
+ {
+ // Arrange
+ OpenApiPagingExtension extension = new();
+
+ // Act
+ // Assert
+ Assert.Throws(() => extension.Write(null, OpenApiSpecVersion.OpenApi3_0));
+ }
+
+ [Fact]
+ public void WritesNothingWhenNoValues()
+ {
+ // Arrange
+ OpenApiPagingExtension extension = new();
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ var result = sWriter.ToString();
+
+ // Assert
+ Assert.Equal("value", extension.ItemName);
+ Assert.Equal("nextLink", extension.NextLinkName);
+ Assert.Empty(extension.OperationName);
+ }
+
+ [Fact]
+ public void WritesPagingInfo()
+ {
+ // Arrange
+ OpenApiPagingExtension extension = new();
+ extension.NextLinkName = "nextLink";
+ extension.OperationName = "usersGet";
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ var result = sWriter.ToString();
+
+ // Assert
+ Assert.Contains("value", result);
+ Assert.Contains("itemName\": \"value", result);
+ Assert.Contains("nextLinkName\": \"nextLink", result);
+ Assert.Contains("operationName\": \"usersGet", result);
+ }
+
+ [Fact]
+ public void ParsesPagingInfo()
+ {
+ // Arrange
+ var obj = new OpenApiObject
+ {
+ ["nextLinkName"] = new OpenApiString("@odata.nextLink"),
+ ["operationName"] = new OpenApiString("more"),
+ ["itemName"] = new OpenApiString("item"),
+ };
+
+ // Act
+ var extension = OpenApiPagingExtension.Parse(obj);
+
+ // Assert
+ Assert.Equal("@odata.nextLink", extension.NextLinkName);
+ Assert.Equal("item", extension.ItemName);
+ Assert.Equal("more", extension.OperationName);
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs
new file mode 100644
index 000000000..6b400671b
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs
@@ -0,0 +1,56 @@
+// ------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
+// ------------------------------------------------------------
+
+using System;
+using System.IO;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Writers;
+using Xunit;
+
+namespace Microsoft.OpenApi.OData.OpenApiExtensions.Tests;
+
+public class OpenApiPrimaryErrorMessageExtensionTests
+{
+ [Fact]
+ public void ExtensionNameMatchesExpected()
+ {
+ // Act
+ string name = OpenApiPrimaryErrorMessageExtension.Name;
+ string expectedName = "x-ms-primary-error-message";
+
+ // Assert
+ Assert.Equal(expectedName, name);
+ }
+ [Fact]
+ public void WritesValue()
+ {
+ // Arrange
+ OpenApiPrimaryErrorMessageExtension extension = new() {
+ IsPrimaryErrorMessage = true
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ // Act
+ extension.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ string result = sWriter.ToString();
+
+ // Assert
+ Assert.True(extension.IsPrimaryErrorMessage);
+ Assert.Equal("true", result);
+ }
+ [Fact]
+ public void ParsesValue()
+ {
+ // Arrange
+ var value = new OpenApiBoolean(true);
+
+ // Act
+ var extension = OpenApiPrimaryErrorMessageExtension.Parse(value);
+
+ // Assert
+ Assert.True(extension.IsPrimaryErrorMessage);
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs
new file mode 100644
index 000000000..ca7870bc0
--- /dev/null
+++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs
@@ -0,0 +1,34 @@
+using System;
+using System.IO;
+using Microsoft.OpenApi.MicrosoftExtensions;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Writers;
+using Xunit;
+
+namespace Microsoft.OpenApi.Tests.MicrosoftExtensions;
+
+public class OpenApiReservedParameterExtensionTests
+{
+ [Fact]
+ public void Parses()
+ {
+ var oaiValue = new OpenApiBoolean(true);
+ var value = OpenApiReservedParameterExtension.Parse(oaiValue);
+ Assert.NotNull(value);
+ Assert.True(value.IsReserved);
+ }
+ [Fact]
+ public void Serializes()
+ {
+ var value = new OpenApiReservedParameterExtension
+ {
+ IsReserved = true
+ };
+ using TextWriter sWriter = new StringWriter();
+ OpenApiJsonWriter writer = new(sWriter);
+
+ value.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+ var result = sWriter.ToString();
+ Assert.Equal("true", result, StringComparer.OrdinalIgnoreCase);
+ }
+}
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index 96071507f..b6828dff7 100755
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -341,6 +341,71 @@ namespace Microsoft.OpenApi
OpenApi3_0 = 1,
}
}
+namespace Microsoft.OpenApi.MicrosoftExtensions
+{
+ public class EnumDescription : Microsoft.OpenApi.Interfaces.IOpenApiElement
+ {
+ public EnumDescription() { }
+ public EnumDescription(Microsoft.OpenApi.Any.OpenApiObject source) { }
+ public string Description { get; set; }
+ public string Name { get; set; }
+ public string Value { get; set; }
+ }
+ public class OpenApiDeprecationExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiDeprecationExtension() { }
+ public System.DateTimeOffset? Date { get; set; }
+ public string Description { get; set; }
+ public System.DateTimeOffset? RemovalDate { get; set; }
+ public string Version { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiDeprecationExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+ public class OpenApiEnumFlagsExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiEnumFlagsExtension() { }
+ public bool IsFlags { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumFlagsExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+ public class OpenApiEnumValuesDescriptionExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiEnumValuesDescriptionExtension() { }
+ public string EnumName { get; set; }
+ public System.Collections.Generic.List ValuesDescriptions { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumValuesDescriptionExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+ public class OpenApiPagingExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiPagingExtension() { }
+ public string ItemName { get; set; }
+ public string NextLinkName { get; set; }
+ public string OperationName { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPagingExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+ public class OpenApiPrimaryErrorMessageExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiPrimaryErrorMessageExtension() { }
+ public bool IsPrimaryErrorMessage { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPrimaryErrorMessageExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+ public class OpenApiReservedParameterExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension
+ {
+ public OpenApiReservedParameterExtension() { }
+ public bool? IsReserved { get; set; }
+ public static string Name { get; }
+ public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { }
+ public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiReservedParameterExtension Parse(Microsoft.OpenApi.Any.IOpenApiAny source) { }
+ }
+}
namespace Microsoft.OpenApi.Models
{
public class OpenApiCallback : Microsoft.OpenApi.Interfaces.IEffective, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable