Skip to content

Commit

Permalink
Merge pull request #7 from almostchristian/develop
Browse files Browse the repository at this point in the history
Refactored source generation code for testability.
  • Loading branch information
almostchristian authored Sep 5, 2023
2 parents 191f6cf + 3906b29 commit 2af4960
Show file tree
Hide file tree
Showing 23 changed files with 356 additions and 193 deletions.
19 changes: 13 additions & 6 deletions ConfigurationProcessor.DependencyInjection.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.Depe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestWebApiGenerator", "sample\TestWebApiGenerator\TestWebApiGenerator.csproj", "{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.Gen.DependencyInjection", "src\ConfigurationProcessor.Gen.DependencyInjection\ConfigurationProcessor.Gen.DependencyInjection.csproj", "{E22B4D07-D154-480D-B27A-7B64E14669D4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.DependencyInjection.SourceGeneration", "src\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj", "{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests", "tests\ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests\ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests.csproj", "{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -93,10 +95,14 @@ Global
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1}.Release|Any CPU.Build.0 = Release|Any CPU
{E22B4D07-D154-480D-B27A-7B64E14669D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E22B4D07-D154-480D-B27A-7B64E14669D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E22B4D07-D154-480D-B27A-7B64E14669D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E22B4D07-D154-480D-B27A-7B64E14669D4}.Release|Any CPU.Build.0 = Release|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC}.Release|Any CPU.Build.0 = Release|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -113,7 +119,8 @@ Global
{53B667D5-FB51-4C83-A040-31724EC96F30} = {645ABE25-B876-4372-8712-C66AA34020FC}
{AD8581E7-B99F-42D8-BBA9-39D631F1F496} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{0945131E-BEAB-4EE0-86FE-A2C44300CCA1} = {645ABE25-B876-4372-8712-C66AA34020FC}
{E22B4D07-D154-480D-B27A-7B64E14669D4} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{06738AF5-221D-44C4-AD3D-3377CA4C1BEC} = {60E2AA27-F390-4152-9039-A05388E2D3D8}
{1FA1DC9D-FF01-4B92-9EB0-5551F4016553} = {14052F2C-4DA2-45FC-8F05-33B7AC728494}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2358CB49-45E6-4E83-85C1-F995C676A43F}
Expand Down
92 changes: 2 additions & 90 deletions sample/TestWebApiGenerator/ServiceRegistrationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,94 +8,6 @@ internal static partial class ServiceRegistrationExtensions
[GenerateServiceRegistration("Services")]
public static partial void AddServicesFromConfiguration(this WebApplicationBuilder builder);

//[GenerateServiceRegistration("Services")]
//internal static partial void AddServicesFromConfiguration(this IServiceCollection services, IConfiguration configurationb);
}

