Use latest C# features

This commit is contained in:
Tyrrrz
2024-01-12 00:10:27 +02:00
parent 76e8d47e03
commit 6aa72e45e8
30 changed files with 186 additions and 390 deletions

View File

@@ -9,7 +9,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.5" /> <PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" /> <PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" /> <PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />

View File

@@ -23,7 +23,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})] [CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
public string? Foo { get; init; } public string? Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;
@@ -48,7 +48,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})] [CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
public string? Foo { get; init; } public string? Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;
@@ -73,7 +73,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})] [CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
public string? Foo { get; init; } public string? Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;

View File

@@ -23,7 +23,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})] [CommandParameter(0, Validators = new[] { typeof(MyValidator) })]
public required string Foo { get; init; } public required string Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;
@@ -48,7 +48,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})] [CommandParameter(0, Validators = new[] { typeof(MyValidator) })]
public required string Foo { get; init; } public required string Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;
@@ -73,7 +73,7 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
[Command] [Command]
public class MyCommand : ICommand public class MyCommand : ICommand
{ {
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})] [CommandParameter(0, Validators = new[] { typeof(MyValidator) })]
public required string Foo { get; init; } public required string Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;

View File

@@ -47,14 +47,14 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer)
// Parse the source code // Parse the source code
var ast = SyntaxFactory.ParseSyntaxTree( var ast = SyntaxFactory.ParseSyntaxTree(
SourceText.From(sourceCodeWithUsings), SourceText.From(sourceCodeWithUsings),
CSharpParseOptions.Default CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview)
); );
// Compile the code to IL // Compile the code to IL
var compilation = CSharpCompilation.Create( var compilation = CSharpCompilation.Create(
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(), "CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
new[] { ast }, [ast],
Net70 Net80
.References .References
.All .All
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)), .Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),

View File

@@ -8,9 +8,9 @@ public partial class Benchmarks
public class CoconaCommand public class CoconaCommand
{ {
public void Execute( public void Execute(
[Option("str", new[] { 's' })] string? strOption, [Option("str", ['s'])] string? strOption,
[Option("int", new[] { 'i' })] int intOption, [Option("int", ['i'])] int intOption,
[Option("bool", new[] { 'b' })] bool boolOption [Option("bool", ['b'])] bool boolOption
) { } ) { }
} }

View File

