Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace PatternKit.Generators.Composer;

/// <summary>
/// Marks a method to be excluded from pipeline composition.
/// Use this to explicitly exclude methods that might otherwise be considered for composition.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ComposeIgnoreAttribute : Attribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace PatternKit.Generators.Composer;

/// <summary>
/// Marks a method as a pipeline step that will be composed into the pipeline.
/// Steps are ordered by the Order property and wrap each other according to the ComposerWrapOrder.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ComposeStepAttribute : Attribute
{
/// <summary>
/// Gets or sets the order of this step in the pipeline.
/// With OuterFirst (default): Lower Order values wrap higher Order values.
/// - Order=0 executes first, wrapping all other steps.
/// With InnerFirst: Higher Order values wrap lower Order values.
/// - Order=0 executes last, closest to the terminal.
/// </summary>
public int Order { get; set; }

/// <summary>
/// Gets or sets an optional name for this step (for diagnostics and debugging).
/// </summary>
public string? Name { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="ComposeStepAttribute"/> class.
/// </summary>
/// <param name="order">The order of this step in the pipeline.</param>
public ComposeStepAttribute(int order)
{
Order = order;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace PatternKit.Generators.Composer;

/// <summary>
/// Marks a method as the terminal step of the pipeline.
/// The terminal is the final step that produces the output without calling a 'next' delegate.
/// A pipeline must have exactly one terminal.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ComposeTerminalAttribute : Attribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
namespace PatternKit.Generators.Composer;

/// <summary>
/// Marks a partial type as a composer pipeline host that will generate deterministic
/// composition of ordered components into a single executable pipeline.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
public sealed class ComposerAttribute : Attribute
{
/// <summary>
/// Gets or sets the name of the generated synchronous invoke method.
/// Default is "Invoke".
/// </summary>
public string InvokeMethodName { get; set; } = "Invoke";

/// <summary>
/// Gets or sets the name of the generated asynchronous invoke method.
/// Default is "InvokeAsync".
/// </summary>
public string InvokeAsyncMethodName { get; set; } = "InvokeAsync";

/// <summary>
/// Gets or sets whether to generate async methods.
/// When null (default), async generation is inferred from the presence of async steps or terminal.
/// Note: Nullable bool in attributes is non-standard but supported by C#.
/// Set to true/false explicitly to control async generation, or leave unset for inference.
/// </summary>
public bool? GenerateAsync { get; set; }

/// <summary>
/// Gets or sets whether to force async generation even if all steps are synchronous.
/// Default is false.
/// </summary>
public bool ForceAsync { get; set; }

/// <summary>
/// Gets or sets the wrapping order for pipeline steps.
/// Default is OuterFirst (step with Order=0 is outermost).
/// </summary>
public ComposerWrapOrder WrapOrder { get; set; } = ComposerWrapOrder.OuterFirst;
}

/// <summary>
/// Defines the order in which pipeline steps wrap each other.
/// </summary>
public enum ComposerWrapOrder
{
/// <summary>
/// Steps with lower Order values wrap steps with higher Order values.
/// Order=0 is the outermost wrapper (executes first).
/// </summary>
OuterFirst = 0,

/// <summary>
/// Steps with higher Order values wrap steps with lower Order values.
/// Order=0 is the innermost wrapper (executes last, closest to terminal).
/// </summary>
InnerFirst = 1
}
Loading
Loading