< Summary

Information
Class: NexusLabs.Needlr.Generators.CodeGen.InjectableTypesCodeGenerator
Assembly: NexusLabs.Needlr.Generators
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/CodeGen/InjectableTypesCodeGenerator.cs
Line coverage
88%
Covered lines: 44
Uncovered lines: 6
Coverable lines: 50
Total lines: 109
Line coverage: 88%
Branch coverage
86%
Covered branches: 19
Total branches: 22
Branch coverage: 86.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GenerateInjectableTypesArray(...)86.36%232288%

File(s)

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

#LineLine coverage
 1// Copyright (c) NexusLabs. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.Text;
 7
 8using NexusLabs.Needlr.Generators.Helpers;
 9using NexusLabs.Needlr.Generators.Models;
 10
 11namespace NexusLabs.Needlr.Generators.CodeGen;
 12
 13/// <summary>
 14/// Generates the static <c>_types</c> array of <see cref="DiscoveredType"/>
 15/// entries for the compile-time type registry.
 16/// </summary>
 17internal static class InjectableTypesCodeGenerator
 18{
 19    internal static void GenerateInjectableTypesArray(StringBuilder builder, IReadOnlyList<DiscoveredType> types, Breadc
 20    {
 45521        builder.AppendLine("    private static readonly InjectableTypeInfo[] _types =");
 45522        builder.AppendLine("    [");
 23
 26240124        var typesByAssembly = types.GroupBy(t => t.AssemblyName).OrderBy(g => g.Key);
 25
 5772626        foreach (var group in typesByAssembly)
 27        {
 2840828            breadcrumbs.WriteInlineComment(builder, "        ", $"From {group.Key}");
 29
 75743030            foreach (var type in group.OrderBy(t => t.TypeName))
 31            {
 32                // Write breadcrumb for this type
 23353833                if (breadcrumbs.Level == BreadcrumbLevel.Verbose)
 34                {
 1513235                    var sourcePath = type.SourceFilePath != null
 1513236                        ? BreadcrumbWriter.GetRelativeSourcePath(type.SourceFilePath, projectDirectory)
 1513237                        : $"[{type.AssemblyName}]";
 1513238                    var interfaces = type.InterfaceNames.Length > 0
 1139                        ? string.Join(", ", type.InterfaceNames.Select(i => i.Split('.').Last()))
 1513240                        : "none";
 1513241                    var keysInfo = type.ServiceKeys.Length > 0
 042                        ? $"Keys: {string.Join(", ", type.ServiceKeys.Select(k => $"\"{k}\""))}"
 1513243                        : null;
 44
 1513245                    if (keysInfo != null)
 46                    {
 047                        breadcrumbs.WriteVerboseBox(builder, "        ",
 048                            $"{type.TypeName.Split('.').Last()} → {interfaces}",
 049                            $"Source: {sourcePath}",
 050                            $"Lifetime: {type.Lifetime}",
 051                            keysInfo);
 52                    }
 53                    else
 54                    {
 1513255                        breadcrumbs.WriteVerboseBox(builder, "        ",
 1513256                            $"{type.TypeName.Split('.').Last()} → {interfaces}",
 1513257                            $"Source: {sourcePath}",
 1513258                            $"Lifetime: {type.Lifetime}");
 59                    }
 60                }
 61
 23353862                builder.Append($"        new(typeof({type.TypeName}), ");
 63
 64                // Interfaces
 23353865                if (type.InterfaceNames.Length == 0)
 66                {
 23328967                    builder.Append("Array.Empty<Type>(), ");
 68                }
 69                else
 70                {
 24971                    builder.Append("[");
 50272                    builder.Append(string.Join(", ", type.InterfaceNames.Select(i => $"typeof({i})")));
 24973                    builder.Append("], ");
 74                }
 75
 76                // Lifetime
 23353877                builder.Append($"InjectableLifetime.{type.Lifetime}, ");
 78
 79                // Factory lambda - resolves dependencies and creates instance without reflection
 23353880                builder.Append("sp => new ");
 23353881                builder.Append(type.TypeName);
 23353882                builder.Append("(");
 23353883                if (type.ConstructorParameters.Length > 0)
 84                {
 7455585                    var parameterExpressions = type.ConstructorParameters
 17034686                        .Select(p => p.IsKeyed
 17034687                            ? $"sp.GetRequiredKeyedService<{p.TypeName}>(\"{GeneratorHelpers.EscapeStringLiteral(p.Servi
 17034688                            : $"sp.GetRequiredService<{p.TypeName}>()");
 7455589                    builder.Append(string.Join(", ", parameterExpressions));
 90                }
 23353891                builder.Append("), ");
 92
 93                // Service keys from [Keyed] attributes
 23353894                if (type.ServiceKeys.Length == 0)
 95                {
 23353396                    builder.AppendLine("Array.Empty<string>()),");
 97                }
 98                else
 99                {
 5100                    builder.Append("[");
 10101                    builder.Append(string.Join(", ", type.ServiceKeys.Select(k => $"\"{GeneratorHelpers.EscapeStringLite
 5102                    builder.AppendLine("]),");
 103                }
 104            }
 105        }
 106
 455107        builder.AppendLine("    ];");
 455108    }
 109}