File: Emitter.cs
Web Access
Project: src\src\Generators\Microsoft.Gen.BuildMetadata\Microsoft.Gen.BuildMetadata.csproj (Microsoft.Gen.BuildMetadata)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using Microsoft.Gen.Shared;
 
namespace Microsoft.Gen.BuildMetadata;
 
[SuppressMessage("Format", "S1199", Justification = "For better visualization of how the generated code will look like.")]
internal sealed class Emitter : EmitterBase
{
    private const string DependencyInjectionNamespace = "global::Microsoft.Extensions.DependencyInjection.";
    private const string ConfigurationNamespace = "global::Microsoft.Extensions.Configuration.";
    private const string HostingNamespace = "global::Microsoft.Extensions.Hosting.";
    private readonly string? _buildId;
    private readonly string? _buildNumber;
    private readonly string? _sourceBranchName;
    private readonly string? _sourceVersion;
 
    public Emitter(BuildMetadata buildMetadata)
    {
        _buildId = buildMetadata.BuildId;
        _buildNumber = buildMetadata.BuildNumber;
        _sourceBranchName = buildMetadata.SourceBranchName;
        _sourceVersion = buildMetadata.SourceVersion;
    }
 
    public string Emit()
    {
        GenerateBuildMetadataExtensions();
        return Capture();
    }
 
    private void GenerateBuildMetadataSource()
    {
        OutGeneratedCodeAttribute();
        OutLn("[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]");
        OutLn($"private sealed class BuildMetadataSource : {ConfigurationNamespace}IConfigurationSource");
        OutOpenBrace();
        {
            OutLn("public string SectionName { get; }");
            OutLn();
 
            OutLn("public BuildMetadataSource(string sectionName)");
            OutOpenBrace();
            {
                OutNullGuards(checkBuilder: false);
                OutLn("SectionName = sectionName;");
            }
 
            OutCloseBrace();
            OutLn();
            OutLn($"public {ConfigurationNamespace}IConfigurationProvider Build({ConfigurationNamespace}IConfigurationBuilder builder)");
            OutOpenBrace();
            {
                OutLn($"return new {ConfigurationNamespace}Memory.MemoryConfigurationProvider(new {ConfigurationNamespace}Memory.MemoryConfigurationSource())");
                OutOpenBrace();
                {
                    OutLn($$"""{ $"{SectionName}:buildid", "{{_buildId}}" },""");
                    OutLn($$"""{ $"{SectionName}:buildnumber", "{{_buildNumber}}" },""");
                    OutLn($$"""{ $"{SectionName}:sourcebranchname", "{{_sourceBranchName}}" },""");
                    OutLn($$"""{ $"{SectionName}:sourceversion", "{{_sourceVersion}}" },""");
                }
 
                OutCloseBraceWithExtra(";");
            }
 
            OutCloseBrace();
        }
 
        OutCloseBrace();
    }
 
    private void GenerateBuildMetadataExtensions()
    {
        OutLn("namespace Microsoft.Extensions.AmbientMetadata");
        OutOpenBrace();
        {
            OutGeneratedCodeAttribute();
            OutLn("internal static class BuildMetadataGeneratedExtensions");
            OutOpenBrace();
            {
                OutLn("private const string DefaultSectionName = \"ambientmetadata:build\";");
                OutLn();
 
                GenerateBuildMetadataSource();
                OutLn();
 
                OutLn($"public static {HostingNamespace}IHostBuilder UseBuildMetadata(this {HostingNamespace}IHostBuilder builder, string sectionName = DefaultSectionName)");
                OutOpenBrace();
                {
                    OutNullGuards();
                    OutLn("_ = builder.ConfigureHostConfiguration(configBuilder => configBuilder.AddBuildMetadata(sectionName))");
                    Indent();
                    OutLn(".ConfigureServices((hostBuilderContext, serviceCollection) =>");
                    Indent();
                    OutLn($"{DependencyInjectionNamespace}BuildMetadataServiceCollectionExtensions.AddBuildMetadata(serviceCollection, hostBuilderContext.Configuration.GetSection(sectionName)));");
                    Unindent();
                    Unindent();
                    OutLn();
 
                    OutLn("return builder;");
                }
 
                OutCloseBrace();
                OutLn();
 
                OutLn("public static TBuilder UseBuildMetadata<TBuilder>(this TBuilder builder, string sectionName = DefaultSectionName)");
                Indent();
                OutLn($"where TBuilder : {HostingNamespace}IHostApplicationBuilder");
                Unindent();
                OutOpenBrace();
                {
                    OutNullGuards();
                    OutLn("_ = builder.Configuration.AddBuildMetadata(sectionName);");
                    OutLn($"{DependencyInjectionNamespace}BuildMetadataServiceCollectionExtensions.AddBuildMetadata(builder.Services, builder.Configuration.GetSection(sectionName));");
                    OutLn();
 
                    OutLn("return builder;");
                }
 
                OutCloseBrace();
                OutLn();
 
#pragma warning disable S103 // Lines should not be too long
                OutLn($"public static {ConfigurationNamespace}IConfigurationBuilder AddBuildMetadata(this {ConfigurationNamespace}IConfigurationBuilder builder, string sectionName = DefaultSectionName)");
#pragma warning restore S103 // Lines should not be too long
                OutOpenBrace();
                {
                    OutNullGuards();
                    OutLn("return builder.Add(new BuildMetadataSource(sectionName));");
                }
 
                OutCloseBrace();
            }
 
            OutCloseBrace();
        }
 
        OutCloseBrace();
    }
 
    private void OutNullGuards(bool checkBuilder = true)
    {
        OutPP("#if !NET");
 
        if (checkBuilder)
        {
            OutLn("if (builder is null)");
            OutOpenBrace();
            OutLn("throw new global::System.ArgumentNullException(nameof(builder));");
            OutCloseBrace();
            OutLn();
        }
 
        OutLn("if (string.IsNullOrWhiteSpace(sectionName))");
        OutOpenBrace();
        {
            OutLn("if (sectionName is null)");
            OutOpenBrace();
            {
                OutLn("throw new global::System.ArgumentNullException(nameof(sectionName));");
            }
 
            OutCloseBrace();
            OutLn();
            OutLn("throw new global::System.ArgumentException(\"The value cannot be an empty string or composed entirely of whitespace.\", nameof(sectionName));");
        }
 
        OutCloseBrace();
 
        OutPP("#else");
 
        if (checkBuilder)
        {
            OutLn("global::System.ArgumentNullException.ThrowIfNull(builder);");
        }
 
        OutLn("global::System.ArgumentException.ThrowIfNullOrWhiteSpace(sectionName);");
 
        OutPP("#endif");
        OutLn();
    }
}