< Summary

Information
Class: NexusLabs.Needlr.Generators.CodeGen.ServiceCatalogCodeGenerator
Assembly: NexusLabs.Needlr.Generators
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/CodeGen/ServiceCatalogCodeGenerator.cs
Line coverage
95%
Covered lines: 148
Uncovered lines: 7
Coverable lines: 155
Total lines: 282
Line coverage: 95.4%
Branch coverage
80%
Covered branches: 50
Total branches: 62
Branch coverage: 80.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GenerateServiceCatalogSource(...)100%11100%
GenerateServicesProperty(...)81.25%161696.77%
GenerateDecoratorsProperty(...)100%44100%
GenerateHostedServicesProperty(...)75%1212100%
GenerateInterceptedServicesProperty(...)75%8890.9%
GenerateOptionsProperty(...)91.66%1212100%
GeneratePluginsProperty(...)100%44100%
GetRelativeSourcePath(...)50%17633.33%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/CodeGen/ServiceCatalogCodeGenerator.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Text;
 5
 6using NexusLabs.Needlr.Generators.Models;
 7
 8namespace NexusLabs.Needlr.Generators.CodeGen;
 9
 10/// <summary>
 11/// Generates the ServiceCatalog implementation from DiscoveryResult.
 12/// </summary>
 13internal static class ServiceCatalogCodeGenerator
 14{
 15    internal static string GenerateServiceCatalogSource(
 16        DiscoveryResult discoveryResult,
 17        string assemblyName,
 18        string? projectDirectory,
 19        BreadcrumbWriter breadcrumbs)
 20    {
 43421        var builder = new StringBuilder();
 43422        var safeAssemblyName = GeneratorHelpers.SanitizeIdentifier(assemblyName);
 43423        var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss");
 24
 43425        builder.AppendLine("// <auto-generated/>");
 43426        builder.AppendLine("// Needlr Service Catalog");
 43427        builder.AppendLine($"// Generated: {timestamp} UTC");
 43428        builder.AppendLine();
 43429        builder.AppendLine("#nullable enable");
 43430        builder.AppendLine();
 43431        builder.AppendLine($"namespace {safeAssemblyName}.Generated;");
 43432        builder.AppendLine();
 33
 43434        breadcrumbs.WriteInlineComment(builder, "", $"ServiceCatalog: {discoveryResult.InjectableTypes.Count} services, 
 35
 43436        builder.AppendLine("/// <summary>");
 43437        builder.AppendLine("/// Compile-time service catalog containing all discovered registrations.");
 43438        builder.AppendLine("/// </summary>");
 43439        builder.AppendLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"NexusLabs.Needlr.Generators\", \"1
 43440        builder.AppendLine($"public sealed class ServiceCatalog : global::NexusLabs.Needlr.Catalog.IServiceCatalog");
 43441        builder.AppendLine("{");
 43442        builder.AppendLine($"    /// <inheritdoc />");
 43443        builder.AppendLine($"    public string AssemblyName => \"{GeneratorHelpers.EscapeStringLiteral(assemblyName)}\";
 43444        builder.AppendLine();
 43445        builder.AppendLine($"    /// <inheritdoc />");
 43446        builder.AppendLine($"    public string GeneratedAt => \"{timestamp}\";");
 43447        builder.AppendLine();
 48
 49        // Services
 43450        GenerateServicesProperty(builder, discoveryResult.InjectableTypes, projectDirectory);
 51
 52        // Decorators
 43453        GenerateDecoratorsProperty(builder, discoveryResult.Decorators, projectDirectory);
 54
 55        // Hosted Services
 43456        GenerateHostedServicesProperty(builder, discoveryResult.HostedServices, projectDirectory);
 57
 58        // Intercepted Services
 43459        GenerateInterceptedServicesProperty(builder, discoveryResult.InterceptedServices, projectDirectory);
 60
 61        // Options
 43462        GenerateOptionsProperty(builder, discoveryResult.Options, projectDirectory);
 63
 64        // Plugins
 43465        GeneratePluginsProperty(builder, discoveryResult.PluginTypes, projectDirectory);
 66
 43467        builder.AppendLine("}");
 68
 43469        return builder.ToString();
 70    }
 71
 72    private static void GenerateServicesProperty(
 73        StringBuilder builder,
 74        IReadOnlyList<DiscoveredType> types,
 75        string? projectDirectory)
 76    {
 43477        builder.AppendLine($"    /// <inheritdoc />");
 43478        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 43479        builder.AppendLine("    {");
 80
 45703281        foreach (var type in types)
 82        {
 22808283            var shortName = GeneratorHelpers.GetShortTypeName(type.TypeName);
 22808284            var lifetimeStr = type.Lifetime switch
 22808285            {
 22805586                GeneratorLifetime.Singleton => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Singleton",
 2387                GeneratorLifetime.Scoped => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Scoped",
 488                GeneratorLifetime.Transient => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Transient",
 089                _ => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Scoped"
 22808290            };
 22808291            var sourceFilePath = GetRelativeSourcePath(type.SourceFilePath, projectDirectory);
 22808292            var sourceFilePathLiteral = sourceFilePath != null
 22808293                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 22808294                : "null";
 95
 96            // Build interfaces array
 22832897            var interfacesArray = $"new string[] {{ {string.Join(", ", type.InterfaceNames.Select(i => $"\"{GeneratorHel
 98
 99            // Build constructor parameters array
 228082100            var constructorParamsBuilder = new StringBuilder();
 228082101            constructorParamsBuilder.Append("new global::NexusLabs.Needlr.Catalog.ConstructorParameterEntry[] { ");
 564096102            foreach (var param in type.ConstructorParameters)
 103            {
 53966104                var serviceKeyLiteral = param.ServiceKey != null
 53966105                    ? $"\"{GeneratorHelpers.EscapeStringLiteral(param.ServiceKey)}\""
 53966106                    : "null";
 53966107                var paramName = param.ParameterName ?? "unknown";
 53966108                constructorParamsBuilder.Append($"new global::NexusLabs.Needlr.Catalog.ConstructorParameterEntry(\"{Gene
 109            }
 228082110            constructorParamsBuilder.Append('}');
 111
 112            // Build service keys array
 228087113            var serviceKeysArray = $"new string[] {{ {string.Join(", ", type.ServiceKeys.Select(k => $"\"{GeneratorHelpe
 114
 228082115            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.ServiceCatalogEntry(\"{GeneratorHelpers.Es
 116        }
 117
 434118        builder.AppendLine("    };");
 434119        builder.AppendLine();
 434120    }
 121
 122    private static void GenerateDecoratorsProperty(
 123        StringBuilder builder,
 124        IReadOnlyList<DiscoveredDecorator> decorators,
 125        string? projectDirectory)
 126    {
 434127        builder.AppendLine($"    /// <inheritdoc />");
 434128        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 434129        builder.AppendLine("    {");
 130
 922131        foreach (var decorator in decorators)
 132        {
 27133            var shortName = GeneratorHelpers.GetShortTypeName(decorator.DecoratorTypeName);
 27134            var sourceFilePath = GetRelativeSourcePath(decorator.SourceFilePath, projectDirectory);
 27135            var sourceFilePathLiteral = sourceFilePath != null
 27136                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 27137                : "null";
 138
 27139            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.DecoratorCatalogEntry(\"{GeneratorHelpers.
 140        }
 141
 434142        builder.AppendLine("    };");
 434143        builder.AppendLine();
 434144    }
 145
 146    private static void GenerateHostedServicesProperty(
 147        StringBuilder builder,
 148        IReadOnlyList<DiscoveredHostedService> hostedServices,
 149        string? projectDirectory)
 150    {
 434151        builder.AppendLine($"    /// <inheritdoc />");
 434152        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 434153        builder.AppendLine("    {");
 154
 882155        foreach (var hosted in hostedServices)
 156        {
 7157            var shortName = GeneratorHelpers.GetShortTypeName(hosted.TypeName);
 7158            var sourceFilePath = GetRelativeSourcePath(hosted.SourceFilePath, projectDirectory);
 7159            var sourceFilePathLiteral = sourceFilePath != null
 7160                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 7161                : "null";
 162
 163            // Build constructor parameters array
 7164            var constructorParamsBuilder = new StringBuilder();
 7165            constructorParamsBuilder.Append("new global::NexusLabs.Needlr.Catalog.ConstructorParameterEntry[] { ");
 16166            foreach (var param in hosted.ConstructorParameters)
 167            {
 1168                var serviceKeyLiteral = param.ServiceKey != null
 1169                    ? $"\"{GeneratorHelpers.EscapeStringLiteral(param.ServiceKey)}\""
 1170                    : "null";
 1171                var paramName = param.ParameterName ?? "unknown";
 1172                constructorParamsBuilder.Append($"new global::NexusLabs.Needlr.Catalog.ConstructorParameterEntry(\"{Gene
 173            }
 7174            constructorParamsBuilder.Append('}');
 175
 7176            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.HostedServiceCatalogEntry(\"{GeneratorHelp
 177        }
 178
 434179        builder.AppendLine("    };");
 434180        builder.AppendLine();
 434181    }
 182
 183    private static void GenerateInterceptedServicesProperty(
 184        StringBuilder builder,
 185        IReadOnlyList<DiscoveredInterceptedService> interceptedServices,
 186        string? projectDirectory)
 187    {
 434188        builder.AppendLine($"    /// <inheritdoc />");
 434189        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 434190        builder.AppendLine("    {");
 191
 898192        foreach (var intercepted in interceptedServices)
 193        {
 15194            var shortName = GeneratorHelpers.GetShortTypeName(intercepted.TypeName);
 15195            var lifetimeStr = intercepted.Lifetime switch
 15196            {
 2197                GeneratorLifetime.Singleton => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Singleton",
 13198                GeneratorLifetime.Scoped => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Scoped",
 0199                GeneratorLifetime.Transient => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Transient",
 0200                _ => "global::NexusLabs.Needlr.Catalog.ServiceCatalogLifetime.Scoped"
 15201            };
 15202            var sourceFilePath = GetRelativeSourcePath(intercepted.SourceFilePath, projectDirectory);
 15203            var sourceFilePathLiteral = sourceFilePath != null
 15204                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 15205                : "null";
 206
 30207            var interfacesArray = $"new string[] {{ {string.Join(", ", intercepted.InterfaceNames.Select(i => $"\"{Gener
 33208            var interceptorsArray = $"new string[] {{ {string.Join(", ", intercepted.AllInterceptorTypeNames.Select(i =>
 209
 15210            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.InterceptedServiceCatalogEntry(\"{Generato
 211        }
 212
 434213        builder.AppendLine("    };");
 434214        builder.AppendLine();
 434215    }
 216
 217    private static void GenerateOptionsProperty(
 218        StringBuilder builder,
 219        IReadOnlyList<DiscoveredOptions> options,
 220        string? projectDirectory)
 221    {
 434222        builder.AppendLine($"    /// <inheritdoc />");
 434223        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 434224        builder.AppendLine("    {");
 225
 1198226        foreach (var opt in options)
 227        {
 165228            var shortName = GeneratorHelpers.GetShortTypeName(opt.TypeName);
 165229            var sourceFilePath = GetRelativeSourcePath(opt.SourceFilePath, projectDirectory);
 165230            var sourceFilePathLiteral = sourceFilePath != null
 165231                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 165232                : "null";
 165233            var nameLiteral = opt.Name != null
 165234                ? $"\"{GeneratorHelpers.EscapeStringLiteral(opt.Name)}\""
 165235                : "null";
 236
 165237            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.OptionsCatalogEntry(\"{GeneratorHelpers.Es
 238        }
 239
 434240        builder.AppendLine("    };");
 434241        builder.AppendLine();
 434242    }
 243
 244    private static void GeneratePluginsProperty(
 245        StringBuilder builder,
 246        IReadOnlyList<DiscoveredPlugin> plugins,
 247        string? projectDirectory)
 248    {
 434249        builder.AppendLine($"    /// <inheritdoc />");
 434250        builder.AppendLine($"    public global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr.Catalo
 434251        builder.AppendLine("    {");
 252
 3626253        foreach (var plugin in plugins)
 254        {
 1379255            var shortName = GeneratorHelpers.GetShortTypeName(plugin.TypeName);
 1379256            var sourceFilePath = GetRelativeSourcePath(plugin.SourceFilePath, projectDirectory);
 1379257            var sourceFilePathLiteral = sourceFilePath != null
 1379258                ? $"\"{GeneratorHelpers.EscapeStringLiteral(sourceFilePath)}\""
 1379259                : "null";
 260
 2768261            var interfacesArray = $"new string[] {{ {string.Join(", ", plugin.InterfaceNames.Select(i => $"\"{GeneratorH
 262
 1379263            builder.AppendLine($"        new global::NexusLabs.Needlr.Catalog.PluginCatalogEntry(\"{GeneratorHelpers.Esc
 264        }
 265
 434266        builder.AppendLine("    };");
 434267    }
 268
 269    private static string? GetRelativeSourcePath(string? fullPath, string? projectDirectory)
 270    {
 229675271        if (fullPath == null || projectDirectory == null)
 229675272            return fullPath;
 273
 0274        if (fullPath.StartsWith(projectDirectory, StringComparison.OrdinalIgnoreCase))
 275        {
 0276            var relative = fullPath.Substring(projectDirectory.Length);
 0277            return relative.TrimStart('/', '\\');
 278        }
 279
 0280        return fullPath;
 281    }
 282}