Skip to content

Feature Catalog

This is the complete catalog of code-generating pipelines in Pragmatic Design: the ~21 feature pipelines inside the unified Pragmatic.SourceGenerator, the inline Manifest generator, and the three standalone generators that ship with their own modules.

Each entry lists the trigger (the attribute or marker that activates it) and a short sketch of the generated output. Triggers are quoted from FeatureDetector.cs / AttributeNames.cs; where the exact output is large, it is summarised rather than reproduced.

Trigger: [DomainAction] / [Action] / [Query] / [EventHandler] (Pragmatic.Actions.Attributes.*) on a partial class. Generates: a typed invoker (validation → authorization → handler dispatch) nested in the action’s partial class, a SetDependencies injection point, and centralized DI registration (_Infra.Actions.Registration.g.cs).

[DomainAction]
public partial class PlaceOrder : IDomainAction<OrderResult> { /* Handle(...) */ }
// → partial class PlaceOrder { internal sealed class Invoker { ... } } + DI registration

Trigger: [Endpoint] / [ExposeEndpoint<T>] / [Get] [Post] [Put] [Delete] (Pragmatic.Endpoints.Attributes.*). Generates: minimal-API endpoint registrations bound to the matching action/query, with route, verb, and parameter binding. Also invokes the Manifest generator inline.

Persistence (orchestrator → 6 sub-features)

Section titled “Persistence (orchestrator → 6 sub-features)”

Trigger: [Query<TEntity, TResult>] (runtime HasPersistence) and [PragmaticDbContext] (HasPersistenceEFCore). PersistenceFeature is a thin orchestrator delegating to six sub-features:

Sub-featureGenerates
EntityCoreentity trait properties (PersistenceId, Id, audit, soft-delete), Create(...) factories, relation setters
Repositoryper-entity repositories, query filters, metadata
QueryQuery/GridFilter/FilterDto + Apply() projection bodies
Projection[Projectable], computed filters, DTO include expressions
Advancedinheritance, hierarchy, timeline, lookup
DbContextBoundaryDbContext, MigrationDbContext, host-level EntityConfig.*

Provider-specific SQL is selected via the detected EfCoreProvider (PostgreSQL / SQL Server / SQLite / Generic).

Trigger: [Validation] / [Validator] (Pragmatic.Validation.Attributes.*). Generates: compiled validators and the validation pass invoked by the action invoker — no expression-tree or reflection cost at runtime.

Trigger: [MapFrom<TSource>] / [MapTo<T>] (Pragmatic.Mapping.Attributes.MapFromAttribute`1). Generates: FromEntity / ToEntity mapping methods on the annotated DTO partial; [MapIgnore] excludes members.

[MapFrom<User>]
public partial class UserDto { public string Name { get; set; } }
// → partial class UserDto { public static UserDto FromEntity(User e) => ...; }

Trigger: [Cacheable] / [CacheKey] / [InvalidatesCache] (Pragmatic.Caching.Attributes.*). Generates: caching decorators around actions/queries, deterministic cache-key builders, and invalidation hooks.

Trigger: [GeneratePatch<T>] (Pragmatic.Patch.Attributes.GeneratePatchAttribute`1). Generates: a patch DTO of Optional<T> fields plus an ApplyTo(target) method that only writes the members that were explicitly set (JSON-merge / PATCH semantics).

Trigger: Composition assembly reference (detected by CompositionDetector); host mode adds an executable entry point + Pragmatic.Composition.Host reference. Generates (host mode): the aggregated PragmaticHost.Services.g.cs DI wiring, endpoint route groups, and RemoteBoundary HTTP invokers/dispatcher for distributed boundaries. This is where most cross-feature aggregation lands. Emits the bulk of the PRAG16xx diagnostics.

Trigger: [Configuration] (Pragmatic.Configuration.ConfigurationAttribute). Generates: strongly-typed options binding + registration for a configuration section, with validation diagnostics (PRAG2000, PRAG2001, PRAG2050).

Trigger: [PragmaticUser] / [ProfileProperty] (Pragmatic.Identity.*); persistence variant via HasIdentityPersistence. Generates: ToProfile() + profile record, claim→entity user resolvers, and permission constants/registry from IPermission/IRole.

Trigger: [MessageHandler] (Pragmatic.Messaging.Attributes.MessageHandlerAttribute) and related saga/outbox attributes. Generates: handler pipelines (with [Retry]/[Timeout] middleware), message-type registry, outbox source, topology + routing registries, and saga orchestrators. Diagnostics PRAG0800-0831.

Trigger: [assembly: TranslationKeys] (Pragmatic.Internationalization.Attributes.TranslationKeysAttribute) + .json translation AdditionalFiles. Generates: strongly-typed translation-key accessors from the resource files, validated against the configured keys (PRAG1800-1803).

Trigger: Pragmatic.Result.IError present (HasResult). Within the unified generator this drives Result-aware composition in other features. The actual Result/VoidResult type variants are emitted by the standalone ResultSourceGenerator (below).

Trigger: [Resource] (Pragmatic.Persistence.Entity.ResourceAttribute) on an entity class. Generates: from a kebab-case route segment + Capabilities flags (Create/Read/Update/Delete/List/Search), the full CRUD surface — Create/Read/Update/Delete actions, List/Search query classes, the matching DTOs, and REST endpoints. The action/query/endpoint models are injected into the Actions/Query/Endpoints pipelines rather than emitted standalone. Diagnostics PRAG2602-2605.

