Skip to content

Commit 704e640

Browse files
authored
Expose Command collection properties as mutable IList, remove AddCommand, AddOption and AddArugment methods (#1989)
* expose Command.Arguments/Options/Subcommands as a mutable List use a custom type that implements IList to ensure that on every added element the parent is set as well * replace Add(Option), Add(Command) and Add(Argument) methods with Add(Symbol) * remove AddArguments, use Arguments.Add instead * remove AddOption, use Options.Add instead * remove AddCommand, use Subcommands.Add instead * hide Command.Add(Symbol) from intellisense (it's public only for C# duck typing)
1 parent d5f3c3b commit 704e640

File tree

27 files changed

+200
-163
lines changed

27 files changed

+200
-163
lines changed

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,15 @@ System.CommandLine
4646
public static Argument<T> AcceptExistingOnly<T>(this Argument<T> argument)
4747
public class Command : IdentifierSymbol, System.Collections.Generic.IEnumerable<Symbol>, System.Collections.IEnumerable
4848
.ctor(System.String name, System.String description = null)
49-
public System.Collections.Generic.IReadOnlyList<Argument> Arguments { get; }
49+
public System.Collections.Generic.IList<Argument> Arguments { get; }
5050
public System.Collections.Generic.IEnumerable<Symbol> Children { get; }
5151
public ICommandHandler Handler { get; set; }
52-
public System.Collections.Generic.IReadOnlyList<Option> Options { get; }
53-
public System.Collections.Generic.IReadOnlyList<Command> Subcommands { get; }
52+
public System.Collections.Generic.IList<Option> Options { get; }
53+
public System.Collections.Generic.IList<Command> Subcommands { get; }
5454
public System.Boolean TreatUnmatchedTokensAsErrors { get; set; }
5555
public System.Collections.Generic.List<System.Action<System.CommandLine.Parsing.CommandResult>> Validators { get; }
56-
public System.Void Add(Option option)
57-
public System.Void Add(Argument argument)
58-
public System.Void Add(Command command)
59-
public System.Void AddArgument(Argument argument)
60-
public System.Void AddCommand(Command command)
56+
public System.Void Add(Symbol symbol)
6157
public System.Void AddGlobalOption(Option option)
62-
public System.Void AddOption(Option option)
6358
public System.Collections.Generic.IEnumerable<System.CommandLine.Completions.CompletionItem> GetCompletions(System.CommandLine.Completions.CompletionContext context)
6459
public System.Collections.Generic.IEnumerator<Symbol> GetEnumerator()
6560
public static class CommandExtensions

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_CustomScenarios.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public void SetupOneOptWithNestedCommand()
2121
var rootCommand = new Command("root_command");
2222
var nestedCommand = new Command("nested_command");
2323
var option = new Option<int>("-opt1", () => 123);
24-
nestedCommand.AddOption(option);
25-
rootCommand.AddCommand(nestedCommand);
24+
nestedCommand.Options.Add(option);
25+
rootCommand.Subcommands.Add(nestedCommand);
2626

2727
_testParser = new Parser(rootCommand);
2828
_testSymbolsAsString = "root_command nested_command -opt1 321";

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_NestedCommands.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private void GenerateTestNestedCommands(Command parent, int depth, int countPerL
4040
{
4141
string cmdName = $"{parent.Name}_{depth}.{i}";
4242
Command cmd = new(cmdName);
43-
parent.AddCommand(cmd);
43+
parent.Subcommands.Add(cmd);
4444
GenerateTestNestedCommands(cmd, depth - 1, countPerLevel);
4545
}
4646
}

src/System.CommandLine.Benchmarks/CommandLine/Perf_Suggestions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void Setup_FromParseResult()
5454

5555
foreach (var option in GenerateOptionsArray(TestSuggestionsCount))
5656
{
57-
testCommand.AddOption(option);
57+
testCommand.Options.Add(option);
5858
}
5959

6060
_testParseResult = testCommand.Parse("--wrong");

src/System.CommandLine.DragonFruit/CommandLine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,12 @@ public static void ConfigureFromMethod(
160160

161161
foreach (var option in method.BuildOptions())
162162
{
163-
command.AddOption(option);
163+
command.Options.Add(option);
164164
}
165165

166166
if (method.GetParameters().FirstOrDefault(p => _argumentParameterNames.Contains(p.Name)) is { } argsParam)
167167
{
168-
command.AddArgument(ArgumentBuilder.CreateArgument(argsParam));
168+
command.Arguments.Add(ArgumentBuilder.CreateArgument(argsParam));
169169
}
170170

171171
command.Handler = CommandHandler.Create(method, target);

src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ void Execute(Character character, IConsole console)
9595

9696
var command = new Command("command");
9797
var nameOption = new Option<string>("--name");
98-
command.AddOption(nameOption);
98+
command.Options.Add(nameOption);
9999
var ageOption = new Option<int>("--age");
100-
command.AddOption(ageOption);
100+
command.Options.Add(ageOption);
101101

102102
command.SetHandler<Action<Character, IConsole>>(Execute, nameOption, ageOption);
103103

@@ -118,9 +118,9 @@ int Execute(int first, int second)
118118

119119
var command = new Command("add");
120120
var firstArgument = new Argument<int>("first");
121-
command.AddArgument(firstArgument);
121+
command.Arguments.Add(firstArgument);
122122
var secondArgument = new Argument<int>("second");
123-
command.AddArgument(secondArgument);
123+
command.Arguments.Add(secondArgument);
124124

125125
command.SetHandler<Func<int, int, int>>(Execute, firstArgument, secondArgument);
126126

@@ -243,12 +243,12 @@ void Execute2(string value)
243243

244244
var command1 = new Command("first");
245245
var argument1 = new Argument<string>("first-value");
246-
command1.AddArgument(argument1);
246+
command1.Arguments.Add(argument1);
247247
command1.SetHandler<Action<string>>(Execute1, argument1);
248248

249249
var command2 = new Command("second");
250250
var argument2 = new Argument<string>("second-value");
251-
command2.AddArgument(argument2);
251+
command2.Arguments.Add(argument2);
252252
command2.SetHandler<Action<string>>(Execute2, argument2);
253253

254254
await command1.InvokeAsync("first v1", _console);

src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ public static async Task Can_have_diferent_handlers_based_on_command()
5959
{
6060
var root = new RootCommand();
6161

62-
root.AddCommand(new MyCommand());
63-
root.AddCommand(new MyOtherCommand());
62+
root.Subcommands.Add(new MyCommand());
63+
root.Subcommands.Add(new MyOtherCommand());
6464
var parser = new CommandLineBuilder(root)
6565
.UseHost(host =>
6666
{
@@ -90,7 +90,7 @@ public static async Task Can_bind_to_arguments_via_injection()
9090
{
9191
var service = new MyService();
9292
var cmd = new RootCommand();
93-
cmd.AddCommand(new MyOtherCommand());
93+
cmd.Subcommands.Add(new MyOtherCommand());
9494
var parser = new CommandLineBuilder(cmd)
9595
.UseHost(host =>
9696
{
@@ -113,8 +113,8 @@ public static async Task Invokes_DerivedClass()
113113
var service = new MyService();
114114

115115
var cmd = new RootCommand();
116-
cmd.AddCommand(new MyCommand());
117-
cmd.AddCommand(new MyOtherCommand());
116+
cmd.Subcommands.Add(new MyCommand());
117+
cmd.Subcommands.Add(new MyOtherCommand());
118118
var parser = new CommandLineBuilder(cmd)
119119
.UseHost((builder) => {
120120
builder.ConfigureServices(services =>
@@ -155,7 +155,7 @@ public class MyCommand : Command
155155
{
156156
public MyCommand() : base(name: "mycommand")
157157
{
158-
AddOption(new Option<int>("--int-option")); // or nameof(Handler.IntOption).ToKebabCase() if you don't like the string literal
158+
Options.Add(new Option<int>("--int-option")); // or nameof(Handler.IntOption).ToKebabCase() if you don't like the string literal
159159
}
160160

161161
public class MyHandler : ICommandHandler
@@ -204,8 +204,8 @@ public class MyOtherCommand : Command
204204
{
205205
public MyOtherCommand() : base(name: "myothercommand")
206206
{
207-
AddOption(new Option<int>("--int-option")); // or nameof(Handler.IntOption).ToKebabCase() if you don't like the string literal
208-
AddArgument(new Argument<string>("One"));
207+
Options.Add(new Option<int>("--int-option")); // or nameof(Handler.IntOption).ToKebabCase() if you don't like the string literal
208+
Arguments.Add(new Argument<string>("One"));
209209
}
210210

211211
public class MyHandler : ICommandHandler

src/System.CommandLine.Hosting.Tests/HostingTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public static void UseHost_binds_parsed_arguments_to_options()
202202
MyOptions options = null;
203203

204204
var rootCmd = new RootCommand();
205-
rootCmd.AddOption(new Option<int>($"-{nameof(MyOptions.MyArgument)}"));
205+
rootCmd.Options.Add(new Option<int>($"-{nameof(MyOptions.MyArgument)}"));
206206
rootCmd.Handler = CommandHandler.Create((IHost host) =>
207207
{
208208
options = host.Services

src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public void Explicitly_configured_default_values_can_be_bound_by_name_to_constru
101101
var option = new Option<string>("--string-option", () => "the default");
102102

103103
var command = new Command("the-command");
104-
command.AddOption(option);
104+
command.Options.Add(option);
105105
var binder = new ModelBinder(typeof(ClassWithMultiLetterCtorParameters));
106106

107107
var parser = new Parser(command);
@@ -176,7 +176,7 @@ public void Types_having_constructors_accepting_a_single_string_are_bound_using_
176176
var option = new Option<DirectoryInfo>("--value");
177177

178178
var command = new Command("the-command");
179-
command.AddOption(option);
179+
command.Options.Add(option);
180180
var binder = new ModelBinder(typeof(ClassWithCtorParameter<DirectoryInfo>));
181181
var bindingContext = new InvocationContext(command.Parse($"--value \"{tempPath}\"")).BindingContext;
182182

@@ -191,7 +191,7 @@ public void Explicitly_configured_default_values_can_be_bound_by_name_to_propert
191191
var option = new Option<string>("--value", () => "the default");
192192

193193
var command = new Command("the-command");
194-
command.AddOption(option);
194+
command.Options.Add(option);
195195
var binder = new ModelBinder(typeof(ClassWithSetter<string>));
196196

197197
var parser = new Parser(command);
@@ -421,7 +421,7 @@ public void PropertyInfo_can_be_bound_to_argument()
421421
{
422422
var command = new Command("the-command");
423423
var argument = new Argument<int> { Arity = ArgumentArity.ExactlyOne };
424-
command.AddArgument(argument);
424+
command.Arguments.Add(argument);
425425

426426
var type = typeof(ClassWithMultiLetterSetters);
427427
var binder = new ModelBinder(type);
@@ -441,7 +441,7 @@ public void PropertyExpression_can_be_bound_to_option()
441441
{
442442
var command = new Command("the-command");
443443
var option = new Option<int>("--fred");
444-
command.AddOption(option);
444+
command.Options.Add(option);
445445

446446
var binder = new ModelBinder<ClassWithMultiLetterSetters>();
447447

@@ -461,7 +461,7 @@ public void PropertyExpression_can_be_bound_to_argument()
461461
{
462462
var command = new Command("the-command");
463463
var argument = new Argument<int> { Arity = ArgumentArity.ExactlyOne };
464-
command.AddArgument(argument);
464+
command.Arguments.Add(argument);
465465

466466
var binder = new ModelBinder<ClassWithMultiLetterSetters>();
467467

@@ -493,7 +493,7 @@ public void Option_argument_is_bound_to_longest_constructor()
493493
public void Command_argument_is_bound_to_longest_constructor()
494494
{
495495
var rootCommand = new RootCommand();
496-
rootCommand.AddArgument(new Argument<int> { Name = nameof(ClassWithMultipleCtor.IntProperty) });
496+
rootCommand.Arguments.Add(new Argument<int> { Name = nameof(ClassWithMultipleCtor.IntProperty) });
497497
var parser = new Parser(rootCommand);
498498

499499
var bindingContext = new InvocationContext(parser.Parse("42")).BindingContext;

src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ void Execute(string name, int age)
3030
}
3131

3232
var command = new Command("command");
33-
command.AddOption(new Option<string>("--name"));
34-
command.AddOption(new Option<int>("--age"));
33+
command.Options.Add(new Option<string>("--name"));
34+
command.Options.Add(new Option<int>("--age"));
3535
command.Handler = CommandHandler.Create<string, int>(Execute);
3636

3737
await command.InvokeAsync("command --age 425 --name Gandalf", _console);
@@ -74,8 +74,8 @@ void Execute(string name, int AGE)
7474
}
7575

7676
var command = new Command("command");
77-
command.AddOption(new Option<string>("--NAME"));
78-
command.AddOption(new Option<int>("--age"));
77+
command.Options.Add(new Option<string>("--NAME"));
78+
command.Options.Add(new Option<int>("--age"));
7979
command.Handler = CommandHandler.Create<string, int>(Execute);
8080

8181
await command.InvokeAsync("command --age 425 --NAME Gandalf", _console);
@@ -350,8 +350,8 @@ void Execute(string name, int age)
350350
}
351351

352352
var command = new Command("command");
353-
command.AddArgument(new Argument<int>("age"));
354-
command.AddArgument(new Argument<string>("name"));
353+
command.Arguments.Add(new Argument<int>("age"));
354+
command.Arguments.Add(new Argument<string>("name"));
355355
command.Handler = CommandHandler.Create<string, int>(Execute);
356356

357357
await command.InvokeAsync("command 425 Gandalf", _console);
@@ -394,8 +394,8 @@ void Execute(string name, int AGE)
394394
}
395395

396396
var command = new Command("command");
397-
command.AddArgument(new Argument<int>("AGE"));
398-
command.AddArgument(new Argument<string>("Name"));
397+
command.Arguments.Add(new Argument<int>("AGE"));
398+
command.Arguments.Add(new Argument<string>("Name"));
399399
command.Handler = CommandHandler.Create<string, int>(Execute);
400400

401401
await command.InvokeAsync("command 425 Gandalf", _console);
@@ -417,8 +417,8 @@ void Execute(string fullnameOrNickname, int age)
417417
}
418418

419419
var command = new Command("command");
420-
command.AddArgument(new Argument<int>("age"));
421-
command.AddArgument(new Argument<string>("fullname|nickname"));
420+
command.Arguments.Add(new Argument<int>("age"));
421+
command.Arguments.Add(new Argument<string>("fullname|nickname"));
422422
command.Handler = CommandHandler.Create<string, int>(Execute);
423423

424424
await command.InvokeAsync("command 425 Gandalf", _console);

0 commit comments

Comments
 (0)