Summary
Add a source generator that produces boilerplate-free, GoF-consistent Composite pattern scaffolding for tree-like object graphs, including generated node/leaf base types, child management helpers, and optional traversal helpers.
The generator lives in PatternKit.Generators and emits self-contained C# with no runtime PatternKit dependency.
Primary goals:
- Provide a consistent, typed composite model (Component / Composite / Leaf).
- Generate child collection handling and safe defaults.
- Enable deterministic traversal helpers (DFS/BFS) optionally.
- Keep implementations readable and debuggable.
Motivation / Problem
Composite implementations frequently repeat:
- base component contract
- child management API (Add/Remove/Clear)
- safe iteration, null handling, and invariants
- traversal helpers
We want a generator that emits the standard scaffolding so consumers can focus on domain behavior.
Supported Targets (must-have)
The generator must support:
partial interface / partial abstract class as the component contract
- user-provided leaf/composite types (partial) or generator-emitted defaults
Two models:
- Contract-first composite: annotate the component contract; generator emits base + helpers.
- Type-first composite: annotate a root type and infer component type.
V1 can focus on contract-first.
Proposed User Experience
A) Contract-first composite
[CompositeComponent]
public partial interface ICategory
{
string Name { get; }
}
Generated (representative shape):
public abstract partial class CategoryComponentBase : ICategory
{
public abstract string Name { get; }
public virtual bool IsLeaf => true;
public virtual IReadOnlyList<ICategory> Children => Array.Empty<ICategory>();
public virtual void Add(ICategory child) => throw new NotSupportedException();
public virtual bool Remove(ICategory child) => throw new NotSupportedException();
public virtual void Clear() => throw new NotSupportedException();
}
public abstract partial class CategoryCompositeBase : CategoryComponentBase
{
public override bool IsLeaf => false;
public override IReadOnlyList<ICategory> Children { get; }
public override void Add(ICategory child);
public override bool Remove(ICategory child);
public override void Clear();
}
Consumers implement leaf/composite behavior by inheriting appropriate base.
B) Optional traversal helpers
public static class CategoryTraversal
{
public static IEnumerable<ICategory> DepthFirst(ICategory root);
public static IEnumerable<ICategory> BreadthFirst(ICategory root);
}
Attributes / Surface Area
Namespace: PatternKit.Generators.Composite
Core
Optional:
[CompositeIgnore] for members that should not appear in base types.
Enums:
CompositeChildrenStorage: List, ImmutableArray (v2)
Semantics (must-have)
Leaf defaults
IsLeaf = true
Children = empty
- Add/Remove/Clear throw NotSupportedException
Composite defaults
IsLeaf = false
- Maintains an internal child collection
Children returns read-only view
- Add/Remove/Clear are deterministic and validated
Validation rules
V1:
- Prevent null children.
- Optional
PreventCycles=true is v2 unless cheap.
Traversal helpers
If enabled:
Diagnostics (must-have)
PKCMP001 Type marked [CompositeComponent] must be partial.
PKCMP002 Component type must be interface or abstract class.
PKCMP003 Name conflicts for generated base types.
PKCMP004 Contract contains unsupported members (events) for v1.
Generated Code Layout
ComponentName.Composite.g.cs
ComponentName.Composite.Traversal.g.cs (optional)
Determinism:
- stable ordering by member name.
Testing Expectations
- Leaf base throws on Add/Remove/Clear.
- Composite base manages children correctly.
- Traversal ordering correct (if enabled).
- Diagnostics: invalid targets, naming conflicts.
Acceptance Criteria
Summary
Add a source generator that produces boilerplate-free, GoF-consistent Composite pattern scaffolding for tree-like object graphs, including generated node/leaf base types, child management helpers, and optional traversal helpers.
The generator lives in
PatternKit.Generatorsand emits self-contained C# with no runtime PatternKit dependency.Primary goals:
Motivation / Problem
Composite implementations frequently repeat:
We want a generator that emits the standard scaffolding so consumers can focus on domain behavior.
Supported Targets (must-have)
The generator must support:
partial interface/partial abstract classas the component contractTwo models:
V1 can focus on contract-first.
Proposed User Experience
A) Contract-first composite
Generated (representative shape):
Consumers implement leaf/composite behavior by inheriting appropriate base.
B) Optional traversal helpers
Attributes / Surface Area
Namespace:
PatternKit.Generators.CompositeCore
[CompositeComponent]on component contractstring? ComponentBaseName(default:<Name>ComponentBase)string? CompositeBaseName(default:<Name>CompositeBase)string ChildrenPropertyName(default:Children)CompositeChildrenStorage Storage(default:List)bool GenerateTraversalHelpers(default: false)Optional:
[CompositeIgnore]for members that should not appear in base types.Enums:
CompositeChildrenStorage:List,ImmutableArray(v2)Semantics (must-have)
Leaf defaults
IsLeaf = trueChildren = emptyComposite defaults
IsLeaf = falseChildrenreturns read-only viewValidation rules
V1:
PreventCycles=trueis v2 unless cheap.Traversal helpers
If enabled:
Diagnostics (must-have)
PKCMP001Type marked[CompositeComponent]must bepartial.PKCMP002Component type must be interface or abstract class.PKCMP003Name conflicts for generated base types.PKCMP004Contract contains unsupported members (events) for v1.Generated Code Layout
ComponentName.Composite.g.csComponentName.Composite.Traversal.g.cs(optional)Determinism:
Testing Expectations
Acceptance Criteria