From 7107e243beee0f09361223e192430f048fd72836 Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sat, 8 Feb 2025 08:52:59 -0500 Subject: [PATCH 1/5] Create a more generic form for registration enrichers This will allow us to add other types of extension registration, such as JSON converters, more easily. --- .../DefaultLiteralConvertersEnricher.cs | 8 +++++--- .../DefaultTypeSerializersEnricher.cs | 5 ++++- .../EnricherServiceCollectionExtensions.cs | 16 +++++++++++++--- .../Enrichment/ICreateDefaultRegistryEnricher.cs | 6 ++---- .../IDefaultLiteralConverterEnricher.cs | 6 ++---- .../Yardarm/Enrichment/IRegistrationEnricher.cs | 10 ++++++++++ 6 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 src/main/Yardarm/Enrichment/IRegistrationEnricher.cs diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs index 01b06cc2..18b34cf6 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs @@ -1,15 +1,17 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Extensions.DependencyInjection; namespace Yardarm.Enrichment.Compilation; public class DefaultLiteralConvertersEnricher( - IEnumerable createDefaultRegistryEnrichers) + [FromKeyedServices(DefaultLiteralConvertersEnricher.RegistrationEnricherKey)] IEnumerable createDefaultRegistryEnrichers) : IResourceFileEnricher { + public const string RegistrationEnricherKey = "DefaultLiteralConverters"; + public bool ShouldEnrich(string resourceName) => resourceName == "Yardarm.Client.Serialization.Literals.LiteralConverterRegistry.cs"; diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs index c3783082..20a91001 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs @@ -2,13 +2,16 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.Extensions.DependencyInjection; namespace Yardarm.Enrichment.Compilation; public class DefaultTypeSerializersEnricher( - IEnumerable createDefaultRegistryEnrichers) : + [FromKeyedServices(DefaultTypeSerializersEnricher.RegistrationEnricherKey)] IEnumerable createDefaultRegistryEnrichers) : IResourceFileEnricher { + public const string RegistrationEnricherKey = "DefaultTypeSerializers"; + public bool ShouldEnrich(string resourceName) => resourceName == "Yardarm.Client.Serialization.TypeSerializerRegistry.cs"; diff --git a/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs b/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs index f250610a..b174910e 100644 --- a/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs +++ b/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Yardarm.Enrichment.Authentication; using Yardarm.Enrichment.Compilation; using Yardarm.Enrichment.Packaging; @@ -21,13 +22,22 @@ public static IServiceCollection AddDefaultEnrichers(this IServiceCollection ser .AddDefaultResponseEnrichers() .AddDefaultTagEnrichers(); + public static IServiceCollection AddRegistrationEnricher(this IServiceCollection services, string registrationType) + where T : class, IRegistrationEnricher + { + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(registrationType); + + return services.AddKeyedTransient(registrationType); + } + public static IServiceCollection AddCreateDefaultRegistryEnricher(this IServiceCollection services) where T : class, ICreateDefaultRegistryEnricher => - services.AddTransient(); + services.AddRegistrationEnricher(DefaultTypeSerializersEnricher.RegistrationEnricherKey); public static IServiceCollection AddDefaultLiteralConverterEnricher(this IServiceCollection services) where T : class, IDefaultLiteralConverterEnricher => - services.AddTransient(); + services.AddRegistrationEnricher(DefaultLiteralConvertersEnricher.RegistrationEnricherKey); public static IServiceCollection AddOpenApiSyntaxNodeEnricher(this IServiceCollection services) where T : class, IOpenApiSyntaxNodeEnricher => diff --git a/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs b/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs index acc8f895..324977af 100644 --- a/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs @@ -1,8 +1,6 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Yardarm.Enrichment +namespace Yardarm.Enrichment { - public interface ICreateDefaultRegistryEnricher : IEnricher + public interface ICreateDefaultRegistryEnricher : IRegistrationEnricher { } } diff --git a/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs b/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs index 617706f0..92a1b4eb 100644 --- a/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs +++ b/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs @@ -1,10 +1,8 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Yardarm.Enrichment; +namespace Yardarm.Enrichment; /// /// Enriches the body of the CreateDefaultRegistry method in the LiteralConverterRegistry class. /// -public interface IDefaultLiteralConverterEnricher : IEnricher +public interface IDefaultLiteralConverterEnricher : IRegistrationEnricher { } diff --git a/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs new file mode 100644 index 00000000..a78a5ed3 --- /dev/null +++ b/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs @@ -0,0 +1,10 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Yardarm.Enrichment; + +/// +/// An expression enricher used by extensions to register themselves in the client. +/// +public interface IRegistrationEnricher : IEnricher +{ +} From 5bf497d23e4166b3273c189ff1432c7acca6ba78 Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sat, 8 Feb 2025 11:54:11 -0500 Subject: [PATCH 2/5] Use a more flexible BlockSyntax pattern --- .../Literals/LiteralConverterRegistry.cs | 14 ++++++- .../Serialization/TypeSerializerRegistry.cs | 7 +++- .../JsonCreateDefaultRegistryEnricher.cs | 7 ++-- .../JsonCreateDefaultRegistryEnricher.cs | 13 +++--- .../DefaultLiteralConvertersEnricher.cs | 7 ++-- .../DefaultTypeSerializersEnricher.cs | 7 ++-- .../Enrichment/IRegistrationEnricher.cs | 2 +- .../ReturnValueRegistrationEnricher.cs | 42 +++++++++++++++++++ 8 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs diff --git a/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs b/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs index 940eda3d..f969811f 100644 --- a/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs +++ b/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs @@ -147,10 +147,10 @@ public LiteralConverterRegistry Add(LiteralConverter converter) } /// - /// Returns a new with the all default converters registered. + /// Returns a new with the built-in converters registered. /// /// A new . - public static LiteralConverterRegistry CreateDefaultRegistry() => + public static LiteralConverterRegistry CreateBasicRegistry() => new LiteralConverterRegistry() .Add(new BooleanLiteralConverter()) .Add(new DateTimeLiteralConverter()) @@ -175,4 +175,14 @@ public static LiteralConverterRegistry CreateDefaultRegistry() => .Add(new TimeOnlyLiteralConverter()) #endif ; + + /// + /// Returns a new with the all default converters registered. + /// + /// A new . + public static LiteralConverterRegistry CreateDefaultRegistry() + { + LiteralConverterRegistry registry = CreateBasicRegistry(); + return registry; + } } diff --git a/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs b/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs index 05589013..39c78f60 100644 --- a/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs +++ b/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs @@ -114,7 +114,10 @@ public static ITypeSerializerRegistry CreateBasicRegistry() => /// Returns a new with the all default serializers registered. /// /// A new . - public static ITypeSerializerRegistry CreateDefaultRegistry() => - CreateBasicRegistry(); + public static ITypeSerializerRegistry CreateDefaultRegistry() + { + ITypeSerializerRegistry registry = CreateBasicRegistry(); + return registry; + } } } diff --git a/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs b/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs index 6e17600a..c544d5a5 100644 --- a/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Yardarm.Enrichment; @@ -7,7 +6,7 @@ namespace Yardarm.NewtonsoftJson { - public class JsonCreateDefaultRegistryEnricher : ICreateDefaultRegistryEnricher + public class JsonCreateDefaultRegistryEnricher : ReturnValueRegistrationEnricher, ICreateDefaultRegistryEnricher { private readonly IJsonSerializationNamespace _jsonSerializationNamespace; @@ -18,10 +17,10 @@ public JsonCreateDefaultRegistryEnricher(IJsonSerializationNamespace jsonSeriali _jsonSerializationNamespace = jsonSerializationNamespace; } - public ExpressionSyntax Enrich(ExpressionSyntax target) => + protected override ExpressionSyntax EnrichReturnValue(ExpressionSyntax expression) => InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - target.WithTrailingTrivia(TriviaList(CarriageReturnLineFeed, Whitespace(" "))), + expression, GenericName( Identifier("Add"), TypeArgumentList(SingletonSeparatedList(_jsonSerializationNamespace.JsonTypeSerializer)))), diff --git a/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs b/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs index 40506f86..92173626 100644 --- a/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Yardarm.Enrichment; @@ -8,7 +7,7 @@ namespace Yardarm.SystemTextJson { - public class JsonCreateDefaultRegistryEnricher : ICreateDefaultRegistryEnricher + public class JsonCreateDefaultRegistryEnricher : ReturnValueRegistrationEnricher, ICreateDefaultRegistryEnricher { private readonly IJsonSerializationNamespace _jsonSerializationNamespace; @@ -19,16 +18,16 @@ public JsonCreateDefaultRegistryEnricher(IJsonSerializationNamespace jsonSeriali _jsonSerializationNamespace = jsonSerializationNamespace; } - public ExpressionSyntax Enrich(ExpressionSyntax target) => + protected override ExpressionSyntax EnrichReturnValue(ExpressionSyntax target) => // Don't use the Add overload here because it will cause trimming to retain // all constructors. This will then cause IL2026 warnings if trimming is enabled. // Instead create a new instance directly using the default constructor and add it. InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - target.WithTrailingTrivia(TriviaList(CarriageReturnLineFeed, Whitespace(" "))), + target, IdentifierName("Add")), - ArgumentList(SeparatedList(new[] - { + ArgumentList(SeparatedList( + [ Argument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, _jsonSerializationNamespace.JsonTypeSerializer, IdentifierName("SupportedMediaTypes"))), @@ -38,6 +37,6 @@ public ExpressionSyntax Enrich(ExpressionSyntax target) => QualifiedName(_jsonSerializationNamespace.Name, IdentifierName(JsonSerializerContextGenerator.TypeName)), IdentifierName("Default"))))), null)) - }))); + ]))); } } diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs index 18b34cf6..69274089 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs @@ -27,11 +27,10 @@ public CompilationUnitSyntax Enrich(CompilationUnitSyntax target, ResourceFileEn .OfType() .FirstOrDefault(p => p.Identifier.ValueText == "CreateDefaultRegistry"); - if (methodDeclaration?.ExpressionBody != null) + if (methodDeclaration?.Body is { } body) { - MethodDeclarationSyntax newMethodDeclaration = methodDeclaration.WithExpressionBody( - methodDeclaration.ExpressionBody.WithExpression( - methodDeclaration.ExpressionBody.Expression.Enrich(createDefaultRegistryEnrichers))); + MethodDeclarationSyntax newMethodDeclaration = methodDeclaration.WithBody( + body.Enrich(createDefaultRegistryEnrichers)); target = target.ReplaceNode(methodDeclaration, newMethodDeclaration); } diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs index 20a91001..249f3b13 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs @@ -27,11 +27,10 @@ public CompilationUnitSyntax Enrich(CompilationUnitSyntax target, ResourceFileEn .OfType() .FirstOrDefault(p => p.Identifier.ValueText == "CreateDefaultRegistry"); - if (methodDeclaration?.ExpressionBody != null) + if (methodDeclaration?.Body is { } body) { - MethodDeclarationSyntax newMethodDeclaration = methodDeclaration.WithExpressionBody( - methodDeclaration.ExpressionBody.WithExpression( - methodDeclaration.ExpressionBody.Expression.Enrich(createDefaultRegistryEnrichers))); + MethodDeclarationSyntax newMethodDeclaration = methodDeclaration.WithBody( + body.Enrich(createDefaultRegistryEnrichers)); target = target.ReplaceNode(methodDeclaration, newMethodDeclaration); } diff --git a/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs index a78a5ed3..f07cba70 100644 --- a/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs +++ b/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs @@ -5,6 +5,6 @@ namespace Yardarm.Enrichment; /// /// An expression enricher used by extensions to register themselves in the client. /// -public interface IRegistrationEnricher : IEnricher +public interface IRegistrationEnricher : IEnricher { } diff --git a/src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs new file mode 100644 index 00000000..95b342a8 --- /dev/null +++ b/src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs @@ -0,0 +1,42 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Yardarm.Enrichment; + +/// +/// Common implementation for an that modifies the return value of a method. +/// +public abstract class ReturnValueRegistrationEnricher : IRegistrationEnricher +{ + public BlockSyntax Enrich(BlockSyntax target) + { + int returnStatementIndex = target.Statements.LastIndexOf(p => p is ReturnStatementSyntax); + if (returnStatementIndex < 0) + { + return target; + } + + ExpressionSyntax? returnExpression = ((ReturnStatementSyntax)target.Statements[returnStatementIndex]).Expression; + if (returnExpression is not IdentifierNameSyntax identifier) + { + return target; + } + + ExpressionSyntax newReturnValue = EnrichReturnValue(identifier); + if (newReturnValue == returnExpression) + { + // Was not changed + return target; + } + + ExpressionStatementSyntax statement = ExpressionStatement(AssignmentExpression( + Microsoft.CodeAnalysis.CSharp.SyntaxKind.SimpleAssignmentExpression, + identifier, + newReturnValue)); + + return target.WithStatements( + target.Statements.Insert(returnStatementIndex, statement)); + } + + protected abstract ExpressionSyntax EnrichReturnValue(ExpressionSyntax expression); +} From 840169199dcded3f70c240fbcc62669fb98be1cd Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sat, 8 Feb 2025 12:04:28 -0500 Subject: [PATCH 3/5] Add comments at enrichment points for clarity --- .../Serialization/Literals/LiteralConverterRegistry.cs | 1 + src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs b/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs index f969811f..b26a6ff8 100644 --- a/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs +++ b/src/main/Yardarm.Client/Serialization/Literals/LiteralConverterRegistry.cs @@ -183,6 +183,7 @@ public static LiteralConverterRegistry CreateBasicRegistry() => public static LiteralConverterRegistry CreateDefaultRegistry() { LiteralConverterRegistry registry = CreateBasicRegistry(); + // Enrichment point return registry; } } diff --git a/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs b/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs index 39c78f60..928cca79 100644 --- a/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs +++ b/src/main/Yardarm.Client/Serialization/TypeSerializerRegistry.cs @@ -117,6 +117,7 @@ public static ITypeSerializerRegistry CreateBasicRegistry() => public static ITypeSerializerRegistry CreateDefaultRegistry() { ITypeSerializerRegistry registry = CreateBasicRegistry(); + // Enrichment point return registry; } } From f330dc02ed3cb43c9b0dbbcb977257368e814d56 Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sun, 9 Feb 2025 10:10:30 -0500 Subject: [PATCH 4/5] Move types to Registration namespace --- .../Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs | 2 +- .../Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs | 2 +- .../Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs | 1 + .../Enrichment/Compilation/DefaultTypeSerializersEnricher.cs | 1 + .../Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs | 1 + .../{ => Registration}/ICreateDefaultRegistryEnricher.cs | 2 +- .../{ => Registration}/IDefaultLiteralConverterEnricher.cs | 2 +- .../Enrichment/{ => Registration}/IRegistrationEnricher.cs | 2 +- .../{ => Registration}/ReturnValueRegistrationEnricher.cs | 2 +- 9 files changed, 9 insertions(+), 6 deletions(-) rename src/main/Yardarm/Enrichment/{ => Registration}/ICreateDefaultRegistryEnricher.cs (67%) rename src/main/Yardarm/Enrichment/{ => Registration}/IDefaultLiteralConverterEnricher.cs (81%) rename src/main/Yardarm/Enrichment/{ => Registration}/IRegistrationEnricher.cs (84%) rename src/main/Yardarm/Enrichment/{ => Registration}/ReturnValueRegistrationEnricher.cs (97%) diff --git a/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs b/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs index c544d5a5..54273928 100644 --- a/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm.NewtonsoftJson/JsonCreateDefaultRegistryEnricher.cs @@ -1,7 +1,7 @@ using System; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Yardarm.Enrichment; +using Yardarm.Enrichment.Registration; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Yardarm.NewtonsoftJson diff --git a/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs b/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs index 92173626..3a090c46 100644 --- a/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm.SystemTextJson/JsonCreateDefaultRegistryEnricher.cs @@ -1,7 +1,7 @@ using System; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Yardarm.Enrichment; +using Yardarm.Enrichment.Registration; using Yardarm.SystemTextJson.Internal; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs index 69274089..de4fb553 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultLiteralConvertersEnricher.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.DependencyInjection; +using Yardarm.Enrichment.Registration; namespace Yardarm.Enrichment.Compilation; diff --git a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs index 249f3b13..f4c802e6 100644 --- a/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs +++ b/src/main/Yardarm/Enrichment/Compilation/DefaultTypeSerializersEnricher.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.DependencyInjection; +using Yardarm.Enrichment.Registration; namespace Yardarm.Enrichment.Compilation; diff --git a/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs b/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs index b174910e..dea5d91d 100644 --- a/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs +++ b/src/main/Yardarm/Enrichment/EnricherServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Yardarm.Enrichment.Authentication; using Yardarm.Enrichment.Compilation; using Yardarm.Enrichment.Packaging; +using Yardarm.Enrichment.Registration; using Yardarm.Enrichment.Requests; using Yardarm.Enrichment.Responses; using Yardarm.Enrichment.Schema; diff --git a/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs b/src/main/Yardarm/Enrichment/Registration/ICreateDefaultRegistryEnricher.cs similarity index 67% rename from src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs rename to src/main/Yardarm/Enrichment/Registration/ICreateDefaultRegistryEnricher.cs index 324977af..a2ed8be3 100644 --- a/src/main/Yardarm/Enrichment/ICreateDefaultRegistryEnricher.cs +++ b/src/main/Yardarm/Enrichment/Registration/ICreateDefaultRegistryEnricher.cs @@ -1,4 +1,4 @@ -namespace Yardarm.Enrichment +namespace Yardarm.Enrichment.Registration { public interface ICreateDefaultRegistryEnricher : IRegistrationEnricher { diff --git a/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs b/src/main/Yardarm/Enrichment/Registration/IDefaultLiteralConverterEnricher.cs similarity index 81% rename from src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs rename to src/main/Yardarm/Enrichment/Registration/IDefaultLiteralConverterEnricher.cs index 92a1b4eb..65829ab7 100644 --- a/src/main/Yardarm/Enrichment/IDefaultLiteralConverterEnricher.cs +++ b/src/main/Yardarm/Enrichment/Registration/IDefaultLiteralConverterEnricher.cs @@ -1,4 +1,4 @@ -namespace Yardarm.Enrichment; +namespace Yardarm.Enrichment.Registration; /// /// Enriches the body of the CreateDefaultRegistry method in the LiteralConverterRegistry class. diff --git a/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/Registration/IRegistrationEnricher.cs similarity index 84% rename from src/main/Yardarm/Enrichment/IRegistrationEnricher.cs rename to src/main/Yardarm/Enrichment/Registration/IRegistrationEnricher.cs index f07cba70..5f71e7dd 100644 --- a/src/main/Yardarm/Enrichment/IRegistrationEnricher.cs +++ b/src/main/Yardarm/Enrichment/Registration/IRegistrationEnricher.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Yardarm.Enrichment; +namespace Yardarm.Enrichment.Registration; /// /// An expression enricher used by extensions to register themselves in the client. diff --git a/src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs similarity index 97% rename from src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs rename to src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs index 95b342a8..10a060d7 100644 --- a/src/main/Yardarm/Enrichment/ReturnValueRegistrationEnricher.cs +++ b/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs @@ -1,7 +1,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -namespace Yardarm.Enrichment; +namespace Yardarm.Enrichment.Registration; /// /// Common implementation for an that modifies the return value of a method. From c390815dc69f42763f995415c7851f0e8265141e Mon Sep 17 00:00:00 2001 From: Brant Burnett Date: Sun, 9 Feb 2025 10:27:15 -0500 Subject: [PATCH 5/5] Add additional abstraction for registration enrichers --- .../ReturnValueRegistrationEnricher.cs | 21 ++++------ .../StatementInsertingRegistrationEnricher.cs | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 src/main/Yardarm/Enrichment/Registration/StatementInsertingRegistrationEnricher.cs diff --git a/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs index 10a060d7..e5580119 100644 --- a/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs +++ b/src/main/Yardarm/Enrichment/Registration/ReturnValueRegistrationEnricher.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Yardarm.Enrichment.Registration; @@ -6,27 +7,20 @@ namespace Yardarm.Enrichment.Registration; /// /// Common implementation for an that modifies the return value of a method. /// -public abstract class ReturnValueRegistrationEnricher : IRegistrationEnricher +public abstract class ReturnValueRegistrationEnricher : StatementInsertingRegistrationEnricher { - public BlockSyntax Enrich(BlockSyntax target) + protected override sealed IEnumerable GenerateStatements(ExpressionSyntax? returnExpression) { - int returnStatementIndex = target.Statements.LastIndexOf(p => p is ReturnStatementSyntax); - if (returnStatementIndex < 0) - { - return target; - } - - ExpressionSyntax? returnExpression = ((ReturnStatementSyntax)target.Statements[returnStatementIndex]).Expression; if (returnExpression is not IdentifierNameSyntax identifier) { - return target; + return []; } ExpressionSyntax newReturnValue = EnrichReturnValue(identifier); if (newReturnValue == returnExpression) { // Was not changed - return target; + return []; } ExpressionStatementSyntax statement = ExpressionStatement(AssignmentExpression( @@ -34,8 +28,7 @@ public BlockSyntax Enrich(BlockSyntax target) identifier, newReturnValue)); - return target.WithStatements( - target.Statements.Insert(returnStatementIndex, statement)); + return [statement]; } protected abstract ExpressionSyntax EnrichReturnValue(ExpressionSyntax expression); diff --git a/src/main/Yardarm/Enrichment/Registration/StatementInsertingRegistrationEnricher.cs b/src/main/Yardarm/Enrichment/Registration/StatementInsertingRegistrationEnricher.cs new file mode 100644 index 00000000..332db320 --- /dev/null +++ b/src/main/Yardarm/Enrichment/Registration/StatementInsertingRegistrationEnricher.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Yardarm.Enrichment.Registration; + +/// +/// Common implementation for an that inserts statements before the return +/// at the end of the method. +/// +public abstract class StatementInsertingRegistrationEnricher : IRegistrationEnricher +{ + public BlockSyntax Enrich(BlockSyntax target) + { + int returnStatementIndex = target.Statements.LastIndexOf(p => p is ReturnStatementSyntax); + ExpressionSyntax? returnExpression = returnStatementIndex >= 0 + ? ((ReturnStatementSyntax)target.Statements[returnStatementIndex]).Expression + : null; + + IEnumerable newStatements = GenerateStatements(returnExpression); + if (newStatements == Enumerable.Empty() || + newStatements is ICollection { Count: 0 }) + { + // No statements added, short-circuit + return target; + } + + return target.WithStatements( + target.Statements.InsertRange(returnStatementIndex, newStatements)); + } + + /// + /// Generates the statements to insert before the return statement. + /// + /// The expression being returned in the return statement. + /// + protected abstract IEnumerable GenerateStatements(ExpressionSyntax? returnExpression); +}