/// <summary>
/// Target codegen output.
/// </summary>
static partial class ServiceRegistrationExtensions
{
//public static partial void AddServicesFromConfiguration(this WebApplicationBuilder app)
// => app.Services.AddServicesFromConfiguration(app.Configuration);

public static void AddServicesFromConfigurationX(this IServiceCollection services, IConfiguration configuration)
{
var servicesSection = configuration.GetSection("Services");
if (!servicesSection.Exists())
{
return;
}

if (servicesSection.GetValue<bool>("Logging"))
{
services.AddLogging();
}

var hstsSection = servicesSection.GetSection("Hsts");
if (hstsSection.Exists())
{
services.AddHsts(x =>
{
if (hstsSection.GetValue<bool>("ExcludedHosts:Clear"))
{
x.ExcludedHosts.Clear();
}
x.Preload = hstsSection.GetValue<bool>("Preload");
x.IncludeSubDomains = hstsSection.GetValue<bool>("IncludeSubDomains");
x.MaxAge = TimeSpan.Parse(hstsSection.GetValue<string>("MaxAge"));
});
}

var configureSection = servicesSection.GetSection("Configure<Microsoft.AspNetCore.Builder.CookiePolicyOptions>");
if (configureSection.Exists())
{
services.Configure<CookiePolicyOptions>(options =>
{
options.HttpOnly = configureSection.GetValue<Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy>("HttpOnly");
options.Secure = configureSection.GetValue<CookieSecurePolicy>("Secure");
});
}

if (servicesSection.GetValue<bool>("Controllers"))
{
services.AddControllers();
}

if (servicesSection.GetValue<bool>("EndpointsApiExplorer"))
{
services.AddEndpointsApiExplorer();
}

if (servicesSection.GetValue<bool>("SwaggerGen"))
{
services.AddSwaggerGen();
}

var openTelemetrySection = servicesSection.GetSection("OpenTelemetryTracing");
services.AddOpenTelemetryTracing(options =>
{
if (openTelemetrySection.GetValue<bool>("AspNetCoreInstrumentation"))
{
options.AddAspNetCoreInstrumentation();
}
if (openTelemetrySection.GetValue<bool>("HttpClientInstrumentation"))
{
options.AddHttpClientInstrumentation();
}
if (openTelemetrySection.GetValue<bool>("SqlClientInstrumentation"))
{
options.AddSqlClientInstrumentation();
}
if (openTelemetrySection.GetValue<bool>("JaegerExporter"))
{
options.AddJaegerExporter();
}
});
}
// [GenerateServiceRegistration("Services")]
// internal static partial void AddServicesFromConfiguration(this IServiceCollection services, IConfiguration configuration);
}
6 changes: 3 additions & 3 deletions sample/TestWebApiGenerator/TestWebApiGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
<!--<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>-->
</PropertyGroup>

<ItemGroup>
Expand All @@ -20,7 +20,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\ConfigurationProcessor.DependencyInjection.Generator\ConfigurationProcessor.DependencyInjection.Generator.csproj" />
<ProjectReference Include="..\..\src\ConfigurationProcessor.Gen.DependencyInjection\ConfigurationProcessor.Gen.DependencyInjection.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,27 @@
<LangVersion>11</LangVersion>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageVersion>0.1.0-beta.5</PackageVersion>
<PackageVersion>0.1.0-beta.6</PackageVersion>
<PackageTags>$(PackageTags);source generation</PackageTags>
<DefineConstants>Generator</DefineConstants>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ConfigurationProcessor.Gen.DependencyInjection\ConfigurationProcessor.Gen.DependencyInjection.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" PackAsAnalyzer="true" />
<ProjectReference Include="..\ConfigurationProcessor.DependencyInjection.SourceGeneration\ConfigurationProcessor.DependencyInjection.SourceGeneration.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" PackAsAnalyzer="true" />

<PackageReference Include="Microsoft.Extensions.Primitives" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="System.Text.Json" Version="7.0.3" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<None Include="$(AssemblyName).targets" Pack="true" PackagePath="build" />
<None Include="$(PKGSystem_Text_Json)\lib\netstandard2.0\System.Text.Json.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_Configuration_Json)\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_Configuration_FileExtensions)\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_Configuration_Abstractions)\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_Configuration)\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_Primitives)\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_FileProviders_Abstractions)\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGMicrosoft_Extensions_FileProviders_Physical)\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
<None Include="$(PKGSystem_Reflection_MetadataLoadContext)\lib\netstandard2.0\System.Reflection.MetadataLoadContext.dll" Pack="true" PackagePath="analyzers/dotnet/cs" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="ConfigurationProcessor.DependencyInjection.SourceGeneration.UnitTests" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.2.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="System.Text.Json" Version="7.0.3" GeneratePathProperty="true" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="7.0.0" GeneratePathProperty="true" PrivateAssets="all" />
Expand All @@ -47,12 +44,8 @@
<Target Name="GetDependencyTargetPaths">
<ItemGroup>
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Text_Json)\lib\netstandard2.0\System.Text.Json.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_Configuration_Json)\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_Configuration_FileExtensions)\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_Configuration_Abstractions)\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_Configuration)\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_FileProviders_Abstractions)\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_FileProviders_Physical)\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGMicrosoft_Extensions_Primitives)\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll" IncludeRuntimeDependency="false" />
<TargetPathWithTargetPlatformMoniker Include="$(PKGSystem_Reflection_MetadataLoadContext)\lib\netstandard2.0\System.Reflection.MetadataLoadContext.dll" IncludeRuntimeDependency="false" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Reflection;
using ConfigurationProcessor.Gen.DependencyInjection.Utility;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Utility;
using Microsoft.Extensions.Configuration;

