Skip to content

Generator: Create Composite Pattern #35

@JerrettDavis

Description

@JerrettDavis

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:

  1. Contract-first composite: annotate the component contract; generator emits base + helpers.
  2. 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

  • [CompositeComponent] on component contract

    • string? 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 = 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:

  • DFS: pre-order
  • BFS: FIFO

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

  • Generates component base + composite base for a contract.
  • Leaf and composite semantics are deterministic and documented.
  • Optional traversal helpers supported.
  • Diagnostics and tests included.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions