-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Still needs support for LiteralSerializer
- Loading branch information
1 parent
8b7fc50
commit dee0339
Showing
16 changed files
with
316 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
src/main/Yardarm.NodaTime.Client/Serialization/Literals/NodaLiteralConverters.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
using NodaTime; | ||
using NodaTime.Text; | ||
using NodaTime.Utility; | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace RootNamespace.Serialization.Literals; | ||
|
||
internal static class NodaLiteralConverters | ||
{ | ||
private static NodaPatternLiteralConverter<LocalDate>? s_localDateConverter; | ||
private static NodaPatternLiteralConverter<LocalTime>? s_localTimeConverter; | ||
private static NodaPatternLiteralConverter<OffsetDateTime>? s_offsetDateTimeConverter; | ||
private static NodaPatternLiteralConverter<OffsetTime>? s_offsetTimeConverter; | ||
|
||
/// <summary> | ||
/// Converter for local dates, using the ISO-8601 date pattern. | ||
/// </summary> | ||
public static LiteralConverter<LocalDate> LocalDateConverter => s_localDateConverter ??= | ||
new NodaPatternLiteralConverter<LocalDate>( | ||
LocalDatePattern.Iso, CreateIsoValidator<LocalDate>(x => x.Calendar)); | ||
|
||
/// <summary> | ||
/// Converter for local times, using the ISO-8601 time pattern, extended as required to accommodate nanoseconds. | ||
/// </summary> | ||
public static LiteralConverter<LocalTime> LocalTimeConverter => s_localTimeConverter ??= | ||
new NodaPatternLiteralConverter<LocalTime>(LocalTimePattern.ExtendedIso); | ||
|
||
/// <summary> | ||
/// Converter for offset date/times. | ||
/// </summary> | ||
public static LiteralConverter<OffsetDateTime> OffsetDateTimeConverter => s_offsetDateTimeConverter ??= | ||
new NodaPatternLiteralConverter<OffsetDateTime>( | ||
OffsetDateTimePattern.Rfc3339, CreateIsoValidator<OffsetDateTime>(x => x.Calendar)); | ||
|
||
/// <summary> | ||
/// Converter for offset times. | ||
/// </summary> | ||
public static LiteralConverter<OffsetTime> OffsetTimeConverter => s_offsetTimeConverter ??= | ||
new NodaPatternLiteralConverter<OffsetTime>(OffsetTimePattern.ExtendedIso); | ||
|
||
private static Action<T> CreateIsoValidator<T>(Func<T, CalendarSystem> calendarProjection) => value => | ||
{ | ||
CalendarSystem calendar = calendarProjection(value); | ||
|
||
if (calendar != CalendarSystem.Iso) | ||
{ | ||
ThrowInvalidNodaDataException($"Values of type {typeof(T).Name} must (currently) use the ISO calendar in order to be serialized."); | ||
} | ||
}; | ||
|
||
[DoesNotReturn] | ||
private static void ThrowInvalidNodaDataException(string message) | ||
{ | ||
throw new InvalidNodaDataException(message); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/Yardarm.NodaTime.Client/Serialization/Literals/NodaPatternLiteralConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using NodaTime.Text; | ||
|
||
namespace RootNamespace.Serialization.Literals; | ||
|
||
internal class NodaPatternLiteralConverter<T>(IPattern<T> pattern, Action<T>? validator) : LiteralConverter<T> | ||
{ | ||
public NodaPatternLiteralConverter(IPattern<T> pattern) | ||
: this(pattern, null) | ||
{ | ||
} | ||
|
||
[return: NotNullIfNotNull(nameof(value))] | ||
public override T? Read(string? value, string? format) | ||
{ | ||
if (value is null) | ||
{ | ||
return default; | ||
} | ||
|
||
return pattern.Parse(value).Value!; | ||
} | ||
|
||
public override string Write(T value, string? format) | ||
{ | ||
validator?.Invoke(value); | ||
|
||
return pattern.Format(value); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/Yardarm.NodaTime.Client/Yardarm.NodaTime.Client.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks> | ||
<OutputType>Library</OutputType> | ||
|
||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<EnableTrimAnalyzer Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</EnableTrimAnalyzer> | ||
<EnableAotAnalyzer Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</EnableAotAnalyzer> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="NodaTime.Serialization.SystemTextJson" /> | ||
<PackageReference Include="System.Threading.Tasks.Extensions" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Yardarm.Client\Yardarm.Client.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
|
||
namespace Yardarm.NodaTime.Helpers; | ||
|
||
internal static class NodaTimeTypes | ||
{ | ||
public static NameSyntax NodaTime { get; } = | ||
AliasQualifiedName(IdentifierName(Token(SyntaxKind.GlobalKeyword)), IdentifierName("NodaTime")); | ||
|
||
public static NameSyntax Duration { get; } = | ||
QualifiedName(NodaTime, IdentifierName("Duration")); | ||
|
||
public static NameSyntax LocalDate { get; } = | ||
QualifiedName(NodaTime, IdentifierName("LocalDate")); | ||
|
||
public static NameSyntax LocalTime { get; } = | ||
QualifiedName(NodaTime, IdentifierName("LocalTime")); | ||
|
||
public static NameSyntax OffsetDateTime { get; } = | ||
QualifiedName(NodaTime, IdentifierName("OffsetDateTime")); | ||
|
||
public static NameSyntax OffsetTime { get; } = | ||
QualifiedName(NodaTime, IdentifierName("OffsetTime")); | ||
|
||
public static class Serialization | ||
{ | ||
public static NameSyntax Name { get; } = | ||
QualifiedName(NodaTime, IdentifierName("Serialization")); | ||
|
||
public static class SystemTextJson | ||
{ | ||
public static NameSyntax Name { get; } = | ||
QualifiedName(Serialization.Name, IdentifierName("SystemTextJson")); | ||
|
||
public static NameSyntax NodaTimeDefaultJsonConverterFactory { get; } = | ||
QualifiedName(Name, IdentifierName("NodaTimeDefaultJsonConverterFactory")); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using Yardarm.Generation; | ||
using Yardarm.Names; | ||
|
||
namespace Yardarm.NodaTime.Internal; | ||
|
||
internal class ClientGenerator(GenerationContext generationContext, IRootNamespace rootNamespace) | ||
: ResourceSyntaxTreeGenerator(generationContext, rootNamespace) | ||
{ | ||
protected override string ResourcePrefix => "Yardarm.NodaTime.Client."; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Collections.Generic; | ||
using NuGet.Frameworks; | ||
using NuGet.LibraryModel; | ||
using NuGet.Versioning; | ||
using Yardarm.Packaging; | ||
|
||
namespace Yardarm.NodaTime; | ||
|
||
public class NodaTimeDependencyGenerator : IDependencyGenerator | ||
{ | ||
public IEnumerable<LibraryDependency> GetDependencies(NuGetFramework targetFramework) => | ||
[ | ||
new LibraryDependency | ||
{ | ||
LibraryRange = new LibraryRange | ||
{ | ||
Name = "NodaTime.Serialization.SystemTextJson", | ||
TypeConstraint = LibraryDependencyTarget.Package, | ||
VersionRange = VersionRange.Parse("1.3.0") | ||
} | ||
} | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Yardarm.Enrichment; | ||
using Yardarm.Generation; | ||
using Yardarm.NodaTime.Internal; | ||
using Yardarm.Packaging; | ||
|
||
namespace Yardarm.NodaTime; | ||
|
||
public class NodaTimeExtension : YardarmExtension | ||
{ | ||
public override bool IsOutputTrimmable(GenerationContext context) => true; | ||
|
||
public override IServiceCollection ConfigureServices(IServiceCollection services) | ||
{ | ||
services | ||
.AddOpenApiSyntaxNodeEnricher<NodaTimePropertyEnricher>() | ||
.AddSingleton<ISyntaxTreeGenerator, ClientGenerator>() | ||
.AddSingleton<IDependencyGenerator, NodaTimeDependencyGenerator>(); | ||
|
||
return services; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
using System; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.OpenApi.Models; | ||
using Yardarm.Enrichment; | ||
using Yardarm.Enrichment.Schema; | ||
using Yardarm.NodaTime.Helpers; | ||
using Yardarm.SystemTextJson.Helpers; | ||
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
|
||
namespace Yardarm.NodaTime; | ||
|
||
/// <summary> | ||
/// Replaces date and type JSON properties with NodaTime types and applies a JSON converter attribute. | ||
/// </summary> | ||
public class NodaTimePropertyEnricher : IOpenApiSyntaxNodeEnricher<PropertyDeclarationSyntax, OpenApiSchema> | ||
{ | ||
public Type[] ExecuteBefore { get; } = [typeof(RequiredPropertyEnricher)]; | ||
|
||
public PropertyDeclarationSyntax Enrich(PropertyDeclarationSyntax target, | ||
OpenApiEnrichmentContext<OpenApiSchema> context) | ||
{ | ||
if (context.Element.Type != "string") | ||
{ | ||
// Not a string, so no change | ||
return target; | ||
} | ||
|
||
TypeSyntax? newType = context.Element.Format switch | ||
{ | ||
"date-time" => NodaTimeTypes.OffsetDateTime, | ||
"date" or "full-date" => NodaTimeTypes.LocalDate, | ||
"partial-time" => NodaTimeTypes.LocalTime, | ||
"time" or "full-time" => NodaTimeTypes.OffsetTime, | ||
_ => null | ||
}; | ||
|
||
if (newType is null) | ||
{ | ||
// No change | ||
return target; | ||
} | ||
|
||
if (target.Type is NullableTypeSyntax) | ||
{ | ||
newType = NullableType(newType); | ||
} | ||
|
||
return target | ||
.WithType(newType) | ||
.AddAttributeLists(AttributeList(SingletonSeparatedList( | ||
Attribute( | ||
SystemTextJsonTypes.Serialization.JsonConverterAttributeName, | ||
AttributeArgumentList(SingletonSeparatedList( | ||
AttributeArgument(TypeOfExpression(NodaTimeTypes.Serialization.SystemTextJson.NodaTimeDefaultJsonConverterFactory))))) | ||
.WithTrailingTrivia(ElasticCarriageReturnLineFeed)))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
|
||
<Nullable>enable</Nullable> | ||
|
||
<PublishRepositoryUrl>true</PublishRepositoryUrl> | ||
<IncludeSymbols>true</IncludeSymbols> | ||
<SymbolPackageFormat>snupkg</SymbolPackageFormat> | ||
<Description>Extension for Yardarm to generate SDKs that use NodaTime for date/time schemas.</Description> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Yardarm\Yardarm.csproj" /> | ||
<ProjectReference Include="..\Yardarm.SystemTextJson\Yardarm.SystemTextJson.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<!-- Collect cs files from Yardarm.NodaTime.Client as resources so we can compile them into generated SDKs --> | ||
<EmbeddedResource Include="../Yardarm.NodaTime.Client/**/*.cs" Exclude="../Yardarm.NodaTime.Client/bin/**;../Yardarm.NodaTime.Client/obj/**"> | ||
<Visible>False</Visible> | ||
<LogicalName>$([System.String]::Copy('%(RelativeDir)').Substring(3).Replace('/', '.').Replace('\', '.'))%(Filename)%(Extension)</LogicalName> | ||
</EmbeddedResource> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly: InternalsVisibleTo("Yardarm.NodaTime, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d09345410b605ba41fa5c08c3e48e094da35fa75bbf0c5ded69ba29147de0a1401798641db4863302209826d0aa926267bb29abde27220de93e980d9b94e52a8b92768eacce7d26eacae4989770bdcd46c6153da0d0e228617d96a0973b717409f8b242d6a46eefc4bb1b7ba63bd6f8f929d8b100c744d5c8c4a4631556fec4")] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters