diff --git a/CliFx/Attributes/CommandAttribute.cs b/CliFx/Attributes/CommandAttribute.cs index d7cbb1d..13025b6 100644 --- a/CliFx/Attributes/CommandAttribute.cs +++ b/CliFx/Attributes/CommandAttribute.cs @@ -4,33 +4,25 @@ namespace CliFx.Attributes; /// /// Annotates a type that defines a command. +/// If a command is named, then the user must provide its name through the command-line arguments in order to execute it. +/// If a command is not named, then it is treated as the application's default command and is executed when no other +/// command is specified. /// +/// +/// Only one default command is allowed per application. +/// All commands registered in an application must have unique names (comparison IS NOT case-sensitive). +/// [AttributeUsage(AttributeTargets.Class, Inherited = false)] -public class CommandAttribute : Attribute +public class CommandAttribute(string? name = null) : Attribute { - /// - /// Initializes an instance of . - /// - public CommandAttribute(string name) => Name = name; - - /// - /// Initializes an instance of . - /// - public CommandAttribute() { } - /// /// Command name. /// - /// - /// Command can have no name, in which case it's treated as the application's default command. - /// Only one default command is allowed in an application. - /// All commands registered in an application must have unique names (comparison IS NOT case-sensitive). - /// - public string? Name { get; } + public string? Name { get; } = name; /// /// Command description. /// This is shown to the user in the help text. /// public string? Description { get; set; } -} +} \ No newline at end of file diff --git a/CliFx/Attributes/CommandHelpOptionAttribute.cs b/CliFx/Attributes/CommandHelpOptionAttribute.cs index 2c7ba04..fa0fd71 100644 --- a/CliFx/Attributes/CommandHelpOptionAttribute.cs +++ b/CliFx/Attributes/CommandHelpOptionAttribute.cs @@ -1,8 +1,11 @@ namespace CliFx.Attributes; /// -/// Annotates a property that defines the help option for a command. +/// Binds a property to the help option of a command. /// +/// +/// This attribute is applied automatically by the framework and should not be used explicitly. +/// public class CommandHelpOptionAttribute : CommandOptionAttribute { /// diff --git a/CliFx/Attributes/CommandInputAttribute.cs b/CliFx/Attributes/CommandInputAttribute.cs new file mode 100644 index 0000000..53457ce --- /dev/null +++ b/CliFx/Attributes/CommandInputAttribute.cs @@ -0,0 +1,34 @@ +using System; +using CliFx.Extensibility; + +namespace CliFx.Attributes; + +/// +/// Binds a property to a command-line input. +/// +[AttributeUsage(AttributeTargets.Property)] +public abstract class CommandInputAttribute : Attribute +{ + /// + /// Input description, as shown in the help text. + /// + public string? Description { get; set; } + + /// + /// Custom converter used for mapping the raw command-line argument into + /// the type and shape expected by the underlying property. + /// + /// + /// Converter must derive from . + /// + public Type? Converter { get; set; } + + /// + /// Custom validators used for verifying the value of the underlying + /// property, after it has been set. + /// + /// + /// Validators must derive from . + /// + public Type[] Validators { get; set; } = []; +} \ No newline at end of file diff --git a/CliFx/Attributes/CommandOptionAttribute.cs b/CliFx/Attributes/CommandOptionAttribute.cs index 4cd8ea6..6dd90a7 100644 --- a/CliFx/Attributes/CommandOptionAttribute.cs +++ b/CliFx/Attributes/CommandOptionAttribute.cs @@ -4,10 +4,13 @@ using CliFx.Extensibility; namespace CliFx.Attributes; /// -/// Annotates a property that defines a command option. +/// Binds a property to a command option — a command-line input that is identified by a name and/or a short name. /// +/// +/// All options in a command must have unique names (comparison IS NOT case-sensitive) and short names (comparison IS case-sensitive). +/// [AttributeUsage(AttributeTargets.Property)] -public class CommandOptionAttribute : Attribute +public class CommandOptionAttribute : CommandInputAttribute { /// /// Initializes an instance of . @@ -39,20 +42,11 @@ public class CommandOptionAttribute : Attribute /// /// Option name. /// - /// - /// Must contain at least two characters and start with a letter. - /// Either or must be set. - /// All options in a command must have unique names (comparison IS NOT case-sensitive). - /// public string? Name { get; } /// /// Option short name. /// - /// - /// Either or must be set. - /// All options in a command must have unique short names (comparison IS case-sensitive). - /// public char? ShortName { get; } /// @@ -70,28 +64,4 @@ public class CommandOptionAttribute : Attribute /// has not been explicitly set through command-line arguments. /// public string? EnvironmentVariable { get; set; } - - /// - /// Option description. - /// This is shown to the user in the help text. - /// - public string? Description { get; set; } - - /// - /// Custom converter used for mapping the raw command-line argument into - /// a value expected by the underlying property. - /// - /// - /// Converter must derive from . - /// - public Type? Converter { get; set; } - - /// - /// Custom validators used for verifying the value of the underlying - /// property, after it has been bound. - /// - /// - /// Validators must derive from . - /// - public Type[] Validators { get; set; } = Array.Empty(); } diff --git a/CliFx/Attributes/CommandParameterAttribute.cs b/CliFx/Attributes/CommandParameterAttribute.cs index db5cc61..9cc1f5e 100644 --- a/CliFx/Attributes/CommandParameterAttribute.cs +++ b/CliFx/Attributes/CommandParameterAttribute.cs @@ -5,21 +5,21 @@ using CliFx.Extensibility; namespace CliFx.Attributes; /// -/// Annotates a property that defines a command parameter. +/// Binds a property to a command parameter — a command-line input that is identified by its relative position (order). +/// Higher order means that the parameter appears later, lower order means that it appears earlier. /// +/// +/// All parameters in a command must have unique order values. +/// If a parameter is bound to a property whose type is a sequence (e.g. Array, ; except ), +/// then it must have the highest order in the command. +/// Only one sequential parameter is allowed per command. +/// [AttributeUsage(AttributeTargets.Property)] -public class CommandParameterAttribute(int order) : Attribute +public class CommandParameterAttribute(int order) : CommandInputAttribute { /// /// Parameter order. - /// Higher order means the parameter appears later, lower order means it appears earlier. /// - /// - /// All parameters in a command must have unique order. - /// Parameter whose type is a sequence (e.g. Array, ; except ), - /// must always be the last parameter based on order. - /// Only one sequential parameter is allowed in a command. - /// public int Order { get; } = order; /// @@ -27,41 +27,16 @@ public class CommandParameterAttribute(int order) : Attribute /// If a parameter is required, the user will get an error if they don't set it. /// /// - /// Parameter marked as non-required must always be the last in order. - /// Only one non-required parameter is allowed in a command. + /// Parameter marked as non-required must have the highest order in the command. + /// Only one non-required parameter is allowed per command. /// public bool IsRequired { get; set; } = true; /// - /// Parameter name. - /// This is shown to the user in the help text. + /// Parameter name, as shown in the help text. /// /// /// If this isn't specified, parameter name is inferred from the property name. /// public string? Name { get; set; } - - /// - /// Parameter description. - /// This is shown to the user in the help text. - /// - public string? Description { get; set; } - - /// - /// Custom converter used for mapping the raw command-line argument into - /// a value expected by the underlying property. - /// - /// - /// Converter must derive from . - /// - public Type? Converter { get; set; } - - /// - /// Custom validators used for verifying the value of the underlying - /// property, after it has been bound. - /// - /// - /// Validators must derive from . - /// - public Type[] Validators { get; set; } = Array.Empty(); } diff --git a/CliFx/Attributes/CommandVersionOptionAttribute.cs b/CliFx/Attributes/CommandVersionOptionAttribute.cs index 44cce02..0169d28 100644 --- a/CliFx/Attributes/CommandVersionOptionAttribute.cs +++ b/CliFx/Attributes/CommandVersionOptionAttribute.cs @@ -1,8 +1,11 @@ namespace CliFx.Attributes; /// -/// Annotates a property that defines the version option for a command. +/// Binds a property to the version option of a command. /// +/// +/// This attribute is applied automatically by the framework and should not be used explicitly. +/// public class CommandVersionOptionAttribute : CommandOptionAttribute { /// diff --git a/CliFx/Schema/InputSchema.cs b/CliFx/Schema/InputSchema.cs index f692e94..94af029 100644 --- a/CliFx/Schema/InputSchema.cs +++ b/CliFx/Schema/InputSchema.cs @@ -14,6 +14,7 @@ namespace CliFx.Schema; /// public abstract class InputSchema( PropertyBinding property, + string? description, IBindingConverter converter, IReadOnlyList validators ) @@ -22,6 +23,11 @@ public abstract class InputSchema( property.Type != typeof(string) && property.Type.TryGetEnumerableUnderlyingType() is not null; + /// + /// Input description, used in the help text. + /// + public string? Description { get; } = description; + /// /// CLR property to which this input is bound. /// @@ -119,7 +125,8 @@ public abstract class InputSchema< TProperty >( PropertyBinding property, + string? description, BindingConverter converter, IReadOnlyList> validators -) : InputSchema(property, converter, validators) +) : InputSchema(property, description, converter, validators) where TCommand : ICommand; diff --git a/CliFx/Schema/OptionSchema.cs b/CliFx/Schema/OptionSchema.cs index 84554b1..52cbd3b 100644 --- a/CliFx/Schema/OptionSchema.cs +++ b/CliFx/Schema/OptionSchema.cs @@ -18,7 +18,7 @@ public class OptionSchema( string? description, IBindingConverter converter, IReadOnlyList validators -) : InputSchema(property, converter, validators) +) : InputSchema(property,description, converter, validators) { /// /// Option name. @@ -40,11 +40,6 @@ public class OptionSchema( /// public bool IsRequired { get; } = isRequired; - /// - /// Option description. - /// - public string? Description { get; } = description; - internal bool MatchesName(string? name) => !string.IsNullOrWhiteSpace(Name) && string.Equals(Name, name, StringComparison.OrdinalIgnoreCase); diff --git a/CliFx/Schema/ParameterSchema.cs b/CliFx/Schema/ParameterSchema.cs index 4ed896f..232fe68 100644 --- a/CliFx/Schema/ParameterSchema.cs +++ b/CliFx/Schema/ParameterSchema.cs @@ -15,7 +15,7 @@ public class ParameterSchema( string? description, IBindingConverter converter, IReadOnlyList validators -) : InputSchema(property, converter, validators) +) : InputSchema(property, description, converter, validators) { /// /// Order, in which the parameter is bound from the command-line arguments. @@ -32,11 +32,6 @@ public class ParameterSchema( /// public bool IsRequired { get; } = isRequired; - /// - /// Parameter description. - /// - public string? Description { get; } = description; - internal override string GetKind() => "Parameter"; internal override string GetFormattedIdentifier() => IsSequence ? $"<{Name}>" : $"<{Name}...>"; diff --git a/CliFx/Utils/NoPreambleEncoding.cs b/CliFx/Utils/NoPreambleEncoding.cs index e6c2ad4..d3494f2 100644 --- a/CliFx/Utils/NoPreambleEncoding.cs +++ b/CliFx/Utils/NoPreambleEncoding.cs @@ -51,7 +51,7 @@ internal class NoPreambleEncoding(Encoding underlyingEncoding) public override bool IsMailNewsSave => underlyingEncoding.IsMailNewsSave; // This is the only part that changes - public override byte[] GetPreamble() => Array.Empty(); + public override byte[] GetPreamble() => []; [ExcludeFromCodeCoverage] public override int GetByteCount(char[] chars, int index, int count) =>