< 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
88%
Covered lines: 30
Uncovered lines: 4
Coverable lines: 34
Total lines: 132
Line coverage: 88.2%
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%2285.71%
WithFallbackBehavior(...)100%4487.5%
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    {
 344        ArgumentNullException.ThrowIfNull(syringe);
 45
 246        if (NeedlrSourceGenBootstrap.TryGetProviders(out var injectableTypeProvider, out var pluginTypeProvider))
 47        {
 148            var configured = new ConfiguredSyringe(syringe) with
 149            {
 150                ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 051                    new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 152            };
 153            return configured.UsingGeneratedComponents(injectableTypeProvider, pluginTypeProvider);
 54        }
 55
 56        // Fallback to reflection
 157        var reflectionSyringe = syringe.UsingReflection();
 158        return reflectionSyringe with
 159        {
 160            ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 061                new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 162        };
 63    }
 64
 65    /// <summary>
 66    /// Configures the syringe with automatic fallback and a custom fallback handler.
 67    /// </summary>
 68    /// <param name="syringe">The syringe to configure.</param>
 69    /// <param name="onFallback">Called when reflection fallback occurs. Can be used for logging or to throw.</param>
 70    /// <returns>A configured syringe ready for further configuration and building.</returns>
 71    [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
 72        Justification = "Reflection components are only used when source-gen is not available.")]
 73    public static ConfiguredSyringe WithFallbackBehavior(
 74        this Syringe syringe,
 75        Action<ReflectionFallbackContext>? onFallback)
 76    {
 577        ArgumentNullException.ThrowIfNull(syringe);
 78
 479        if (NeedlrSourceGenBootstrap.TryGetProviders(out var injectableTypeProvider, out var pluginTypeProvider))
 80        {
 381            var configured = new ConfiguredSyringe(syringe) with
 382            {
 383                ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 084                    new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 385            };
 386            return configured.UsingGeneratedComponents(injectableTypeProvider, pluginTypeProvider);
 87        }
 88
 89        // Invoke fallback handler if provided
 190        if (onFallback is not null)
 91        {
 192            onFallback(ReflectionFallbackHandlers.CreateTypeRegistrarContext());
 93        }
 94
 195        var reflectionSyringe = syringe.UsingReflection();
 196        return reflectionSyringe with
 197        {
 198            ServiceProviderBuilderFactory = (populator, assemblyProvider, additionalAssemblies) =>
 099                new ServiceProviderBuilder(populator, assemblyProvider, additionalAssemblies)
 1100        };
 101    }
 102
 103    /// <summary>
 104    /// Configures the syringe to throw an exception if reflection fallback would occur.
 105    /// </summary>
 106    /// <remarks>
 107    /// Use this in AOT/trimming scenarios to ensure that source-generated components are always used.
 108    /// If no source-generated providers are registered, an <see cref="InvalidOperationException"/> is thrown.
 109    /// </remarks>
 110    /// <param name="syringe">The syringe to configure.</param>
 111    /// <returns>A configured syringe ready for further configuration and building.</returns>
 112    public static ConfiguredSyringe WithFastFailOnReflection(this Syringe syringe)
 113    {
 2114        ArgumentNullException.ThrowIfNull(syringe);
 115
 1116        return syringe.WithFallbackBehavior(ReflectionFallbackHandlers.ThrowException);
 117    }
 118
 119    /// <summary>
 120    /// Configures the syringe to log warnings when reflection fallback occurs.
 121    /// </summary>
 122    /// <param name="syringe">The syringe to configure.</param>
 123    /// <returns>A configured syringe ready for further configuration and building.</returns>
 124    [UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
 125        Justification = "Reflection components are only used when source-gen is not available.")]
 126    public static ConfiguredSyringe WithFallbackLogging(this Syringe syringe)
 127    {
 2128        ArgumentNullException.ThrowIfNull(syringe);
 129
 1130        return syringe.WithFallbackBehavior(ReflectionFallbackHandlers.LogWarning);
 131    }
 132}