< Summary

Information
Class: NexusLabs.Needlr.Injection.Bundle.SyringeBundleExtensions
Assembly: NexusLabs.Needlr.Injection.Bundle
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection.Bundle/SyringeBundleExtensions.cs
Line coverage
91%
Covered lines: 42
Uncovered lines: 4
Coverable lines: 46
Total lines: 144
Line coverage: 91.3%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
UsingAutoConfiguration(...)100%2290%
WithFallbackBehavior(...)100%4490.9%
WithFastFailOnReflection(...)100%11100%
WithFallbackLogging(...)100%11100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Injection.Bundle/SyringeBundleExtensions.cs

#LineLine coverage
 1using NexusLabs.Needlr.Generators;
 2using NexusLabs.Needlr.Injection.Reflection;
 3using NexusLabs.Needlr.Injection.SourceGen;
 4
 5using System.Diagnostics.CodeAnalysis;
 6
 7namespace NexusLabs.Needlr.Injection.Bundle;
 8
 9/// <summary>
 10/// Extension methods that provide automatic fallback between source-generated and reflection-based components.
 11/// </summary>
 12/// <remarks>
 13/// <para>
 14/// When using the Bundle package, Needlr will automatically:
 15/// <list type="number">
 16/// <item>Try to use source-generated components if available (via NeedlrSourceGenBootstrap)</item>
 17/// <item>Fall back to reflection-based components if source generation is not configured</item>
 18/// </list>
 19/// </para>
 20/// <para>
 21/// Use <see cref="WithFallbackBehavior"/> to configure the fallback behavior, or
 22/// <see cref="WithFastFailOnReflection"/> to throw if reflection is used.
 23/// </para>
 24/// </remarks>
 25public static class SyringeBundleExtensions
 26{
 27    /// <summary>
 28    /// Configures the syringe with automatic fallback from source-gen to reflection.
 29    /// </summary>
 30    /// <remarks>
 31    /// <para>
 32    /// This method automatically detects whether source generation is available
 33    /// and configures the appropriate components. If source-generated providers
 34    /// are registered via NeedlrSourceGenBootstrap, they will be used. Otherwise,
 35    /// reflection-based components are used as fallback.
 36    /// </para>
 37    /// </remarks>
 38    /// <param name="syringe">The syringe to configure.</param>
 39    /// <returns>A configured syringe ready for further configuration and building.</returns>
 40    [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
 41        Justification = "Reflection components are only used when source-gen is not available.")]
 42    public static ConfiguredSyringe UsingAutoConfiguration(this Syringe syringe)
 43    {
 444        ArgumentNullException.ThrowIfNull(syringe);
 45
 346        if (NeedlrSourceGenBootstrap.TryGetProviders(
 347            out var injectableTypeProvider,
 348            out var pluginTypeProvider,
 349            out var registryParticipantTypes))
 50        {
 251            var configured = new ConfiguredSyringe(syringe) with
 252            {
 253                ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 054                    new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 255            };
 256            return configured.UsingGeneratedComponents(
 257                injectableTypeProvider,
 258                pluginTypeProvider,
 259                registryParticipantTypes);
 60        }
 61
 62        // Fallback to reflection
 163        var reflectionSyringe = syringe.UsingReflection();
 164        return reflectionSyringe with
 165        {
 166            ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 067                new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 168        };
 69    }
 70
 71    /// <summary>
 72    /// Configures the syringe with automatic fallback and a custom fallback handler.
 73    /// </summary>
 74    /// <param name="syringe">The syringe to configure.</param>
 75    /// <param name="onFallback">Called when reflection fallback occurs. Can be used for logging or to throw.</param>
 76    /// <returns>A configured syringe ready for further configuration and building.</returns>
 77    [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
 78        Justification = "Reflection components are only used when source-gen is not available.")]
 79    public static ConfiguredSyringe WithFallbackBehavior(
 80        this Syringe syringe,
 81        Action<ReflectionFallbackContext>? onFallback)
 82    {
 583        ArgumentNullException.ThrowIfNull(syringe);
 84
 485        if (NeedlrSourceGenBootstrap.TryGetProviders(
 486            out var injectableTypeProvider,
 487            out var pluginTypeProvider,
 488            out var registryParticipantTypes))
 89        {
 390            var configured = new ConfiguredSyringe(syringe) with
 391            {
 392                ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 093                    new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 394            };
 395            return configured.UsingGeneratedComponents(
 396                injectableTypeProvider,
 397                pluginTypeProvider,
 398                registryParticipantTypes);
 99        }
 100
 101        // Invoke fallback handler if provided
 1102        if (onFallback is not null)
 103        {
 1104            onFallback(ReflectionFallbackHandlers.CreateTypeRegistrarContext());
 105        }
 106
 1107        var reflectionSyringe = syringe.UsingReflection();
 1108        return reflectionSyringe with
 1109        {
 1110            ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 0111                new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 1112        };
 113    }
 114
 115    /// <summary>
 116    /// Configures the syringe to throw an exception if reflection fallback would occur.
 117    /// </summary>
 118    /// <remarks>
 119    /// Use this in AOT/trimming scenarios to ensure that source-generated components are always used.
 120    /// If no source-generated providers are registered, an <see cref="InvalidOperationException"/> is thrown.
 121    /// </remarks>
 122    /// <param name="syringe">The syringe to configure.</param>
 123    /// <returns>A configured syringe ready for further configuration and building.</returns>
 124    public static ConfiguredSyringe WithFastFailOnReflection(this Syringe syringe)
 125    {
 2126        ArgumentNullException.ThrowIfNull(syringe);
 127
 1128        return syringe.WithFallbackBehavior(ReflectionFallbackHandlers.ThrowException);
 129    }
 130
 131    /// <summary>
 132    /// Configures the syringe to log warnings when reflection fallback occurs.
 133    /// </summary>
 134    /// <param name="syringe">The syringe to configure.</param>
 135    /// <returns>A configured syringe ready for further configuration and building.</returns>
 136    [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
 137        Justification = "Reflection components are only used when source-gen is not available.")]
 138    public static ConfiguredSyringe WithFallbackLogging(this Syringe syringe)
 139    {
 2140        ArgumentNullException.ThrowIfNull(syringe);
 141
 1142        return syringe.WithFallbackBehavior(ReflectionFallbackHandlers.LogWarning);
 143    }
 144}