From e726d1bc3055c4e2712c8496156cb36fad2617b6 Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Tue, 26 May 2026 16:40:41 -0500 Subject: [PATCH] Document the source-generated extension/option discovery manifest Adds a "Source-generated extension manifest" section to the AOT guide (sibling to the existing command-manifest docs) covering JasperFx.Generated.DiscoveredExtensions, the eligibility gate ([JasperFxAssembly]-derived or executable), the two discovery sources (attribute-declared types + IJasperFxExtension implementers), and GeneratedExtensionManifest runtime consumption. Cross-references it from the AssemblyFinder trim-hostile note. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/codegen/aot.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/codegen/aot.md b/docs/codegen/aot.md index 03c6384..b858bf9 100644 --- a/docs/codegen/aot.md +++ b/docs/codegen/aot.md @@ -166,7 +166,7 @@ As of JasperFx 2.0.0-alpha.12 and JasperFx.Events 2.0.0-alpha.5: ### Annotated (RUC / RDC; available in dev, warns at AOT publish) - All of `JasperFx.CommandLine` — `CommandFactory`, `CommandExecutor`, `CommandLineHostingExtensions`. The CLI is a dev-time tool. AOT consumers route command discovery through the [`JasperFx.SourceGenerator`-emitted `DiscoveredCommands` manifest](#source-generated-command-manifest) instead of reflective assembly scanning. -- `TypeRepository` / `AssemblyFinder` / `AssemblyTypes` — assembly scanning is fundamentally trim-hostile. +- `TypeRepository` / `AssemblyFinder` / `AssemblyTypes` — assembly scanning is fundamentally trim-hostile. Command discovery and extension/option discovery route around it via the [`DiscoveredCommands`](#source-generated-command-manifest) and [`DiscoveredExtensions`](#source-generated-extension-manifest) manifests. - `JasperFx.Core.IoC` convention-based registration (`AssemblyScanner.Scan`, `IRegistrationConvention` impls). AOT consumers use explicit `services.AddSingleton()` registrations. - `JasperFx.Core.Reflection.LambdaBuilder` + `ValueTypeInfo` — expression-tree compilation via FastExpressionCompiler. AOT consumers source-generate accessor delegates. - `JasperFx.CodeGeneration.GeneratedType` / `GeneratedAssembly` / `MethodCall` — the codegen builder API. Reached only at codegen-write time, not at production startup in Static mode. @@ -187,6 +187,31 @@ To enable it, reference the source generator in your csproj: The generator runs at compile time, so this reference doesn't end up in your published binary. +### Source-generated extension manifest + +The same generator package emits a companion `JasperFx.Generated.DiscoveredExtensions` class that lists the assembly's **extension / option types** at compile time, so consuming frameworks (Wolverine, Marten, …) can register or apply their extensions without the reflective, filesystem-probing assembly scan (`AssemblyFinder.FindAssemblies`). + +A type is discovered when, in an **eligible** assembly, it is either: + +1. declared by the assembly's `[JasperFxAssembly]`-derived attribute — the generic argument of a `[WolverineModule]`-style attribute, or a `typeof(...)` argument to `[JasperFxAssembly(typeof(T))]`; or +2. a concrete class implementing the **`JasperFx.IJasperFxExtension`** marker interface (which `IServiceRegistrations`, and framework interfaces such as Wolverine's `IWolverineExtension`, extend). + +An assembly is *eligible* if it carries a `[JasperFxAssembly]`-derived attribute **or** is an executable (entry) assembly — matching the assemblies the runtime scanner would otherwise consider. The two sources are de-duplicated. + +At runtime, `JasperFx.GeneratedExtensionManifest` aggregates these manifests across the loaded assemblies: + +```csharp +// All compile-time-discovered extension types, then filter by your framework's interface: +var extensions = GeneratedExtensionManifest + .ReadFromLoadedAssemblies() + .Where(t => typeof(IWolverineExtension).IsAssignableFrom(t)); + +// AnyManifestPresent() lets a consumer fall back to reflective scanning +// when the generator isn't referenced (no behavior change for non-AOT apps). +``` + +Enable it with the same `JasperFx.SourceGenerator` package reference shown above; no separate package is required. + ## Cross-stack AOT story | Package | AOT status (as of 2026-wave alphas) |