@@ -15,9 +15,9 @@ public partial class Benchmarks
{ {
var command = new RootCommand var command = new RootCommand
{ {
new Option(new[] { "--str", "-s" }) { Argument = new Argument<string?>() }, new Option(["--str", "-s"]) { Argument = new Argument<string?>() },
new Option(new[] { "--int", "-i" }) { Argument = new Argument<int>() }, new Option(["--int", "-i"]) { Argument = new Argument<int>() },
new Option(new[] { "--bool", "-b" }) { Argument = new Argument<bool>() } new Option(["--bool", "-b"]) { Argument = new Argument<bool>() }
}; };
command.Handler = CommandHandler.Create( command.Handler = CommandHandler.Create(

View File

@@ -9,7 +9,7 @@ namespace CliFx.Benchmarks;
[Orderer(SummaryOrderPolicy.FastestToSlowest)] [Orderer(SummaryOrderPolicy.FastestToSlowest)]
public partial class Benchmarks public partial class Benchmarks
{ {
private static readonly string[] Arguments = { "--str", "hello world", "-i", "13", "-b" }; private static readonly string[] Arguments = ["--str", "hello world", "-i", "13", "-b"];
public static void Main() => public static void Main() =>
BenchmarkRunner.Run<Benchmarks>( BenchmarkRunner.Run<Benchmarks>(

View File

@@ -32,8 +32,8 @@ public class ApplicationSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutp
var app = new CliApplicationBuilder() var app = new CliApplicationBuilder()
.AddCommand<NoOpCommand>() .AddCommand<NoOpCommand>()
.AddCommandsFrom(typeof(NoOpCommand).Assembly) .AddCommandsFrom(typeof(NoOpCommand).Assembly)
.AddCommands(new[] { typeof(NoOpCommand) }) .AddCommands([typeof(NoOpCommand)])
.AddCommandsFrom(new[] { typeof(NoOpCommand).Assembly }) .AddCommandsFrom([typeof(NoOpCommand).Assembly])
.AddCommandsFromThisAssembly() .AddCommandsFromThisAssembly()
.AllowDebugMode() .AllowDebugMode()
.AllowPreviewMode() .AllowPreviewMode()

View File

@@ -9,7 +9,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.5" /> <PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
<PackageReference Include="CliWrap" Version="3.6.4" /> <PackageReference Include="CliWrap" Version="3.6.4" />
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" /> <PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" /> <PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />

View File

@@ -38,10 +38,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "xyz"], new Dictionary<string, string>());
new[] { "-f", "xyz" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -78,10 +75,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "xyz"], new Dictionary<string, string>());
new[] { "-f", "xyz" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -128,7 +122,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "true", "-b", "false", "-c" }, ["-f", "true", "-b", "false", "-c"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -167,10 +161,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "32"], new Dictionary<string, string>());
new[] { "-f", "32" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -208,7 +199,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "32.14" }, ["-f", "32.14"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -248,7 +239,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "1995-04-28Z" }, ["-f", "1995-04-28Z"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -288,7 +279,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "12:34:56" }, ["-f", "12:34:56"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -329,10 +320,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "two"], new Dictionary<string, string>());
new[] { "-f", "two" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -374,10 +362,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-b", "123"], new Dictionary<string, string>());
new[] { "-b", "123" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -421,10 +406,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-b", "two"], new Dictionary<string, string>());
new[] { "-b", "two" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -468,10 +450,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "xyz"], new Dictionary<string, string>());
new[] { "-f", "xyz" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -534,7 +513,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "hello", "-b", "world" }, ["-f", "hello", "-b", "world"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -580,7 +559,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "hello world" }, ["-f", "hello world"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -622,7 +601,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "two", "three" }, ["-f", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -664,7 +643,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "two", "three" }, ["-f", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -706,7 +685,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "two", "three" }, ["-f", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -748,7 +727,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "1", "13", "27" }, ["-f", "1", "13", "27"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -787,10 +766,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "xyz"], new Dictionary<string, string>());
new[] { "-f", "xyz" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -831,7 +807,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "two" }, ["-f", "one", "two"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -867,7 +843,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "12.34" }, ["-f", "12.34"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -898,7 +874,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
[Command] [Command]
public class Command : ICommand public class Command : ICommand
{ {
[CommandOption('f', Validators = new[] {typeof(ValidatorA), typeof(ValidatorB)})] [CommandOption('f', Validators = [typeof(ValidatorA), typeof(ValidatorB)])]
public int Foo { get; init; } public int Foo { get; init; }
public ValueTask ExecuteAsync(IConsole console) => default; public ValueTask ExecuteAsync(IConsole console) => default;
@@ -912,10 +888,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "12"], new Dictionary<string, string>());
new[] { "-f", "12" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -957,10 +930,7 @@ public class ConversionSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["-f", "bar"], new Dictionary<string, string>());
new[] { "-f", "bar" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);

View File

@@ -63,7 +63,7 @@ public class DirectivesSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutpu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "[preview]", "cmd", "param", "-abc", "--option", "foo" }, ["[preview]", "cmd", "param", "-abc", "--option", "foo"],
new Dictionary<string, string> { ["ENV_QOP"] = "hello", ["ENV_KIL"] = "world" } new Dictionary<string, string> { ["ENV_QOP"] = "hello", ["ENV_KIL"] = "world" }
); );

View File

@@ -48,7 +48,7 @@ public class EnvironmentSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutp
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "42" }, ["--foo", "42"],
new Dictionary<string, string> { ["ENV_FOO"] = "100", ["ENV_BAR"] = "200" } new Dictionary<string, string> { ["ENV_FOO"] = "100", ["ENV_BAR"] = "200" }
); );

View File