Trigger: [HasComments], [HasTags], [HasNotes<T>], [HasAttachments] (Pragmatic.Comments / Pragmatic.Tags / Pragmatic.Notes / Pragmatic.Attachments) on an entity. Generates: a complete sub-feature per trait — the child entity (e.g. OrderComment), its EF EntityConfig, the parent navigation property, CRUD action classes, permission constants, a DTO, a paged list query, and (when a [Resource] is present) REST endpoints. Tags additionally generate a junction entity. Requires HasPersistenceEFCore; actions/endpoints require HasActions. Diagnostics PRAG2600-2601.

[Resource("comments")]
[HasComments]
public partial class Article { ... }
// → ArticleComment entity + config + nav, Add/GetById/Update/Delete actions,
// ArticleCommentDto, ListArticleCommentsQuery, permissions, endpoints

Trigger: [FastEnum] (Pragmatic.FastEnumAttribute) on an enum. Generates: a {Enum}Extensions static class with zero-reflection helpers — ToStringFast(), IsDefined(value) / IsDefined(string), TryParse(...) (+ case-insensitive overload), GetValues(), GetNames(), Count — plus a separate AOT-safe {Enum}JsonConverter (serializes as the string name). Optional GetDisplayName() (from [Display]/[Description]) and, when I18n is referenced, GetI18nKey() / GetLocalizedName().

[FastEnum] public enum Status { Active, Archived }
// → public static class StatusExtensions { ToStringFast, IsDefined, TryParse, GetValues, GetNames, Count }
// public sealed class StatusJsonConverter : JsonConverter<Status>

Trigger: [Job] / [RecurringJob] (+ [Retry], [Timeout], [ContinueWith<T>]) on a partial IJob/IJob<T>. Generates: a typed job invoker, a job-type registry, recurring-job registration (cron-validated), and DI/metadata. Diagnostics PRAG2500-2506.

Trigger: [ValueObject] (Pragmatic.Persistence.Entity.ValueObjectAttribute) on a partial record. Generates: factory methods into the record — Create(...) (calls the user’s Validate(...), returning the value object or a validation error) when a Validate method exists, and CreateUnsafe(...) (direct construction, for deserialization / trusted paths) when a constructor exists. Neither is emitted if the user already declared it. Diagnostics PRAG2700-2702.

[ValueObject]
public partial record Email(string Value)
{
public static Result<Email, ValidationError> Validate(string value) => ...;
}
// → public static Result<Email, ValidationError> Create(string value) => Validate(value);
// public static Email CreateUnsafe(string value) => new Email(value);

Trigger: runs from EndpointsFeature when endpoint models exist (not a standalone [Generator]). Generates: a unified compile-time API manifest (JSON) aggregating endpoint + DTO metadata. Feeds OpenAPI enrichment, CLI client generation, and the WASM client generator. Generation failure surfaces as PRAG9001 (Warning) without breaking the build.

These are separate [Generator] assemblies, not feature pipelines inside the unified generator.

Result — ResultSourceGenerator + ErrorLocalizationGenerator

Section titled “Result — ResultSourceGenerator + ErrorLocalizationGenerator”

Assembly: Pragmatic.Result.SourceGenerator.

  • ResultSourceGenerator runs only while compiling the Pragmatic.Result assembly itself. It emits the multi-error Result variants Result3Result9 (2–8 error types) and VoidResult<E1,E2>VoidResult<E1..E8> — the Match/Map/Bind arity overloads the library ships.
  • ErrorLocalizationGenerator targets any partial type implementing Pragmatic.Result.IError. It generates convention-based TitleKey / DescriptionKey properties ({namespace}.{class-without-Error}.{title|description}, lowercased), and skips types that already declare those keys.
public partial class NotFoundError : IError { }
// in MyApp.Errors → TitleKey = "myapp.errors.notfound.title", DescriptionKey = "...description"

Internationalization — Country / Currency / Language code generators

Section titled “Internationalization — Country / Currency / Language code generators”

Assembly: Pragmatic.Internationalization.SourceGenerator.

Three generators that emit static ISO code tables from embedded JSON resources. Each is gated by an AdditionalFiles marker file (empty file with a magic name):

GeneratorMarker fileOutput
CountryCodeGenerator.generate-countriesstatic CountryCode properties (ISO 3166-1)
CurrencyCodeGenerator.generate-currenciesstatic CurrencyCode properties (ISO 4217)
LanguageCodeGenerator.generate-languagesstatic LanguageCode properties (ISO 639)

Without the marker file, the generator stays silent — so apps pay nothing unless they opt in.

Assembly: Pragmatic.Logging.SourceGenerator.

Trigger: [LoggerMethod] (Pragmatic.Logging.Attributes.LoggerMethodAttribute) on a partial method. Generates: zero-allocation partial method bodies (one generated file per containing type, grouping all of that type’s logger methods), in the spirit of [LoggerMessage] but tailored to the Pragmatic logging contract.

public partial class OrderService
{
[LoggerMethod(Level = LogLevel.Information, Message = "Order {OrderId} placed")]
public partial void OrderPlaced(Guid orderId);
}
// → generated partial method body, no boxing / no string.Format on the hot path