-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Add a source generator that produces boilerplate-free, GoF-consistent Facade pattern implementations for subsystems, enabling an explicit “front door” API over multiple collaborators.
The generator lives in PatternKit.Generators and emits self-contained, readable C# with no runtime PatternKit dependency.
Primary goals:
- Define a façade surface that is explicitly mapped to subsystem operations.
- Keep mappings deterministic and easy to debug.
- Support both interface- and class-based façade shapes.
- Provide optional grouping/organization and diagnostics for drift.
Motivation / Problem
Facade implementations are often:
- hand-written thin wrappers that drift as subsystems evolve
- inconsistent about naming and responsibility boundaries
- missing documentation for “what is actually exposed”
A generator can:
- formalize a façade contract
- ensure exposed operations stay in sync
- provide guardrails and tests
Supported Targets (must-have)
The generator must support:
partial class/partial structpartial record class/partial record struct
Facade can be generated as:
- Facade type: annotate a partial façade contract and map methods.
- Facade host: annotate a static/instance host containing mapping methods.
Proposed User Experience
A) Contract-first facade (interface)
public interface IBillingSubsystem
{
Receipt Pay(PaymentRequest req);
Refund Refund(RefundRequest req);
}
[GenerateFacade]
public partial interface IBillingFacade
{
Receipt Pay(PaymentRequest req);
Refund Refund(RefundRequest req);
}
public sealed class BillingFacadeImpl
{
private readonly IBillingSubsystem _billing;
public BillingFacadeImpl(IBillingSubsystem billing) => _billing = billing;
[FacadeMap]
private Receipt PayImpl(PaymentRequest req) => _billing.Pay(req);
[FacadeMap]
private Refund RefundImpl(RefundRequest req) => _billing.Refund(req);
}Generated (representative shape):
- A façade implementation that wires each contract method to the mapped method.
B) Host-first facade (mapping methods define surface)
[GenerateFacade(FacadeTypeName = "BillingFacade")]
public static partial class BillingFacadeHost
{
[FacadeExpose]
public static Receipt Pay(IBillingSubsystem billing, PaymentRequest req) => billing.Pay(req);
[FacadeExpose]
public static Refund Refund(IBillingSubsystem billing, RefundRequest req) => billing.Refund(req);
}Generated:
BillingFacadetype with instance methods, constructed withIBillingSubsystem.
Attributes / Surface Area
Namespace: PatternKit.Generators.Facade
Core
-
[GenerateFacade]on facade contract or hoststring? FacadeTypeName(default:<Name>Facade)bool GenerateAsync(default: inferred)bool ForceAsync(default: false)FacadeMissingMapPolicy MissingMap(default: Error)
Mapping attributes:
[FacadeMap]identifies the implementation method backing a contract method.[FacadeExpose]identifies host methods to expose.[FacadeIgnore]excludes contract members.
Policies:
MissingMapPolicy: Error | Stub (v2) | Ignore (discouraged)
Semantics (must-have)
Deterministic mapping
-
Contract-first:
- each facade contract member must map to exactly one
[FacadeMap]method. - mapping by explicit attribute, not by name convention (v1).
- each facade contract member must map to exactly one
-
Host-first:
- each
[FacadeExpose]method becomes a facade method.
- each
Async
- If any mapping method returns
ValueTask<T>/Task<T>or acceptsCancellationToken, emit async facade variants. - Prefer
ValueTaskfor generated async facade methods.
Naming and organization
-
Keep generated code readable:
- clear regions or comments per method
- deterministic ordering by contract member name
Diagnostics (must-have)
Stable IDs, actionable:
PKFCD001Type marked[GenerateFacade]must bepartial.PKFCD002No mapped methods found for facade members.PKFCD003Multiple mappings found for a single facade member.PKFCD004Map method signature mismatch.PKFCD005Facade type name conflicts with existing type.PKFCD006Async mapping detected but async generation disabled.
Generated Code Layout
Name.Facade.g.cs
Determinism:
- stable ordering by member name, then signature.
Testing Expectations
-
Contract-first mapping routes to correct subsystem calls.
-
Host-first generates façade type correctly.
-
Async path respects cancellation.
-
Diagnostics:
- missing mapping
- duplicate mapping
- signature mismatch
Acceptance Criteria
-
[GenerateFacade]works for class/struct/record class/record struct (host) and supports interface contracts. - Deterministic mapping and generated method ordering.
- Async variants generated when needed (ValueTask preferred).
- Diagnostics cover missing/duplicate/mismatch mappings.
- Tests cover routing, async behavior, and diagnostics.