@@ -55,10 +55,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -95,10 +92,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -141,7 +135,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "cmd", "--help" }, ["cmd", "--help"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -186,7 +180,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "cmd", "sub", "--help" }, ["cmd", "sub", "--help"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -209,7 +203,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "invalid-command", "--invalid-option" }, ["invalid-command", "--invalid-option"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -235,10 +229,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -268,10 +259,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -307,10 +295,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -349,10 +334,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -398,10 +380,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -440,10 +419,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -481,10 +457,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -523,10 +496,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -566,7 +536,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "cmd", "--help" }, ["cmd", "--help"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -609,10 +579,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -665,10 +632,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -721,10 +685,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -777,10 +738,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -846,10 +804,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -927,10 +882,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -1001,10 +953,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--help"], new Dictionary<string, string>());
new[] { "--help" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -1035,10 +984,7 @@ public class HelpTextSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--version"], new Dictionary<string, string>());
new[] { "--version" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);

View File

@@ -39,10 +39,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--foo"], new Dictionary<string, string>());
new[] { "--foo" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -79,7 +76,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync(new[] { "-f" }, new Dictionary<string, string>()); var exitCode = await application.RunAsync(["-f"], new Dictionary<string, string>());
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -122,7 +119,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "--bar", "two" }, ["--foo", "one", "--bar", "two"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -167,7 +164,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "-b", "two" }, ["-f", "one", "-b", "two"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -212,7 +209,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-fb", "value" }, ["-fb", "value"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -254,7 +251,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "two", "three" }, ["--foo", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -296,7 +293,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "two", "three" }, ["-f", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -338,7 +335,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "--foo", "two", "--foo", "three" }, ["--foo", "one", "--foo", "two", "--foo", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -380,7 +377,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "-f", "one", "-f", "two", "-f", "three" }, ["-f", "one", "-f", "two", "-f", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -422,7 +419,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "-f", "two", "--foo", "three" }, ["--foo", "one", "-f", "two", "--foo", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -467,7 +464,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one" }, ["--foo", "one"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -541,7 +538,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync(new[] { "--foo", "42", "--bar", "--baz", "xyz" }); var exitCode = await application.RunAsync(["--foo", "42", "--bar", "--baz", "xyz"]);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -579,7 +576,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "-13" }, ["--foo", "-13"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -650,10 +647,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--foo"], new Dictionary<string, string>());
new[] { "--foo" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -686,10 +680,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["--foo"], new Dictionary<string, string>());
new[] { "--foo" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -723,7 +714,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "--bar", "two" }, ["--foo", "one", "--bar", "two"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -759,7 +750,7 @@ public class OptionBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOu
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "--foo", "one", "two", "three" }, ["--foo", "one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );

View File

@@ -43,10 +43,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["one", "two"], new Dictionary<string, string>());
new[] { "one", "two" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -98,7 +95,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "one", "two", "three", "four", "five", "--boo", "xxx" }, ["one", "two", "three", "four", "five", "--boo", "xxx"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );
@@ -138,10 +135,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["one"], new Dictionary<string, string>());
new[] { "one" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -177,10 +171,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["one"], new Dictionary<string, string>());
new[] { "one" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().NotBe(0); exitCode.Should().NotBe(0);
@@ -222,10 +213,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["abc"], new Dictionary<string, string>());
new[] { "abc" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -262,7 +250,7 @@ public class ParameterBindingSpecs(ITestOutputHelper testOutput) : SpecsBase(tes
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "one", "two", "three" }, ["one", "two", "three"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );

View File

@@ -112,10 +112,7 @@ public class RoutingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
.Build(); .Build();
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(["cmd"], new Dictionary<string, string>());
new[] { "cmd" },
new Dictionary<string, string>()
);
// Assert // Assert
exitCode.Should().Be(0); exitCode.Should().Be(0);
@@ -170,7 +167,7 @@ public class RoutingSpecs(ITestOutputHelper testOutput) : SpecsBase(testOutput)
// Act // Act
var exitCode = await application.RunAsync( var exitCode = await application.RunAsync(
new[] { "cmd", "child" }, ["cmd", "child"],
new Dictionary<string, string>() new Dictionary<string, string>()
); );

View File

@@ -49,14 +49,14 @@ internal static class DynamicCommandBuilder
// Parse the source code // Parse the source code
var ast = SyntaxFactory.ParseSyntaxTree( var ast = SyntaxFactory.ParseSyntaxTree(
SourceText.From(sourceCodeWithUsings), SourceText.From(sourceCodeWithUsings),
CSharpParseOptions.Default CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview)
); );
// Compile the code to IL // Compile the code to IL
var compilation = CSharpCompilation.Create( var compilation = CSharpCompilation.Create(
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(), "CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
new[] { ast }, [ast],
Net70 Net80
.References .References
.All .All
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)) .Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))

View File

