| | | 1 | | // Copyright (c) NexusLabs. All rights reserved. |
| | | 2 | | // Licensed under the MIT License. |
| | | 3 | | |
| | | 4 | | using System.Text; |
| | | 5 | | |
| | | 6 | | namespace NexusLabs.Needlr.Generators.CodeGen; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// Emits a minimal <c>TypeRegistry</c> and module-initializer bootstrap for an assembly that |
| | | 10 | | /// declares <c>[GenerateTypeRegistry]</c> but has nothing to register. |
| | | 11 | | /// </summary> |
| | | 12 | | /// <remarks> |
| | | 13 | | /// The emitted code depends only on the attributes package (<c>InjectableTypeInfo</c>, |
| | | 14 | | /// <c>PluginTypeInfo</c>, and <c>NeedlrSourceGenBootstrap</c>) — never on the injection packages. |
| | | 15 | | /// A project must reference the attributes package to use <c>[GenerateTypeRegistry]</c> at all, so |
| | | 16 | | /// this registry always compiles, even for a project that references no Needlr injection packages |
| | | 17 | | /// (a documentation, contracts, or abstractions library). Emitting it keeps a type-less participant |
| | | 18 | | /// force-loadable by consumers (<c>typeof(<Assembly>.Generated.TypeRegistry)</c>) without the |
| | | 19 | | /// <c>CS0234</c> failure that omitting it would cause. |
| | | 20 | | /// </remarks> |
| | | 21 | | internal static class EmptyTypeRegistryCodeGenerator |
| | | 22 | | { |
| | | 23 | | /// <summary> |
| | | 24 | | /// Emits the empty <c>TypeRegistry</c> exposing empty injectable and plugin providers. |
| | | 25 | | /// </summary> |
| | | 26 | | /// <param name="assemblyName">The assembly the registry is generated for.</param> |
| | | 27 | | /// <param name="breadcrumbs">The breadcrumb writer supplied by the orchestration method.</param> |
| | | 28 | | /// <returns>The generated C# source for the empty <c>TypeRegistry</c>.</returns> |
| | | 29 | | internal static string GenerateTypeRegistrySource(string assemblyName, BreadcrumbWriter breadcrumbs) |
| | | 30 | | { |
| | 7 | 31 | | var builder = new StringBuilder(); |
| | 7 | 32 | | var safeAssemblyName = GeneratorHelpers.SanitizeIdentifier(assemblyName); |
| | | 33 | | |
| | 7 | 34 | | breadcrumbs.WriteFileHeader(builder, assemblyName, "Needlr Type Registry (empty)"); |
| | 7 | 35 | | builder.AppendLine("#nullable enable"); |
| | 7 | 36 | | builder.AppendLine(); |
| | 7 | 37 | | builder.AppendLine($"namespace {safeAssemblyName}.Generated;"); |
| | 7 | 38 | | builder.AppendLine(); |
| | 7 | 39 | | builder.AppendLine("/// <summary>"); |
| | 7 | 40 | | builder.AppendLine("/// Compile-time generated registry for an assembly that declares [GenerateTypeRegistry]"); |
| | 7 | 41 | | builder.AppendLine("/// but contains no registerable types. Exposes empty providers so that consumers which"); |
| | 7 | 42 | | builder.AppendLine("/// force-load this type compile, without depending on the Needlr injection packages."); |
| | 7 | 43 | | builder.AppendLine("/// </summary>"); |
| | 7 | 44 | | builder.AppendLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"NexusLabs.Needlr.Generators\", \"1 |
| | 7 | 45 | | builder.AppendLine("public static class TypeRegistry"); |
| | 7 | 46 | | builder.AppendLine("{"); |
| | 7 | 47 | | builder.AppendLine(" private static readonly global::NexusLabs.Needlr.Generators.InjectableTypeInfo[] _types |
| | 7 | 48 | | builder.AppendLine(" private static readonly global::NexusLabs.Needlr.Generators.PluginTypeInfo[] _plugins = |
| | 7 | 49 | | builder.AppendLine(); |
| | 7 | 50 | | builder.AppendLine(" /// <summary>Gets all injectable types discovered at compile time (none).</summary>"); |
| | 7 | 51 | | builder.AppendLine(" /// <returns>An empty read-only list.</returns>"); |
| | 7 | 52 | | builder.AppendLine(" public static global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr. |
| | 7 | 53 | | builder.AppendLine(); |
| | 7 | 54 | | builder.AppendLine(" /// <summary>Gets all plugin types discovered at compile time (none).</summary>"); |
| | 7 | 55 | | builder.AppendLine(" /// <returns>An empty read-only list.</returns>"); |
| | 7 | 56 | | builder.AppendLine(" public static global::System.Collections.Generic.IReadOnlyList<global::NexusLabs.Needlr. |
| | 7 | 57 | | builder.AppendLine("}"); |
| | | 58 | | |
| | 7 | 59 | | return builder.ToString(); |
| | | 60 | | } |
| | | 61 | | |
| | | 62 | | /// <summary> |
| | | 63 | | /// Emits the module-initializer bootstrap that registers the empty providers with |
| | | 64 | | /// <c>NeedlrSourceGenBootstrap</c>. |
| | | 65 | | /// </summary> |
| | | 66 | | /// <param name="assemblyName">The assembly the bootstrap is generated for.</param> |
| | | 67 | | /// <param name="breadcrumbs">The breadcrumb writer supplied by the orchestration method.</param> |
| | | 68 | | /// <returns>The generated C# source for the module-initializer bootstrap.</returns> |
| | | 69 | | /// <remarks> |
| | | 70 | | /// Uses the two-argument <c>Register</c> overload (no decorator applier, no options registrar), |
| | | 71 | | /// which takes no <c>IServiceCollection</c>/<c>IConfiguration</c> parameters and therefore keeps |
| | | 72 | | /// the emitted code free of any Microsoft.Extensions.DependencyInjection dependency. |
| | | 73 | | /// </remarks> |
| | | 74 | | internal static string GenerateBootstrapSource(string assemblyName, BreadcrumbWriter breadcrumbs) |
| | | 75 | | { |
| | 7 | 76 | | var builder = new StringBuilder(); |
| | 7 | 77 | | var safeAssemblyName = GeneratorHelpers.SanitizeIdentifier(assemblyName); |
| | | 78 | | |
| | 7 | 79 | | breadcrumbs.WriteFileHeader(builder, assemblyName, "Needlr Source-Gen Bootstrap (empty)"); |
| | 7 | 80 | | builder.AppendLine("#nullable enable"); |
| | 7 | 81 | | builder.AppendLine(); |
| | 7 | 82 | | builder.AppendLine($"namespace {safeAssemblyName}.Generated;"); |
| | 7 | 83 | | builder.AppendLine(); |
| | 7 | 84 | | builder.AppendLine("internal static class NeedlrSourceGenModuleInitializer"); |
| | 7 | 85 | | builder.AppendLine("{"); |
| | 7 | 86 | | builder.AppendLine(" [global::System.Runtime.CompilerServices.ModuleInitializer]"); |
| | 7 | 87 | | builder.AppendLine(" internal static void Initialize()"); |
| | 7 | 88 | | builder.AppendLine(" {"); |
| | 7 | 89 | | builder.AppendLine(" global::NexusLabs.Needlr.Generators.NeedlrSourceGenBootstrap.Register("); |
| | 7 | 90 | | builder.AppendLine($" global::{safeAssemblyName}.Generated.TypeRegistry.GetInjectableTypes,"); |
| | 7 | 91 | | builder.AppendLine($" global::{safeAssemblyName}.Generated.TypeRegistry.GetPluginTypes);"); |
| | 7 | 92 | | builder.AppendLine(" }"); |
| | 7 | 93 | | builder.AppendLine("}"); |
| | | 94 | | |
| | 7 | 95 | | return builder.ToString(); |
| | | 96 | | } |
| | | 97 | | } |