mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48f157a51e | ||
|
|
b1995fa4f7 | ||
|
|
74bc973f77 | ||
|
|
3420c3d039 | ||
|
|
b10577fec5 | ||
|
|
af96d0d31d | ||
|
|
bd29ad31cc | ||
|
|
15150cb3ed | ||
|
|
aac9c968eb | ||
|
|
85a9f157ad | ||
|
|
d24a79361d | ||
|
|
5785720f31 | ||
|
|
3f6f0b9f1b | ||
|
|
128bb5be8b | ||
|
|
36b3814f4e | ||
|
|
c4a975d5f1 | ||
|
|
79d86d39c1 | ||
|
|
c476700168 | ||
|
|
5e97ebe7f0 | ||
|
|
64cbdaaeab |
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
|
- name: ⚠ Feature request
|
||||||
|
url: https://github.com/Tyrrrz/.github/blob/master/docs/project-status.md
|
||||||
|
about: Sorry, but this project is in maintenance mode and no longer accepts new feature requests.
|
||||||
- name: 💬 Discord server
|
- name: 💬 Discord server
|
||||||
url: https://discord.gg/2SUWKFnHSm
|
url: https://discord.gg/2SUWKFnHSm
|
||||||
about: Chat with the project community.
|
about: Chat with the project community.
|
||||||
|
|||||||
22
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
22
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
name: ✨ Feature request
|
|
||||||
description: Request a new feature.
|
|
||||||
labels: [enhancement]
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
🧐 **Guidelines:**
|
|
||||||
|
|
||||||
- Search through [existing issues](https://github.com/Tyrrrz/CliFx/issues?q=is%3Aissue) first to ensure that this feature has not been requested before.
|
|
||||||
- Write a descriptive title for your issue. Avoid generic or vague titles such as "Some suggestions" or "Ideas for improvement".
|
|
||||||
- Keep your issue focused on one single problem. If you have multiple feature requests, please create separate issues for each of them.
|
|
||||||
- Provide as much context as possible in the details section. Include screenshots, screen recordings, links, references, or anything else you may consider relevant.
|
|
||||||
- If you want to ask a question instead of requesting a feature, please use [discussions](https://github.com/Tyrrrz/CliFx/discussions/new) instead.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Details
|
|
||||||
description: Clear and thorough explanation of the feature you have in mind.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
|||||||
main:
|
main:
|
||||||
uses: Tyrrrz/.github/.github/workflows/nuget.yml@master
|
uses: Tyrrrz/.github/.github/workflows/nuget.yml@master
|
||||||
with:
|
with:
|
||||||
dotnet-version: 6.0.x
|
dotnet-version: 7.0.x
|
||||||
secrets:
|
secrets:
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
|
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
### v2.3.1 (08-Dec-2022)
|
||||||
|
|
||||||
|
- Added support for the `required` keyword introduced in C# 11. Command options bound to required properties are now marked as required by default (equivalent to setting `IsRequired = true` on the attribute). Also added analyzers that prevent marking an option or parameter non-required if it's bound to a required property.
|
||||||
|
|
||||||
|
### v2.3 (12-Jul-2022)
|
||||||
|
|
||||||
|
- Added console dimension properties `WindowWidth` and `WindowHeight` to `IConsole` interface and implementing classes.
|
||||||
|
- Improved inline documentation for members of `IConsole` interface.
|
||||||
|
|
||||||
### v2.2.6 (14-Jun-2022)
|
### v2.2.6 (14-Jun-2022)
|
||||||
|
|
||||||
- Added an overload of `CliApplicationBuilder.UseTypeActivator(...)` that accepts an instance of `IServiceProvider`. This slightly simplifies integration with many DI containers.
|
- Added an overload of `CliApplicationBuilder.UseTypeActivator(...)` that accepts an instance of `IServiceProvider`. This slightly simplifies integration with many DI containers.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -9,14 +9,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies" Version="1.2.4" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.1" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.0" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.1" PrivateAssets="all" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
<PackageReference Include="FluentAssertions" Version="6.8.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all" />
|
||||||
<PackageReference Include="coverlet.collector" Version="3.1.2" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="3.2.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ public class CommandMustBeAnnotatedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyCommand : ICommand
|
"""
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -28,12 +30,14 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public abstract class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public abstract class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -44,11 +48,13 @@ public abstract class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public abstract class MyCommand : ICommand
|
"""
|
||||||
{
|
public abstract class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -59,11 +65,13 @@ public abstract class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class Foo
|
"""
|
||||||
{
|
public class Foo
|
||||||
public int Bar { get; set; } = 5;
|
{
|
||||||
}";
|
public int Bar { get; set; } = 5;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ public class CommandMustImplementInterfaceAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand
|
[Command]
|
||||||
{
|
public class MyCommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -29,12 +31,14 @@ public class MyCommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -45,11 +49,13 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class Foo
|
"""
|
||||||
{
|
public class Foo
|
||||||
public int Bar { get; set; } = 5;
|
{
|
||||||
}";
|
public int Bar { get; set; } = 5;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ public class OptionMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyClass
|
"""
|
||||||
{
|
public class MyClass
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
}";
|
public string Foo { get; set; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -29,15 +31,17 @@ public class MyClass
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}";
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -48,12 +52,14 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public abstract class MyCommand
|
"""
|
||||||
{
|
public abstract class MyCommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
}";
|
public string Foo { get; set; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -64,14 +70,16 @@ public abstract class MyCommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}";
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using CliFx.Analyzers.Tests.Utils;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
||||||
|
{
|
||||||
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeRequiredIfPropertyRequiredAnalyzer();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_reports_an_error_if_a_non_required_option_is_bound_to_a_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f', IsRequired = false)]
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_required_option_is_bound_to_a_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f', IsRequired = true)]
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_non_required_option_is_bound_to_a_non_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f', IsRequired = false)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_required_option_is_bound_to_a_non_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f', IsRequired = true)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_an_option()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,15 +13,17 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(null)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption(null)]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -32,15 +34,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -51,15 +55,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -70,14 +76,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandOption(""foo"")]
|
|
||||||
public string Bar { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public string Bar { get; set; }
|
[CommandOption("bar")]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,15 +61,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -76,14 +82,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandOption('f')]
|
|
||||||
public string Bar { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandOption('b')]
|
|
||||||
public string Bar { get; set; }
|
[CommandOption('b')]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,18 +61,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandOption('F')]
|
|
||||||
public string Bar { get; set; }
|
[CommandOption('F')]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -79,15 +85,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -98,14 +106,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,20 +13,22 @@ public class OptionMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter
|
"""
|
||||||
{
|
public class MyConverter
|
||||||
public string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -37,20 +39,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<int>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<int>
|
||||||
public override int Convert(string rawValue) => 42;
|
{
|
||||||
}
|
public override int Convert(string rawValue) => 42;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -61,20 +65,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<string>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<string>
|
||||||
public override string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public override string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -85,20 +91,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<int>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<int>
|
||||||
public override int Convert(string rawValue) => 42;
|
{
|
||||||
}
|
public override int Convert(string rawValue) => 42;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public int? Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public int? Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -109,20 +117,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<string>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<string>
|
||||||
public override string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public override string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -133,15 +143,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -152,14 +164,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,15 +13,17 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""f"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("f")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -32,15 +34,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""1foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("1foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -51,15 +55,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -70,15 +76,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -89,14 +97,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,15 +13,17 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('1')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('1')]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -32,15 +34,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption('f')]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption('f')]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -51,15 +55,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -70,14 +76,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,20 +13,22 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator
|
"""
|
||||||
{
|
public class MyValidator
|
||||||
public void Validate(string value) {}
|
{
|
||||||
}
|
public void Validate(string value) {}
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -37,20 +39,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator : BindingValidator<int>
|
"""
|
||||||
{
|
public class MyValidator : BindingValidator<int>
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
{
|
||||||
}
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -61,20 +65,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator : BindingValidator<string>
|
"""
|
||||||
{
|
public class MyValidator : BindingValidator<string>
|
||||||
public override BindingValidationError Validate(string value) => Ok();
|
{
|
||||||
}
|
public override BindingValidationError Validate(string value) => Ok();
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -85,15 +91,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -104,14 +112,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyClass
|
"""
|
||||||
{
|
public class MyClass
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
}";
|
public string Foo { get; set; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -29,15 +31,17 @@ public class MyClass
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -48,12 +52,14 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public abstract class MyCommand
|
"""
|
||||||
{
|
public abstract class MyCommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
}";
|
public string Foo { get; set; }
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -64,14 +70,16 @@ public abstract class MyCommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class ParameterMustBeLastIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"", IsRequired = false)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, IsRequired = false)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, Name = ""bar"")]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, Name = ""bar"", IsRequired = false)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, IsRequired = false)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,18 +61,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, Name = ""bar"", IsRequired = true)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, IsRequired = true)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -79,14 +85,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string[] Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string[] Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string[] Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string[] Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,18 +61,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -79,14 +85,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using CliFx.Analyzers.Tests.Utils;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustBeRequiredIfPropertyRequiredAnalyzerSpecs
|
||||||
|
{
|
||||||
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeRequiredIfPropertyRequiredAnalyzer();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_reports_an_error_if_a_non_required_parameter_is_bound_to_a_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0, IsRequired = false)]
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_required_parameter_is_bound_to_a_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0, IsRequired = true)]
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_non_required_parameter_is_bound_to_a_non_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0, IsRequired = false)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_required_parameter_is_bound_to_a_non_required_property()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0, IsRequired = true)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_on_a_property_that_is_not_a_parameter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code =
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,18 +13,20 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, IsRequired = false)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, IsRequired = false)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, IsRequired = false)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, IsRequired = false)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, IsRequired = false)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, IsRequired = false)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,18 +61,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, IsRequired = true)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, IsRequired = true)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -79,14 +85,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string[] Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string[] Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string[] Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string[] Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string[] Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string[] Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,18 +61,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -79,14 +85,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Name = "foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, Name = ""foo"")]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, Name = "foo")]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Name = "foo")]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1, Name = ""bar"")]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1, Name = "bar")]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,14 +61,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,18 +13,20 @@ public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(0)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -35,18 +37,20 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
[CommandParameter(1)]
|
|
||||||
public string Bar { get; set; }
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -57,14 +61,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,20 +13,22 @@ public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter
|
"""
|
||||||
{
|
public class MyConverter
|
||||||
public string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -37,20 +39,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<int>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<int>
|
||||||
public override int Convert(string rawValue) => 42;
|
{
|
||||||
}
|
public override int Convert(string rawValue) => 42;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
@@ -62,20 +66,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<string>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<string>
|
||||||
public override string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public override string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Converter = typeof(MyConverter))]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Converter = typeof(MyConverter))]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -86,20 +92,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<int>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<int>
|
||||||
public override int Convert(string rawValue) => 42;
|
{
|
||||||
}
|
public override int Convert(string rawValue) => 42;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandOption(""foo"", Converter = typeof(MyConverter))]
|
{
|
||||||
public int? Foo { get; set; }
|
[CommandOption("foo", Converter = typeof(MyConverter))]
|
||||||
|
public int? Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -110,20 +118,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyConverter : BindingConverter<string>
|
"""
|
||||||
{
|
public class MyConverter : BindingConverter<string>
|
||||||
public override string Convert(string rawValue) => rawValue;
|
{
|
||||||
}
|
public override string Convert(string rawValue) => rawValue;
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Converter = typeof(MyConverter))]
|
{
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
[CommandParameter(0, Converter = typeof(MyConverter))]
|
||||||
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -134,15 +144,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -153,14 +165,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,20 +13,22 @@ public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator
|
"""
|
||||||
{
|
public class MyValidator
|
||||||
public void Validate(string value) {}
|
{
|
||||||
}
|
public void Validate(string value) {}
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -37,20 +39,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator : BindingValidator<int>
|
"""
|
||||||
{
|
public class MyValidator : BindingValidator<int>
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
{
|
||||||
}
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -61,20 +65,22 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
public class MyValidator : BindingValidator<string>
|
"""
|
||||||
{
|
public class MyValidator : BindingValidator<string>
|
||||||
public override BindingValidationError Validate(string value) => Ok();
|
{
|
||||||
}
|
public override BindingValidationError Validate(string value) => Ok();
|
||||||
|
}
|
||||||
[Command]
|
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Validators = new[] {typeof(MyValidator)})]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -85,15 +91,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -104,14 +112,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public string Foo { get; set; }
|
{
|
||||||
|
public string Foo { get; set; }
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -13,16 +13,18 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
{
|
||||||
{
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
Console.WriteLine(""Hello world"");
|
{
|
||||||
return default;
|
Console.WriteLine("Hello world");
|
||||||
}
|
return default;
|
||||||
}";
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -33,16 +35,19 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
{
|
||||||
{
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
Console.ForegroundColor = ConsoleColor.Black;
|
{
|
||||||
return default;
|
Console.ForegroundColor = ConsoleColor.Black;
|
||||||
}
|
return default;
|
||||||
}";
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
@@ -52,16 +57,18 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
{
|
||||||
{
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
Console.Error.WriteLine(""Hello world"");
|
{
|
||||||
return default;
|
Console.Error.WriteLine("Hello world");
|
||||||
}
|
return default;
|
||||||
}";
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().ProduceDiagnostics(code);
|
Analyzer.Should().ProduceDiagnostics(code);
|
||||||
@@ -72,16 +79,18 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
{
|
||||||
{
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
console.Output.WriteLine(""Hello world"");
|
{
|
||||||
return default;
|
console.Output.WriteLine("Hello world");
|
||||||
}
|
return default;
|
||||||
}";
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -92,14 +101,16 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public void SomeOtherMethod() => Console.WriteLine(""Test"");
|
{
|
||||||
|
public void SomeOtherMethod() => Console.WriteLine("Test");
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}";
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
@@ -110,15 +121,17 @@ public class MyCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
// language=cs
|
// language=cs
|
||||||
const string code = @"
|
const string code =
|
||||||
[Command]
|
"""
|
||||||
public class MyCommand : ICommand
|
[Command]
|
||||||
{
|
public class MyCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
{
|
||||||
{
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
return default;
|
{
|
||||||
}
|
return default;
|
||||||
}";
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] { ast },
|
new[] { ast },
|
||||||
ReferenceAssemblies.Net50
|
Net70.References.All
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
|
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
|
||||||
// DLL to avoid having to define the Main() method
|
// DLL to avoid having to define the Main() method
|
||||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||||
@@ -72,9 +72,10 @@ internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer,
|
|||||||
if (compilationErrors.Any())
|
if (compilationErrors.Any())
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Failed to compile code." +
|
$"""
|
||||||
Environment.NewLine +
|
Failed to compile code.
|
||||||
string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))
|
{string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))}
|
||||||
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,20 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
<Nullable>annotations</Nullable>
|
<GenerateDependencyFile>true</GenerateDependencyFile>
|
||||||
<NoWarn>$(NoWarn);RS1025;RS1026</NoWarn>
|
<NoWarn>$(NoWarn);RS1025;RS1026</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!--
|
||||||
|
Because this project only has a single target framework, the condition in
|
||||||
|
Directory.Build.props does not appear to work. This is a workaround for that.
|
||||||
|
-->
|
||||||
|
<Nullable>annotations</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- Keep this dependency as low as possible since we can't bundle it -->
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
|
||||||
<!-- https://github.com/Tyrrrz/CliFx/issues/127 -->
|
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -13,6 +13,8 @@ internal partial class CommandOptionSymbol : ICommandMemberSymbol
|
|||||||
|
|
||||||
public char? ShortName { get; }
|
public char? ShortName { get; }
|
||||||
|
|
||||||
|
public bool? IsRequired { get; }
|
||||||
|
|
||||||
public ITypeSymbol? ConverterType { get; }
|
public ITypeSymbol? ConverterType { get; }
|
||||||
|
|
||||||
public IReadOnlyList<ITypeSymbol> ValidatorTypes { get; }
|
public IReadOnlyList<ITypeSymbol> ValidatorTypes { get; }
|
||||||
@@ -21,12 +23,14 @@ internal partial class CommandOptionSymbol : ICommandMemberSymbol
|
|||||||
IPropertySymbol property,
|
IPropertySymbol property,
|
||||||
string? name,
|
string? name,
|
||||||
char? shortName,
|
char? shortName,
|
||||||
|
bool? isRequired,
|
||||||
ITypeSymbol? converterType,
|
ITypeSymbol? converterType,
|
||||||
IReadOnlyList<ITypeSymbol> validatorTypes)
|
IReadOnlyList<ITypeSymbol> validatorTypes)
|
||||||
{
|
{
|
||||||
Property = property;
|
Property = property;
|
||||||
Name = name;
|
Name = name;
|
||||||
ShortName = shortName;
|
ShortName = shortName;
|
||||||
|
IsRequired = isRequired;
|
||||||
ConverterType = converterType;
|
ConverterType = converterType;
|
||||||
ValidatorTypes = validatorTypes;
|
ValidatorTypes = validatorTypes;
|
||||||
}
|
}
|
||||||
@@ -56,6 +60,12 @@ internal partial class CommandOptionSymbol
|
|||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.FirstOrDefault() as char?;
|
.FirstOrDefault() as char?;
|
||||||
|
|
||||||
|
var isRequired = attribute
|
||||||
|
.NamedArguments
|
||||||
|
.Where(a => a.Key == "IsRequired")
|
||||||
|
.Select(a => a.Value.Value)
|
||||||
|
.FirstOrDefault() as bool?;
|
||||||
|
|
||||||
var converter = attribute
|
var converter = attribute
|
||||||
.NamedArguments
|
.NamedArguments
|
||||||
.Where(a => a.Key == "Converter")
|
.Where(a => a.Key == "Converter")
|
||||||
@@ -71,7 +81,7 @@ internal partial class CommandOptionSymbol
|
|||||||
.Cast<ITypeSymbol>()
|
.Cast<ITypeSymbol>()
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return new CommandOptionSymbol(property, name, shortName, converter, validators);
|
return new CommandOptionSymbol(property, name, shortName, isRequired, converter, validators);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsOptionProperty(IPropertySymbol property) =>
|
public static bool IsOptionProperty(IPropertySymbol property) =>
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using CliFx.Analyzers.ObjectModel;
|
||||||
|
using CliFx.Analyzers.Utils.Extensions;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
||||||
|
{
|
||||||
|
public OptionMustBeRequiredIfPropertyRequiredAnalyzer()
|
||||||
|
: base(
|
||||||
|
"Options bound to required properties cannot be marked as non-required",
|
||||||
|
"This option cannot be marked as non-required because it's bound to a required property.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Analyze(
|
||||||
|
SyntaxNodeAnalysisContext context,
|
||||||
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
|
IPropertySymbol property)
|
||||||
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!property.IsRequired)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
|
if (option is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (option.IsRequired != false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context.ReportDiagnostic(
|
||||||
|
CreateDiagnostic(
|
||||||
|
propertyDeclaration.Identifier.GetLocation()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(AnalysisContext context)
|
||||||
|
{
|
||||||
|
base.Initialize(context);
|
||||||
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using CliFx.Analyzers.ObjectModel;
|
||||||
|
using CliFx.Analyzers.Utils.Extensions;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustBeRequiredIfPropertyRequiredAnalyzer : AnalyzerBase
|
||||||
|
{
|
||||||
|
public ParameterMustBeRequiredIfPropertyRequiredAnalyzer()
|
||||||
|
: base(
|
||||||
|
"Parameters bound to required properties cannot be marked as non-required",
|
||||||
|
"This parameter cannot be marked as non-required because it's bound to a required property.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Analyze(
|
||||||
|
SyntaxNodeAnalysisContext context,
|
||||||
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
|
IPropertySymbol property)
|
||||||
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!property.IsRequired)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var parameter = CommandParameterSymbol.TryResolve(property);
|
||||||
|
if (parameter is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parameter.IsRequired != false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context.ReportDiagnostic(
|
||||||
|
CreateDiagnostic(
|
||||||
|
propertyDeclaration.Identifier.GetLocation()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(AnalysisContext context)
|
||||||
|
{
|
||||||
|
base.Initialize(context);
|
||||||
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
|
||||||
<PackageReference Include="clipr" Version="1.6.1" />
|
<PackageReference Include="clipr" Version="1.6.1" />
|
||||||
<PackageReference Include="Cocona" Version="2.0.3" />
|
<PackageReference Include="Cocona" Version="2.1.0" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.1" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.2" />
|
||||||
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
<PackageReference Include="PowerArgs" Version="4.0.0" />
|
||||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ public partial class BookAddCommand : ICommand
|
|||||||
private readonly LibraryProvider _libraryProvider;
|
private readonly LibraryProvider _libraryProvider;
|
||||||
|
|
||||||
[CommandParameter(0, Name = "title", Description = "Book title.")]
|
[CommandParameter(0, Name = "title", Description = "Book title.")]
|
||||||
public string Title { get; init; } = "";
|
public required string Title { get; init; }
|
||||||
|
|
||||||
[CommandOption("author", 'a', IsRequired = true, Description = "Book author.")]
|
[CommandOption("author", 'a', IsRequired = true, Description = "Book author.")]
|
||||||
public string Author { get; init; } = "";
|
public required string Author { get; init; }
|
||||||
|
|
||||||
[CommandOption("published", 'p', Description = "Book publish date.")]
|
[CommandOption("published", 'p', Description = "Book publish date.")]
|
||||||
public DateTimeOffset Published { get; init; } = CreateRandomDate();
|
public DateTimeOffset Published { get; init; } = CreateRandomDate();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class BookCommand : ICommand
|
|||||||
private readonly LibraryProvider _libraryProvider;
|
private readonly LibraryProvider _libraryProvider;
|
||||||
|
|
||||||
[CommandParameter(0, Name = "title", Description = "Title of the book to retrieve.")]
|
[CommandParameter(0, Name = "title", Description = "Title of the book to retrieve.")]
|
||||||
public string Title { get; init; } = "";
|
public required string Title { get; init; }
|
||||||
|
|
||||||
public BookCommand(LibraryProvider libraryProvider)
|
public BookCommand(LibraryProvider libraryProvider)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class BookRemoveCommand : ICommand
|
|||||||
private readonly LibraryProvider _libraryProvider;
|
private readonly LibraryProvider _libraryProvider;
|
||||||
|
|
||||||
[CommandParameter(0, Name = "title", Description = "Title of the book to remove.")]
|
[CommandParameter(0, Name = "title", Description = "Title of the book to remove.")]
|
||||||
public string Title { get; init; } = "";
|
public required string Title { get; init; }
|
||||||
|
|
||||||
public BookRemoveCommand(LibraryProvider libraryProvider)
|
public BookRemoveCommand(LibraryProvider libraryProvider)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Sample command line interface for managing a library of books.
|
Sample command line interface for managing a library of books.
|
||||||
|
|
||||||
This demo project showcases basic CliFx functionality such as command routing, argument parsing, autogenerated help text.
|
This demo project showcases basic CliFx functionality such as command routing, argument parsing, and autogenerated help text.
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -21,28 +21,30 @@ public class CancellationSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public async ValueTask ExecuteAsync(IConsole console)
|
public async ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(
|
await Task.Delay(
|
||||||
TimeSpan.FromSeconds(3),
|
TimeSpan.FromSeconds(3),
|
||||||
console.RegisterCancellationHandler()
|
console.RegisterCancellationHandler()
|
||||||
);
|
);
|
||||||
|
|
||||||
console.Output.WriteLine(""Completed successfully"");
|
console.Output.WriteLine("Completed successfully");
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Cancelled"");
|
console.Output.WriteLine("Cancelled");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -9,16 +9,16 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies" Version="1.2.4" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.1" />
|
||||||
<PackageReference Include="CliWrap" Version="3.4.4" />
|
<PackageReference Include="CliWrap" Version="3.5.0" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.7.0" />
|
<PackageReference Include="FluentAssertions" Version="6.8.0" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.0" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.0.1" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" PrivateAssets="all" />
|
||||||
<PackageReference Include="coverlet.collector" Version="3.1.2" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="3.2.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -26,12 +26,4 @@
|
|||||||
<ProjectReference Include="..\CliFx\CliFx.csproj" />
|
<ProjectReference Include="..\CliFx\CliFx.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="../CliFx.Tests.Dummy/bin/$(Configuration)/$(TargetFramework)/CliFx.Tests.Dummy.runtimeconfig.json">
|
|
||||||
<Link>CliFx.Tests.Dummy.runtimeconfig.json</Link>
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
<Visible>false</Visible>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -48,25 +48,28 @@ public class ConsoleSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.ResetColor();
|
console.ResetColor();
|
||||||
console.ForegroundColor = ConsoleColor.DarkMagenta;
|
console.ForegroundColor = ConsoleColor.DarkMagenta;
|
||||||
console.BackgroundColor = ConsoleColor.DarkMagenta;
|
console.BackgroundColor = ConsoleColor.DarkMagenta;
|
||||||
console.CursorLeft = 42;
|
console.WindowWidth = 100;
|
||||||
console.CursorTop = 24;
|
console.WindowHeight = 25;
|
||||||
|
console.CursorLeft = 42;
|
||||||
|
console.CursorTop = 24;
|
||||||
|
|
||||||
console.Output.WriteLine(""Hello "");
|
console.Output.WriteLine("Hello ");
|
||||||
console.Error.WriteLine(""world!"");
|
console.Error.WriteLine("world!");
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -90,6 +93,8 @@ public class Command : ICommand
|
|||||||
Console.BackgroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
Console.BackgroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
||||||
|
|
||||||
// This fails because tests don't spawn a console window
|
// This fails because tests don't spawn a console window
|
||||||
|
//Console.WindowWidth.Should().Be(100);
|
||||||
|
//Console.WindowHeight.Should().Be(25);
|
||||||
//Console.CursorLeft.Should().NotBe(42);
|
//Console.CursorLeft.Should().NotBe(42);
|
||||||
//Console.CursorTop.Should().NotBe(24);
|
//Console.CursorTop.Should().NotBe(24);
|
||||||
|
|
||||||
@@ -104,20 +109,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
var input = console.Input.ReadToEnd();
|
var input = console.Input.ReadToEnd();
|
||||||
console.Output.WriteLine(input);
|
console.Output.WriteLine(input);
|
||||||
console.Error.WriteLine(input);
|
console.Error.WriteLine(input);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -147,20 +153,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(console.ReadKey().Key);
|
console.Output.WriteLine(console.ReadKey().Key);
|
||||||
console.Output.WriteLine(console.ReadKey().Key);
|
console.Output.WriteLine(console.ReadKey().Key);
|
||||||
console.Output.WriteLine(console.ReadKey().Key);
|
console.Output.WriteLine(console.ReadKey().Key);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -21,20 +21,22 @@ public class ConversionSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -59,20 +61,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public object Foo { get; set; }
|
public object Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -97,25 +101,27 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public bool Foo { get; set; }
|
public bool Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public bool Bar { get; set; }
|
public bool Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -143,20 +149,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public bool Foo { get; set; }
|
public bool Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -181,20 +189,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public int Foo { get; set; }
|
public int Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -219,20 +229,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public double Foo { get; set; }
|
public double Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo.ToString(CultureInfo.InvariantCulture));
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo.ToString(CultureInfo.InvariantCulture));
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -257,20 +269,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public DateTimeOffset Foo { get; set; }
|
public DateTimeOffset Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo.ToString("u", CultureInfo.InvariantCulture));
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo.ToString(""u"", CultureInfo.InvariantCulture));
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -295,20 +309,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public TimeSpan Foo { get; set; }
|
public TimeSpan Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo.ToString(null, CultureInfo.InvariantCulture));
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo.ToString(null, CultureInfo.InvariantCulture));
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -333,22 +349,24 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One = 1, Two = 2, Three = 3 }
|
public enum CustomEnum { One = 1, Two = 2, Three = 3 }
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomEnum Foo { get; set; }
|
public CustomEnum Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine((int) Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine((int) Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -373,25 +391,27 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public int? Foo { get; set; }
|
public int? Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public int? Bar { get; set; }
|
public int? Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -419,27 +439,29 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One = 1, Two = 2, Three = 3 }
|
public enum CustomEnum { One = 1, Two = 2, Three = 3 }
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomEnum? Foo { get; set; }
|
public CustomEnum? Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public CustomEnum? Bar { get; set; }
|
public CustomEnum? Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + (int?) Foo);
|
console.Output.WriteLine("Foo = " + (int?) Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + (int?) Bar);
|
console.Output.WriteLine("Bar = " + (int?) Bar);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -467,27 +489,29 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomType
|
public class CustomType
|
||||||
{
|
{
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
|
|
||||||
public CustomType(string value) => Value = value;
|
public CustomType(string value) => Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomType Foo { get; set; }
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo.Value);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo.Value);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -512,45 +536,47 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomTypeA
|
public class CustomTypeA
|
||||||
{
|
{
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
|
|
||||||
private CustomTypeA(string value) => Value = value;
|
private CustomTypeA(string value) => Value = value;
|
||||||
|
|
||||||
public static CustomTypeA Parse(string value) =>
|
public static CustomTypeA Parse(string value) =>
|
||||||
new CustomTypeA(value);
|
new CustomTypeA(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomTypeB
|
public class CustomTypeB
|
||||||
{
|
{
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
|
|
||||||
private CustomTypeB(string value) => Value = value;
|
private CustomTypeB(string value) => Value = value;
|
||||||
|
|
||||||
public static CustomTypeB Parse(string value, IFormatProvider formatProvider) =>
|
public static CustomTypeB Parse(string value, IFormatProvider formatProvider) =>
|
||||||
new CustomTypeB(value);
|
new CustomTypeB(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomTypeA Foo { get; set; }
|
public CustomTypeA Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public CustomTypeB Bar { get; set; }
|
public CustomTypeB Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo.Value);
|
console.Output.WriteLine("Foo = " + Foo.Value);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar.Value);
|
console.Output.WriteLine("Bar = " + Bar.Value);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -578,26 +604,28 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomConverter : BindingConverter<int>
|
public class CustomConverter : BindingConverter<int>
|
||||||
{
|
{
|
||||||
public override int Convert(string rawValue) =>
|
public override int Convert(string rawValue) =>
|
||||||
rawValue.Length;
|
rawValue.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f', Converter = typeof(CustomConverter))]
|
[CommandOption('f', Converter = typeof(CustomConverter))]
|
||||||
public int Foo { get; set; }
|
public int Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
console.Output.WriteLine(Foo);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
|
||||||
{
|
|
||||||
console.Output.WriteLine(Foo);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -622,22 +650,24 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string[] Foo { get; set; }
|
public string[] Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -666,22 +696,24 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -710,22 +742,24 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public List<string> Foo { get; set; }
|
public List<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -754,22 +788,24 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public int[] Foo { get; set; }
|
public int[] Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -798,16 +834,18 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public int Foo { get; set; }
|
public int Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -832,18 +870,20 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomType {}
|
public class CustomType {}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomType Foo { get; set; }
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -868,23 +908,25 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomType : IEnumerable<object>
|
public class CustomType : IEnumerable<object>
|
||||||
{
|
{
|
||||||
public IEnumerator<object> GetEnumerator() => Enumerable.Empty<object>().GetEnumerator();
|
public IEnumerator<object> GetEnumerator() => Enumerable.Empty<object>().GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomType Foo { get; set; }
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -909,26 +951,28 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class ValidatorA : BindingValidator<int>
|
public class ValidatorA : BindingValidator<int>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ValidatorB : BindingValidator<int>
|
public class ValidatorB : BindingValidator<int>
|
||||||
{
|
{
|
||||||
public override BindingValidationError Validate(int value) => Error(""Hello world"");
|
public override BindingValidationError Validate(int value) => Error("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f', Validators = new[] {typeof(ValidatorA), typeof(ValidatorB)})]
|
[CommandOption('f', Validators = new[] {typeof(ValidatorA), typeof(ValidatorB)})]
|
||||||
public int Foo { get; set; }
|
public int Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
@@ -953,25 +997,27 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public class CustomType
|
public class CustomType
|
||||||
{
|
{
|
||||||
public string Value { get; }
|
public string Value { get; }
|
||||||
|
|
||||||
private CustomType(string value) => Value = value;
|
private CustomType(string value) => Value = value;
|
||||||
|
|
||||||
public static CustomType Parse(string value) => throw new Exception(""Hello world"");
|
public static CustomType Parse(string value) => throw new Exception("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public CustomType Foo { get; set; }
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
.UseConsole(FakeConsole)
|
.UseConsole(FakeConsole)
|
||||||
|
|||||||
@@ -75,13 +75,14 @@ public class DirectivesSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -25,20 +25,21 @@ public class EnvironmentSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", IsRequired = true, EnvironmentVariable = ""ENV_FOO"")]
|
[CommandOption("foo", IsRequired = true, EnvironmentVariable = "ENV_FOO")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -67,20 +68,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", EnvironmentVariable = ""ENV_FOO"")]
|
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -109,22 +111,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", EnvironmentVariable = ""ENV_FOO"")]
|
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -156,20 +159,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", EnvironmentVariable = ""ENV_FOO"")]
|
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -198,20 +202,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", EnvironmentVariable = ""ENV_FOO"")]
|
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -22,14 +22,15 @@ public class ErrorReportingSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) =>
|
public ValueTask ExecuteAsync(IConsole console) =>
|
||||||
throw new Exception(""Something went wrong"");
|
throw new Exception("Something went wrong");
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -60,14 +61,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) =>
|
public ValueTask ExecuteAsync(IConsole console) =>
|
||||||
throw new Exception(""Something went wrong"", new Exception(""Another exception""));
|
throw new Exception("Something went wrong", new Exception("Another exception"));
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -99,14 +101,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) =>
|
public ValueTask ExecuteAsync(IConsole console) =>
|
||||||
throw new CommandException(""Something went wrong"", 69);
|
throw new CommandException("Something went wrong", 69);
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -134,14 +137,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) =>
|
public ValueTask ExecuteAsync(IConsole console) =>
|
||||||
throw new CommandException("""", 69);
|
throw new CommandException("", 69);
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -172,14 +176,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) =>
|
public ValueTask ExecuteAsync(IConsole console) =>
|
||||||
throw new CommandException(""Something went wrong"", 69, true);
|
throw new CommandException("Something went wrong", 69, true);
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -44,13 +44,14 @@ public class HelpTextSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -77,19 +78,20 @@ public class DefaultCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"")]
|
[Command("cmd child")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -116,25 +118,26 @@ public class NamedChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd"", Description = ""Description of a named command."")]
|
[Command("cmd", Description = "Description of a named command.")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"")]
|
[Command("cmd child")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -160,25 +163,26 @@ public class NamedChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"", Description = ""Description of a named child command."")]
|
[Command("cmd child", Description = "Description of a named child command.")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -257,13 +261,15 @@ public class NamedChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(Description = ""Description of the default command."")]
|
|
||||||
public class DefaultCommand : ICommand
|
[Command(Description = "Description of the default command.")]
|
||||||
{
|
public class DefaultCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
");
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -292,19 +298,21 @@ public class DefaultCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
|
||||||
public class DefaultCommand : ICommand
|
[Command]
|
||||||
{
|
public class DefaultCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd")]
|
||||||
|
public class NamedCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(""cmd"")]
|
""");
|
||||||
public class NamedCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -333,22 +341,24 @@ public class NamedCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
|
||||||
public class Command : ICommand
|
[Command]
|
||||||
{
|
public class Command : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
|
|
||||||
|
[CommandParameter(2)]
|
||||||
|
public IReadOnlyList<string> Baz { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandParameter(1)]
|
""");
|
||||||
public string Bar { get; set; }
|
|
||||||
|
|
||||||
[CommandParameter(2)]
|
|
||||||
public IReadOnlyList<string> Baz { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -378,28 +388,30 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
// Base members appear last in reflection order
|
|
||||||
public abstract class CommandBase : ICommand
|
// Base members appear last in reflection order
|
||||||
{
|
public abstract class CommandBase : ICommand
|
||||||
[CommandParameter(0)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
public abstract ValueTask ExecuteAsync(IConsole console);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : CommandBase
|
||||||
|
{
|
||||||
|
[CommandParameter(2)]
|
||||||
|
public IReadOnlyList<string> Baz { get; set; }
|
||||||
|
|
||||||
|
[CommandParameter(1)]
|
||||||
|
public string Bar { get; set; }
|
||||||
|
|
||||||
|
public override ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract ValueTask ExecuteAsync(IConsole console);
|
""");
|
||||||
}
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
public class Command : CommandBase
|
|
||||||
{
|
|
||||||
[CommandParameter(2)]
|
|
||||||
public IReadOnlyList<string> Baz { get; set; }
|
|
||||||
|
|
||||||
[CommandParameter(1)]
|
|
||||||
public string Bar { get; set; }
|
|
||||||
|
|
||||||
public override ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -428,22 +440,24 @@ public class Command : CommandBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
|
||||||
public class Command : ICommand
|
[Command]
|
||||||
{
|
public class Command : ICommand
|
||||||
[CommandOption(""foo"", IsRequired = true)]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandOption("foo", IsRequired = true)]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar")]
|
||||||
|
public string Bar { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("baz", IsRequired = true)]
|
||||||
|
public IReadOnlyList<string> Baz { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
""");
|
||||||
public string Bar { get; set; }
|
|
||||||
|
|
||||||
[CommandOption(""baz"", IsRequired = true)]
|
|
||||||
public IReadOnlyList<string> Baz { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -472,19 +486,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
|
||||||
public class Command : ICommand
|
[Command]
|
||||||
{
|
public class Command : ICommand
|
||||||
[CommandParameter(0, Name = ""foo"", Description = ""Description of foo."")]
|
{
|
||||||
public string Foo { get; set; }
|
[CommandParameter(0, Name = "foo", Description = "Description of foo.")]
|
||||||
|
public string Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar", Description = "Description of bar.")]
|
||||||
|
public string Bar { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandOption(""bar"", Description = ""Description of bar."")]
|
""");
|
||||||
public string Bar { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -515,13 +531,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
|
||||||
public class Command : ICommand
|
[Command]
|
||||||
{
|
public class Command : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
");
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -551,13 +569,15 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd"")]
|
|
||||||
public class Command : ICommand
|
[Command("cmd")]
|
||||||
{
|
public class Command : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
");
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -589,21 +609,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One, Two, Three }
|
|
||||||
|
public enum CustomEnum { One, Two, Three }
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0)]
|
||||||
|
public CustomEnum Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar")]
|
||||||
|
public CustomEnum Bar { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
""");
|
||||||
public class Command : ICommand
|
|
||||||
{
|
|
||||||
[CommandParameter(0)]
|
|
||||||
public CustomEnum Foo { get; set; }
|
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public CustomEnum Bar { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -634,21 +656,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One, Two, Three }
|
|
||||||
|
public enum CustomEnum { One, Two, Three }
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0)]
|
||||||
|
public IReadOnlyList<CustomEnum> Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar")]
|
||||||
|
public IReadOnlyList<CustomEnum> Bar { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
""");
|
||||||
public class Command : ICommand
|
|
||||||
{
|
|
||||||
[CommandParameter(0)]
|
|
||||||
public IReadOnlyList<CustomEnum> Foo { get; set; }
|
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public IReadOnlyList<CustomEnum> Bar { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -679,21 +703,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One, Two, Three }
|
|
||||||
|
public enum CustomEnum { One, Two, Three }
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandParameter(0)]
|
||||||
|
public CustomEnum? Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar")]
|
||||||
|
public IReadOnlyList<CustomEnum?> Bar { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
""");
|
||||||
public class Command : ICommand
|
|
||||||
{
|
|
||||||
[CommandParameter(0)]
|
|
||||||
public CustomEnum? Foo { get; set; }
|
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public IReadOnlyList<CustomEnum?> Bar { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -724,21 +750,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One, Two, Three }
|
|
||||||
|
public enum CustomEnum { One, Two, Three }
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
|
||||||
|
public CustomEnum Foo { get; set; }
|
||||||
|
|
||||||
|
[CommandOption("bar", EnvironmentVariable = "ENV_BAR")]
|
||||||
|
public CustomEnum Bar { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
""");
|
||||||
public class Command : ICommand
|
|
||||||
{
|
|
||||||
[CommandOption(""foo"", EnvironmentVariable = ""ENV_FOO"")]
|
|
||||||
public CustomEnum Foo { get; set; }
|
|
||||||
|
|
||||||
[CommandOption(""bar"", EnvironmentVariable = ""ENV_BAR"")]
|
|
||||||
public CustomEnum Bar { get; set; }
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -768,39 +796,41 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public enum CustomEnum { One, Two, Three }
|
|
||||||
|
public enum CustomEnum { One, Two, Three }
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption("foo")]
|
||||||
|
public object Foo { get; set; } = 42;
|
||||||
|
|
||||||
|
[CommandOption("bar")]
|
||||||
|
public string Bar { get; set; } = "hello";
|
||||||
|
|
||||||
|
[CommandOption("baz")]
|
||||||
|
public IReadOnlyList<string> Baz { get; set; } = new[] {"one", "two", "three"};
|
||||||
|
|
||||||
|
[CommandOption("qwe")]
|
||||||
|
public bool Qwe { get; set; } = true;
|
||||||
|
|
||||||
|
[CommandOption("qop")]
|
||||||
|
public int? Qop { get; set; } = 1337;
|
||||||
|
|
||||||
|
[CommandOption("zor")]
|
||||||
|
public TimeSpan Zor { get; set; } = TimeSpan.FromMinutes(123);
|
||||||
|
|
||||||
|
[CommandOption("lol")]
|
||||||
|
public CustomEnum Lol { get; set; } = CustomEnum.Two;
|
||||||
|
|
||||||
|
[CommandOption("hmm", IsRequired = true)]
|
||||||
|
public string Hmm { get; set; } = "not printed";
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
""");
|
||||||
public class Command : ICommand
|
|
||||||
{
|
|
||||||
[CommandOption(""foo"")]
|
|
||||||
public object Foo { get; set; } = 42;
|
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
|
||||||
public string Bar { get; set; } = ""hello"";
|
|
||||||
|
|
||||||
[CommandOption(""baz"")]
|
|
||||||
public IReadOnlyList<string> Baz { get; set; } = new[] {""one"", ""two"", ""three""};
|
|
||||||
|
|
||||||
[CommandOption(""qwe"")]
|
|
||||||
public bool Qwe { get; set; } = true;
|
|
||||||
|
|
||||||
[CommandOption(""qop"")]
|
|
||||||
public int? Qop { get; set; } = 1337;
|
|
||||||
|
|
||||||
[CommandOption(""zor"")]
|
|
||||||
public TimeSpan Zor { get; set; } = TimeSpan.FromMinutes(123);
|
|
||||||
|
|
||||||
[CommandOption(""lol"")]
|
|
||||||
public CustomEnum Lol { get; set; } = CustomEnum.Two;
|
|
||||||
|
|
||||||
[CommandOption(""hmm"", IsRequired = true)]
|
|
||||||
public string Hmm { get; set; } = ""not printed"";
|
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -836,25 +866,27 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd1"", Description = ""Description of one command."")]
|
|
||||||
public class FirstCommand : ICommand
|
[Command("cmd1", Description = "Description of one command.")]
|
||||||
{
|
public class FirstCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2", Description = "Description of another command.")]
|
||||||
|
public class SecondCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2 child", Description = "Description of another command's child command.")]
|
||||||
|
public class SecondCommandChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(""cmd2"", Description = ""Description of another command."")]
|
""");
|
||||||
public class SecondCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(""cmd2 child"", Description = ""Description of another command's child command."")]
|
|
||||||
public class SecondCommandChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -890,37 +922,39 @@ public class SecondCommandChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd1"")]
|
|
||||||
public class FirstCommand : ICommand
|
[Command("cmd1")]
|
||||||
{
|
public class FirstCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd1 child1")]
|
||||||
|
public class FirstCommandFirstChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2")]
|
||||||
|
public class SecondCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2 child11")]
|
||||||
|
public class SecondCommandFirstChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2 child2")]
|
||||||
|
public class SecondCommandSecondChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(""cmd1 child1"")]
|
""");
|
||||||
public class FirstCommandFirstChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(""cmd2"")]
|
|
||||||
public class SecondCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(""cmd2 child11"")]
|
|
||||||
public class SecondCommandFirstChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(""cmd2 child2"")]
|
|
||||||
public class SecondCommandSecondChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -950,25 +984,27 @@ public class SecondCommandSecondChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command(""cmd1"")]
|
|
||||||
public class FirstCommand : ICommand
|
[Command("cmd1")]
|
||||||
{
|
public class FirstCommand : ICommand
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
{
|
||||||
}
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2 child1")]
|
||||||
|
public class SecondCommandFirstChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("cmd2 child2")]
|
||||||
|
public class SecondCommandSecondChildCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(""cmd2 child1"")]
|
""");
|
||||||
public class SecondCommandFirstChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command(""cmd2 child2"")]
|
|
||||||
public class SecondCommandSecondChildCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
|
||||||
}
|
|
||||||
");
|
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
|
|||||||
@@ -22,19 +22,21 @@ public class OptionBindingSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public bool Foo { get; set; }
|
public bool Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -60,19 +62,21 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public bool Foo { get; set; }
|
public bool Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -98,24 +102,26 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
[CommandOption("bar")]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -144,24 +150,26 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -190,24 +198,26 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -236,21 +246,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""Foo"")]
|
[CommandOption("Foo")]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -280,21 +292,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -324,21 +338,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -368,21 +384,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -412,21 +430,23 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", 'f')]
|
[CommandOption("foo", 'f')]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
foreach (var i in Foo)
|
foreach (var i in Foo)
|
||||||
console.Output.WriteLine(i);
|
console.Output.WriteLine(i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -456,24 +476,26 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandOption(""bar"")]
|
[CommandOption("bar")]
|
||||||
public string Bar { get; set; } = ""hello"";
|
public string Bar { get; set; } = "hello";
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -502,55 +524,56 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
public static class SharedContext
|
public static class SharedContext
|
||||||
{
|
{
|
||||||
public static int Foo { get; set; }
|
public static int Foo { get; set; }
|
||||||
|
|
||||||
public static bool Bar { get; set; }
|
public static bool Bar { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHasFoo : ICommand
|
public interface IHasFoo : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public int Foo
|
public int Foo
|
||||||
{
|
{
|
||||||
get => SharedContext.Foo;
|
get => SharedContext.Foo;
|
||||||
set => SharedContext.Foo = value;
|
set => SharedContext.Foo = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHasBar : ICommand
|
public interface IHasBar : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""bar"")]
|
[CommandOption("bar")]
|
||||||
public bool Bar
|
public bool Bar
|
||||||
{
|
{
|
||||||
get => SharedContext.Bar;
|
get => SharedContext.Bar;
|
||||||
set => SharedContext.Bar = value;
|
set => SharedContext.Bar = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHasBaz : ICommand
|
public interface IHasBaz : ICommand
|
||||||
{
|
{
|
||||||
public string Baz { get; set; }
|
public string Baz { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : IHasFoo, IHasBar, IHasBaz
|
public class Command : IHasFoo, IHasBar, IHasBaz
|
||||||
{
|
{
|
||||||
[CommandOption(""baz"")]
|
[CommandOption("baz")]
|
||||||
public string Baz { get; set; }
|
public string Baz { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + SharedContext.Foo);
|
console.Output.WriteLine("Foo = " + SharedContext.Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + SharedContext.Bar);
|
console.Output.WriteLine("Bar = " + SharedContext.Bar);
|
||||||
console.Output.WriteLine(""Baz = "" + Baz);
|
console.Output.WriteLine("Baz = " + Baz);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -579,20 +602,22 @@ public class Command : IHasFoo, IHasBar, IHasBaz
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(Foo);
|
console.Output.WriteLine(Foo);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -618,15 +643,17 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", IsRequired = true)]
|
[CommandOption("foo", IsRequired = true)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -652,15 +679,17 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", IsRequired = true)]
|
[CommandOption("foo", IsRequired = true)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -686,15 +715,17 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"", IsRequired = true)]
|
[CommandOption("foo", IsRequired = true)]
|
||||||
public IReadOnlyList<string> Foo { get; set; }
|
public IReadOnlyList<string> Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -720,15 +751,17 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -754,15 +787,17 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption(""foo"")]
|
[CommandOption("foo")]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -781,4 +816,40 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
stdErr.Should().Contain("expects a single argument, but provided with multiple");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Option_binding_fails_if_a_required_property_option_has_not_been_provided()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
"""
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption("foo")]
|
||||||
|
public required string Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
Array.Empty<string>(),
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().NotBe(0);
|
||||||
|
stdErr.Should().Contain("Missing required option(s)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -21,24 +21,26 @@ public class ParameterBindingSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1)]
|
[CommandParameter(1)]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -67,33 +69,35 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1)]
|
[CommandParameter(1)]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
[CommandParameter(2)]
|
[CommandParameter(2)]
|
||||||
public IReadOnlyList<string> Baz { get; set; }
|
public IReadOnlyList<string> Baz { get; set; }
|
||||||
|
|
||||||
[CommandOption(""boo"")]
|
[CommandOption("boo")]
|
||||||
public string Boo { get; set; }
|
public string Boo { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
foreach (var i in Baz)
|
foreach (var i in Baz)
|
||||||
console.Output.WriteLine(""Baz = "" + i);
|
console.Output.WriteLine("Baz = " + i);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -125,24 +129,26 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1, IsRequired = false)]
|
[CommandParameter(1, IsRequired = false)]
|
||||||
public string Bar { get; set; } = ""xyz"";
|
public string Bar { get; set; } = "xyz";
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""Foo = "" + Foo);
|
console.Output.WriteLine("Foo = " + Foo);
|
||||||
console.Output.WriteLine(""Bar = "" + Bar);
|
console.Output.WriteLine("Bar = " + Bar);
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -171,18 +177,20 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1)]
|
[CommandParameter(1)]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -208,18 +216,20 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1)]
|
[CommandParameter(1)]
|
||||||
public IReadOnlyList<string> Bar { get; set; }
|
public IReadOnlyList<string> Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -245,18 +255,20 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
[CommandParameter(0)]
|
[CommandParameter(0)]
|
||||||
public string Foo { get; set; }
|
public string Foo { get; set; }
|
||||||
|
|
||||||
[CommandParameter(1)]
|
[CommandParameter(1)]
|
||||||
public string Bar { get; set; }
|
public string Bar { get; set; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -21,37 +21,38 @@ public class RoutingSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""default"");
|
console.Output.WriteLine("default");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd"");
|
console.Output.WriteLine("cmd");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"")]
|
[Command("cmd child")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd child"");
|
console.Output.WriteLine("cmd child");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -77,37 +78,38 @@ public class NamedChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""default"");
|
console.Output.WriteLine("default");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd"");
|
console.Output.WriteLine("cmd");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"")]
|
[Command("cmd child")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd child"");
|
console.Output.WriteLine("cmd child");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
@@ -133,37 +135,38 @@ public class NamedChildCommand : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandTypes = DynamicCommandBuilder.CompileMany(
|
var commandTypes = DynamicCommandBuilder.CompileMany(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class DefaultCommand : ICommand
|
public class DefaultCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""default"");
|
console.Output.WriteLine("default");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd"")]
|
[Command("cmd")]
|
||||||
public class NamedCommand : ICommand
|
public class NamedCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd"");
|
console.Output.WriteLine("cmd");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(""cmd child"")]
|
[Command("cmd child")]
|
||||||
public class NamedChildCommand : ICommand
|
public class NamedChildCommand : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""cmd child"");
|
console.Output.WriteLine("cmd child");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
");
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommands(commandTypes)
|
.AddCommands(commandTypes)
|
||||||
|
|||||||
@@ -23,16 +23,18 @@ public class TypeActivationSpecs : SpecsBase
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""foo"");
|
console.Output.WriteLine("foo");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -59,14 +61,16 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public Command(string foo) {}
|
public Command(string foo) {}
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -93,20 +97,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
private readonly string _foo;
|
private readonly string _foo;
|
||||||
|
|
||||||
public Command(string foo) => _foo = foo;
|
public Command(string foo) => _foo = foo;
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(_foo);
|
console.Output.WriteLine(_foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
@@ -133,20 +139,22 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
private readonly string _foo;
|
private readonly string _foo;
|
||||||
|
|
||||||
public Command(string foo) => _foo = foo;
|
public Command(string foo) => _foo = foo;
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(_foo);
|
console.Output.WriteLine(_foo);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var serviceProvider = new ServiceCollection()
|
var serviceProvider = new ServiceCollection()
|
||||||
.AddSingleton(commandType, Activator.CreateInstance(commandType, "Hello world")!)
|
.AddSingleton(commandType, Activator.CreateInstance(commandType, "Hello world")!)
|
||||||
@@ -177,16 +185,18 @@ public class Command : ICommand
|
|||||||
// Arrange
|
// Arrange
|
||||||
var commandType = DynamicCommandBuilder.Compile(
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
// language=cs
|
// language=cs
|
||||||
@"
|
"""
|
||||||
[Command]
|
[Command]
|
||||||
public class Command : ICommand
|
public class Command : ICommand
|
||||||
{
|
{
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
console.Output.WriteLine(""foo"");
|
console.Output.WriteLine("foo");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}");
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
var application = new CliApplicationBuilder()
|
var application = new CliApplicationBuilder()
|
||||||
.AddCommand(commandType)
|
.AddCommand(commandType)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ internal static class DynamicCommandBuilder
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] {ast},
|
new[] {ast},
|
||||||
ReferenceAssemblies.Net50
|
Net70.References.All
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(DynamicCommandBuilder).Assembly.Location)),
|
.Append(MetadataReference.CreateFromFile(typeof(DynamicCommandBuilder).Assembly.Location)),
|
||||||
// DLL to avoid having to define the Main() method
|
// DLL to avoid having to define the Main() method
|
||||||
@@ -76,9 +76,10 @@ internal static class DynamicCommandBuilder
|
|||||||
if (compilationErrors.Any())
|
if (compilationErrors.Any())
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Failed to compile code." +
|
$"""
|
||||||
Environment.NewLine +
|
Failed to compile code.
|
||||||
string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))
|
{string.Join(Environment.NewLine, compilationErrors.Select(e => e.ToString()))}
|
||||||
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +95,10 @@ internal static class DynamicCommandBuilder
|
|||||||
if (emitErrors.Any())
|
if (emitErrors.Any())
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Failed to emit code." +
|
$"""
|
||||||
Environment.NewLine +
|
Failed to emit code.
|
||||||
string.Join(Environment.NewLine, emitErrors.Select(e => e.ToString()))
|
{string.Join(Environment.NewLine, emitErrors.Select(e => e.ToString()))}
|
||||||
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class ApplicationConfiguration
|
|||||||
public bool IsPreviewModeAllowed { get; }
|
public bool IsPreviewModeAllowed { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="ApplicationConfiguration"/>.
|
/// Initializes an instance of <see cref="ApplicationConfiguration" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ApplicationConfiguration(
|
public ApplicationConfiguration(
|
||||||
IReadOnlyList<Type> commandTypes,
|
IReadOnlyList<Type> commandTypes,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class ApplicationMetadata
|
|||||||
public string? Description { get; }
|
public string? Description { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="ApplicationMetadata"/>.
|
/// Initializes an instance of <see cref="ApplicationMetadata" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ApplicationMetadata(
|
public ApplicationMetadata(
|
||||||
string title,
|
string title,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public sealed class CommandAttribute : Attribute
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandAttribute"/>.
|
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandAttribute(string name)
|
public CommandAttribute(string name)
|
||||||
{
|
{
|
||||||
@@ -34,7 +34,7 @@ public sealed class CommandAttribute : Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandAttribute"/>.
|
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandAttribute()
|
public CommandAttribute()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Must contain at least two characters and start with a letter.
|
/// Must contain at least two characters and start with a letter.
|
||||||
/// Either <see cref="Name"/> or <see cref="ShortName"/> must be set.
|
/// Either <see cref="Name" /> or <see cref="ShortName" /> must be set.
|
||||||
/// All options in a command must have unique names (comparison IS NOT case-sensitive).
|
/// All options in a command must have unique names (comparison IS NOT case-sensitive).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public string? Name { get; }
|
public string? Name { get; }
|
||||||
@@ -23,7 +23,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
/// Option short name.
|
/// Option short name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Either <see cref="Name"/> or <see cref="ShortName"/> must be set.
|
/// Either <see cref="Name" /> or <see cref="ShortName" /> must be set.
|
||||||
/// All options in a command must have unique short names (comparison IS case-sensitive).
|
/// All options in a command must have unique short names (comparison IS case-sensitive).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public char? ShortName { get; }
|
public char? ShortName { get; }
|
||||||
@@ -32,6 +32,10 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
/// Whether this option is required (default: <c>false</c>).
|
/// Whether this option is required (default: <c>false</c>).
|
||||||
/// If an option is required, the user will get an error if they don't set it.
|
/// If an option is required, the user will get an error if they don't set it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You can use the <c>required</c> keyword on the property (introduced in C# 11) to implicitly
|
||||||
|
/// set <see cref="IsRequired" /> to <c>true</c>.
|
||||||
|
/// </remarks>
|
||||||
public bool IsRequired { get; set; }
|
public bool IsRequired { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,7 +55,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
/// a value expected by the underlying property.
|
/// a value expected by the underlying property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Converter must derive from <see cref="BindingConverter{T}"/>.
|
/// Converter must derive from <see cref="BindingConverter{T}" />.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public Type? Converter { get; set; }
|
public Type? Converter { get; set; }
|
||||||
|
|
||||||
@@ -60,12 +64,12 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
/// property, after it has been bound.
|
/// property, after it has been bound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 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>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
|
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CommandOptionAttribute(string? name, char? shortName)
|
private CommandOptionAttribute(string? name, char? shortName)
|
||||||
{
|
{
|
||||||
@@ -74,7 +78,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
|
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandOptionAttribute(string name, char shortName)
|
public CommandOptionAttribute(string name, char shortName)
|
||||||
: this(name, (char?) shortName)
|
: this(name, (char?) shortName)
|
||||||
@@ -82,7 +86,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
|
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandOptionAttribute(string name)
|
public CommandOptionAttribute(string name)
|
||||||
: this(name, null)
|
: this(name, null)
|
||||||
@@ -90,7 +94,7 @@ public sealed class CommandOptionAttribute : Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandOptionAttribute"/>.
|
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandOptionAttribute(char shortName)
|
public CommandOptionAttribute(char shortName)
|
||||||
: this(null, (char?) shortName)
|
: this(null, (char?) shortName)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public sealed class CommandParameterAttribute : Attribute
|
|||||||
/// a value expected by the underlying property.
|
/// a value expected by the underlying property.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Converter must derive from <see cref="BindingConverter{T}"/>.
|
/// Converter must derive from <see cref="BindingConverter{T}" />.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public Type? Converter { get; set; }
|
public Type? Converter { get; set; }
|
||||||
|
|
||||||
@@ -60,12 +60,12 @@ public sealed class CommandParameterAttribute : Attribute
|
|||||||
/// property, after it has been bound.
|
/// property, after it has been bound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 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>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandParameterAttribute"/>.
|
/// Initializes an instance of <see cref="CommandParameterAttribute" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandParameterAttribute(int order)
|
public CommandParameterAttribute(int order)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class CliApplication
|
|||||||
private readonly CommandBinder _commandBinder;
|
private readonly CommandBinder _commandBinder;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CliApplication"/>.
|
/// Initializes an instance of <see cref="CliApplication" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliApplication(
|
public CliApplication(
|
||||||
ApplicationMetadata metadata,
|
ApplicationMetadata metadata,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using CliFx.Utils.Extensions;
|
|||||||
namespace CliFx;
|
namespace CliFx;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builder for <see cref="CliApplication"/>.
|
/// Builder for <see cref="CliApplication" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class CliApplicationBuilder
|
public partial class CliApplicationBuilder
|
||||||
{
|
{
|
||||||
@@ -58,8 +58,8 @@ public partial class CliApplicationBuilder
|
|||||||
/// Adds commands from the specified assembly to the application.
|
/// Adds commands from the specified assembly to the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method looks for public non-abstract classes that implement <see cref="ICommand"/>
|
/// This method looks for public non-abstract classes that implement <see cref="ICommand" />
|
||||||
/// and are annotated by <see cref="CommandAttribute"/>.
|
/// and are annotated by <see cref="CommandAttribute" />.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public CliApplicationBuilder AddCommandsFrom(Assembly commandAssembly)
|
public CliApplicationBuilder AddCommandsFrom(Assembly commandAssembly)
|
||||||
{
|
{
|
||||||
@@ -73,8 +73,8 @@ public partial class CliApplicationBuilder
|
|||||||
/// Adds commands from the specified assemblies to the application.
|
/// Adds commands from the specified assemblies to the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method looks for public non-abstract classes that implement <see cref="ICommand"/>
|
/// This method looks for public non-abstract classes that implement <see cref="ICommand" />
|
||||||
/// and are annotated by <see cref="CommandAttribute"/>.
|
/// and are annotated by <see cref="CommandAttribute" />.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public CliApplicationBuilder AddCommandsFrom(IEnumerable<Assembly> commandAssemblies)
|
public CliApplicationBuilder AddCommandsFrom(IEnumerable<Assembly> commandAssemblies)
|
||||||
{
|
{
|
||||||
@@ -88,8 +88,8 @@ public partial class CliApplicationBuilder
|
|||||||
/// Adds commands from the calling assembly to the application.
|
/// Adds commands from the calling assembly to the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method looks for public non-abstract classes that implement <see cref="ICommand"/>
|
/// This method looks for public non-abstract classes that implement <see cref="ICommand" />
|
||||||
/// and are annotated by <see cref="CommandAttribute"/>.
|
/// and are annotated by <see cref="CommandAttribute" />.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public CliApplicationBuilder AddCommandsFromThisAssembly() => AddCommandsFrom(Assembly.GetCallingAssembly());
|
public CliApplicationBuilder AddCommandsFromThisAssembly() => AddCommandsFrom(Assembly.GetCallingAssembly());
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ public partial class CliApplicationBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the application to use the specified implementation of <see cref="IConsole"/>.
|
/// Configures the application to use the specified implementation of <see cref="IConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliApplicationBuilder UseConsole(IConsole console)
|
public CliApplicationBuilder UseConsole(IConsole console)
|
||||||
{
|
{
|
||||||
@@ -168,7 +168,7 @@ public partial class CliApplicationBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the application to use the specified implementation of <see cref="ITypeActivator"/>.
|
/// Configures the application to use the specified implementation of <see cref="ITypeActivator" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliApplicationBuilder UseTypeActivator(ITypeActivator typeActivator)
|
public CliApplicationBuilder UseTypeActivator(ITypeActivator typeActivator)
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ public partial class CliApplicationBuilder
|
|||||||
UseTypeActivator(serviceProvider.GetService);
|
UseTypeActivator(serviceProvider.GetService);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a configured instance of <see cref="CliApplication"/>.
|
/// Creates a configured instance of <see cref="CliApplication" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliApplication Build()
|
public CliApplication Build()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.1;netstandard2.0</TargetFrameworks>
|
||||||
|
<IsPackable>true</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
<Authors>$(Company)</Authors>
|
<Authors>$(Company)</Authors>
|
||||||
<Description>Declarative framework for building command line applications</Description>
|
<Description>Declarative framework for building command line applications</Description>
|
||||||
<IsPackable>true</IsPackable>
|
|
||||||
<PackageTags>command line executable interface framework parser arguments cli app application net core</PackageTags>
|
<PackageTags>command line executable interface framework parser arguments cli app application net core</PackageTags>
|
||||||
<PackageProjectUrl>https://github.com/Tyrrrz/CliFx</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Tyrrrz/CliFx</PackageProjectUrl>
|
||||||
<PackageReleaseNotes>https://github.com/Tyrrrz/CliFx/blob/master/Changelog.md</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/Tyrrrz/CliFx/blob/master/Changelog.md</PackageReleaseNotes>
|
||||||
@@ -24,16 +27,17 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
|
||||||
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />
|
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Pack the analyzer assembly inside the package -->
|
<!-- Embed the analyzer inside the package -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../CliFx.Analyzers/CliFx.Analyzers.csproj" ReferenceOutputAssembly="false" OutputItemType="analyzer" />
|
<ProjectReference Include="../CliFx.Analyzers/CliFx.Analyzers.csproj" ReferenceOutputAssembly="false" OutputItemType="analyzer" />
|
||||||
|
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/CliFx.Analyzers.deps.json" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/CliFx.Analyzers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/CliFx.Analyzers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/System.Buffers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/System.Buffers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/System.Collections.Immutable.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
<None Include="../CliFx.Analyzers/bin/$(Configuration)/netstandard2.0/System.Collections.Immutable.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
|||||||
@@ -99,11 +99,11 @@ internal class CommandBinder
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw CliFxException.InternalError(
|
throw CliFxException.InternalError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type." +
|
$"""
|
||||||
Environment.NewLine +
|
{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
|
||||||
$"There is no known way to convert a string value into an instance of type `{targetType.FullName}`." +
|
There is no known way to convert a string value into an instance of type `{targetType.FullName}`
|
||||||
Environment.NewLine +
|
To fix this, either change the property to use a supported type or configure a custom converter.
|
||||||
"To fix this, either change the property to use a supported type or configure a custom converter."
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,11 +133,11 @@ internal class CommandBinder
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw CliFxException.InternalError(
|
throw CliFxException.InternalError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type." +
|
$"""
|
||||||
Environment.NewLine +
|
{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has an unsupported underlying property type.
|
||||||
$"There is no known way to convert an array of `{targetElementType.FullName}` into an instance of type `{targetEnumerableType.FullName}`." +
|
There is no known way to convert an array of `{targetElementType.FullName}` into an instance of type `{targetEnumerableType.FullName}`.
|
||||||
Environment.NewLine +
|
To fix this, change the property to use a type which can be assigned from an array or a type that has a constructor which accepts an array.
|
||||||
"To fix this, change the property to use a type which can be assigned from an array or a type that has a constructor which accepts an array."
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,20 +169,21 @@ internal class CommandBinder
|
|||||||
: ex.Message;
|
: ex.Message;
|
||||||
|
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from the provided argument(s):" +
|
$"""
|
||||||
Environment.NewLine +
|
{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from the provided argument(s):
|
||||||
rawValues.Select(v => '<' + v + '>').JoinToString(" ") +
|
{rawValues.Select(v => '<' + v + '>').JoinToString(" ")}
|
||||||
Environment.NewLine +
|
Error: {errorMessage}
|
||||||
$"Error: {errorMessage}",
|
""",
|
||||||
ex
|
ex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mismatch (scalar but too many values)
|
// Mismatch (scalar but too many values)
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} expects a single argument, but provided with multiple:" +
|
$"""
|
||||||
Environment.NewLine +
|
{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} expects a single argument, but provided with multiple:
|
||||||
rawValues.Select(v => '<' + v + '>').JoinToString(" ")
|
{rawValues.Select(v => '<' + v + '>').JoinToString(" ")}
|
||||||
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,11 +203,11 @@ internal class CommandBinder
|
|||||||
if (errors.Any())
|
if (errors.Any())
|
||||||
{
|
{
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has been provided with an invalid value." +
|
$"""
|
||||||
Environment.NewLine +
|
{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has been provided with an invalid value.
|
||||||
"Error(s):" +
|
Error(s):
|
||||||
Environment.NewLine +
|
{errors.Select(e => "- " + e.Message).JoinToString(Environment.NewLine)}
|
||||||
errors.Select(e => "- " + e.Message).JoinToString(Environment.NewLine)
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,22 +265,20 @@ internal class CommandBinder
|
|||||||
if (remainingParameterInputs.Any())
|
if (remainingParameterInputs.Any())
|
||||||
{
|
{
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
"Unexpected parameter(s):" +
|
$"""
|
||||||
Environment.NewLine +
|
Unexpected parameter(s):
|
||||||
remainingParameterInputs
|
{remainingParameterInputs.Select(p => p.GetFormattedIdentifier()).JoinToString(" ")}
|
||||||
.Select(p => p.GetFormattedIdentifier())
|
"""
|
||||||
.JoinToString(" ")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingRequiredParameterSchemas.Any())
|
if (remainingRequiredParameterSchemas.Any())
|
||||||
{
|
{
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
"Missing required parameter(s):" +
|
$"""
|
||||||
Environment.NewLine +
|
Missing required parameter(s):
|
||||||
remainingRequiredParameterSchemas
|
{remainingRequiredParameterSchemas.Select(p => p.GetFormattedIdentifier()).JoinToString(" ")}
|
||||||
.Select(p => p.GetFormattedIdentifier())
|
"""
|
||||||
.JoinToString(" ")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,22 +336,20 @@ internal class CommandBinder
|
|||||||
if (remainingOptionInputs.Any())
|
if (remainingOptionInputs.Any())
|
||||||
{
|
{
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
"Unrecognized option(s):" +
|
$"""
|
||||||
Environment.NewLine +
|
Unrecognized option(s):
|
||||||
remainingOptionInputs
|
{remainingOptionInputs.Select(o => o.GetFormattedIdentifier()).JoinToString(", ")}
|
||||||
.Select(o => o.GetFormattedIdentifier())
|
"""
|
||||||
.JoinToString(", ")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingRequiredOptionSchemas.Any())
|
if (remainingRequiredOptionSchemas.Any())
|
||||||
{
|
{
|
||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
"Missing required option(s):" +
|
$"""
|
||||||
Environment.NewLine +
|
Missing required option(s):
|
||||||
remainingRequiredOptionSchemas
|
{remainingRequiredOptionSchemas.Select(o => o.GetFormattedIdentifier()).JoinToString(", ")}
|
||||||
.Select(o => o.GetFormattedIdentifier())
|
"""
|
||||||
.JoinToString(", ")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public partial class CliFxException : Exception
|
|||||||
public bool ShowHelp { get; }
|
public bool ShowHelp { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CliFxException"/>.
|
/// Initializes an instance of <see cref="CliFxException" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliFxException(
|
public CliFxException(
|
||||||
string message,
|
string message,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace CliFx.Exceptions;
|
|||||||
public class CommandException : CliFxException
|
public class CommandException : CliFxException
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="CommandException"/>.
|
/// Initializes an instance of <see cref="CommandException" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommandException(
|
public CommandException(
|
||||||
string message,
|
string message,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class BindingValidationError
|
|||||||
public string Message { get; }
|
public string Message { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="BindingValidationError"/>.
|
/// Initializes an instance of <see cref="BindingValidationError" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BindingValidationError(string message) => Message = message;
|
public BindingValidationError(string message) => Message = message;
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ public abstract class BindingValidator<T> : IBindingValidator
|
|||||||
/// Returns null if validation is successful, or an error in case of failure.
|
/// Returns null if validation is successful, or an error in case of failure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// You can use the utility methods <see cref="Ok"/> and <see cref="Error"/> to
|
/// You can use the utility methods <see cref="Ok" /> and <see cref="Error" /> to
|
||||||
/// create an appropriate result.
|
/// create an appropriate result.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public abstract BindingValidationError? Validate(T? value);
|
public abstract BindingValidationError? Validate(T? value);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace CliFx;
|
|||||||
public interface ICommand
|
public interface ICommand
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the command using the specified implementation of <see cref="IConsole"/>.
|
/// Executes the command using the specified implementation of <see cref="IConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If the execution of the command is not asynchronous, simply end the method with
|
/// If the execution of the command is not asynchronous, simply end the method with
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements a <see cref="TextReader"/> for reading characters from a console stream.
|
/// Implements a <see cref="TextReader" /> for reading characters from a console stream.
|
||||||
/// </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
|
||||||
@@ -19,7 +19,7 @@ public partial class ConsoleReader : StreamReader
|
|||||||
public IConsole Console { get; }
|
public IConsole Console { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="ConsoleReader"/>.
|
/// Initializes an instance of <see cref="ConsoleReader" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConsoleReader(IConsole console, Stream stream, Encoding encoding)
|
public ConsoleReader(IConsole console, Stream stream, Encoding encoding)
|
||||||
: base(stream, encoding, false, 4096)
|
: base(stream, encoding, false, 4096)
|
||||||
@@ -28,7 +28,7 @@ public partial class ConsoleReader : StreamReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <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)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using CliFx.Utils;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements a <see cref="TextWriter"/> for writing characters to a console stream.
|
/// Implements a <see cref="TextWriter" /> for writing characters to a console stream.
|
||||||
/// </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
|
||||||
@@ -20,7 +20,7 @@ public partial class ConsoleWriter : StreamWriter
|
|||||||
public IConsole Console { get; }
|
public IConsole Console { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="ConsoleWriter"/>.
|
/// Initializes an instance of <see cref="ConsoleWriter" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConsoleWriter(IConsole console, Stream stream, Encoding encoding)
|
public ConsoleWriter(IConsole console, Stream stream, Encoding encoding)
|
||||||
: base(stream, encoding.WithoutPreamble(), 256)
|
: base(stream, encoding.WithoutPreamble(), 256)
|
||||||
@@ -29,7 +29,7 @@ public partial class ConsoleWriter : StreamWriter
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <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)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using CliFx.Exceptions;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="ITypeActivator"/> that instantiates an object
|
/// Implementation of <see cref="ITypeActivator" /> that instantiates an object
|
||||||
/// by using its parameterless constructor.
|
/// by using its parameterless constructor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DefaultTypeActivator : ITypeActivator
|
public class DefaultTypeActivator : ITypeActivator
|
||||||
@@ -20,11 +20,11 @@ public class DefaultTypeActivator : ITypeActivator
|
|||||||
catch (MemberAccessException ex)
|
catch (MemberAccessException ex)
|
||||||
{
|
{
|
||||||
throw CliFxException.InternalError(
|
throw CliFxException.InternalError(
|
||||||
$"Failed to create an instance of type `{type.FullName}`, could not access the constructor." +
|
$"""
|
||||||
Environment.NewLine +
|
Failed to create an instance of type `{type.FullName}`, could not access the constructor.
|
||||||
"Default type activator is only capable of instantiating a type if it has a public parameterless constructor." +
|
Default type activator is only capable of instantiating a type if it has a public parameterless constructor.
|
||||||
Environment.NewLine +
|
To fix this, either add a parameterless constructor to the type or configure a custom activator for the application.
|
||||||
"To fix this, either add a parameterless constructor to the type or configure a custom activator for the application.",
|
""",
|
||||||
ex
|
ex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using CliFx.Exceptions;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="ITypeActivator"/> that instantiates an object
|
/// Implementation of <see cref="ITypeActivator" /> that instantiates an object
|
||||||
/// by using a predefined function.
|
/// by using a predefined function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DelegateTypeActivator : ITypeActivator
|
public class DelegateTypeActivator : ITypeActivator
|
||||||
@@ -12,7 +12,7 @@ public class DelegateTypeActivator : ITypeActivator
|
|||||||
private readonly Func<Type, object> _func;
|
private readonly Func<Type, object> _func;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="DelegateTypeActivator"/>.
|
/// Initializes an instance of <see cref="DelegateTypeActivator" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DelegateTypeActivator(Func<Type, object> func) => _func = func;
|
public DelegateTypeActivator(Func<Type, object> func) => _func = func;
|
||||||
|
|
||||||
@@ -24,11 +24,11 @@ public class DelegateTypeActivator : ITypeActivator
|
|||||||
if (instance is null)
|
if (instance is null)
|
||||||
{
|
{
|
||||||
throw CliFxException.InternalError(
|
throw CliFxException.InternalError(
|
||||||
$"Failed to create an instance of type `{type.FullName}`, received <null> instead." +
|
$"""
|
||||||
Environment.NewLine +
|
Failed to create an instance of type `{type.FullName}`, received <null> instead.
|
||||||
"To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return <null>." +
|
To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return <null>.
|
||||||
Environment.NewLine +
|
If you are relying on a dependency container, this error may indicate that the specified type has not been registered.
|
||||||
"If you are relying on a dependency container, this error may indicate that the specified type has not been registered."
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System.Threading;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="IConsole"/> that uses the provided fake
|
/// Implementation of <see cref="IConsole" /> that uses the provided fake
|
||||||
/// standard input, output, and error streams.
|
/// standard input, output, and error streams.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
@@ -42,11 +42,10 @@ public class FakeConsole : IConsole, IDisposable
|
|||||||
public ConsoleColor BackgroundColor { get; set; } = ConsoleColor.Black;
|
public ConsoleColor BackgroundColor { get; set; } = ConsoleColor.Black;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ResetColor()
|
public int WindowWidth { get; set; } = 232; // Windows defaults
|
||||||
{
|
|
||||||
ForegroundColor = ConsoleColor.Gray;
|
/// <inheritdoc />
|
||||||
BackgroundColor = ConsoleColor.Black;
|
public int WindowHeight { get; set; } = 14; // Windows defaults
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int CursorLeft { get; set; }
|
public int CursorLeft { get; set; }
|
||||||
@@ -55,7 +54,7 @@ public class FakeConsole : IConsole, IDisposable
|
|||||||
public int CursorTop { get; set; }
|
public int CursorTop { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="FakeConsole"/>.
|
/// Initializes an instance of <see cref="FakeConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FakeConsole(Stream? input = null, Stream? output = null, Stream? error = null)
|
public FakeConsole(Stream? input = null, Stream? output = null, Stream? error = null)
|
||||||
{
|
{
|
||||||
@@ -74,10 +73,17 @@ public class FakeConsole : IConsole, IDisposable
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues a simulated key press, which can then be read by calling <see cref="ReadKey"/>.
|
/// Enqueues a simulated key press, which can then be read by calling <see cref="ReadKey" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void EnqueueKey(ConsoleKeyInfo key) => _keys.Enqueue(key);
|
public void EnqueueKey(ConsoleKeyInfo key) => _keys.Enqueue(key);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ResetColor()
|
||||||
|
{
|
||||||
|
ForegroundColor = ConsoleColor.Gray;
|
||||||
|
BackgroundColor = ConsoleColor.Black;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
@@ -85,12 +91,12 @@ public class FakeConsole : IConsole, IDisposable
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token;
|
public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a cancellation signal to the currently executing command.
|
/// Sends a cancellation signal to the currently executing command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If the command is not cancellation-aware (i.e. it doesn't call <see cref="IConsole.RegisterCancellationHandler"/>),
|
/// If the command is not cancellation-aware (i.e. it doesn't call <see cref="IConsole.RegisterCancellationHandler" />),
|
||||||
/// this method will not have any effect.
|
/// this method will not have any effect.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void RequestCancellation(TimeSpan? delay = null)
|
public void RequestCancellation(TimeSpan? delay = null)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="IConsole"/> that uses fake
|
/// Implementation of <see cref="IConsole" /> that uses fake
|
||||||
/// standard input, output, and error streams backed by in-memory stores.
|
/// standard input, output, and error streams backed by in-memory stores.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
@@ -24,7 +24,7 @@ public class FakeInMemoryConsole : FakeConsole
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="FakeInMemoryConsole"/>.
|
/// Initializes an instance of <see cref="FakeInMemoryConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FakeInMemoryConsole()
|
public FakeInMemoryConsole()
|
||||||
: this(new MemoryStream(), new MemoryStream(), new MemoryStream())
|
: this(new MemoryStream(), new MemoryStream(), new MemoryStream())
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public interface IConsole
|
|||||||
ConsoleReader Input { get; }
|
ConsoleReader Input { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the input stream is redirected.
|
/// Gets a value that indicates whether input has been redirected from the standard input stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsInputRedirected { get; }
|
bool IsInputRedirected { get; }
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ public interface IConsole
|
|||||||
ConsoleWriter Output { get; }
|
ConsoleWriter Output { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the output stream is redirected.
|
/// Gets a value that indicates whether output has been redirected from the standard output stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsOutputRedirected { get; }
|
bool IsOutputRedirected { get; }
|
||||||
|
|
||||||
@@ -35,32 +35,37 @@ public interface IConsole
|
|||||||
ConsoleWriter Error { get; }
|
ConsoleWriter Error { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the error stream is redirected.
|
/// Gets a value that indicates whether error output has been redirected from the standard error stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsErrorRedirected { get; }
|
bool IsErrorRedirected { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current foreground color.
|
/// Gets or sets the foreground color of the console
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ConsoleColor ForegroundColor { get; set; }
|
ConsoleColor ForegroundColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current background color.
|
/// Gets or sets the background color of the console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ConsoleColor BackgroundColor { get; set; }
|
ConsoleColor BackgroundColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets foreground and background colors to their default values.
|
/// Gets or sets the width of the console window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ResetColor();
|
int WindowWidth { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cursor left offset.
|
/// Gets or sets the height of the console window.
|
||||||
|
/// </summary>
|
||||||
|
int WindowHeight { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the column position of the cursor within the buffer area.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int CursorLeft { get; set; }
|
int CursorLeft { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cursor top offset.
|
/// Gets or sets the row position of the cursor within the buffer area.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int CursorTop { get; set; }
|
int CursorTop { get; set; }
|
||||||
|
|
||||||
@@ -68,12 +73,17 @@ public interface IConsole
|
|||||||
/// Obtains the next character or function key pressed by the user.
|
/// Obtains the next character or function key pressed by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ConsoleKeyInfo ReadKey(bool intercept = false);
|
ConsoleKeyInfo ReadKey(bool intercept = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the foreground and background console colors to their defaults.
|
||||||
|
/// </summary>
|
||||||
|
void ResetColor();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the console buffer and corresponding console window of display information.
|
/// Clears the console buffer and corresponding console window of display information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a handler for the interrupt signal (Ctrl+C) on the console and returns
|
/// Registers a handler for the interrupt signal (Ctrl+C) on the console and returns
|
||||||
/// a token representing the cancellation request.
|
/// a token representing the cancellation request.
|
||||||
@@ -95,12 +105,12 @@ public interface IConsole
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extensions for <see cref="IConsole"/>.
|
/// Extensions for <see cref="IConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ConsoleExtensions
|
public static class ConsoleExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the specified foreground color and returns an <see cref="IDisposable"/>
|
/// Sets the specified foreground color and returns an <see cref="IDisposable" />
|
||||||
/// that will reset the color back to its previous value upon disposal.
|
/// that will reset the color back to its previous value upon disposal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IDisposable WithForegroundColor(this IConsole console, ConsoleColor foregroundColor)
|
public static IDisposable WithForegroundColor(this IConsole console, ConsoleColor foregroundColor)
|
||||||
@@ -112,7 +122,7 @@ public static class ConsoleExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the specified background color and returns an <see cref="IDisposable"/>
|
/// Sets the specified background color and returns an <see cref="IDisposable" />
|
||||||
/// that will reset the color back to its previous value upon disposal.
|
/// that will reset the color back to its previous value upon disposal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IDisposable WithBackgroundColor(this IConsole console, ConsoleColor backgroundColor)
|
public static IDisposable WithBackgroundColor(this IConsole console, ConsoleColor backgroundColor)
|
||||||
@@ -124,7 +134,7 @@ public static class ConsoleExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the specified foreground and background colors and returns an <see cref="IDisposable"/>
|
/// Sets the specified foreground and background colors and returns an <see cref="IDisposable" />
|
||||||
/// that will reset the colors back to their previous values upon disposal.
|
/// that will reset the colors back to their previous values upon disposal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IDisposable WithColors(
|
public static IDisposable WithColors(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Threading;
|
|||||||
namespace CliFx.Infrastructure;
|
namespace CliFx.Infrastructure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of <see cref="IConsole"/> that represents the real system console.
|
/// Implementation of <see cref="IConsole" /> that represents the real system console.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemConsole : IConsole, IDisposable
|
public class SystemConsole : IConsole, IDisposable
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,21 @@ public class SystemConsole : IConsole, IDisposable
|
|||||||
get => Console.BackgroundColor;
|
get => Console.BackgroundColor;
|
||||||
set => Console.BackgroundColor = value;
|
set => Console.BackgroundColor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int WindowWidth
|
||||||
|
{
|
||||||
|
get => Console.WindowWidth;
|
||||||
|
set => Console.WindowWidth = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int WindowHeight
|
||||||
|
{
|
||||||
|
get => Console.WindowHeight;
|
||||||
|
set => Console.WindowHeight = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int CursorLeft
|
public int CursorLeft
|
||||||
{
|
{
|
||||||
@@ -57,7 +71,7 @@ public class SystemConsole : IConsole, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes an instance of <see cref="SystemConsole"/>.
|
/// Initializes an instance of <see cref="SystemConsole" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SystemConsole()
|
public SystemConsole()
|
||||||
{
|
{
|
||||||
@@ -66,15 +80,15 @@ public class SystemConsole : IConsole, IDisposable
|
|||||||
Error = ConsoleWriter.Create(this, Console.OpenStandardError());
|
Error = ConsoleWriter.Create(this, Console.OpenStandardError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ConsoleKeyInfo ReadKey(bool intercept = false) => Console.ReadKey(intercept);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ResetColor() => Console.ResetColor();
|
public void ResetColor() => Console.ResetColor();
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ConsoleKeyInfo ReadKey(bool intercept = false) => Console.ReadKey(intercept);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Clear() => Console.Clear();
|
public void Clear() => Console.Clear();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CancellationToken RegisterCancellationHandler()
|
public CancellationToken RegisterCancellationHandler()
|
||||||
{
|
{
|
||||||
@@ -95,7 +109,7 @@ public class SystemConsole : IConsole, IDisposable
|
|||||||
|
|
||||||
return (_cancellationTokenSource = cts).Token;
|
return (_cancellationTokenSource = cts).Token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using CliFx.Utils.Extensions;
|
using CliFx.Utils.Extensions;
|
||||||
|
|
||||||
namespace CliFx.Input;
|
namespace CliFx.Input;
|
||||||
|
|||||||
@@ -129,15 +129,13 @@ internal partial class CommandSchema
|
|||||||
if (schema is null)
|
if (schema is null)
|
||||||
{
|
{
|
||||||
throw CliFxException.InternalError(
|
throw CliFxException.InternalError(
|
||||||
$"Type `{type.FullName}` is not a valid command type." +
|
$"""
|
||||||
Environment.NewLine +
|
Type `{type.FullName}` is not a valid command type.
|
||||||
"In order to be a valid command type, it must:" +
|
In order to be a valid command type, it must:
|
||||||
Environment.NewLine +
|
- Implement `{typeof(ICommand).FullName}`
|
||||||
$"- Implement `{typeof(ICommand).FullName}`" +
|
- Be annotated with `{typeof(CommandAttribute).FullName}`
|
||||||
Environment.NewLine +
|
- Not be an abstract class
|
||||||
$"- Be annotated with `{typeof(CommandAttribute).FullName}`" +
|
"""
|
||||||
Environment.NewLine +
|
|
||||||
"- Not be an abstract class"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
|
using CliFx.Utils.Extensions;
|
||||||
|
|
||||||
namespace CliFx.Schema;
|
namespace CliFx.Schema;
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@ internal partial class OptionSchema
|
|||||||
// The user may mistakenly specify dashes, thinking it's required, so trim them
|
// The user may mistakenly specify dashes, thinking it's required, so trim them
|
||||||
var name = attribute.Name?.TrimStart('-').Trim();
|
var name = attribute.Name?.TrimStart('-').Trim();
|
||||||
var environmentVariable = attribute.EnvironmentVariable?.Trim();
|
var environmentVariable = attribute.EnvironmentVariable?.Trim();
|
||||||
|
var isRequired = attribute.IsRequired || property.IsRequired();
|
||||||
var description = attribute.Description?.Trim();
|
var description = attribute.Description?.Trim();
|
||||||
|
|
||||||
return new OptionSchema(
|
return new OptionSchema(
|
||||||
@@ -108,7 +110,7 @@ internal partial class OptionSchema
|
|||||||
name,
|
name,
|
||||||
attribute.ShortName,
|
attribute.ShortName,
|
||||||
environmentVariable,
|
environmentVariable,
|
||||||
attribute.IsRequired,
|
isRequired,
|
||||||
description,
|
description,
|
||||||
attribute.Converter,
|
attribute.Converter,
|
||||||
attribute.Validators
|
attribute.Validators
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
|
using CliFx.Utils.Extensions;
|
||||||
|
|
||||||
namespace CliFx.Schema;
|
namespace CliFx.Schema;
|
||||||
|
|
||||||
@@ -53,13 +54,14 @@ internal partial class ParameterSchema
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var name = attribute.Name?.Trim() ?? property.Name.ToLowerInvariant();
|
var name = attribute.Name?.Trim() ?? property.Name.ToLowerInvariant();
|
||||||
|
var isRequired = attribute.IsRequired || property.IsRequired();
|
||||||
var description = attribute.Description?.Trim();
|
var description = attribute.Description?.Trim();
|
||||||
|
|
||||||
return new ParameterSchema(
|
return new ParameterSchema(
|
||||||
new BindablePropertyDescriptor(property),
|
new BindablePropertyDescriptor(property),
|
||||||
attribute.Order,
|
attribute.Order,
|
||||||
name,
|
name,
|
||||||
attribute.IsRequired,
|
isRequired,
|
||||||
description,
|
description,
|
||||||
attribute.Converter,
|
attribute.Converter,
|
||||||
attribute.Validators
|
attribute.Validators
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -37,4 +38,14 @@ internal static class CollectionExtensions
|
|||||||
dictionary
|
dictionary
|
||||||
.Cast<DictionaryEntry>()
|
.Cast<DictionaryEntry>()
|
||||||
.ToDictionary(entry => (TKey) entry.Key, entry => (TValue) entry.Value, comparer);
|
.ToDictionary(entry => (TKey) entry.Key, entry => (TValue) entry.Value, comparer);
|
||||||
|
|
||||||
|
public static Array ToNonGenericArray<T>(this IEnumerable<T> source, Type elementType)
|
||||||
|
{
|
||||||
|
var sourceAsCollection = source as ICollection ?? source.ToArray();
|
||||||
|
|
||||||
|
var array = Array.CreateInstance(elementType, sourceAsCollection.Count);
|
||||||
|
sourceAsCollection.CopyTo(array, 0);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
18
CliFx/Utils/Extensions/PropertyExtensions.cs
Normal file
18
CliFx/Utils/Extensions/PropertyExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace CliFx.Utils.Extensions;
|
||||||
|
|
||||||
|
internal static class PropertyExtensions
|
||||||
|
{
|
||||||
|
public static bool IsRequired(this PropertyInfo propertyInfo) =>
|
||||||
|
// Match attribute by name to avoid depending on .NET 7.0+ and to allow polyfilling
|
||||||
|
propertyInfo.GetCustomAttributes().Any(a =>
|
||||||
|
string.Equals(
|
||||||
|
a.GetType().FullName,
|
||||||
|
"System.Runtime.CompilerServices.RequiredMemberAttribute",
|
||||||
|
StringComparison.Ordinal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -11,7 +11,8 @@ internal static class TypeExtensions
|
|||||||
public static bool Implements(this Type type, Type interfaceType) =>
|
public static bool Implements(this Type type, Type interfaceType) =>
|
||||||
type.GetInterfaces().Contains(interfaceType);
|
type.GetInterfaces().Contains(interfaceType);
|
||||||
|
|
||||||
public static Type? TryGetNullableUnderlyingType(this Type type) => Nullable.GetUnderlyingType(type);
|
public static Type? TryGetNullableUnderlyingType(this Type type) =>
|
||||||
|
Nullable.GetUnderlyingType(type);
|
||||||
|
|
||||||
public static Type? TryGetEnumerableUnderlyingType(this Type type)
|
public static Type? TryGetEnumerableUnderlyingType(this Type type)
|
||||||
{
|
{
|
||||||
@@ -44,16 +45,6 @@ internal static class TypeExtensions
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Array ToNonGenericArray<T>(this IEnumerable<T> source, Type elementType)
|
|
||||||
{
|
|
||||||
var sourceAsCollection = source as ICollection ?? source.ToArray();
|
|
||||||
|
|
||||||
var array = Array.CreateInstance(elementType, sourceAsCollection.Count);
|
|
||||||
sourceAsCollection.CopyTo(array, 0);
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsToStringOverriden(this Type type)
|
public static bool IsToStringOverriden(this Type type)
|
||||||
{
|
{
|
||||||
var toStringMethod = type.GetMethod(nameof(ToString), Type.EmptyTypes);
|
var toStringMethod = type.GetMethod(nameof(ToString), Type.EmptyTypes);
|
||||||
|
|||||||
@@ -96,9 +96,10 @@ internal partial class StackFrame
|
|||||||
// If parsing fails, we include the original stacktrace in the
|
// If parsing fails, we include the original stacktrace in the
|
||||||
// exception so that it's shown to the user.
|
// exception so that it's shown to the user.
|
||||||
throw new FormatException(
|
throw new FormatException(
|
||||||
"Could not parse stacktrace:" +
|
$"""
|
||||||
Environment.NewLine +
|
Could not parse stacktrace:
|
||||||
stackTrace
|
{stackTrace}
|
||||||
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>2.2.6</Version>
|
<Version>2.3.1</Version>
|
||||||
<Company>Tyrrrz</Company>
|
<Company>Tyrrrz</Company>
|
||||||
<Copyright>Copyright (C) Oleksii Holub</Copyright>
|
<Copyright>Copyright (C) Oleksii Holub</Copyright>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||||
|
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
30
Readme.md
30
Readme.md
@@ -9,7 +9,7 @@
|
|||||||
[](https://tyrrrz.me/donate)
|
[](https://tyrrrz.me/donate)
|
||||||
[](https://twitter.com/tyrrrz/status/1495972128977571848)
|
[](https://twitter.com/tyrrrz/status/1495972128977571848)
|
||||||
|
|
||||||
> 🟢 **Project status**: active<sup>[[?]](https://github.com/Tyrrrz/.github/blob/master/docs/project-status.md)</sup>
|
> 🟡 **Project status**: maintenance mode<sup>[[?]](https://github.com/Tyrrrz/.github/blob/master/docs/project-status.md)</sup>
|
||||||
|
|
||||||
**CliFx** is a simple to use, yet powerful framework for building command line applications.
|
**CliFx** is a simple to use, yet powerful framework for building command line applications.
|
||||||
Its primary goal is to completely take over the user input layer, allowing you to forget about infrastructural concerns and instead focus on writing your application.
|
Its primary goal is to completely take over the user input layer, allowing you to forget about infrastructural concerns and instead focus on writing your application.
|
||||||
@@ -144,7 +144,7 @@ public class LogCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Order: 0
|
// Order: 0
|
||||||
[CommandParameter(0, Description = "Value whose logarithm is to be found.")]
|
[CommandParameter(0, Description = "Value whose logarithm is to be found.")]
|
||||||
public double Value { get; init; }
|
public required double Value { get; init; }
|
||||||
|
|
||||||
// Name: --base
|
// Name: --base
|
||||||
// Short name: -b
|
// Short name: -b
|
||||||
@@ -212,14 +212,14 @@ OPTIONS
|
|||||||
Overall, parameters and options are both used to consume input from the command line, but they differ in a few important ways:
|
Overall, parameters and options are both used to consume input from the command line, but they differ in a few important ways:
|
||||||
|
|
||||||
| | Parameter | Option |
|
| | Parameter | Option |
|
||||||
|--------------------|--------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|
|
| ------------------ | ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
|
||||||
| **Identification** | Positional (by relative order). | Nominal (by name or short name). |
|
| **Identification** | Positional (by relative order). | Nominal (by name or short name). |
|
||||||
| **Requiredness** | Required by default. Only the last parameter can be configured to be optional. | Optional by default. Any option can be configured to be required without limitations. |
|
| **Requiredness** | Required by default. Only the last parameter can be configured to be optional. | Optional by default. Any option can be configured to be required without limitations. |
|
||||||
| **Arity** | Only the last parameter can be bound to a non-scalar property (i.e. an array). | Any option can be bound to a non-scalar property without limitations. |
|
| **Arity** | Only the last parameter can be bound to a non-scalar property (i.e. an array). | Any option can be bound to a non-scalar property without limitations. |
|
||||||
| **Fallback** | — | Can be configured to use an environment variable as fallback if the value isn't explicitly provided. |
|
| **Fallback** | — | Can be configured to use an environment variable as fallback if the value isn't explicitly provided. |
|
||||||
|
|
||||||
As a general guideline, use parameters for required inputs that the command can't function without.
|
As a general guideline, use parameters for required inputs that the command can't function without.
|
||||||
Use options for all other non-required inputs or when specifying the name explicitly makes the usage clearer.
|
Use options for all other non-required inputs, or when specifying the name explicitly makes the usage clearer.
|
||||||
|
|
||||||
### Argument syntax
|
### Argument syntax
|
||||||
|
|
||||||
@@ -382,8 +382,8 @@ If the user does not provide value for such option through command line argument
|
|||||||
[Command]
|
[Command]
|
||||||
public class AuthCommand : ICommand
|
public class AuthCommand : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption("token", IsRequired = true, EnvironmentVariable = "AUTH_TOKEN")]
|
[CommandOption("token", EnvironmentVariable = "AUTH_TOKEN")]
|
||||||
public string AuthToken { get; init; }
|
public required string AuthToken { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
@@ -403,7 +403,7 @@ test
|
|||||||
```
|
```
|
||||||
|
|
||||||
Environment variables can be configured for options of non-scalar types (arrays, lists, etc.) as well.
|
Environment variables can be configured for options of non-scalar types (arrays, lists, etc.) as well.
|
||||||
In such case, the values of the environment variable will be split by `Path.PathSeparator` (`;` on Windows, `:` on Linux).
|
In such case, the values of the environment variable will be split by `Path.PathSeparator` (`;` on Windows, `:` on Unix systems).
|
||||||
|
|
||||||
### Multiple commands
|
### Multiple commands
|
||||||
|
|
||||||
@@ -488,7 +488,7 @@ You can run `dotnet myapp.dll cmd1 [command] --help` to show help on a specific
|
|||||||
|
|
||||||
> **Note**:
|
> **Note**:
|
||||||
> Defining a default (unnamed) command is not required.
|
> Defining a default (unnamed) command is not required.
|
||||||
> If it's absent, running the application without specifying a command will just show the root level help text.
|
> If it's absent, running the application without specifying a command will just show the root-level help text.
|
||||||
|
|
||||||
### Reporting errors
|
### Reporting errors
|
||||||
|
|
||||||
@@ -499,11 +499,11 @@ This special exception can be used to print an error message to the console, ret
|
|||||||
[Command]
|
[Command]
|
||||||
public class DivideCommand : ICommand
|
public class DivideCommand : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption("dividend", IsRequired = true)]
|
[CommandOption("dividend")]
|
||||||
public double Dividend { get; init; }
|
public required double Dividend { get; init; }
|
||||||
|
|
||||||
[CommandOption("divisor", IsRequired = true)]
|
[CommandOption("divisor")]
|
||||||
public double Divisor { get; init; }
|
public required double Divisor { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
@@ -567,12 +567,12 @@ public class CancellableCommand : ICommand
|
|||||||
```
|
```
|
||||||
|
|
||||||
> **Warning**:
|
> **Warning**:
|
||||||
> Forceful termination of a command can only be delayed once.
|
> Cancellation handler is only respected when the user sends the interrupt signal for the first time.
|
||||||
> If the user issues a second interrupt signal, the process will be killed immediately without waiting for graceful cancellation.
|
> If the user decides to issue the signal again, the application will terminate immediately regardless of whether the command is cancellation-aware.
|
||||||
|
|
||||||
### Type activation
|
### Type activation
|
||||||
|
|
||||||
Because **CliFx** takes responsibility for the application's entire lifecycle, it needs to be capable of instantiating various user-defined types at runtime.
|
Because **CliFx** takes responsibility for the application's entire lifecycle, it needs to be capable of instantiating various user-defined types at run-time.
|
||||||
To facilitate that, it uses an interface called `ITypeActivator` that determines how to create a new instance of a given type.
|
To facilitate that, it uses an interface called `ITypeActivator` that determines how to create a new instance of a given type.
|
||||||
|
|
||||||
The default implementation of `ITypeActivator` only supports types that have public parameterless constructors, which is sufficient for the majority of scenarios.
|
The default implementation of `ITypeActivator` only supports types that have public parameterless constructors, which is sufficient for the majority of scenarios.
|
||||||
|
|||||||
Reference in New Issue
Block a user