namespace ConfigurationProcessor.Core.Implementation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
using System.Reflection;
using ConfigurationProcessor.Gen.DependencyInjection.Parsing;
using ConfigurationProcessor.Gen.DependencyInjection.Utility;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Parsing;
using ConfigurationProcessor.DependencyInjection.SourceGeneration.Utility;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Configuration;

namespace ConfigurationProcessor.Gen.DependencyInjection;
namespace ConfigurationProcessor.DependencyInjection.SourceGeneration;

internal class Emitter
{
private GeneratorExecutionContext context;
private readonly Action<Diagnostic> reportDiagnostic;

public Emitter(GeneratorExecutionContext context, Action<Diagnostic> reportDiagnostic)
{
this.context = context;
this.reportDiagnostic = reportDiagnostic;
}

public string Emit(IReadOnlyList<ServiceRegistrationClass> generateConfigurationClasses, CancellationToken cancellationToken)
public string Emit(IReadOnlyList<ServiceRegistrationClass> generateConfigurationClasses, List<Assembly> references, CancellationToken cancellationToken)
{
var paths = context.Compilation.ExternalReferences.Select(x => x.Display!).ToList();
var resolver = new PathAssemblyResolver(paths);
var mlc = new MetadataLoadContext(resolver);

var references = context.Compilation.ExternalReferences.Select(x => mlc.LoadFromAssemblyPath(x.Display!)).ToList();

var emitContext = new EmitContext(generateConfigurationClasses.First().Namespace, references);

foreach (var configClass in generateConfigurationClasses)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}

emitContext.Write($@"
namespace {configClass.Namespace}
{{
Expand All @@ -40,14 +30,6 @@ static partial class {configClass.Name}
foreach (var configMethod in configClass.Methods)
{
var sectionName = configMethod.ConfigurationSectionName;
var configFile = configMethod.FileName;

var jsonFile = context.AdditionalFiles.FirstOrDefault(x => Path.GetFileName(x.Path) == configFile);
if (jsonFile == null)
{
Diag(DiagnosticDescriptors.ConfigurationFileNotFound, configMethod.Location, configMethod.FileName);
continue;
}

string configSectionVariableName = "servicesSection";

Expand All @@ -62,7 +44,7 @@ static partial class {configClass.Name}
}}");

emitContext.IncreaseIndent();
BuildMethods(emitContext, jsonFile.Path, sectionName, configMethod.ServiceCollectionField!, configSectionVariableName);
BuildMethods(emitContext, configMethod.ConfigurationValues, sectionName, configMethod.ServiceCollectionField!, configSectionVariableName);
emitContext.DecreaseIndent();
emitContext.Write("}");
}
Expand All @@ -78,10 +60,10 @@ static partial class {configClass.Name}
return emitContext.ToString();
}

private void BuildMethods(EmitContext emitContext, string jsonFilePath, string sectionName, string targetExpression, string configSectionVariableName)
private void BuildMethods(EmitContext emitContext, IEnumerable<KeyValuePair<string, string?>> configurationValues, string sectionName, string targetExpression, string configSectionVariableName)
{
var configBuilder = new ConfigurationBuilder();
configBuilder.AddJsonFile(jsonFilePath);
configBuilder.AddInMemoryCollection(configurationValues);
var config = configBuilder.Build();

var directive = config.GetSection(sectionName);
Expand All @@ -95,9 +77,4 @@ private void BuildMethods(EmitContext emitContext, string jsonFilePath, string s
Parser.ServiceCollectionTypeName,
serviceCollectionParameterName);
}

private void Diag(DiagnosticDescriptor desc, Location? location, params object?[]? messageArgs)
{
reportDiagnostic(Diagnostic.Create(desc, location, messageArgs));
}
}
Loading

0 comments on commit 2af4960

Please sign in to comment.