Kiwify.Kiwi.CLI.Declarative
1.0.0
Prefix Reserved
dotnet add package Kiwify.Kiwi.CLI.Declarative --version 1.0.0
NuGet\Install-Package Kiwify.Kiwi.CLI.Declarative -Version 1.0.0
<PackageReference Include="Kiwify.Kiwi.CLI.Declarative" Version="1.0.0" />
<PackageVersion Include="Kiwify.Kiwi.CLI.Declarative" Version="1.0.0" />
<PackageReference Include="Kiwify.Kiwi.CLI.Declarative" />
paket add Kiwify.Kiwi.CLI.Declarative --version 1.0.0
#r "nuget: Kiwify.Kiwi.CLI.Declarative, 1.0.0"
#:package Kiwify.Kiwi.CLI.Declarative@1.0.0
#addin nuget:?package=Kiwify.Kiwi.CLI.Declarative&version=1.0.0
#tool nuget:?package=Kiwify.Kiwi.CLI.Declarative&version=1.0.0
Kiwify.Kiwi.CLI.Declarative
Attribute-based command definition for Kiwify.Kiwi.CLI. Decorate plain C# classes with attributes and let CommandLoader build the Command<T> objects automatically - no manual AddOption or validation-rule wiring required.
Target: netstandard2.1
Dependencies: Kiwify.Kiwi.CLI
Attributes
Command definition
| Attribute | Target | Purpose |
|---|---|---|
[CliCommand(name)] |
Class | Marks a class as a CLI command |
[CliOption(name, aliases…)] |
Property | Binds a property to a CLI option |
[CliHandler] |
Method | Marks the handler; omit to use Execute by convention |
[CliRegExValidation(pattern)] |
Property | Regex constraint on the option value |
Validation
| Attribute | Target | Purpose |
|---|---|---|
[RequiredWhen(field, value)] |
Class | Field(s) become required when a condition holds |
[RequiredWholeFieldGroupOrNone(fields…)] |
Class | All fields must appear together or not at all |
[RequiredOnlyOneFieldGroup(fields…, GroupId=n)] |
Class | Exactly one group (identified by GroupId) must be fully provided |
[CustomValidation(methodName)] |
Class | Calls a static bool method for complex validation |
Quick start
[CliCommand("deploy", Description = "Deploy to an environment.")]
[RequiredWhen("Environment", "production", RequiredFields = ["BackupPath"])]
[CustomValidation(nameof(ValidateReplicas))]
public class DeployCommand
{
[CliOption("--environment", "-e", Description = "Target environment", IsRequired = true)]
public string Environment { get; set; } = "";
[CliOption("--replicas", "-r", Description = "Instance count", DefaultValue = 1)]
public int Replicas { get; set; }
[CliOption("--backup-path", Description = "Snapshot path (required in production)")]
public string? BackupPath { get; set; }
[CliHandler]
public void Execute(IOutput output)
{
output.WriteInfo($"Deploying to {Environment} with {Replicas} replica(s).");
}
public static bool ValidateReplicas(DeployCommand cmd) =>
cmd.Replicas >= 1 && cmd.Replicas <= 10;
}
Registering commands
using Kiwify.Kiwi.CLI.Declarative.Extensions;
var app = new CommandLineApplication("mytool", "1.0.0");
// Option 1: auto-discover every [CliCommand] in the calling assembly
app.LoadCommandsFromAssembly();
// Option 2: load from a specific assembly
app.LoadCommandsFromAssembly(typeof(DeployCommand).Assembly);
// Option 3: load a single known type
app.LoadCommandFrom<DeployCommand>();
// Option 4: mix with manually-added fluent commands
app.AddCommand(myFluentCommand);
app.LoadCommandsFromAssembly(); // adds the declarative ones on top
app.Execute(args);
Handler signatures
CommandLoader recognises four handler signatures - static or instance, with or without IOutput:
// Static - command object is passed as the first parameter
public static void Execute(MyCommand cmd) { ... }
public static void Execute(MyCommand cmd, IOutput output) { ... }
// Instance - access properties via `this`; preferred in declarative mode
public void Execute() { ... }
public void Execute(IOutput output) { ... }
A method named Execute is discovered automatically. Use [CliHandler] to designate a differently-named method. Instance handlers are the recommended style: they read naturally and work seamlessly with dependency-injected command objects (the DI container constructs the command, so services are already available as fields).
Enum options
Declare a property with an enum type - CommandLoader maps it to EnumOption<TEnum> automatically, constraining accepted input to the enum member names:
[CliOption("--scope", "-s", DefaultValue = "local")]
public ConfigScope Scope { get; set; }
public enum ConfigScope { Local, Project, Global }
RequiredWhen with operators
Use ComparisonOperator for non-equality conditions on numeric or boolean fields:
using Kiwify.Kiwi.CLI.Declarative.Attributes.Enums;
[RequiredWhen(nameof(RetryCount), 4,
Operator = ComparisonOperator.GreaterThan,
RequiredFields = [nameof(BackupPath)])]
public class CopyCommand
{
public int RetryCount { get; set; }
public string? BackupPath { get; set; }
...
}
Available operators: Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual.
Per-command case sensitivity
Set CaseSensitiveFlags = true on [CliCommand] to make flag matching case-sensitive for that command, independent of the application-level setting:
[CliCommand("diagnose", CaseSensitiveFlags = true)]
public class DiagnoseCommand
{
[CliOption("--host", "-H")] // -H is distinct from -h (help)
public string Host { get; set; } = "";
[CliOption("--verbose", "-V")] // -V is distinct from -v (version)
public bool Verbose { get; set; }
public void Execute(IOutput output)
{
output.WriteInfo($"Checking {Host}...");
}
}
Either the app-level caseSensitiveFlags constructor parameter or the attribute-level CaseSensitiveFlags property opts the command in - whichever is true wins:
// app-level flag off, but DiagnoseCommand is still case-sensitive via its attribute
var app = new CommandLineApplication("mytool", "1.0.0");
app.LoadCommandFrom<DiagnoseCommand>();
app.Execute(args);
RequiredOnlyOneFieldGroup - same GroupId pattern
Multiple [RequiredOnlyOneFieldGroup] attributes sharing the same GroupId define the option groups within one constraint. Exactly one group must be fully satisfied:
// Exactly one of { Username+Password } or { CredentialFile } must be provided.
[RequiredOnlyOneFieldGroup(nameof(Username), nameof(Password), GroupId = 1)]
[RequiredOnlyOneFieldGroup(nameof(CredentialFile), GroupId = 1)]
public class LoginCommand { ... }
Attributes with different GroupId values create independent constraints.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Kiwify.Kiwi.CLI (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 96 | 5/28/2026 |