diff --git a/src/Common/ArgumentBuilder.cs b/src/Common/ArgumentBuilder.cs index b5e01e9f60..5c24853f32 100644 --- a/src/Common/ArgumentBuilder.cs +++ b/src/Common/ArgumentBuilder.cs @@ -9,7 +9,7 @@ internal static class ArgumentBuilder static ArgumentBuilder() { - _ctor = typeof(Argument).GetConstructor(new[] { typeof(string), typeof(string) }); + _ctor = typeof(Argument).GetConstructor(new[] { typeof(string) }); } public static Argument CreateArgument(Type valueType, string name = "value") @@ -19,10 +19,10 @@ public static Argument CreateArgument(Type valueType, string name = "value") #if NET6_0_OR_GREATER var ctor = (ConstructorInfo)argumentType.GetMemberWithSameMetadataDefinitionAs(_ctor); #else - var ctor = argumentType.GetConstructor(new[] { typeof(string), typeof(string) }); + var ctor = argumentType.GetConstructor(new[] { typeof(string) }); #endif - return (Argument)ctor.Invoke(new object[] { name, null }); + return (Argument)ctor.Invoke(new object[] { name }); } internal static Argument CreateArgument(ParameterInfo argsParam) @@ -32,10 +32,20 @@ internal static Argument CreateArgument(ParameterInfo argsParam) return CreateArgument(argsParam.ParameterType, argsParam.Name); } - var argumentType = typeof(Argument<>).MakeGenericType(argsParam.ParameterType); + var argumentType = typeof(Bridge<>).MakeGenericType(argsParam.ParameterType); - var ctor = argumentType.GetConstructor(new[] { typeof(string), argsParam.ParameterType, typeof(string) }); + var ctor = argumentType.GetConstructor(new[] { typeof(string), argsParam.ParameterType }); - return (Argument)ctor.Invoke(new object[] { argsParam.Name, argsParam.DefaultValue, null }); + return (Argument)ctor.Invoke(new object[] { argsParam.Name, argsParam.DefaultValue }); + } + + private sealed class Bridge : Argument + { + public Bridge(string name, T defaultValue) + : base(name) + { + // this type exists only for an easy T => Func transformation + DefaultValueFactory = (_) => defaultValue; + } } } \ No newline at end of file diff --git a/src/Common/OptionBuilder.cs b/src/Common/OptionBuilder.cs index 25d33bb959..fa9ca5d232 100644 --- a/src/Common/OptionBuilder.cs +++ b/src/Common/OptionBuilder.cs @@ -11,25 +11,27 @@ internal static class OptionBuilder static OptionBuilder() { - _ctor = typeof(Option).GetConstructor(new[] { typeof(string), typeof(string) }); + _ctor = typeof(Option).GetConstructor(new[] { typeof(string), typeof(string[]) }); } - public static Option CreateOption(string name, Type valueType, string description = null) + internal static Option CreateOption(string name, Type valueType, string description = null) { var optionType = typeof(Option<>).MakeGenericType(valueType); #if NET6_0_OR_GREATER var ctor = (ConstructorInfo)optionType.GetMemberWithSameMetadataDefinitionAs(_ctor); #else - var ctor = optionType.GetConstructor(new[] { typeof(string), typeof(string) }); + var ctor = optionType.GetConstructor(new[] { typeof(string), typeof(string[]) }); #endif - var option = (Option)ctor.Invoke(new object[] { name, description }); + var option = (Option)ctor.Invoke(new object[] { name, Array.Empty() }); + + option.Description = description; return option; } - public static Option CreateOption(string name, Type valueType, string description, Func defaultValueFactory) + internal static Option CreateOption(string name, Type valueType, string description, Func defaultValueFactory) { if (defaultValueFactory == null) { @@ -45,13 +47,14 @@ public static Option CreateOption(string name, Type valueType, string descriptio return option; } - private class Bridge : Option + private sealed class Bridge : Option { public Bridge(string name, Func defaultValueFactory, string description) - : base(name, - () => (T)defaultValueFactory(), // this type exists only for an easy Func => Func transformation - description) + : base(name) { + // this type exists only for an easy Func => Func transformation + DefaultValueFactory = (_) => (T)defaultValueFactory(); + Description = description; } } } \ No newline at end of file diff --git a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt index 81680080eb..02b7a38200 100644 --- a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt +++ b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt @@ -10,21 +10,14 @@ System.CommandLine public System.Object GetDefaultValue() public System.String ToString() public class Argument : Argument, IValueDescriptor, System.CommandLine.Binding.IValueDescriptor - .ctor() - .ctor(System.String name, System.String description = null) - .ctor(System.String name, Func defaultValueFactory, System.String description = null) - .ctor(System.String name, T defaultValue, System.String description = null) - .ctor(Func defaultValueFactory) - .ctor(System.String name, Func parse, System.Boolean isDefault = False, System.String description = null) - .ctor(Func parse, System.Boolean isDefault = False) + .ctor(System.String name) + public Func CustomParser { get; set; } + public Func DefaultValueFactory { get; set; } public System.Boolean HasDefaultValue { get; } public System.Type ValueType { get; } public System.Void AcceptLegalFileNamesOnly() public System.Void AcceptLegalFilePathsOnly() public System.Void AcceptOnlyFromAmong(System.String[] values) - public System.Void SetDefaultValue(T value) - public System.Void SetDefaultValueFactory(Func defaultValueFactory) - public System.Void SetDefaultValueFactory(Func defaultValueFactory) public struct ArgumentArity : System.ValueType, System.IEquatable public static ArgumentArity ExactlyOne { get; } public static ArgumentArity OneOrMore { get; } @@ -42,8 +35,9 @@ System.CommandLine public static Argument AcceptExistingOnly(this Argument argument) public static Argument AcceptExistingOnly(this Argument argument) public static Argument AcceptExistingOnly(this Argument argument) - public class Command : IdentifierSymbol, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable + public class Command : Symbol, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable .ctor(System.String name, System.String description = null) + public System.Collections.Generic.ICollection Aliases { get; } public System.Collections.Generic.IList Arguments { get; } public System.Collections.Generic.IEnumerable Children { get; } public ICommandHandler Handler { get; set; } @@ -75,7 +69,7 @@ System.CommandLine public CommandLineBuilder UseEnvironmentVariableDirective() public CommandLineBuilder UseExceptionHandler(System.Action onException = null, System.Nullable errorExitCode = null) public CommandLineBuilder UseHelp(System.Nullable maxWidth = null) - public CommandLineBuilder UseHelp(System.String[] helpAliases) + public CommandLineBuilder UseHelp(System.String name, System.String[] helpAliases) public CommandLineBuilder UseHelp(System.Action customize, System.Nullable maxWidth = null) public CommandLineBuilder UseHelpBuilder(System.Func getHelpBuilder) public CommandLineBuilder UseParseDirective(System.Int32 errorExitCode = 1) @@ -84,7 +78,7 @@ System.CommandLine public CommandLineBuilder UseTokenReplacer(System.CommandLine.Parsing.TryReplaceToken replaceToken) public CommandLineBuilder UseTypoCorrections(System.Int32 maxLevenshteinDistance = 3) public CommandLineBuilder UseVersionOption() - public CommandLineBuilder UseVersionOption(System.String[] aliases) + public CommandLineBuilder UseVersionOption(System.String name, System.String[] aliases) public class CommandLineConfiguration public static CommandLineBuilder CreateBuilder(Command rootCommand) .ctor(Command command, System.Boolean enablePosixBundling = True, System.Boolean enableDirectives = True, System.Boolean enableTokenReplacement = True, System.Collections.Generic.IReadOnlyList middlewarePipeline = null, System.Func helpBuilderFactory = null, System.CommandLine.Parsing.TryReplaceToken tokenReplacer = null) @@ -137,32 +131,24 @@ System.CommandLine public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context) public System.Threading.Tasks.Task InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null) public interface IConsole : System.CommandLine.IO.IStandardError, System.CommandLine.IO.IStandardIn, System.CommandLine.IO.IStandardOut - public abstract class IdentifierSymbol : Symbol - public System.Collections.Generic.IReadOnlyCollection Aliases { get; } - public System.Void AddAlias(System.String alias) - public System.Boolean HasAlias(System.String alias) - public abstract class Option : IdentifierSymbol, System.CommandLine.Binding.IValueDescriptor + public abstract class Option : Symbol, System.CommandLine.Binding.IValueDescriptor + public System.Collections.Generic.ICollection Aliases { get; } public System.Boolean AllowMultipleArgumentsPerToken { get; set; } public System.Boolean AppliesToSelfAndChildren { get; set; } - public System.String ArgumentHelpName { get; set; } public ArgumentArity Arity { get; set; } public System.Collections.Generic.List>> CompletionSources { get; } + public System.String HelpName { get; set; } public System.Boolean IsRequired { get; set; } public System.Collections.Generic.List> Validators { get; } public System.Type ValueType { get; } public System.Collections.Generic.IEnumerable GetCompletions(System.CommandLine.Completions.CompletionContext context) public class Option : Option, IValueDescriptor, System.CommandLine.Binding.IValueDescriptor - .ctor(System.String name, System.String description = null) - .ctor(System.String[] aliases, System.String description = null) - .ctor(System.String name, Func parseArgument, System.Boolean isDefault = False, System.String description = null) - .ctor(System.String[] aliases, Func parseArgument, System.Boolean isDefault = False, System.String description = null) - .ctor(System.String name, Func defaultValueFactory, System.String description = null) - .ctor(System.String[] aliases, Func defaultValueFactory, System.String description = null) + .ctor(System.String name, System.String[] aliases) + public Func CustomParser { get; set; } + public Func DefaultValueFactory { get; set; } public System.Void AcceptLegalFileNamesOnly() public System.Void AcceptLegalFilePathsOnly() public System.Void AcceptOnlyFromAmong(System.String[] values) - public System.Void SetDefaultValue(T value) - public System.Void SetDefaultValueFactory(Func defaultValueFactory) public static class OptionValidation public static Option AcceptExistingOnly(this Option option) public static Option AcceptExistingOnly(this Option option) @@ -194,7 +180,7 @@ System.CommandLine public abstract class Symbol public System.String Description { get; set; } public System.Boolean IsHidden { get; set; } - public System.String Name { get; set; } + public System.String Name { get; } public System.Collections.Generic.IEnumerable Parents { get; } public System.Collections.Generic.IEnumerable GetCompletions(System.CommandLine.Completions.CompletionContext context) public System.String ToString() @@ -258,9 +244,9 @@ System.CommandLine.Help public static System.String GetArgumentDefaultValue(System.CommandLine.Argument argument) public static System.String GetArgumentDescription(System.CommandLine.Argument argument) public static System.String GetArgumentUsageLabel(System.CommandLine.Argument argument) - public static System.String GetIdentifierSymbolDescription(System.CommandLine.IdentifierSymbol symbol) - public static System.String GetIdentifierSymbolUsageLabel(System.CommandLine.IdentifierSymbol symbol, HelpContext context) + public static System.String GetCommandUsageLabel(System.CommandLine.Command symbol) public static System.Collections.Generic.IEnumerable> GetLayout() + public static System.String GetOptionUsageLabel(System.CommandLine.Option symbol) public static System.Action OptionsSection() public static System.Action SubcommandsSection() public static System.Action SynopsisSection() @@ -350,12 +336,14 @@ System.CommandLine.Parsing public System.Collections.Generic.IEnumerable Children { get; } public System.CommandLine.Command Command { get; } public Token Token { get; } + public System.String ToString() public class OptionResult : SymbolResult public System.Boolean IsImplicit { get; } public System.CommandLine.Option Option { get; } public Token Token { get; } public System.Object GetValueOrDefault() public T GetValueOrDefault() + public System.String ToString() public class ParseError public System.String Message { get; } public SymbolResult SymbolResult { get; } @@ -374,7 +362,6 @@ System.CommandLine.Parsing public OptionResult FindResultFor(System.CommandLine.Option option) public T GetValue(Argument argument) public T GetValue(Option option) - public System.String ToString() public class Token, System.IEquatable public static System.Boolean op_Equality(Token left, Token right) public static System.Boolean op_Inequality(Token left, Token right) diff --git a/src/System.CommandLine.ApiCompatibility.Tests/LocalizationTests.cs b/src/System.CommandLine.ApiCompatibility.Tests/LocalizationTests.cs index 97abc2e674..3d730759b1 100644 --- a/src/System.CommandLine.ApiCompatibility.Tests/LocalizationTests.cs +++ b/src/System.CommandLine.ApiCompatibility.Tests/LocalizationTests.cs @@ -21,7 +21,7 @@ public void ErrorMessages_AreLocalized(string cultureName, string expectedMessag Command command = new(CommandName) { - new Argument() + new Argument("arg") }; ParseResult parseResult = command.Parse(CommandName); diff --git a/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_CustomScenarios.cs b/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_CustomScenarios.cs index dce90160e9..c0af04fb20 100644 --- a/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_CustomScenarios.cs +++ b/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_CustomScenarios.cs @@ -21,7 +21,7 @@ public void SetupOneOptWithNestedCommand() { _rootCommand = new Command("root_command"); var nestedCommand = new Command("nested_command"); - var option = new Option("-opt1", () => 123); + var option = new Option("-opt1") { DefaultValueFactory = (_) => 123 }; nestedCommand.Options.Add(option); _rootCommand.Subcommands.Add(nestedCommand); diff --git a/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Simple.cs b/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Simple.cs index 38a51da411..ffe283f11b 100644 --- a/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Simple.cs +++ b/src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Simple.cs @@ -24,8 +24,8 @@ public class Perf_Parser_Simple private static RootCommand BuildCommand() { - Option boolOption = new(new[] { "--bool", "-b" }, "Bool option"); - Option stringOption = new(new[] { "--string", "-s" }, "String option"); + Option boolOption = new("--bool", "-b") { Description = "Bool option" }; + Option stringOption = new("--string", "-s") { Description = "String option" }; RootCommand command = new() { diff --git a/src/System.CommandLine.DragonFruit.Tests/CommandLineTests.cs b/src/System.CommandLine.DragonFruit.Tests/CommandLineTests.cs index eba1f8a52f..ef22320fb2 100644 --- a/src/System.CommandLine.DragonFruit.Tests/CommandLineTests.cs +++ b/src/System.CommandLine.DragonFruit.Tests/CommandLineTests.cs @@ -63,7 +63,7 @@ public async Task It_shows_help_text_based_on_XML_documentation_comments() .Contain(" These are arguments") .And.Contain("Arguments:"); stdOut.Should() - .ContainAll("--name ", "Specifies the name option") + .ContainAll("--name", "Specifies the name option") .And.Contain("Options:"); stdOut.Should() .Contain($"Description:{Environment.NewLine} Normal summary"); @@ -87,7 +87,7 @@ public async Task When_XML_documentation_comment_contains_a_para_tag_then_help_i .Contain(" These are arguments") .And.Contain("Arguments:"); stdOut.Should() - .ContainAll("--name ", "Specifies the name option") + .ContainAll("--name", "Specifies the name option") .And.Contain("Options:"); stdOut.Should() .Contain($"Description:{Environment.NewLine} Help for the test program{Environment.NewLine} More help for the test program{Environment.NewLine}"); @@ -111,7 +111,7 @@ public async Task When_XML_documentation_comment_contains_a_para_tag_and_some_te .Contain(" These are arguments") .And.Contain("Arguments:"); stdOut.Should() - .ContainAll("--name ", "Specifies the name option") + .ContainAll("--name", "Specifies the name option") .And.Contain("Options:"); stdOut.Should() .Contain($"Description:{Environment.NewLine} Help for the test program{Environment.NewLine} More help for the test program{Environment.NewLine}"); @@ -132,7 +132,7 @@ public void It_synchronously_shows_help_text_based_on_XML_documentation_comments var stdOut = _terminal.Out.ToString(); stdOut.Should() - .ContainAll("--name ","name [default: Bruce]") + .ContainAll("--name","name [default: Bruce]") .And.Contain("Options:"); } diff --git a/src/System.CommandLine.DragonFruit/CommandLine.cs b/src/System.CommandLine.DragonFruit/CommandLine.cs index 113dba6990..41bf355f91 100644 --- a/src/System.CommandLine.DragonFruit/CommandLine.cs +++ b/src/System.CommandLine.DragonFruit/CommandLine.cs @@ -310,6 +310,11 @@ private static bool HasAliasIgnoringPrefix(Option option, string alias) { ReadOnlySpan rawAlias = alias.AsSpan(GetPrefixLength(alias)); + if (MemoryExtensions.Equals(option.Name.AsSpan(GetPrefixLength(option.Name)), rawAlias, StringComparison.CurrentCulture)) + { + return true; + } + foreach (string existingAlias in option.Aliases) { if (MemoryExtensions.Equals(existingAlias.AsSpan(GetPrefixLength(existingAlias)), rawAlias, StringComparison.CurrentCulture)) diff --git a/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs b/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs index 1ba6b23c9e..c9a6e50fce 100644 --- a/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs +++ b/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs @@ -29,7 +29,7 @@ void Execute(string fullnameOrNickname, IConsole console, int age) boundAge = age; } - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") @@ -55,7 +55,7 @@ public async Task Can_generate_handler_for_void_returning_delegate() int boundAge = default; IConsole? boundConsole = null; - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") @@ -180,7 +180,7 @@ async Task ExecuteAsync(string fullnameOrNickname, IConsole console, int age) boundAge = age; } - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") @@ -272,7 +272,7 @@ void Execute(string fullnameOrNickname, IConsole console, int age) boundAge = age; } - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") @@ -297,7 +297,7 @@ public async Task Can_generate_handler_for_lambda() int boundAge = default; IConsole? boundConsole = null; - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") @@ -327,7 +327,7 @@ public async Task Can_generate_handler_for_lambda_wth_return_type_specified() int boundAge = default; IConsole? boundConsole = null; - var nameArgument = new Argument(); + var nameArgument = new Argument("arg"); var ageOption = new Option("--age"); var command = new Command("command") diff --git a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs index 02014170d4..ab3be94522 100644 --- a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs +++ b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs @@ -98,7 +98,10 @@ public void Command_arguments_are_bound_by_name_to_complex_constructor_parameter [Fact] public void Explicitly_configured_default_values_can_be_bound_by_name_to_constructor_parameters() { - var option = new Option("--string-option", () => "the default"); + var option = new Option("--string-option") + { + DefaultValueFactory = (_) => "the default", + }; var command = new Command("the-command"); command.Options.Add(option); @@ -185,7 +188,7 @@ public void Types_having_constructors_accepting_a_single_string_are_bound_using_ [Fact] public void Explicitly_configured_default_values_can_be_bound_by_name_to_property_setters() { - var option = new Option("--value", () => "the default"); + var option = new Option("--value") { DefaultValueFactory = (_) => "the default" }; var command = new Command("the-command"); command.Options.Add(option); @@ -286,7 +289,10 @@ public void Default_values_from_options_on_parent_commands_are_bound_by_name_by_ { var parentCommand = new Command("parent-command") { - new Option("--int-option", () => 123), + new Option("--int-option") + { + DefaultValueFactory = (_) => 123, + }, new Command("child-command") }; @@ -306,10 +312,7 @@ public void Values_from_parent_command_arguments_are_bound_by_name_by_default() { var parentCommand = new Command("parent-command") { - new Argument - { - Name = nameof(ClassWithMultiLetterSetters.IntOption) - }, + new Argument(nameof(ClassWithMultiLetterSetters.IntOption)), new Command("child-command") }; @@ -329,9 +332,9 @@ public void Default_values_from_parent_command_arguments_are_bound_by_name_by_de { var parentCommand = new Command("parent-command") { - new Argument(() => 123) + new Argument(nameof(ClassWithMultiLetterSetters.IntOption)) { - Name = nameof(ClassWithMultiLetterSetters.IntOption) + DefaultValueFactory = (_) => 123 }, new Command("child-command") }; @@ -415,7 +418,7 @@ public void PropertyInfo_can_be_bound_to_option() public void PropertyInfo_can_be_bound_to_argument() { var command = new Command("the-command"); - var argument = new Argument { Arity = ArgumentArity.ExactlyOne }; + var argument = new Argument("arg") { Arity = ArgumentArity.ExactlyOne }; command.Arguments.Add(argument); var type = typeof(ClassWithMultiLetterSetters); @@ -455,7 +458,7 @@ public void PropertyExpression_can_be_bound_to_option() public void PropertyExpression_can_be_bound_to_argument() { var command = new Command("the-command"); - var argument = new Argument { Arity = ArgumentArity.ExactlyOne }; + var argument = new Argument("arg") { Arity = ArgumentArity.ExactlyOne }; command.Arguments.Add(argument); var binder = new ModelBinder(); @@ -488,7 +491,7 @@ public void Option_argument_is_bound_to_longest_constructor() public void Command_argument_is_bound_to_longest_constructor() { var rootCommand = new RootCommand(); - rootCommand.Arguments.Add(new Argument { Name = nameof(ClassWithMultipleCtor.IntProperty) }); + rootCommand.Arguments.Add(new Argument(nameof(ClassWithMultipleCtor.IntProperty))); var bindingContext = new InvocationContext(rootCommand.Parse("42")).BindingContext; var binder = new ModelBinder(); @@ -633,7 +636,7 @@ public void Custom_ModelBinders_specified_via_BindingContext_can_be_used_for_com var rootCommand = new RootCommand { - new Argument() + new Argument("arg") }; rootCommand.Handler = CommandHandler.Create>(x => boundInstance = x); @@ -661,8 +664,8 @@ public void Default_values_from_options_with_the_same_type_are_bound_and_use_the var rootCommand = new RootCommand { - new Option("one", () => 1), - new Option("two", () => 2) + new Option("one") { DefaultValueFactory = (_) => 1 }, + new Option("two") { DefaultValueFactory = (_) => 2 } }; rootCommand.Handler = CommandHandler.Create((one, two) => { @@ -746,12 +749,14 @@ public void Binder_does_not_match_by_substring() { var rootCommand = new RootCommand { - new Option( - new[] { "-b", "--bundle" }, - "the path to the app bundle to be installed"), - new Option( - new[] { "-1", "--bundle_id", "--bundle-id" }, - "specify bundle id for list and upload") + new Option("--bundle", "-b") + { + Description = "the path to the app bundle to be installed" + }, + new Option("--bundle-id", "--bundle_id", "-1") + { + Description = "specify bundle id for list and upload" + } }; DeployOptions boundOptions = null; @@ -787,15 +792,15 @@ public void InvocationContext_GetValue_with_generic_option_returns_value() [Fact] public void InvocationContext_GetValue_with_generic_argument_returns_value() { - Argument option = new(); + Argument argument = new("arg"); Command command = new("the-command") { - option + argument }; InvocationContext invocationContext = new(command.Parse("the-command 42")); - invocationContext.GetValue(option) + invocationContext.GetValue(argument) .Should() .Be(42); } diff --git a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBindingCommandHandlerTests.cs b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBindingCommandHandlerTests.cs index 14d8748525..016aa1c0ad 100644 --- a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBindingCommandHandlerTests.cs +++ b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBindingCommandHandlerTests.cs @@ -136,9 +136,7 @@ public async Task When_binding_fails_due_to_parameter_naming_mismatch_then_handl { string[] received = { "this should get overwritten" }; - var o = new Option( - new[] { "-i" }, - "Path to an image or directory of supported images"); + var o = new Option("-i") { Description = "Path to an image or directory of supported images" }; var command = new Command("command") { o }; command.Handler = CommandHandler.Create((nameDoesNotMatch, c) => received = nameDoesNotMatch); diff --git a/src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs b/src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs index 614e0eebe8..0bdb91b6d0 100644 --- a/src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs +++ b/src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs @@ -124,8 +124,8 @@ void Execute(string name, int age) var command = new Command("command") { - new Option(new[] { "-n", "--NAME" }), - new Option(new[] { "-a", "--age" }) + new Option("--NAME", "-n"), + new Option("--age", "-a") }; command.Handler = CommandHandler.Create(Execute); diff --git a/src/System.CommandLine.NamingConventionBinder/CommandResultExtensions.cs b/src/System.CommandLine.NamingConventionBinder/CommandResultExtensions.cs index 3e7c95fa0b..1da0d4e9b6 100644 --- a/src/System.CommandLine.NamingConventionBinder/CommandResultExtensions.cs +++ b/src/System.CommandLine.NamingConventionBinder/CommandResultExtensions.cs @@ -18,7 +18,7 @@ internal static bool TryGetValueForArgument( { var argument = arguments[i]; - if (valueDescriptor.ValueName.IsMatch(argument.Name)) + if (valueDescriptor.ValueName.IsMatch(RemovePrefix(argument.Name))) { if (commandResult.FindResultFor(argument) is { } argumentResult) { @@ -72,7 +72,8 @@ static bool HasMatchingAlias( IValueDescriptor valueDescriptor, Option option) { - if (option.HasAlias(valueDescriptor.ValueName)) + string nameWithoutPrefix = RemovePrefix(option.Name); + if (valueDescriptor.ValueName.Equals(nameWithoutPrefix, StringComparison.OrdinalIgnoreCase) || valueDescriptor.ValueName.IsMatch(nameWithoutPrefix)) { return true; } @@ -150,4 +151,29 @@ static int IndexAfterPrefix(string alias) return 0; } } + + private static string RemovePrefix(string name) + { + int prefixLength = GetPrefixLength(name); + return prefixLength > 0 + ? name.Substring(prefixLength) + : name; + + static int GetPrefixLength(string name) + { + if (name[0] == '-') + { + return name.Length > 1 && name[1] == '-' + ? 2 + : 1; + } + + if (name[0] == '/') + { + return 1; + } + + return 0; + } + } } \ No newline at end of file diff --git a/src/System.CommandLine.Rendering.Tests/TableRenderingTests.cs b/src/System.CommandLine.Rendering.Tests/TableRenderingTests.cs index 69dd68eb03..a2319202bb 100644 --- a/src/System.CommandLine.Rendering.Tests/TableRenderingTests.cs +++ b/src/System.CommandLine.Rendering.Tests/TableRenderingTests.cs @@ -34,8 +34,8 @@ public TableRenderingTests(ITestOutputHelper output) public void A_row_is_written_for_each_item_and_a_header_for_each_column(OutputMode outputMode) { var options = new[] { - new Option("-s", "a short option"), - new Option("--very-long", "a long option") + new Option("-s") { Description = "a short option" }, + new Option("--very-long") { Description = "a long option" } }; var view = new OptionsHelpView(options); @@ -56,10 +56,10 @@ public void A_row_is_written_for_each_item_and_a_header_for_each_column(OutputMo public void A_row_is_written_for_each_item_and_a_header_for_each_column_in_file_mode() { var options = new[] - { - new Option("-s", "a short option"), - new Option("--very-long", "a long option") - }; + { + new Option("-s") { Description = "a short option" }, + new Option("--very-long") { Description = "a long option" } + }; var view = new OptionsHelpView(options); @@ -80,8 +80,8 @@ public void A_row_is_written_for_each_item_and_a_header_for_each_column_in_file_ public void Column_widths_are_aligned_to_the_longest_cell(OutputMode outputMode) { var options = new[] { - new Option("-s", "an option"), - new Option("--very-long", "an option") + new Option("-s") { Description = "an option" }, + new Option("--very-long") { Description = "an option" }, }; var view = new OptionsHelpView(options); @@ -101,8 +101,8 @@ public void Column_widths_are_aligned_to_the_longest_cell(OutputMode outputMode) public void Column_widths_are_aligned_to_the_longest_cell_in_file_mode() { var options = new[] { - new Option("-s", "an option"), - new Option("--very-long", "an option") + new Option("-s") { Description = "an option" }, + new Option("--very-long") { Description = "an option" }, }; var view = new OptionsHelpView(options); @@ -127,7 +127,7 @@ public OptionsHelpView(IEnumerable