@@ -6,34 +6,24 @@ namespace CliFx;
/// <summary> /// <summary>
/// Configuration of an application. /// Configuration of an application.
/// </summary> /// </summary>
public class ApplicationConfiguration public class ApplicationConfiguration(
IReadOnlyList<Type> commandTypes,
bool isDebugModeAllowed,
bool isPreviewModeAllowed
)
{ {
/// <summary> /// <summary>
/// Command types defined in the application. /// Command types defined in the application.
/// </summary> /// </summary>
public IReadOnlyList<Type> CommandTypes { get; } public IReadOnlyList<Type> CommandTypes { get; } = commandTypes;
/// <summary> /// <summary>
/// Whether debug mode is allowed in the application. /// Whether debug mode is allowed in the application.
/// </summary> /// </summary>
public bool IsDebugModeAllowed { get; } public bool IsDebugModeAllowed { get; } = isDebugModeAllowed;
/// <summary> /// <summary>
/// Whether preview mode is allowed in the application. /// Whether preview mode is allowed in the application.
/// </summary> /// </summary>
public bool IsPreviewModeAllowed { get; } public bool IsPreviewModeAllowed { get; } = isPreviewModeAllowed;
/// <summary>
/// Initializes an instance of <see cref="ApplicationConfiguration" />.
/// </summary>
public ApplicationConfiguration(
IReadOnlyList<Type> commandTypes,
bool isDebugModeAllowed,
bool isPreviewModeAllowed
)
{
CommandTypes = commandTypes;
IsDebugModeAllowed = isDebugModeAllowed;
IsPreviewModeAllowed = isPreviewModeAllowed;
}
} }

View File

@@ -3,41 +3,30 @@
/// <summary> /// <summary>
/// Metadata associated with an application. /// Metadata associated with an application.
/// </summary> /// </summary>
public class ApplicationMetadata public class ApplicationMetadata(
string title,
string executableName,
string version,
string? description
)
{ {
/// <summary> /// <summary>
/// Application title. /// Application title.
/// </summary> /// </summary>
public string Title { get; } public string Title { get; } = title;
/// <summary> /// <summary>
/// Application executable name. /// Application executable name.
/// </summary> /// </summary>
public string ExecutableName { get; } public string ExecutableName { get; } = executableName;
/// <summary> /// <summary>
/// Application version. /// Application version.
/// </summary> /// </summary>
public string Version { get; } public string Version { get; } = version;
/// <summary> /// <summary>
/// Application description. /// Application description.
/// </summary> /// </summary>
public string? Description { get; } public string? Description { get; } = description;
/// <summary>
/// Initializes an instance of <see cref="ApplicationMetadata" />.
/// </summary>
public ApplicationMetadata(
string title,
string executableName,
string version,
string? description
)
{
Title = title;
ExecutableName = executableName;
Version = version;
Description = description;
}
} }

View File

@@ -7,7 +7,7 @@ namespace CliFx.Attributes;
/// Annotates a property that defines a command parameter. /// Annotates a property that defines a command parameter.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public sealed class CommandParameterAttribute : Attribute public sealed class CommandParameterAttribute(int order) : Attribute
{ {
/// <summary> /// <summary>
/// Parameter order. /// Parameter order.
@@ -18,7 +18,7 @@ public sealed class CommandParameterAttribute : Attribute
/// Parameter whose type is a non-scalar (e.g. array), must always be the last in order. /// Parameter whose type is a non-scalar (e.g. array), must always be the last in order.
/// Only one non-scalar parameter is allowed in a command. /// Only one non-scalar parameter is allowed in a command.
/// </remarks> /// </remarks>
public int Order { get; } public int Order { get; } = order;
/// <summary> /// <summary>
/// Whether this parameter is required (default: <c>true</c>). /// Whether this parameter is required (default: <c>true</c>).
@@ -62,12 +62,4 @@ public sealed class CommandParameterAttribute : Attribute
/// Validators must derive from <see cref="BindingValidator{T}" />. /// Validators must derive from <see cref="BindingValidator{T}" />.
/// </remarks> /// </remarks>
public Type[] Validators { get; set; } = Array.Empty<Type>(); public Type[] Validators { get; set; } = Array.Empty<Type>();
/// <summary>
/// Initializes an instance of <see cref="CommandParameterAttribute" />.
/// </summary>
public CommandParameterAttribute(int order)
{
Order = order;
}
} }

View File

