Skip to content

Commit

Permalink
Merge pull request #2157 from microsoft/fix/deprecation-extension-dates
Browse files Browse the repository at this point in the history
fix: an issue where deprecation extension parsing would fail
  • Loading branch information
baywet authored Feb 19, 2025
2 parents e039532 + d49c38d commit 5db8757
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using System.Collections.Generic;
using System.Text.Json.Nodes;

namespace Microsoft.OpenApi.Hidi.Extensions
{
Expand All @@ -14,9 +15,9 @@ internal static class OpenApiExtensibleExtensions
/// <returns>A <see cref="string"/> value matching the provided extensionKey. Return null when extensionKey is not found. </returns>
internal static string GetExtension(this IDictionary<string, IOpenApiExtension> extensions, string extensionKey)
{
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny castValue)
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny { Node: JsonValue castValue } && castValue.TryGetValue<string>(out var stringValue))
{
return castValue.Node.GetValue<string>();
return stringValue;
}
return string.Empty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Writers;
using System.Text.Json.Nodes;
using System.Text.Json;
using System.Globalization;

namespace Microsoft.OpenApi.MicrosoftExtensions;

Expand Down Expand Up @@ -71,6 +73,35 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
writer.WriteEndObject();
}
}
private static readonly DateTimeStyles datesStyle = DateTimeStyles.AssumeUniversal | DateTimeStyles.RoundtripKind;
private static DateTimeOffset? GetDateTimeOffsetValue(string propertyName, JsonObject rawObject)
{
if (!rawObject.TryGetPropertyValue(propertyName.ToFirstCharacterLowerCase(), out var jsonNode) ||
jsonNode is not JsonValue jsonValue ||
jsonNode.GetValueKind() is not JsonValueKind.String)
return null;

if (jsonValue.TryGetValue<string>(out var strValue) &&
DateTimeOffset.TryParse(strValue, CultureInfo.InvariantCulture, datesStyle, out var parsedValue))
{
return parsedValue;
}
if (jsonValue.TryGetValue<DateTimeOffset>(out var returnedDto))
{
return returnedDto;
}
if (jsonValue.TryGetValue<DateTime>(out var returnedDt))
{
return new DateTimeOffset(returnedDt, TimeSpan.FromHours(0));
}
#if NET6_0_OR_GREATER
if (jsonValue.TryGetValue<DateOnly>(out var returnedDo))
{
return new(returnedDo.Year, returnedDo.Month, returnedDo.Day, 0, 0, 0, TimeSpan.FromHours(0));
}
#endif
return null;
}
/// <summary>
/// Parses the <see cref="OpenApiAny"/> to <see cref="OpenApiDeprecationExtension"/>.
/// </summary>
Expand All @@ -80,15 +111,15 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
public static OpenApiDeprecationExtension Parse(JsonNode source)
{
if (source is not JsonObject rawObject) return null;
var extension = new OpenApiDeprecationExtension();
if (rawObject.TryGetPropertyValue(nameof(RemovalDate).ToFirstCharacterLowerCase(), out var removalDate) && removalDate is JsonNode removalDateValue)
extension.RemovalDate = removalDateValue.GetValue<DateTimeOffset>();
if (rawObject.TryGetPropertyValue(nameof(Date).ToFirstCharacterLowerCase(), out var date) && date is JsonNode dateValue)
extension.Date = dateValue.GetValue<DateTimeOffset>();
if (rawObject.TryGetPropertyValue(nameof(Version).ToFirstCharacterLowerCase(), out var version) && version is JsonNode versionValue)
extension.Version = versionValue.GetValue<string>();
if (rawObject.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var description) && description is JsonNode descriptionValue)
extension.Description = descriptionValue.GetValue<string>();
var extension = new OpenApiDeprecationExtension
{
RemovalDate = GetDateTimeOffsetValue(nameof(RemovalDate), rawObject),
Date = GetDateTimeOffsetValue(nameof(Date), rawObject)
};
if (rawObject.TryGetPropertyValue(nameof(Version).ToFirstCharacterLowerCase(), out var version) && version is JsonValue versionValue && versionValue.TryGetValue<string>(out var versionStr))
extension.Version = versionStr;
if (rawObject.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var description) && description is JsonValue descriptionValue && descriptionValue.TryGetValue<string>(out var descriptionStr))
extension.Description = descriptionStr;
return extension;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public static OpenApiEnumFlagsExtension Parse(JsonNode source)
{
if (source is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source));
var extension = new OpenApiEnumFlagsExtension();
if (rawObject.TryGetPropertyValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is JsonNode isFlags)
if (rawObject.TryGetPropertyValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is JsonValue isFlags && isFlags.TryGetValue<bool>(out var isFlagsValue))
{
extension.IsFlags = isFlags.GetValue<bool>();
extension.IsFlags = isFlagsValue;
}
return extension;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,15 @@ public EnumDescription()
public EnumDescription(JsonObject source)
{
if (source is null) throw new ArgumentNullException(nameof(source));
if (source.TryGetPropertyValue(nameof(Value).ToFirstCharacterLowerCase(), out var rawValue) && rawValue is JsonNode value)
if (value.GetValueKind() == JsonValueKind.Number)
Value = value.GetValue<decimal>().ToString(CultureInfo.InvariantCulture);
else
Value = value.GetValue<string>();
if (source.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var rawDescription) && rawDescription is JsonNode description)
Description = description.GetValue<string>();
if (source.TryGetPropertyValue(nameof(Name).ToFirstCharacterLowerCase(), out var rawName) && rawName is JsonNode name)
Name = name.GetValue<string>();
if (source.TryGetPropertyValue(nameof(Value).ToFirstCharacterLowerCase(), out var rawValue) && rawValue is JsonValue value)
if (value.GetValueKind() == JsonValueKind.Number && value.TryGetValue<decimal>(out var decimalValue))
Value = decimalValue.ToString(CultureInfo.InvariantCulture);
else if (value.TryGetValue<string>(out var stringValue))
Value = stringValue;
if (source.TryGetPropertyValue(nameof(Description).ToFirstCharacterLowerCase(), out var rawDescription) && rawDescription is JsonValue description && description.TryGetValue<string>(out var stringValueDescription))
Description = stringValueDescription;
if (source.TryGetPropertyValue(nameof(Name).ToFirstCharacterLowerCase(), out var rawName) && rawName is JsonValue name && name.TryGetValue<string>(out var stringValueName))
Name = stringValueName;
}
/// <summary>
/// The description for the enum symbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ public static OpenApiPagingExtension Parse(JsonNode source)
{
if (source is not JsonObject rawObject) return null;
var extension = new OpenApiPagingExtension();
if (rawObject.TryGetPropertyValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is JsonNode nextLinkNameStr)
if (rawObject.TryGetPropertyValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is JsonValue nextLinkNameValue && nextLinkNameValue.TryGetValue<string>(out var nextLinkNameStr))
{
extension.NextLinkName = nextLinkNameStr.GetValue<string>();
extension.NextLinkName = nextLinkNameStr;
}

if (rawObject.TryGetPropertyValue(nameof(OperationName).ToFirstCharacterLowerCase(), out var opName) && opName is JsonNode opNameStr)
if (rawObject.TryGetPropertyValue(nameof(OperationName).ToFirstCharacterLowerCase(), out var opName) && opName is JsonValue opNameValue && opNameValue.TryGetValue<string>(out var opNameStr))
{
extension.OperationName = opNameStr.GetValue<string>();
extension.OperationName = opNameStr;
}

if (rawObject.TryGetPropertyValue(nameof(ItemName).ToFirstCharacterLowerCase(), out var itemName) && itemName is JsonNode itemNameStr)
if (rawObject.TryGetPropertyValue(nameof(ItemName).ToFirstCharacterLowerCase(), out var itemName) && itemName is JsonValue itemNameValue && itemNameValue.TryGetValue<string>(out var itemNameStr))
{
extension.ItemName = itemNameStr.GetValue<string>();
extension.ItemName = itemNameStr;
}

return extension;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
/// <returns>The <see cref="OpenApiPrimaryErrorMessageExtension"/>.</returns>
public static OpenApiPrimaryErrorMessageExtension Parse(JsonNode source)
{
if (source is not JsonNode rawObject) return null;
if (source is not JsonValue rawObject) return null;
return new()
{
IsPrimaryErrorMessage = rawObject.GetValue<bool>()
IsPrimaryErrorMessage = rawObject.TryGetValue<bool>(out var value) && value
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public bool? IsReserved
/// <returns></returns>
public static OpenApiReservedParameterExtension Parse(JsonNode source)
{
if (source is not JsonNode rawBoolean) return null;
if (source is not JsonValue rawBoolean) return null;
return new()
{
IsReserved = rawBoolean.GetValue<bool>()
IsReserved = rawBoolean.TryGetValue<bool>(out var value) && value
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ public void Parses()
{
var oaiValue = new JsonObject
{
{ "date", new OpenApiAny(new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new(4, 0, 0))).Node},
{ "removalDate", new OpenApiAny(new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new(4, 0, 0))).Node},
{ "version", new OpenApiAny("v1.0").Node},
{ "description", new OpenApiAny("removing").Node}
{ "date", new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new(4, 0, 0))},
{ "removalDate", new DateTimeOffset(2023,05,04, 16, 0, 0, 0, 0, new(4, 0, 0))},
{ "version", "v1.0"},
{ "description", "removing"}
};
var value = OpenApiDeprecationExtension.Parse(oaiValue);
Assert.NotNull(value);
Expand All @@ -88,6 +88,23 @@ public void Parses()
Assert.Equal(new DateTimeOffset(2023, 05, 04, 16, 0, 0, 0, 0, new(4, 0, 0)), value.RemovalDate);
}
[Fact]
public void ParsesStringValues()
{
var oaiValue = new JsonObject
{
{ "date", "2023-05-04T16:00:00Z"},
{ "removalDate", "2023-05-04"},
{ "version", "v1.0"},
{ "description", "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(0, 0, 0)), value.Date);
Assert.Equal(new DateTimeOffset(2023, 05, 04, 0, 0, 0, 0, 0, new(0, 0, 0)), value.RemovalDate);
}
[Fact]
public void Serializes()
{
var value = new OpenApiDeprecationExtension
Expand Down

0 comments on commit 5db8757

Please sign in to comment.