Skip to content

Commit

Permalink
- moves extensions from kiota
Browse files Browse the repository at this point in the history
  • Loading branch information
baywet committed Sep 6, 2023
1 parent 1c0a191 commit 1152540
Show file tree
Hide file tree
Showing 6 changed files with 413 additions and 0 deletions.
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);
}
}
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;
}
Original file line number Diff line number Diff line change
@@ -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;

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

/// <summary>
/// The name of the property that provides the collection of pageable items.
/// </summary>
public string ItemName
{
get; set;
} = "value";

/// <summary>
/// The name of the property that provides the next link (common: nextLink)
/// </summary>
public string NextLinkName
{
get; set;
} = "nextLink";

/// <summary>
/// The name (operationId) of the operation for retrieving the next page.
/// </summary>
public string OperationName
{
get; set;
} = string.Empty;

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

0 comments on commit 1152540

Please sign in to comment.