Skip to content

Commit

Permalink
Merge pull request #1333 from microsoft/feature/ms-extensions
Browse files Browse the repository at this point in the history
moves all microsoft extensions to a single place
  • Loading branch information
baywet authored Sep 7, 2023
2 parents 43b16cd + bbf1c73 commit ab78dee
Show file tree
Hide file tree
Showing 18 changed files with 993 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<PackageId>Microsoft.OpenApi.Hidi</PackageId>
<ToolCommandName>hidi</ToolCommandName>
<PackageOutputPath>./../../artifacts</PackageOutputPath>
<Version>1.2.8</Version>
<Version>1.2.9</Version>
<Description>OpenAPI.NET CLI tool for slicing OpenAPI documents</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageTags>OpenAPI .NET</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Company>Microsoft</Company>
<Title>Microsoft.OpenApi.Readers</Title>
<PackageId>Microsoft.OpenApi.Readers</PackageId>
<Version>1.6.7</Version>
<Version>1.6.8</Version>
<Description>OpenAPI.NET Readers for JSON and YAML documents</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageTags>OpenAPI .NET</PackageTags>
Expand Down
27 changes: 27 additions & 0 deletions src/Microsoft.OpenApi.Readers/OpenApiReaderSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,5 +75,31 @@ public class OpenApiReaderSettings
/// from an <see cref="OpenApiStreamReader"/> object.
/// </summary>
public bool LeaveStreamOpen { get; set; }

/// <summary>
/// Adds parsers for Microsoft OpenAPI extensions:
/// - <see cref="OpenApiPagingExtension"/>
/// - <see cref="OpenApiEnumValuesDescriptionExtension"/>
/// - <see cref="OpenApiPrimaryErrorMessageExtension"/>
/// - <see cref="OpenApiDeprecationExtension"/>
/// - <see cref="OpenApiReservedParameterExtension"/>
/// - <see cref="OpenApiEnumFlagsExtension"/>
/// NOTE: The list of extensions is subject to change.
/// </summary>
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));
}
}
}
2 changes: 2 additions & 0 deletions src/Microsoft.OpenApi/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@ public static T GetEnumFromDisplayName<T>(this string displayName)

return default;
}
internal static string ToFirstCharacterLowerCase(this string input)
=> string.IsNullOrEmpty(input) ? string.Empty : char.ToLowerInvariant(input[0]) + input.Substring(1);
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Company>Microsoft</Company>
<Title>Microsoft.OpenApi</Title>
<PackageId>Microsoft.OpenApi</PackageId>
<Version>1.6.7</Version>
<Version>1.6.8</Version>
<Description>.NET models with JSON and YAML writers for OpenAPI specification</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageTags>OpenAPI .NET</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Extension element for OpenAPI to add deprecation information. x-ms-deprecation
/// </summary>
public class OpenApiDeprecationExtension : IOpenApiExtension
{
/// <summary>
/// Name of the extension as used in the description.
/// </summary>
public static string Name => "x-ms-deprecation";
/// <summary>
/// The date at which the element has been/will be removed entirely from the service.
/// </summary>
public DateTimeOffset? RemovalDate
{
get; set;
}
/// <summary>
/// The date at which the element has been/will be deprecated.
/// </summary>
public DateTimeOffset? Date
{
get; set;
}
/// <summary>
/// The version this revision was introduced.
/// </summary>
public string Version
{
get; set;
} = string.Empty;
/// <summary>
/// The description of the revision.
/// </summary>
public string Description
{
get; set;
} = string.Empty;
/// <inheritdoc />
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();
}
}
/// <summary>
/// Parses the <see cref="IOpenApiAny"/> to <see cref="OpenApiDeprecationExtension"/>.
/// </summary>
/// <param name="source">The source object.</param>
/// <returns>The <see cref="OpenApiDeprecationExtension"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">When the source element is not an object</exception>
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;
}
}
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Extension element for OpenAPI to add deprecation information. x-ms-enum-flags
/// </summary>
public class OpenApiEnumFlagsExtension : IOpenApiExtension
{
/// <summary>
/// Name of the extension as used in the description.
/// </summary>
public static string Name => "x-ms-enum-flags";
/// <summary>
/// Whether the enum is a flagged enum.
/// </summary>
public bool IsFlags
{
get; set;
}
/// <inheritdoc />
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();
}
/// <summary>
/// Parse the extension from the raw IOpenApiAny object.
/// </summary>
/// <param name="source">The source element to parse.</param>
/// <returns>The <see cref="OpenApiEnumFlagsExtension"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">When the source element is not an object</exception>
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;
}
}
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// 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
/// </summary>
public class OpenApiEnumValuesDescriptionExtension : IOpenApiExtension
{
/// <summary>
/// Name of the extension as used in the description.
/// </summary>
public static string Name => "x-ms-enum";

/// <summary>
/// The of the enum.
/// </summary>
public string EnumName { get; set; } = string.Empty;

/// <summary>
/// Descriptions for the enum symbols, where the value MUST match the enum symbols in the main description
/// </summary>
public List<EnumDescription> ValuesDescriptions { get; set; } = new();

/// <inheritdoc />
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();
}
}
/// <summary>
/// Parse the extension from the raw IOpenApiAny object.
/// </summary>
/// <param name="source">The source element to parse.</param>
/// <returns>The <see cref="OpenApiEnumValuesDescriptionExtension"/>.</returns>
/// <exception cref="ArgumentOutOfRangeException">When the source element is not an object</exception>
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<OpenApiObject>()
.Select(x => new EnumDescription(x)));
}
return extension;
}
}

/// <summary>
/// Description of an enum symbol
/// </summary>
public class EnumDescription : IOpenApiElement
{
/// <summary>
/// Default constructor
/// </summary>
public EnumDescription()
{

}
/// <summary>
/// Constructor from a raw OpenApiObject
/// </summary>
/// <param name="source">The source object</param>
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;
}
/// <summary>
/// The description for the enum symbol
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// The symbol for the enum symbol to use for code-generation
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// The symbol as described in the main enum schema.
/// </summary>
public string Value { get; set; } = string.Empty;
}
Loading

0 comments on commit ab78dee

Please sign in to comment.