@@ -17,40 +17,24 @@ namespace CliFx;
/// <summary> /// <summary>
/// Command-line application facade. /// Command-line application facade.
/// </summary> /// </summary>
public class CliApplication public class CliApplication(
ApplicationMetadata metadata,
ApplicationConfiguration configuration,
IConsole console,
ITypeActivator typeActivator
)
{ {
private readonly CommandBinder _commandBinder = new(typeActivator);
/// <summary> /// <summary>
/// Application metadata. /// Application metadata.
/// </summary> /// </summary>
public ApplicationMetadata Metadata { get; } public ApplicationMetadata Metadata { get; } = metadata;
/// <summary> /// <summary>
/// Application configuration. /// Application configuration.
/// </summary> /// </summary>
public ApplicationConfiguration Configuration { get; } public ApplicationConfiguration Configuration { get; } = configuration;
private readonly IConsole _console;
private readonly ITypeActivator _typeActivator;
private readonly CommandBinder _commandBinder;
/// <summary>
/// Initializes an instance of <see cref="CliApplication" />.
/// </summary>
public CliApplication(
ApplicationMetadata metadata,
ApplicationConfiguration configuration,
IConsole console,
ITypeActivator typeActivator
)
{
Metadata = metadata;
Configuration = configuration;
_console = console;
_typeActivator = typeActivator;
_commandBinder = new CommandBinder(typeActivator);
}
private bool IsDebugModeEnabled(CommandInput commandInput) => private bool IsDebugModeEnabled(CommandInput commandInput) =>
Configuration.IsDebugModeAllowed && commandInput.IsDebugDirectiveSpecified; Configuration.IsDebugModeAllowed && commandInput.IsDebugDirectiveSpecified;
@@ -70,9 +54,9 @@ public class CliApplication
private async ValueTask PromptDebuggerAsync() private async ValueTask PromptDebuggerAsync()
{ {
using (_console.WithForegroundColor(ConsoleColor.Green)) using (console.WithForegroundColor(ConsoleColor.Green))
{ {
_console console
.Output .Output
.WriteLine( .WriteLine(
$"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue." $"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue."
@@ -93,7 +77,7 @@ public class CliApplication
{ {
// Console colors may have already been overridden by the parent process, // Console colors may have already been overridden by the parent process,
// so we need to reset it to make sure that everything we write looks properly. // so we need to reset it to make sure that everything we write looks properly.
_console.ResetColor(); console.ResetColor();
// Handle the debug directive // Handle the debug directive
if (IsDebugModeEnabled(commandInput)) if (IsDebugModeEnabled(commandInput))
@@ -104,7 +88,7 @@ public class CliApplication
// Handle the preview directive // Handle the preview directive
if (IsPreviewModeEnabled(commandInput)) if (IsPreviewModeEnabled(commandInput))
{ {
_console.Output.WriteCommandInput(commandInput); console.Output.WriteCommandInput(commandInput);
return 0; return 0;
} }
@@ -128,7 +112,7 @@ public class CliApplication
var commandInstance = var commandInstance =
commandSchema == FallbackDefaultCommand.Schema commandSchema == FallbackDefaultCommand.Schema
? new FallbackDefaultCommand() // bypass the activator ? new FallbackDefaultCommand() // bypass the activator
: _typeActivator.CreateInstance<ICommand>(commandSchema.Type); : typeActivator.CreateInstance<ICommand>(commandSchema.Type);
// Assemble the help context // Assemble the help context
var helpContext = new HelpContext( var helpContext = new HelpContext(
@@ -141,14 +125,14 @@ public class CliApplication
// Handle the help option // Handle the help option
if (ShouldShowHelpText(commandSchema, commandInput)) if (ShouldShowHelpText(commandSchema, commandInput))
{ {
_console.Output.WriteHelpText(helpContext); console.Output.WriteHelpText(helpContext);
return 0; return 0;
} }
// Handle the version option // Handle the version option
if (ShouldShowVersionText(commandSchema, commandInput)) if (ShouldShowVersionText(commandSchema, commandInput))
{ {
_console.Output.WriteLine(Metadata.Version); console.Output.WriteLine(Metadata.Version);
return 0; return 0;
} }
@@ -160,18 +144,18 @@ public class CliApplication
{ {
// Bind and execute the command // Bind and execute the command
_commandBinder.Bind(commandInput, commandSchema, commandInstance); _commandBinder.Bind(commandInput, commandSchema, commandInstance);
await commandInstance.ExecuteAsync(_console); await commandInstance.ExecuteAsync(console);
return 0; return 0;
} }
catch (CliFxException ex) catch (CliFxException ex)
{ {
_console.Error.WriteException(ex); console.Error.WriteException(ex);
if (ex.ShowHelp) if (ex.ShowHelp)
{ {
_console.Output.WriteLine(); console.Output.WriteLine();
_console.Output.WriteHelpText(helpContext); console.Output.WriteHelpText(helpContext);
} }
return ex.ExitCode; return ex.ExitCode;
@@ -211,7 +195,7 @@ public class CliApplication
// developer, so we don't swallow them in that case. // developer, so we don't swallow them in that case.
catch (Exception ex) when (!Debugger.IsAttached) catch (Exception ex) when (!Debugger.IsAttached)
{ {
_console.Error.WriteException(ex); console.Error.WriteException(ex);
return 1; return 1;
} }
} }

View File

@@ -16,7 +16,7 @@ namespace CliFx;
/// </summary> /// </summary>
public partial class CliApplicationBuilder public partial class CliApplicationBuilder
{ {
private readonly HashSet<Type> _commandTypes = new(); private readonly HashSet<Type> _commandTypes = [];
private bool _isDebugModeAllowed = true; private bool _isDebugModeAllowed = true;
private bool _isPreviewModeAllowed = true; private bool _isPreviewModeAllowed = true;

View File

@@ -74,27 +74,24 @@ internal class CommandBinder(ITypeActivator typeActivator)
} }
// String-constructable (FileInfo, etc) // String-constructable (FileInfo, etc)
var stringConstructor = targetType.GetConstructor(new[] { typeof(string) }); var stringConstructor = targetType.GetConstructor([typeof(string)]);
if (stringConstructor is not null) if (stringConstructor is not null)
{ {
return stringConstructor.Invoke(new object?[] { rawValue }); return stringConstructor.Invoke([rawValue]);
} }
// String-parseable (with IFormatProvider) // String-parseable (with IFormatProvider)
var parseMethodWithFormatProvider = targetType.TryGetStaticParseMethod(true); var parseMethodWithFormatProvider = targetType.TryGetStaticParseMethod(true);
if (parseMethodWithFormatProvider is not null) if (parseMethodWithFormatProvider is not null)
{ {
return parseMethodWithFormatProvider.Invoke( return parseMethodWithFormatProvider.Invoke(null, [rawValue, _formatProvider]);
null,
new object?[] { rawValue, _formatProvider }
);
} }
// String-parseable (without IFormatProvider) // String-parseable (without IFormatProvider)
var parseMethod = targetType.TryGetStaticParseMethod(); var parseMethod = targetType.TryGetStaticParseMethod();
if (parseMethod is not null) if (parseMethod is not null)
{ {
return parseMethod.Invoke(null, new object?[] { rawValue }); return parseMethod.Invoke(null, [rawValue]);
} }
throw CliFxException.InternalError( throw CliFxException.InternalError(
@@ -126,10 +123,10 @@ internal class CommandBinder(ITypeActivator typeActivator)
} }
// Array-constructable (List<T>, HashSet<T>, etc) // Array-constructable (List<T>, HashSet<T>, etc)
var arrayConstructor = targetEnumerableType.GetConstructor(new[] { arrayType }); var arrayConstructor = targetEnumerableType.GetConstructor([arrayType]);
if (arrayConstructor is not null) if (arrayConstructor is not null)
{ {
return arrayConstructor.Invoke(new object?[] { array }); return arrayConstructor.Invoke([array]);
} }
throw CliFxException.InternalError( throw CliFxException.InternalError(
@@ -263,12 +260,9 @@ internal class CommandBinder(ITypeActivator typeActivator)
if (parameterSchema.Property.IsScalar()) if (parameterSchema.Property.IsScalar())
{ {
var parameterInput = commandInput.Parameters[position]; var parameterInput = commandInput.Parameters[position];
BindMember(parameterSchema, commandInstance, [parameterInput.Value]);
var rawValues = new[] { parameterInput.Value };
BindMember(parameterSchema, commandInstance, rawValues);
position++; position++;
remainingParameterInputs.Remove(parameterInput); remainingParameterInputs.Remove(parameterInput);
} }
// Non-scalar: take all remaining inputs starting from the current position // Non-scalar: take all remaining inputs starting from the current position
@@ -276,11 +270,13 @@ internal class CommandBinder(ITypeActivator typeActivator)
{ {
var parameterInputs = commandInput.Parameters.Skip(position).ToArray(); var parameterInputs = commandInput.Parameters.Skip(position).ToArray();
var rawValues = parameterInputs.Select(p => p.Value).ToArray(); BindMember(
BindMember(parameterSchema, commandInstance, rawValues); parameterSchema,
commandInstance,
parameterInputs.Select(p => p.Value).ToArray()
);
position += parameterInputs.Length; position += parameterInputs.Length;
remainingParameterInputs.RemoveRange(parameterInputs); remainingParameterInputs.RemoveRange(parameterInputs);
} }
@@ -347,7 +343,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
else if (environmentVariableInput is not null) else if (environmentVariableInput is not null)
{ {
var rawValues = optionSchema.Property.IsScalar() var rawValues = optionSchema.Property.IsScalar()
? new[] { environmentVariableInput.Value } ? [environmentVariableInput.Value]
: environmentVariableInput.SplitValues(); : environmentVariableInput.SplitValues();
BindMember(optionSchema, commandInstance, rawValues); BindMember(optionSchema, commandInstance, rawValues);

View File

@@ -5,7 +5,12 @@ namespace CliFx.Exceptions;
/// <summary> /// <summary>
/// Exception thrown when there is an error during application execution. /// Exception thrown when there is an error during application execution.
/// </summary> /// </summary>
public partial class CliFxException : Exception public partial class CliFxException(
string message,
int exitCode = CliFxException.DefaultExitCode,
bool showHelp = false,
Exception? innerException = null
) : Exception(message, innerException)
{ {
internal const int DefaultExitCode = 1; internal const int DefaultExitCode = 1;
@@ -13,33 +18,17 @@ public partial class CliFxException : Exception
// provides a default message that is not very useful. // provides a default message that is not very useful.
// This property is used to identify whether this instance was created with // This property is used to identify whether this instance was created with
// a custom message, so that we can avoid printing the default message. // a custom message, so that we can avoid printing the default message.
internal bool HasCustomMessage { get; } internal bool HasCustomMessage { get; } = !string.IsNullOrWhiteSpace(message);
/// <summary> /// <summary>
/// Returned exit code. /// Returned exit code.
/// </summary> /// </summary>
public int ExitCode { get; } public int ExitCode { get; } = exitCode;
/// <summary> /// <summary>
/// Whether to show the help text before exiting. /// Whether to show the help text before exiting.
/// </summary> /// </summary>
public bool ShowHelp { get; } public bool ShowHelp { get; } = showHelp;
/// <summary>
/// Initializes an instance of <see cref="CliFxException" />.
/// </summary>
public CliFxException(
string message,
int exitCode = DefaultExitCode,
bool showHelp = false,
Exception? innerException = null
)
: base(message, innerException)
{
HasCustomMessage = !string.IsNullOrWhiteSpace(message);
ExitCode = exitCode;
ShowHelp = showHelp;
}
} }
public partial class CliFxException public partial class CliFxException

View File

@@ -6,16 +6,9 @@ namespace CliFx.Exceptions;
/// Exception thrown when a command cannot proceed with its normal execution due to an error. /// Exception thrown when a command cannot proceed with its normal execution due to an error.
/// Use this exception to report an error to the console and return a specific exit code. /// Use this exception to report an error to the console and return a specific exit code.
/// </summary> /// </summary>
public class CommandException : CliFxException public class CommandException(
{ string message,
/// <summary> int exitCode = CliFxException.DefaultExitCode,
/// Initializes an instance of <see cref="CommandException" />. bool showHelp = false,
/// </summary> Exception? innerException = null
public CommandException( ) : CliFxException(message, exitCode, showHelp, innerException);
string message,
int exitCode = DefaultExitCode,
bool showHelp = false,
Exception? innerException = null
)
: base(message, exitCode, showHelp, innerException) { }
}

View File

@@ -3,15 +3,10 @@
/// <summary> /// <summary>
/// Represents a validation error. /// Represents a validation error.
/// </summary> /// </summary>
public class BindingValidationError public class BindingValidationError(string message)
{ {
/// <summary> /// <summary>
/// Error message shown to the user. /// Error message shown to the user.
/// </summary> /// </summary>
public string Message { get; } public string Message { get; } = message;
/// <summary>
/// Initializes an instance of <see cref="BindingValidationError" />.
/// </summary>
public BindingValidationError(string message) => Message = message;
} }

View File

@@ -11,28 +11,20 @@ namespace CliFx.Infrastructure;
/// </summary> /// </summary>
// Both the underlying stream AND the stream reader must be synchronized! // Both the underlying stream AND the stream reader must be synchronized!
// https://github.com/Tyrrrz/CliFx/issues/123 // https://github.com/Tyrrrz/CliFx/issues/123
public partial class ConsoleReader : StreamReader public partial class ConsoleReader(IConsole console, Stream stream, Encoding encoding)
: StreamReader(stream, encoding, false, 4096)
{ {
/// <summary>
/// Console that owns this stream.
/// </summary>
public IConsole Console { get; }
/// <summary>
/// Initializes an instance of <see cref="ConsoleReader" />.
/// </summary>
public ConsoleReader(IConsole console, Stream stream, Encoding encoding)
: base(stream, encoding, false, 4096)
{
Console = console;
}
/// <summary> /// <summary>
/// Initializes an instance of <see cref="ConsoleReader" />. /// Initializes an instance of <see cref="ConsoleReader" />.
/// </summary> /// </summary>
public ConsoleReader(IConsole console, Stream stream) public ConsoleReader(IConsole console, Stream stream)
: this(console, stream, System.Console.InputEncoding) { } : this(console, stream, System.Console.InputEncoding) { }
/// <summary>
/// Console that owns this stream.
/// </summary>
public IConsole Console { get; } = console;
// The following overrides are required to establish thread-safe behavior // The following overrides are required to establish thread-safe behavior
// in methods deriving from StreamReader. // in methods deriving from StreamReader.

View File

@@ -12,28 +12,20 @@ namespace CliFx.Infrastructure;
/// </summary> /// </summary>
// Both the underlying stream AND the stream writer must be synchronized! // Both the underlying stream AND the stream writer must be synchronized!
// https://github.com/Tyrrrz/CliFx/issues/123 // https://github.com/Tyrrrz/CliFx/issues/123
public partial class ConsoleWriter : StreamWriter public partial class ConsoleWriter(IConsole console, Stream stream, Encoding encoding)
: StreamWriter(stream, encoding.WithoutPreamble(), 256)
{ {
/// <summary>
/// Console that owns this stream.
/// </summary>
public IConsole Console { get; }
/// <summary>
/// Initializes an instance of <see cref="ConsoleWriter" />.
/// </summary>
public ConsoleWriter(IConsole console, Stream stream, Encoding encoding)
: base(stream, encoding.WithoutPreamble(), 256)
{
Console = console;
}
/// <summary> /// <summary>
/// Initializes an instance of <see cref="ConsoleWriter" />. /// Initializes an instance of <see cref="ConsoleWriter" />.
/// </summary> /// </summary>
public ConsoleWriter(IConsole console, Stream stream) public ConsoleWriter(IConsole console, Stream stream)
: this(console, stream, System.Console.OutputEncoding) { } : this(console, stream, System.Console.OutputEncoding) { }
/// <summary>
/// Console that owns this stream.
/// </summary>
public IConsole Console { get; } = console;
// The following overrides are required to establish thread-safe behavior // The following overrides are required to establish thread-safe behavior
// in methods deriving from StreamWriter. // in methods deriving from StreamWriter.

View File

@@ -6,20 +6,12 @@ namespace CliFx.Infrastructure;
/// <summary> /// <summary>
/// Implementation of <see cref="ITypeActivator" /> that instantiates an object by using a predefined delegate. /// Implementation of <see cref="ITypeActivator" /> that instantiates an object by using a predefined delegate.
/// </summary> /// </summary>
public class DelegateTypeActivator : ITypeActivator public class DelegateTypeActivator(Func<Type, object> createInstance) : ITypeActivator
{ {
private readonly Func<Type, object> _createInstance;
/// <summary>
/// Initializes an instance of <see cref="DelegateTypeActivator" />.
/// </summary>
public DelegateTypeActivator(Func<Type, object> createInstance) =>
_createInstance = createInstance;
/// <inheritdoc /> /// <inheritdoc />
public object CreateInstance(Type type) public object CreateInstance(Type type)
{ {
var instance = _createInstance(type); var instance = createInstance(type);
if (instance is null) if (instance is null)
{ {

View File

@@ -160,7 +160,7 @@ internal partial class CommandInput
result.Add(new OptionInput(lastOptionIdentifier, lastOptionValues)); result.Add(new OptionInput(lastOptionIdentifier, lastOptionValues));
lastOptionIdentifier = argument[2..]; lastOptionIdentifier = argument[2..];
lastOptionValues = new List<string>(); lastOptionValues = [];
} }
// Short name // Short name
else if (argument.StartsWith('-') && argument.Length > 1 && char.IsLetter(argument[1])) else if (argument.StartsWith('-') && argument.Length > 1 && char.IsLetter(argument[1]))
@@ -172,7 +172,7 @@ internal partial class CommandInput
result.Add(new OptionInput(lastOptionIdentifier, lastOptionValues)); result.Add(new OptionInput(lastOptionIdentifier, lastOptionValues));
lastOptionIdentifier = identifier.AsString(); lastOptionIdentifier = identifier.AsString();
lastOptionValues = new List<string>(); lastOptionValues = [];
} }
} }
// Value // Value