mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05a70175cc | ||
|
|
33ec2eb3a0 | ||
|
|
f6ef6cd4c0 | ||
|
|
a9ef693dc1 | ||
|
|
98bbd666dc | ||
|
|
4e7ed830f8 | ||
|
|
ef87ff76fc | ||
|
|
2feeb21270 | ||
|
|
9990387cfa | ||
|
|
bc1bdca7c6 | ||
|
|
2a992d37df | ||
|
|
15c87aecbb | ||
|
|
10a46451ac | ||
|
|
e4c6a4174b | ||
|
|
4c65f7bbee | ||
|
|
5f21de0df5 | ||
|
|
9b01b67d98 | ||
|
|
4508f5e211 | ||
|
|
f0cbc46df4 | ||
|
|
6c96e9e173 | ||
|
|
51cca36d2a | ||
|
|
84672c92f6 | ||
|
|
b1d01898b6 | ||
|
|
441a47a1a8 | ||
|
|
8abd7219a1 | ||
|
|
df73a0bfe8 | ||
|
|
55d12dc721 | ||
|
|
a6ee44c1bb | ||
|
|
76816e22f1 | ||
|
|
daf25e59d6 | ||
|
|
f2b4e53615 | ||
|
|
2d519ab190 | ||
|
|
2d479c9cb6 | ||
|
|
2bb7e13e51 | ||
|
|
6e1dfdcdd4 | ||
|
|
5ba647e5c1 | ||
|
|
853492695f | ||
|
|
d5d72c7c50 | ||
|
|
d676b5832e | ||
|
|
28097afc1e | ||
|
|
fda96586f3 | ||
|
|
fc5af8dbbc | ||
|
|
4835e64388 | ||
|
|
0999c33f93 | ||
|
|
595805255a | ||
|
|
65eaa912cf | ||
|
|
038f48b78e | ||
|
|
d7460244b7 | ||
|
|
02766868fc | ||
|
|
8d7d25a144 | ||
|
|
17ded54e24 | ||
|
|
54a4c32ddf | ||
|
|
6d46e82145 | ||
|
|
fd4a2a18fe | ||
|
|
bfe99d620e | ||
|
|
c5a111207f | ||
|
|
544945c0e6 | ||
|
|
c616cdd750 | ||
|
|
d3c396956d | ||
|
|
d0cbbc6d9a |
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
|||||||
github: Tyrrrz
|
|
||||||
patreon: Tyrrrz
|
|
||||||
custom: ['buymeacoffee.com/Tyrrrz', 'tyrrrz.me/donate']
|
|
||||||
42
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: 🐞 Bug report
|
||||||
|
description: Report broken functionality.
|
||||||
|
labels: [bug]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
🧐 **Guidelines:**
|
||||||
|
|
||||||
|
- Search through [existing issues](https://github.com/Tyrrrz/CliFx/issues?q=is%3Aissue) first to ensure that this bug has not been reported before.
|
||||||
|
- Write a descriptive title for your issue. Avoid generic or vague titles such as "Something's not working" or "A couple of problems".
|
||||||
|
- Keep your issue focused on one single problem. If you have multiple bug reports, 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 reporting a bug, please use [discussions](https://github.com/Tyrrrz/CliFx/discussions/new) instead.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Version
|
||||||
|
description: Which version of CliFx does this bug affect?
|
||||||
|
placeholder: ver X.Y.Z
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Details
|
||||||
|
description: Clear and thorough explanation of the bug.
|
||||||
|
placeholder: I was doing X expecting Y to happen, but Z happened instead.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Minimum steps required to reproduce the bug.
|
||||||
|
placeholder: |
|
||||||
|
- Step 1
|
||||||
|
- Step 2
|
||||||
|
- Step 3
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: 💬 Discord server
|
||||||
|
url: https://discord.gg/2SUWKFnHSm
|
||||||
|
about: Chat with the project community.
|
||||||
|
- name: 🗨 Discussions
|
||||||
|
url: https://github.com/Tyrrrz/CliFx/discussions/new
|
||||||
|
about: Ask and answer questions.
|
||||||
22
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
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
|
||||||
27
.github/workflows/CD.yml
vendored
27
.github/workflows/CD.yml
vendored
@@ -1,27 +0,0 @@
|
|||||||
name: CD
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2.3.3
|
|
||||||
|
|
||||||
- name: Install .NET
|
|
||||||
uses: actions/setup-dotnet@v1.7.2
|
|
||||||
with:
|
|
||||||
dotnet-version: 5.0.x
|
|
||||||
|
|
||||||
- name: Pack
|
|
||||||
run: |
|
|
||||||
dotnet nuget locals all --clear
|
|
||||||
dotnet pack CliFx --configuration Release
|
|
||||||
|
|
||||||
- name: Deploy
|
|
||||||
run: dotnet nuget push CliFx/bin/Release/*.nupkg -s nuget.org -k ${{ secrets.NUGET_TOKEN }}
|
|
||||||
30
.github/workflows/CI.yml
vendored
30
.github/workflows/CI.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2.3.3
|
|
||||||
|
|
||||||
- name: Install .NET
|
|
||||||
uses: actions/setup-dotnet@v1.7.2
|
|
||||||
with:
|
|
||||||
dotnet-version: 5.0.x
|
|
||||||
|
|
||||||
- name: Build & test
|
|
||||||
run: |
|
|
||||||
dotnet nuget locals all --clear
|
|
||||||
dotnet test --configuration Release --logger GitHubActions
|
|
||||||
|
|
||||||
- name: Upload coverage
|
|
||||||
uses: codecov/codecov-action@v1.0.5
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
11
.github/workflows/main.yml
vendored
Normal file
11
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
name: main
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
uses: Tyrrrz/.github/.github/workflows/NuGet.yml@master
|
||||||
|
secrets:
|
||||||
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
|
||||||
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
36
Changelog.md
36
Changelog.md
@@ -1,3 +1,39 @@
|
|||||||
|
### v2.1 (04-Jan-2022)
|
||||||
|
|
||||||
|
- Added `IConsole.Clear()` with corresponding implementations in `SystemConsole`, `FakeConsole`, and `FakeInMemoryConsole`. (Thanks [@Alex Rosenfeld](https://github.com/alexrosenfeld10))
|
||||||
|
- Added `IConsole.ReadKey()` with corresponding implementations in `SystemConsole`, `FakeConsole`, and `FakeInMemoryConsole`. (Thanks [@Alex Rosenfeld](https://github.com/alexrosenfeld10))
|
||||||
|
- Fixed an issue that caused parameters to appear out of order in the usage format section of the help text. (Thanks [@David Fallah](https://github.com/TAGC))
|
||||||
|
|
||||||
|
### v2.0.6 (17-Jul-2021)
|
||||||
|
|
||||||
|
- Fixed an issue where an exception thrown via reflection during parameter or option binding resulted in `Exception has been thrown by the target of an invocation` error instead of a more useful message. Such exceptions will now be unwrapped to provide better user experience.
|
||||||
|
|
||||||
|
### v2.0.5 (09-Jul-2021)
|
||||||
|
|
||||||
|
- Fixed an issue where calling `IConsole.Output.Encoding.EncodingName` and some other members threw an exception.
|
||||||
|
- Added readme file to the package.
|
||||||
|
|
||||||
|
### v2.0.4 (24-Apr-2021)
|
||||||
|
|
||||||
|
- Fixed an issue where output and error streams in `SystemConsole` defaulted to UTF8 encoding with BOM when the application was running with UTF8 codepage. `ConsoleWriter` will now discard preamble from the specified encoding. This fix brings the behavior of `SystemConsole` in line with .NET's own `System.Console` which also discards preamble for output and error streams.
|
||||||
|
- Fixed an issue where help text tried to show default values for parameters and options whose type does not override `ToString()` method.
|
||||||
|
- Fixed an issue where help text didn't show default values for parameters and options whose type is an enumerable of nullable enums. (Thanks [@Robert Dailey](https://github.com/rcdailey))
|
||||||
|
- Fixed an issue where specific parts of the help text weren't legible in some terminals due to low color resolution. Removed the usage of `ConsoleColor.DarkGray` in help text.
|
||||||
|
|
||||||
|
### v2.0.3 (09-Apr-2021)
|
||||||
|
|
||||||
|
- Improved help text by showing valid values for non-scalar enum parameters and options. (Thanks [@Robert Dailey](https://github.com/rcdailey))
|
||||||
|
|
||||||
|
### v2.0.2 (31-Mar-2021)
|
||||||
|
|
||||||
|
- Fixed an issue where having a transitive reference to CliFx sometimes resulted in `SystemConsoleShouldBeAvoidedAnalyzer` throwing `NullReferenceException` during build.
|
||||||
|
- Fixed some documentation typos and inconsistencies.
|
||||||
|
|
||||||
|
### v2.0.1 (24-Mar-2021)
|
||||||
|
|
||||||
|
- Fixed an issue where some exceptions with async stack traces generated on .NET 3.1 or earlier were not parsed and formatted correctly.
|
||||||
|
- Fixed an issue where help text applied slightly incorrect formatting when displaying choices for enum-based parameters and properties.
|
||||||
|
|
||||||
### v2.0 (21-Mar-2021)
|
### v2.0 (21-Mar-2021)
|
||||||
|
|
||||||
> Note: this major release includes many breaking changes.
|
> Note: this major release includes many breaking changes.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
<CollectCoverage>true</CollectCoverage>
|
<CollectCoverage>true</CollectCoverage>
|
||||||
@@ -13,13 +13,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Basic.Reference.Assemblies" Version="1.2.4" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="1.2.0" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="1.2.0" />
|
||||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
<PackageReference Include="FluentAssertions" Version="6.2.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.0" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="coverlet.msbuild" Version="3.0.3" PrivateAssets="all" />
|
<PackageReference Include="coverlet.msbuild" Version="3.1.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class CommandMustBeAnnotatedAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class CommandMustBeAnnotatedAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustBeAnnotatedAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustBeAnnotatedAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -68,5 +68,4 @@ public class Foo
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class CommandMustImplementInterfaceAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class CommandMustImplementInterfaceAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustImplementInterfaceAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new CommandMustImplementInterfaceAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -54,5 +54,4 @@ public class Foo
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,10 +4,10 @@ using FluentAssertions;
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class GeneralSpecs
|
||||||
{
|
{
|
||||||
public class GeneralSpecs
|
|
||||||
{
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void All_analyzers_have_unique_diagnostic_IDs()
|
public void All_analyzers_have_unique_diagnostic_IDs()
|
||||||
{
|
{
|
||||||
@@ -27,5 +27,4 @@ namespace CliFx.Analyzers.Tests
|
|||||||
// Assert
|
// Assert
|
||||||
diagnosticIds.Should().OnlyHaveUniqueItems();
|
diagnosticIds.Should().OnlyHaveUniqueItems();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustBeInsideCommandAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustBeInsideCommandAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeInsideCommandAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustBeInsideCommandAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -76,5 +76,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveNameOrShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveNameOrShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -82,5 +82,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveUniqueNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -88,5 +88,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveUniqueShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -110,5 +110,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveValidConverterAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveValidConverterAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidConverterAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidConverterAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -92,5 +92,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveValidNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveValidNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -101,5 +101,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveValidShortNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidShortNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidShortNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -82,5 +82,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidValidatorsAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new OptionMustHaveValidValidatorsAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -92,5 +92,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustBeInsideCommandAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustBeInsideCommandAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeInsideCommandAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeInsideCommandAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -76,5 +76,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustBeLastIfNonScalarAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonScalarAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeLastIfNonScalarAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -91,5 +91,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustBeSingleIfNonScalarAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonScalarAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustBeSingleIfNonScalarAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -91,5 +91,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustHaveUniqueNameAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueNameAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueNameAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -69,5 +69,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustHaveUniqueOrderAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueOrderAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveUniqueOrderAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -69,5 +69,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustHaveValidConverterAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustHaveValidConverterAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidConverterAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidConverterAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -92,5 +92,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class ParameterMustHaveValidValidatorsAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidValidatorsAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new ParameterMustHaveValidValidatorsAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -92,5 +92,4 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests
|
namespace CliFx.Analyzers.Tests;
|
||||||
|
|
||||||
|
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
||||||
{
|
{
|
||||||
public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|
||||||
{
|
|
||||||
private static DiagnosticAnalyzer Analyzer { get; } = new SystemConsoleShouldBeAvoidedAnalyzer();
|
private static DiagnosticAnalyzer Analyzer { get; } = new SystemConsoleShouldBeAvoidedAnalyzer();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -104,5 +104,23 @@ public class MyCommand : ICommand
|
|||||||
// Act & assert
|
// Act & assert
|
||||||
Analyzer.Should().NotProduceDiagnostics(code);
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Analyzer_does_not_report_an_error_if_a_command_does_not_access_SystemConsole()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// language=cs
|
||||||
|
const string code = @"
|
||||||
|
[Command]
|
||||||
|
public class MyCommand : ICommand
|
||||||
|
{
|
||||||
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
|
||||||
|
// Act & assert
|
||||||
|
Analyzer.Should().NotProduceDiagnostics(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Basic.Reference.Assemblies;
|
||||||
using FluentAssertions.Execution;
|
using FluentAssertions.Execution;
|
||||||
using FluentAssertions.Primitives;
|
using FluentAssertions.Primitives;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
@@ -11,10 +11,10 @@ using Microsoft.CodeAnalysis.CSharp;
|
|||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Tests.Utils
|
namespace CliFx.Analyzers.Tests.Utils;
|
||||||
|
|
||||||
|
internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer, AnalyzerAssertions>
|
||||||
{
|
{
|
||||||
internal class AnalyzerAssertions : ReferenceTypeAssertions<DiagnosticAnalyzer, AnalyzerAssertions>
|
|
||||||
{
|
|
||||||
protected override string Identifier { get; } = "analyzer";
|
protected override string Identifier { get; } = "analyzer";
|
||||||
|
|
||||||
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
public AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
||||||
@@ -58,14 +58,8 @@ namespace CliFx.Analyzers.Tests.Utils
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] {ast},
|
new[] {ast},
|
||||||
new[]
|
ReferenceAssemblies.Net50
|
||||||
{
|
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
|
||||||
MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location),
|
|
||||||
MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
|
|
||||||
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)
|
||||||
);
|
);
|
||||||
@@ -165,10 +159,9 @@ namespace CliFx.Analyzers.Tests.Utils
|
|||||||
return new FailReason(buffer.ToString());
|
return new FailReason(buffer.ToString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class AnalyzerAssertionsExtensions
|
internal static class AnalyzerAssertionsExtensions
|
||||||
{
|
{
|
||||||
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
|
public static AnalyzerAssertions Should(this DiagnosticAnalyzer analyzer) => new(analyzer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,10 @@ using CliFx.Analyzers.Utils.Extensions;
|
|||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
public abstract class AnalyzerBase : DiagnosticAnalyzer
|
||||||
{
|
{
|
||||||
public abstract class AnalyzerBase : DiagnosticAnalyzer
|
|
||||||
{
|
|
||||||
public DiagnosticDescriptor SupportedDiagnostic { get; }
|
public DiagnosticDescriptor SupportedDiagnostic { get; }
|
||||||
|
|
||||||
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
|
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
|
||||||
@@ -36,5 +36,4 @@ namespace CliFx.Analyzers
|
|||||||
context.EnableConcurrentExecution();
|
context.EnableConcurrentExecution();
|
||||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class CommandMustBeAnnotatedAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public CommandMustBeAnnotatedAnalyzer()
|
public CommandMustBeAnnotatedAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Commands must be annotated with `{SymbolNames.CliFxCommandAttribute}`",
|
$"Commands must be annotated with `{SymbolNames.CliFxCommandAttribute}`",
|
||||||
@@ -50,5 +50,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandleClassDeclaration(Analyze);
|
context.HandleClassDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class CommandMustImplementInterfaceAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class CommandMustImplementInterfaceAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public CommandMustImplementInterfaceAnalyzer()
|
public CommandMustImplementInterfaceAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Commands must implement `{SymbolNames.CliFxCommandInterface}` interface",
|
$"Commands must implement `{SymbolNames.CliFxCommandInterface}` interface",
|
||||||
@@ -44,5 +44,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandleClassDeclaration(Analyze);
|
context.HandleClassDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,10 @@ using Microsoft.CodeAnalysis;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CliFx.Analyzers.Utils.Extensions;
|
using CliFx.Analyzers.Utils.Extensions;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.ObjectModel
|
namespace CliFx.Analyzers.ObjectModel;
|
||||||
|
|
||||||
|
internal partial class CommandOptionSymbol
|
||||||
{
|
{
|
||||||
internal partial class CommandOptionSymbol
|
|
||||||
{
|
|
||||||
public string? Name { get; }
|
public string? Name { get; }
|
||||||
|
|
||||||
public char? ShortName { get; }
|
public char? ShortName { get; }
|
||||||
@@ -26,10 +26,10 @@ namespace CliFx.Analyzers.ObjectModel
|
|||||||
ConverterType = converterType;
|
ConverterType = converterType;
|
||||||
ValidatorTypes = validatorTypes;
|
ValidatorTypes = validatorTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal partial class CommandOptionSymbol
|
internal partial class CommandOptionSymbol
|
||||||
{
|
{
|
||||||
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
|
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
|
||||||
property
|
property
|
||||||
.GetAttributes()
|
.GetAttributes()
|
||||||
@@ -79,5 +79,4 @@ namespace CliFx.Analyzers.ObjectModel
|
|||||||
|
|
||||||
public static bool IsOptionProperty(IPropertySymbol property) =>
|
public static bool IsOptionProperty(IPropertySymbol property) =>
|
||||||
TryGetOptionAttribute(property) is not null;
|
TryGetOptionAttribute(property) is not null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,10 @@ using System.Linq;
|
|||||||
using CliFx.Analyzers.Utils.Extensions;
|
using CliFx.Analyzers.Utils.Extensions;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.ObjectModel
|
namespace CliFx.Analyzers.ObjectModel;
|
||||||
|
|
||||||
|
internal partial class CommandParameterSymbol
|
||||||
{
|
{
|
||||||
internal partial class CommandParameterSymbol
|
|
||||||
{
|
|
||||||
public int Order { get; }
|
public int Order { get; }
|
||||||
|
|
||||||
public string? Name { get; }
|
public string? Name { get; }
|
||||||
@@ -26,10 +26,10 @@ namespace CliFx.Analyzers.ObjectModel
|
|||||||
ConverterType = converterType;
|
ConverterType = converterType;
|
||||||
ValidatorTypes = validatorTypes;
|
ValidatorTypes = validatorTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal partial class CommandParameterSymbol
|
internal partial class CommandParameterSymbol
|
||||||
{
|
{
|
||||||
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
|
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
|
||||||
property
|
property
|
||||||
.GetAttributes()
|
.GetAttributes()
|
||||||
@@ -78,5 +78,4 @@ namespace CliFx.Analyzers.ObjectModel
|
|||||||
|
|
||||||
public static bool IsParameterProperty(IPropertySymbol property) =>
|
public static bool IsParameterProperty(IPropertySymbol property) =>
|
||||||
TryGetParameterAttribute(property) is not null;
|
TryGetParameterAttribute(property) is not null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace CliFx.Analyzers.ObjectModel
|
namespace CliFx.Analyzers.ObjectModel;
|
||||||
|
|
||||||
|
internal static class SymbolNames
|
||||||
{
|
{
|
||||||
internal static class SymbolNames
|
|
||||||
{
|
|
||||||
public const string CliFxCommandInterface = "CliFx.ICommand";
|
public const string CliFxCommandInterface = "CliFx.ICommand";
|
||||||
public const string CliFxCommandAttribute = "CliFx.Attributes.CommandAttribute";
|
public const string CliFxCommandAttribute = "CliFx.Attributes.CommandAttribute";
|
||||||
public const string CliFxCommandParameterAttribute = "CliFx.Attributes.CommandParameterAttribute";
|
public const string CliFxCommandParameterAttribute = "CliFx.Attributes.CommandParameterAttribute";
|
||||||
@@ -11,5 +11,4 @@
|
|||||||
public const string CliFxBindingConverterClass = "CliFx.Extensibility.BindingConverter<T>";
|
public const string CliFxBindingConverterClass = "CliFx.Extensibility.BindingConverter<T>";
|
||||||
public const string CliFxBindingValidatorInterface = "CliFx.Extensibility.IBindingValidator";
|
public const string CliFxBindingValidatorInterface = "CliFx.Extensibility.IBindingValidator";
|
||||||
public const string CliFxBindingValidatorClass = "CliFx.Extensibility.BindingValidator<T>";
|
public const string CliFxBindingValidatorClass = "CliFx.Extensibility.BindingValidator<T>";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustBeInsideCommandAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustBeInsideCommandAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustBeInsideCommandAnalyzer()
|
public OptionMustBeInsideCommandAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must be defined inside commands",
|
"Options must be defined inside commands",
|
||||||
@@ -22,6 +22,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (property.ContainingType.IsAbstract)
|
if (property.ContainingType.IsAbstract)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -44,5 +47,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveNameOrShortNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveNameOrShortNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveNameOrShortNameAnalyzer()
|
public OptionMustHaveNameOrShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have either a name or short name specified",
|
"Options must have either a name or short name specified",
|
||||||
@@ -36,5 +36,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveUniqueNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveUniqueNameAnalyzer()
|
public OptionMustHaveUniqueNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have unique names",
|
"Options must have unique names",
|
||||||
@@ -23,6 +23,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
return;
|
return;
|
||||||
@@ -58,5 +61,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveUniqueShortNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveUniqueShortNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveUniqueShortNameAnalyzer()
|
public OptionMustHaveUniqueShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have unique short names",
|
"Options must have unique short names",
|
||||||
@@ -22,6 +22,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
var option = CommandOptionSymbol.TryResolve(property);
|
var option = CommandOptionSymbol.TryResolve(property);
|
||||||
if (option is null)
|
if (option is null)
|
||||||
return;
|
return;
|
||||||
@@ -57,5 +60,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveValidConverterAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveValidConverterAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveValidConverterAnalyzer()
|
public OptionMustHaveValidConverterAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Option converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
$"Option converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
||||||
@@ -46,5 +46,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveValidNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveValidNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveValidNameAnalyzer()
|
public OptionMustHaveValidNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Options must have valid names",
|
"Options must have valid names",
|
||||||
@@ -39,5 +39,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveValidShortNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveValidShortNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveValidShortNameAnalyzer()
|
public OptionMustHaveValidShortNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Option short names must be letter characters",
|
"Option short names must be letter characters",
|
||||||
@@ -39,5 +39,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class OptionMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class OptionMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public OptionMustHaveValidValidatorsAnalyzer()
|
public OptionMustHaveValidValidatorsAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Option validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
$"Option validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
||||||
@@ -48,5 +48,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustBeInsideCommandAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustBeInsideCommandAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustBeInsideCommandAnalyzer()
|
public ParameterMustBeInsideCommandAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must be defined inside commands",
|
"Parameters must be defined inside commands",
|
||||||
@@ -22,6 +22,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (property.ContainingType.IsAbstract)
|
if (property.ContainingType.IsAbstract)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -44,5 +47,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustBeLastIfNonScalarAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustBeLastIfNonScalarAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustBeLastIfNonScalarAnalyzer()
|
public ParameterMustBeLastIfNonScalarAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters of non-scalar types must be last in order",
|
"Parameters of non-scalar types must be last in order",
|
||||||
@@ -29,6 +29,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (IsScalar(property.Type))
|
if (IsScalar(property.Type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -61,5 +64,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustBeSingleIfNonScalarAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustBeSingleIfNonScalarAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustBeSingleIfNonScalarAnalyzer()
|
public ParameterMustBeSingleIfNonScalarAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters of non-scalar types are limited to one per command",
|
"Parameters of non-scalar types are limited to one per command",
|
||||||
@@ -29,6 +29,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!CommandParameterSymbol.IsParameterProperty(property))
|
if (!CommandParameterSymbol.IsParameterProperty(property))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -59,5 +62,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustHaveUniqueNameAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustHaveUniqueNameAnalyzer()
|
public ParameterMustHaveUniqueNameAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must have unique names",
|
"Parameters must have unique names",
|
||||||
@@ -23,6 +23,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
var parameter = CommandParameterSymbol.TryResolve(property);
|
var parameter = CommandParameterSymbol.TryResolve(property);
|
||||||
if (parameter is null)
|
if (parameter is null)
|
||||||
return;
|
return;
|
||||||
@@ -58,5 +61,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustHaveUniqueOrderAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustHaveUniqueOrderAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustHaveUniqueOrderAnalyzer()
|
public ParameterMustHaveUniqueOrderAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
"Parameters must have unique order",
|
"Parameters must have unique order",
|
||||||
@@ -22,6 +22,9 @@ namespace CliFx.Analyzers
|
|||||||
PropertyDeclarationSyntax propertyDeclaration,
|
PropertyDeclarationSyntax propertyDeclaration,
|
||||||
IPropertySymbol property)
|
IPropertySymbol property)
|
||||||
{
|
{
|
||||||
|
if (property.ContainingType is null)
|
||||||
|
return;
|
||||||
|
|
||||||
var parameter = CommandParameterSymbol.TryResolve(property);
|
var parameter = CommandParameterSymbol.TryResolve(property);
|
||||||
if (parameter is null)
|
if (parameter is null)
|
||||||
return;
|
return;
|
||||||
@@ -51,5 +54,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustHaveValidConverterAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustHaveValidConverterAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustHaveValidConverterAnalyzer()
|
public ParameterMustHaveValidConverterAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Parameter converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
$"Parameter converters must derive from `{SymbolNames.CliFxBindingConverterClass}`",
|
||||||
@@ -46,5 +46,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class ParameterMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class ParameterMustHaveValidValidatorsAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public ParameterMustHaveValidValidatorsAnalyzer()
|
public ParameterMustHaveValidValidatorsAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Parameter validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
$"Parameter validators must derive from `{SymbolNames.CliFxBindingValidatorClass}`",
|
||||||
@@ -48,5 +48,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.HandlePropertyDeclaration(Analyze);
|
context.HandlePropertyDeclaration(Analyze);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,11 +6,11 @@ using Microsoft.CodeAnalysis.CSharp;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers
|
namespace CliFx.Analyzers;
|
||||||
|
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
||||||
{
|
{
|
||||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
|
||||||
public class SystemConsoleShouldBeAvoidedAnalyzer : AnalyzerBase
|
|
||||||
{
|
|
||||||
public SystemConsoleShouldBeAvoidedAnalyzer()
|
public SystemConsoleShouldBeAvoidedAnalyzer()
|
||||||
: base(
|
: base(
|
||||||
$"Avoid calling `System.Console` where `{SymbolNames.CliFxConsoleInterface}` is available",
|
$"Avoid calling `System.Console` where `{SymbolNames.CliFxConsoleInterface}` is available",
|
||||||
@@ -27,9 +27,9 @@ namespace CliFx.Analyzers
|
|||||||
|
|
||||||
while (currentNode is MemberAccessExpressionSyntax memberAccess)
|
while (currentNode is MemberAccessExpressionSyntax memberAccess)
|
||||||
{
|
{
|
||||||
var symbol = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol;
|
var member = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol;
|
||||||
|
|
||||||
if (symbol is not null && symbol.ContainingType.DisplayNameMatches("System.Console"))
|
if (member?.ContainingType?.DisplayNameMatches("System.Console") == true)
|
||||||
{
|
{
|
||||||
return memberAccess;
|
return memberAccess;
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,8 @@ namespace CliFx.Analyzers
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Check if IConsole is available in scope as an alternative to System.Console
|
// Check if IConsole is available in scope as an alternative to System.Console
|
||||||
var isConsoleInterfaceAvailable = context.Node
|
var isConsoleInterfaceAvailable = context
|
||||||
|
.Node
|
||||||
.Ancestors()
|
.Ancestors()
|
||||||
.OfType<MethodDeclarationSyntax>()
|
.OfType<MethodDeclarationSyntax>()
|
||||||
.SelectMany(m => m.ParameterList.Parameters)
|
.SelectMany(m => m.ParameterList.Parameters)
|
||||||
@@ -73,5 +74,4 @@ namespace CliFx.Analyzers
|
|||||||
base.Initialize(context);
|
base.Initialize(context);
|
||||||
context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.SimpleMemberAccessExpression);
|
context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.SimpleMemberAccessExpression);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,16 +4,21 @@ using Microsoft.CodeAnalysis.CSharp;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Diagnostics;
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Utils.Extensions
|
namespace CliFx.Analyzers.Utils.Extensions;
|
||||||
|
|
||||||
|
internal static class RoslynExtensions
|
||||||
{
|
{
|
||||||
internal static class RoslynExtensions
|
|
||||||
{
|
|
||||||
public static bool DisplayNameMatches(this ISymbol symbol, string name) =>
|
public static bool DisplayNameMatches(this ISymbol symbol, string name) =>
|
||||||
string.Equals(symbol.ToDisplayString(), name, StringComparison.Ordinal);
|
string.Equals(
|
||||||
|
// Fully qualified name, without `global::`
|
||||||
|
symbol.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat),
|
||||||
|
name,
|
||||||
|
StringComparison.Ordinal
|
||||||
|
);
|
||||||
|
|
||||||
public static void HandleClassDeclaration(
|
public static void HandleClassDeclaration(
|
||||||
this AnalysisContext analysisContext,
|
this AnalysisContext analysisContext,
|
||||||
Action<SyntaxNodeAnalysisContext, ClassDeclarationSyntax, ITypeSymbol> handler)
|
Action<SyntaxNodeAnalysisContext, ClassDeclarationSyntax, ITypeSymbol> analyze)
|
||||||
{
|
{
|
||||||
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
||||||
{
|
{
|
||||||
@@ -24,13 +29,13 @@ namespace CliFx.Analyzers.Utils.Extensions
|
|||||||
if (type is null)
|
if (type is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handler(ctx, classDeclaration, type);
|
analyze(ctx, classDeclaration, type);
|
||||||
}, SyntaxKind.ClassDeclaration);
|
}, SyntaxKind.ClassDeclaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HandlePropertyDeclaration(
|
public static void HandlePropertyDeclaration(
|
||||||
this AnalysisContext analysisContext,
|
this AnalysisContext analysisContext,
|
||||||
Action<SyntaxNodeAnalysisContext, PropertyDeclarationSyntax, IPropertySymbol> handler)
|
Action<SyntaxNodeAnalysisContext, PropertyDeclarationSyntax, IPropertySymbol> analyze)
|
||||||
{
|
{
|
||||||
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
analysisContext.RegisterSyntaxNodeAction(ctx =>
|
||||||
{
|
{
|
||||||
@@ -41,8 +46,7 @@ namespace CliFx.Analyzers.Utils.Extensions
|
|||||||
if (property is null)
|
if (property is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handler(ctx, propertyDeclaration, property);
|
analyze(ctx, propertyDeclaration, property);
|
||||||
}, SyntaxKind.PropertyDeclaration);
|
}, SyntaxKind.PropertyDeclaration);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CliFx.Analyzers.Utils.Extensions
|
namespace CliFx.Analyzers.Utils.Extensions;
|
||||||
|
|
||||||
|
internal static class StringExtensions
|
||||||
{
|
{
|
||||||
internal static class StringExtensions
|
|
||||||
{
|
|
||||||
public static string TrimEnd(
|
public static string TrimEnd(
|
||||||
this string str,
|
this string str,
|
||||||
string sub,
|
string sub,
|
||||||
@@ -14,5 +14,4 @@ namespace CliFx.Analyzers.Utils.Extensions
|
|||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,10 +4,10 @@ using BenchmarkDotNet.Attributes;
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
[Command]
|
[Command]
|
||||||
public class CliFxCommand : ICommand
|
public class CliFxCommand : ICommand
|
||||||
{
|
{
|
||||||
@@ -29,5 +29,4 @@ namespace CliFx.Benchmarks
|
|||||||
.AddCommand<CliFxCommand>()
|
.AddCommand<CliFxCommand>()
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync(Arguments, new Dictionary<string, string>());
|
.RunAsync(Arguments, new Dictionary<string, string>());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using clipr;
|
using clipr;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class CliprCommand
|
public class CliprCommand
|
||||||
{
|
{
|
||||||
[NamedArgument('s', "str")]
|
[NamedArgument('s', "str")]
|
||||||
@@ -23,5 +23,4 @@ namespace CliFx.Benchmarks
|
|||||||
|
|
||||||
[Benchmark(Description = "Clipr")]
|
[Benchmark(Description = "Clipr")]
|
||||||
public void ExecuteWithClipr() => CliParser.Parse<CliprCommand>(Arguments).Execute();
|
public void ExecuteWithClipr() => CliParser.Parse<CliprCommand>(Arguments).Execute();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Cocona;
|
using Cocona;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class CoconaCommand
|
public class CoconaCommand
|
||||||
{
|
{
|
||||||
public void Execute(
|
public void Execute(
|
||||||
@@ -20,5 +20,4 @@ namespace CliFx.Benchmarks
|
|||||||
|
|
||||||
[Benchmark(Description = "Cocona")]
|
[Benchmark(Description = "Cocona")]
|
||||||
public void ExecuteWithCocona() => CoconaApp.Run<CoconaCommand>(Arguments);
|
public void ExecuteWithCocona() => CoconaApp.Run<CoconaCommand>(Arguments);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using CommandLine;
|
using CommandLine;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class CommandLineParserCommand
|
public class CommandLineParserCommand
|
||||||
{
|
{
|
||||||
[Option('s', "str")]
|
[Option('s', "str")]
|
||||||
@@ -26,5 +26,4 @@ namespace CliFx.Benchmarks
|
|||||||
new Parser()
|
new Parser()
|
||||||
.ParseArguments(Arguments, typeof(CommandLineParserCommand))
|
.ParseArguments(Arguments, typeof(CommandLineParserCommand))
|
||||||
.WithParsed<CommandLineParserCommand>(c => c.Execute());
|
.WithParsed<CommandLineParserCommand>(c => c.Execute());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using McMaster.Extensions.CommandLineUtils;
|
using McMaster.Extensions.CommandLineUtils;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class McMasterCommand
|
public class McMasterCommand
|
||||||
{
|
{
|
||||||
[Option("--str|-s")]
|
[Option("--str|-s")]
|
||||||
@@ -21,5 +21,4 @@ namespace CliFx.Benchmarks
|
|||||||
|
|
||||||
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
[Benchmark(Description = "McMaster.Extensions.CommandLineUtils")]
|
||||||
public int ExecuteWithMcMaster() => CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
public int ExecuteWithMcMaster() => CommandLineApplication.Execute<McMasterCommand>(Arguments);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using PowerArgs;
|
using PowerArgs;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class PowerArgsCommand
|
public class PowerArgsCommand
|
||||||
{
|
{
|
||||||
[ArgShortcut("--str"), ArgShortcut("-s")]
|
[ArgShortcut("--str"), ArgShortcut("-s")]
|
||||||
@@ -23,5 +23,4 @@ namespace CliFx.Benchmarks
|
|||||||
|
|
||||||
[Benchmark(Description = "PowerArgs")]
|
[Benchmark(Description = "PowerArgs")]
|
||||||
public void ExecuteWithPowerArgs() => Args.InvokeMain<PowerArgsCommand>(Arguments);
|
public void ExecuteWithPowerArgs() => Args.InvokeMain<PowerArgsCommand>(Arguments);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,10 @@ using System.CommandLine.Invocation;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
public class SystemCommandLineCommand
|
public class SystemCommandLineCommand
|
||||||
{
|
{
|
||||||
public static int ExecuteHandler(string s, int i, bool b) => 0;
|
public static int ExecuteHandler(string s, int i, bool b) => 0;
|
||||||
@@ -40,5 +40,4 @@ namespace CliFx.Benchmarks
|
|||||||
[Benchmark(Description = "System.CommandLine")]
|
[Benchmark(Description = "System.CommandLine")]
|
||||||
public async Task<int> ExecuteWithSystemCommandLine() =>
|
public async Task<int> ExecuteWithSystemCommandLine() =>
|
||||||
await new SystemCommandLineCommand().ExecuteAsync(Arguments);
|
await new SystemCommandLineCommand().ExecuteAsync(Arguments);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,18 +3,17 @@ using BenchmarkDotNet.Configs;
|
|||||||
using BenchmarkDotNet.Order;
|
using BenchmarkDotNet.Order;
|
||||||
using BenchmarkDotNet.Running;
|
using BenchmarkDotNet.Running;
|
||||||
|
|
||||||
namespace CliFx.Benchmarks
|
namespace CliFx.Benchmarks;
|
||||||
|
|
||||||
|
[RankColumn]
|
||||||
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
|
public partial class Benchmarks
|
||||||
{
|
{
|
||||||
[RankColumn]
|
|
||||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
|
||||||
public partial class Benchmarks
|
|
||||||
{
|
|
||||||
private static readonly string[] Arguments = {"--str", "hello world", "-i", "13", "-b"};
|
private static readonly string[] Arguments = {"--str", "hello world", "-i", "13", "-b"};
|
||||||
|
|
||||||
public static void Main() => BenchmarkRunner.Run<Benchmarks>(
|
public static void Main() => BenchmarkRunner.Run<Benchmarks>(
|
||||||
DefaultConfig
|
DefaultConfig
|
||||||
.Instance
|
.Instance
|
||||||
.With(ConfigOptions.DisableOptimizationsValidator)
|
.WithOptions(ConfigOptions.DisableOptimizationsValidator)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||||
<PackageReference Include="clipr" Version="1.6.1" />
|
<PackageReference Include="clipr" Version="1.6.1" />
|
||||||
<PackageReference Include="Cocona" Version="1.5.0" />
|
<PackageReference Include="Cocona" Version="1.6.0" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.1.0" />
|
||||||
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
<PackageReference Include="PowerArgs" Version="3.6.0" />
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ using CliFx.Demo.Utils;
|
|||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Demo.Commands
|
namespace CliFx.Demo.Commands;
|
||||||
|
|
||||||
|
[Command("book add", Description = "Add a book to the library.")]
|
||||||
|
public partial class BookAddCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("book add", Description = "Add a book to the library.")]
|
|
||||||
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.")]
|
||||||
@@ -43,10 +43,10 @@ namespace CliFx.Demo.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class BookAddCommand
|
public partial class BookAddCommand
|
||||||
{
|
{
|
||||||
private static readonly Random Random = new();
|
private static readonly Random Random = new();
|
||||||
|
|
||||||
private static DateTimeOffset CreateRandomDate() => new(
|
private static DateTimeOffset CreateRandomDate() => new(
|
||||||
@@ -66,5 +66,4 @@ namespace CliFx.Demo.Commands
|
|||||||
Random.Next(0, 99),
|
Random.Next(0, 99),
|
||||||
Random.Next(0, 9)
|
Random.Next(0, 9)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,11 @@ using CliFx.Demo.Utils;
|
|||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Demo.Commands
|
namespace CliFx.Demo.Commands;
|
||||||
|
|
||||||
|
[Command("book", Description = "Retrieve a book from the library.")]
|
||||||
|
public class BookCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("book", Description = "Retrieve a book from the library.")]
|
|
||||||
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.")]
|
||||||
@@ -31,5 +31,4 @@ namespace CliFx.Demo.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ using CliFx.Demo.Domain;
|
|||||||
using CliFx.Demo.Utils;
|
using CliFx.Demo.Utils;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Demo.Commands
|
namespace CliFx.Demo.Commands;
|
||||||
|
|
||||||
|
[Command("book list", Description = "List all books in the library.")]
|
||||||
|
public class BookListCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("book list", Description = "List all books in the library.")]
|
|
||||||
public class BookListCommand : ICommand
|
|
||||||
{
|
|
||||||
private readonly LibraryProvider _libraryProvider;
|
private readonly LibraryProvider _libraryProvider;
|
||||||
|
|
||||||
public BookListCommand(LibraryProvider libraryProvider)
|
public BookListCommand(LibraryProvider libraryProvider)
|
||||||
@@ -33,5 +33,4 @@ namespace CliFx.Demo.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ using CliFx.Demo.Domain;
|
|||||||
using CliFx.Exceptions;
|
using CliFx.Exceptions;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Demo.Commands
|
namespace CliFx.Demo.Commands;
|
||||||
|
|
||||||
|
[Command("book remove", Description = "Remove a book from the library.")]
|
||||||
|
public class BookRemoveCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("book remove", Description = "Remove a book from the library.")]
|
|
||||||
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.")]
|
||||||
@@ -32,5 +32,4 @@ namespace CliFx.Demo.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CliFx.Demo.Domain
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
|
public class Book
|
||||||
{
|
{
|
||||||
public class Book
|
|
||||||
{
|
|
||||||
public string Title { get; }
|
public string Title { get; }
|
||||||
|
|
||||||
public string Author { get; }
|
public string Author { get; }
|
||||||
@@ -19,5 +19,4 @@ namespace CliFx.Demo.Domain
|
|||||||
Published = published;
|
Published = published;
|
||||||
Isbn = isbn;
|
Isbn = isbn;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CliFx.Demo.Domain
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
|
public partial class Isbn
|
||||||
{
|
{
|
||||||
public partial class Isbn
|
|
||||||
{
|
|
||||||
public int EanPrefix { get; }
|
public int EanPrefix { get; }
|
||||||
|
|
||||||
public int RegistrationGroup { get; }
|
public int RegistrationGroup { get; }
|
||||||
@@ -25,10 +25,10 @@ namespace CliFx.Demo.Domain
|
|||||||
|
|
||||||
public override string ToString() =>
|
public override string ToString() =>
|
||||||
$"{EanPrefix:000}-{RegistrationGroup:00}-{Registrant:00000}-{Publication:00}-{CheckDigit:0}";
|
$"{EanPrefix:000}-{RegistrationGroup:00}-{Registrant:00000}-{Publication:00}-{CheckDigit:0}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class Isbn
|
public partial class Isbn
|
||||||
{
|
{
|
||||||
public static Isbn Parse(string value, IFormatProvider formatProvider)
|
public static Isbn Parse(string value, IFormatProvider formatProvider)
|
||||||
{
|
{
|
||||||
var components = value.Split('-', 5, StringSplitOptions.RemoveEmptyEntries);
|
var components = value.Split('-', 5, StringSplitOptions.RemoveEmptyEntries);
|
||||||
@@ -41,5 +41,4 @@ namespace CliFx.Demo.Domain
|
|||||||
int.Parse(components[4], formatProvider)
|
int.Parse(components[4], formatProvider)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace CliFx.Demo.Domain
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
|
public partial class Library
|
||||||
{
|
{
|
||||||
public partial class Library
|
|
||||||
{
|
|
||||||
public IReadOnlyList<Book> Books { get; }
|
public IReadOnlyList<Book> Books { get; }
|
||||||
|
|
||||||
public Library(IReadOnlyList<Book> books)
|
public Library(IReadOnlyList<Book> books)
|
||||||
@@ -27,10 +27,9 @@ namespace CliFx.Demo.Domain
|
|||||||
|
|
||||||
return new Library(books);
|
return new Library(books);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class Library
|
public partial class Library
|
||||||
{
|
{
|
||||||
public static Library Empty { get; } = new(Array.Empty<Book>());
|
public static Library Empty { get; } = new(Array.Empty<Book>());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CliFx.Demo.Domain
|
namespace CliFx.Demo.Domain;
|
||||||
|
|
||||||
|
public class LibraryProvider
|
||||||
{
|
{
|
||||||
public class LibraryProvider
|
|
||||||
{
|
|
||||||
private static string StorageFilePath { get; } = Path.Combine(Directory.GetCurrentDirectory(), "Library.json");
|
private static string StorageFilePath { get; } = Path.Combine(Directory.GetCurrentDirectory(), "Library.json");
|
||||||
|
|
||||||
private void StoreLibrary(Library library)
|
private void StoreLibrary(Library library)
|
||||||
@@ -21,7 +21,7 @@ namespace CliFx.Demo.Domain
|
|||||||
|
|
||||||
var data = File.ReadAllText(StorageFilePath);
|
var data = File.ReadAllText(StorageFilePath);
|
||||||
|
|
||||||
return JsonConvert.DeserializeObject<Library>(data);
|
return JsonConvert.DeserializeObject<Library>(data) ?? Library.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Book? TryGetBook(string title) => GetLibrary().Books.FirstOrDefault(b => b.Title == title);
|
public Book? TryGetBook(string title) => GetLibrary().Books.FirstOrDefault(b => b.Title == title);
|
||||||
@@ -37,5 +37,4 @@ namespace CliFx.Demo.Domain
|
|||||||
var updatedLibrary = GetLibrary().WithoutBook(book);
|
var updatedLibrary = GetLibrary().WithoutBook(book);
|
||||||
StoreLibrary(updatedLibrary);
|
StoreLibrary(updatedLibrary);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,36 +1,25 @@
|
|||||||
using System;
|
using CliFx;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using CliFx.Demo.Commands;
|
using CliFx.Demo.Commands;
|
||||||
using CliFx.Demo.Domain;
|
using CliFx.Demo.Domain;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace CliFx.Demo
|
// We use Microsoft.Extensions.DependencyInjection for injecting dependencies in commands
|
||||||
{
|
var services = new ServiceCollection();
|
||||||
public static class Program
|
|
||||||
{
|
|
||||||
private static IServiceProvider GetServiceProvider()
|
|
||||||
{
|
|
||||||
// We use Microsoft.Extensions.DependencyInjection for injecting dependencies in commands
|
|
||||||
var services = new ServiceCollection();
|
|
||||||
|
|
||||||
// Register services
|
// Register services
|
||||||
services.AddSingleton<LibraryProvider>();
|
services.AddSingleton<LibraryProvider>();
|
||||||
|
|
||||||
// Register commands
|
// Register commands
|
||||||
services.AddTransient<BookCommand>();
|
services.AddTransient<BookCommand>();
|
||||||
services.AddTransient<BookAddCommand>();
|
services.AddTransient<BookAddCommand>();
|
||||||
services.AddTransient<BookRemoveCommand>();
|
services.AddTransient<BookRemoveCommand>();
|
||||||
services.AddTransient<BookListCommand>();
|
services.AddTransient<BookListCommand>();
|
||||||
|
|
||||||
return services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<int> Main() =>
|
return await new CliApplicationBuilder()
|
||||||
await new CliApplicationBuilder()
|
|
||||||
.SetDescription("Demo application showcasing CliFx features.")
|
.SetDescription("Demo application showcasing CliFx features.")
|
||||||
.AddCommandsFromThisAssembly()
|
.AddCommandsFromThisAssembly()
|
||||||
.UseTypeActivator(GetServiceProvider().GetRequiredService)
|
.UseTypeActivator(serviceProvider.GetRequiredService)
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync();
|
.RunAsync();
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
using CliFx.Demo.Domain;
|
using CliFx.Demo.Domain;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Demo.Utils
|
namespace CliFx.Demo.Utils;
|
||||||
|
|
||||||
|
internal static class ConsoleExtensions
|
||||||
{
|
{
|
||||||
internal static class ConsoleExtensions
|
|
||||||
{
|
|
||||||
public static void WriteBook(this ConsoleWriter writer, Book book)
|
public static void WriteBook(this ConsoleWriter writer, Book book)
|
||||||
{
|
{
|
||||||
// Title
|
// Title
|
||||||
@@ -33,5 +33,4 @@ namespace CliFx.Demo.Utils
|
|||||||
using (writer.Console.WithForegroundColor(ConsoleColor.White))
|
using (writer.Console.WithForegroundColor(ConsoleColor.White))
|
||||||
writer.WriteLine(book.Isbn);
|
writer.WriteLine(book.Isbn);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ using System.Threading.Tasks;
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Tests.Dummy.Commands
|
namespace CliFx.Tests.Dummy.Commands;
|
||||||
|
|
||||||
|
[Command("console-test")]
|
||||||
|
public class ConsoleTestCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("console-test")]
|
|
||||||
public class ConsoleTestCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console)
|
public ValueTask ExecuteAsync(IConsole console)
|
||||||
{
|
{
|
||||||
var input = console.Input.ReadToEnd();
|
var input = console.Input.ReadToEnd();
|
||||||
@@ -20,5 +20,4 @@ namespace CliFx.Tests.Dummy.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,11 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Tests.Dummy.Commands
|
namespace CliFx.Tests.Dummy.Commands;
|
||||||
|
|
||||||
|
[Command("env-test")]
|
||||||
|
public class EnvironmentTestCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command("env-test")]
|
|
||||||
public class EnvironmentTestCommand : ICommand
|
|
||||||
{
|
|
||||||
[CommandOption("target", EnvironmentVariable = "ENV_TARGET")]
|
[CommandOption("target", EnvironmentVariable = "ENV_TARGET")]
|
||||||
public string GreetingTarget { get; set; } = "World";
|
public string GreetingTarget { get; set; } = "World";
|
||||||
|
|
||||||
@@ -16,5 +16,4 @@ namespace CliFx.Tests.Dummy.Commands
|
|||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,22 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CliFx.Tests.Dummy
|
namespace CliFx.Tests.Dummy;
|
||||||
{
|
// This dummy application is used in tests for scenarios
|
||||||
// This dummy application is used in tests for scenarios
|
// that require an external process to properly verify.
|
||||||
// that require an external process to properly verify.
|
|
||||||
|
|
||||||
public static partial class Program
|
public static partial class Program
|
||||||
{
|
{
|
||||||
public static Assembly Assembly { get; } = typeof(Program).Assembly;
|
public static Assembly Assembly { get; } = typeof(Program).Assembly;
|
||||||
|
|
||||||
public static string Location { get; } = Assembly.Location;
|
public static string Location { get; } = Assembly.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class Program
|
public static partial class Program
|
||||||
{
|
{
|
||||||
public static async Task Main() =>
|
public static async Task Main() =>
|
||||||
await new CliApplicationBuilder()
|
await new CliApplicationBuilder()
|
||||||
.AddCommandsFromThisAssembly()
|
.AddCommandsFromThisAssembly()
|
||||||
.Build()
|
.Build()
|
||||||
.RunAsync();
|
.RunAsync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class ApplicationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class ApplicationSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public ApplicationSpecs(ITestOutputHelper testOutput)
|
public ApplicationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -82,5 +82,4 @@ namespace CliFx.Tests
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("not a valid command");
|
stdErr.Should().Contain("not a valid command");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class CancellationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class CancellationSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public CancellationSpecs(ITestOutputHelper testOutput)
|
public CancellationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -63,5 +63,4 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdOut.Trim().Should().Be("Cancelled");
|
stdOut.Trim().Should().Be("Cancelled");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsTestProject>true</IsTestProject>
|
<IsTestProject>true</IsTestProject>
|
||||||
<CollectCoverage>true</CollectCoverage>
|
<CollectCoverage>true</CollectCoverage>
|
||||||
@@ -13,14 +13,15 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CliWrap" Version="3.3.1" />
|
<PackageReference Include="Basic.Reference.Assemblies" Version="1.2.4" />
|
||||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
<PackageReference Include="CliWrap" Version="3.3.3" />
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.2.0" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="1.2.0" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="1.2.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="coverlet.msbuild" Version="3.0.3" PrivateAssets="all" />
|
<PackageReference Include="coverlet.msbuild" Version="3.1.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CliFx.Infrastructure;
|
||||||
using CliFx.Tests.Utils;
|
using CliFx.Tests.Utils;
|
||||||
using CliWrap;
|
using CliWrap;
|
||||||
using CliWrap.Buffered;
|
using CliWrap.Buffered;
|
||||||
@@ -8,10 +11,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class ConsoleSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class ConsoleSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public ConsoleSpecs(ITestOutputHelper testOutput)
|
public ConsoleSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -77,9 +80,9 @@ public class Command : ICommand
|
|||||||
// Assert
|
// Assert
|
||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
|
|
||||||
Console.OpenStandardInput().Should().NotBe(FakeConsole.Input.BaseStream);
|
Console.OpenStandardInput().Should().NotBeSameAs(FakeConsole.Input.BaseStream);
|
||||||
Console.OpenStandardOutput().Should().NotBe(FakeConsole.Output.BaseStream);
|
Console.OpenStandardOutput().Should().NotBeSameAs(FakeConsole.Output.BaseStream);
|
||||||
Console.OpenStandardError().Should().NotBe(FakeConsole.Error.BaseStream);
|
Console.OpenStandardError().Should().NotBeSameAs(FakeConsole.Error.BaseStream);
|
||||||
|
|
||||||
Console.ForegroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
Console.ForegroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
||||||
Console.BackgroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
Console.BackgroundColor.Should().NotBe(ConsoleColor.DarkMagenta);
|
||||||
@@ -135,5 +138,21 @@ public class Command : ICommand
|
|||||||
stdOut.Trim().Should().Be("Hello world");
|
stdOut.Trim().Should().Be("Hello world");
|
||||||
stdErr.Trim().Should().Be("Hello world");
|
stdErr.Trim().Should().Be("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Console_does_not_emit_preamble_when_used_with_encoding_that_has_it()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using var buffer = new MemoryStream();
|
||||||
|
using var consoleWriter = new ConsoleWriter(FakeConsole, buffer, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
consoleWriter.Write("Hello world");
|
||||||
|
consoleWriter.Flush();
|
||||||
|
|
||||||
|
var output = consoleWriter.Encoding.GetString(buffer.ToArray());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
output.Should().Be("Hello world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class ConversionSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class ConversionSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public ConversionSpecs(ITestOutputHelper testOutput)
|
public ConversionSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -946,5 +946,47 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("Hello world");
|
stdErr.Should().Contain("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Parameter_or_option_value_conversion_fails_if_the_static_parse_method_throws()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
public class CustomType
|
||||||
|
{
|
||||||
|
public string Value { get; }
|
||||||
|
|
||||||
|
private CustomType(string value) => Value = value;
|
||||||
|
|
||||||
|
public static CustomType Parse(string value) => throw new Exception(""Hello world"");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class Command : ICommand
|
||||||
|
{
|
||||||
|
[CommandOption('f')]
|
||||||
|
public CustomType Foo { get; set; }
|
||||||
|
|
||||||
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] {"-f", "bar"},
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdErr = FakeConsole.ReadErrorString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().NotBe(0);
|
||||||
|
stdErr.Should().Contain("Hello world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,10 +10,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class DirectivesSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class DirectivesSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public DirectivesSpecs(ITestOutputHelper testOutput)
|
public DirectivesSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -108,5 +108,4 @@ public class Command : ICommand
|
|||||||
"ENV_KIL", "=", "\"world\""
|
"ENV_KIL", "=", "\"world\""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -10,10 +10,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class EnvironmentSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class EnvironmentSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public EnvironmentSpecs(ITestOutputHelper testOutput)
|
public EnvironmentSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -256,5 +256,4 @@ public class Command : ICommand
|
|||||||
// Assert
|
// Assert
|
||||||
result.StandardOutput.Trim().Should().Be("Hello Mars!");
|
result.StandardOutput.Trim().Should().Be("Hello Mars!");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class ErrorReportingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class ErrorReportingSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public ErrorReportingSpecs(ITestOutputHelper testOutput)
|
public ErrorReportingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -201,5 +201,4 @@ public class Command : ICommand
|
|||||||
stdOut.Should().Contain("This will be in help text");
|
stdOut.Should().Contain("This will be in help text");
|
||||||
stdErr.Trim().Should().Be("Something went wrong");
|
stdErr.Trim().Should().Be("Something went wrong");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class HelpTextSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class HelpTextSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public HelpTextSpecs(ITestOutputHelper testOutput)
|
public HelpTextSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -371,6 +371,57 @@ public class Command : ICommand
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/Tyrrrz/CliFx/issues/117
|
||||||
|
[Fact]
|
||||||
|
public async Task Help_text_shows_usage_format_which_lists_all_parameters_in_specified_order()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
// Base members appear last in reflection order
|
||||||
|
public abstract class CommandBase : ICommand
|
||||||
|
{
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] { "--help" },
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().Be(0);
|
||||||
|
stdOut.Should().ContainAllInOrder(
|
||||||
|
"USAGE",
|
||||||
|
"<foo>", "<bar>", "<baz...>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Help_text_shows_usage_format_which_lists_all_required_options()
|
public async Task Help_text_shows_usage_format_which_lists_all_required_options()
|
||||||
{
|
{
|
||||||
@@ -577,6 +628,96 @@ public class Command : ICommand
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Help_text_shows_all_valid_values_for_non_scalar_enum_parameters_and_options()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] {"--help"},
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().Be(0);
|
||||||
|
stdOut.Should().ContainAllInOrder(
|
||||||
|
"PARAMETERS",
|
||||||
|
"foo", "Choices:", "One", "Two", "Three",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar", "Choices:", "One", "Two", "Three"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Help_text_shows_all_valid_values_for_nullable_enum_parameters_and_options()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var commandType = DynamicCommandBuilder.Compile(
|
||||||
|
// language=cs
|
||||||
|
@"
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
");
|
||||||
|
|
||||||
|
var application = new CliApplicationBuilder()
|
||||||
|
.AddCommand(commandType)
|
||||||
|
.UseConsole(FakeConsole)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var exitCode = await application.RunAsync(
|
||||||
|
new[] {"--help"},
|
||||||
|
new Dictionary<string, string>()
|
||||||
|
);
|
||||||
|
|
||||||
|
var stdOut = FakeConsole.ReadOutputString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
exitCode.Should().Be(0);
|
||||||
|
stdOut.Should().ContainAllInOrder(
|
||||||
|
"PARAMETERS",
|
||||||
|
"foo", "Choices:", "One", "Two", "Three",
|
||||||
|
"OPTIONS",
|
||||||
|
"--bar", "Choices:", "One", "Two", "Three"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Help_text_shows_environment_variables_for_options_that_have_them_configured_as_fallback()
|
public async Task Help_text_shows_environment_variables_for_options_that_have_them_configured_as_fallback()
|
||||||
{
|
{
|
||||||
@@ -874,5 +1015,4 @@ public class SecondCommandSecondChildCommand : ICommand
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
stdOut.Trim().Should().Be("v6.9");
|
stdOut.Trim().Should().Be("v6.9");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class OptionBindingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class OptionBindingSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public OptionBindingSpecs(ITestOutputHelper testOutput)
|
public OptionBindingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -704,5 +704,4 @@ 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");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class ParameterBindingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class ParameterBindingSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public ParameterBindingSpecs(ITestOutputHelper testOutput)
|
public ParameterBindingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -229,5 +229,4 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("Unexpected parameter(s)");
|
stdErr.Should().Contain("Unexpected parameter(s)");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class RoutingSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class RoutingSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public RoutingSpecs(ITestOutputHelper testOutput)
|
public RoutingSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -182,5 +182,4 @@ public class NamedChildCommand : ICommand
|
|||||||
exitCode.Should().Be(0);
|
exitCode.Should().Be(0);
|
||||||
stdOut.Trim().Should().Be("cmd child");
|
stdOut.Trim().Should().Be("cmd child");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,10 @@ using CliFx.Infrastructure;
|
|||||||
using CliFx.Tests.Utils.Extensions;
|
using CliFx.Tests.Utils.Extensions;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public abstract class SpecsBase : IDisposable
|
||||||
{
|
{
|
||||||
public abstract class SpecsBase : IDisposable
|
|
||||||
{
|
|
||||||
public ITestOutputHelper TestOutput { get; }
|
public ITestOutputHelper TestOutput { get; }
|
||||||
|
|
||||||
public FakeInMemoryConsole FakeConsole { get; } = new();
|
public FakeInMemoryConsole FakeConsole { get; } = new();
|
||||||
@@ -19,5 +19,4 @@ namespace CliFx.Tests
|
|||||||
FakeConsole.DumpToTestOutput(TestOutput);
|
FakeConsole.DumpToTestOutput(TestOutput);
|
||||||
FakeConsole.Dispose();
|
FakeConsole.Dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,10 @@ using FluentAssertions;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests
|
namespace CliFx.Tests;
|
||||||
|
|
||||||
|
public class TypeActivationSpecs : SpecsBase
|
||||||
{
|
{
|
||||||
public class TypeActivationSpecs : SpecsBase
|
|
||||||
{
|
|
||||||
public TypeActivationSpecs(ITestOutputHelper testOutput)
|
public TypeActivationSpecs(ITestOutputHelper testOutput)
|
||||||
: base(testOutput)
|
: base(testOutput)
|
||||||
{
|
{
|
||||||
@@ -161,5 +161,4 @@ public class Command : ICommand
|
|||||||
exitCode.Should().NotBe(0);
|
exitCode.Should().NotBe(0);
|
||||||
stdErr.Should().Contain("Failed to create an instance of type");
|
stdErr.Should().Contain("Failed to create an instance of type");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,24 +3,25 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Basic.Reference.Assemblies;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
namespace CliFx.Tests.Utils
|
namespace CliFx.Tests.Utils;
|
||||||
|
|
||||||
|
// This class uses Roslyn to compile commands dynamically.
|
||||||
|
//
|
||||||
|
// It allows us to collocate commands with tests more
|
||||||
|
// easily, which helps a lot when reasoning about them.
|
||||||
|
// Unfortunately, this comes at a cost of static typing,
|
||||||
|
// but this is still a worthwhile trade off.
|
||||||
|
//
|
||||||
|
// Maybe one day C# will allow declaring classes inside
|
||||||
|
// methods and doing this will no longer be necessary.
|
||||||
|
// Language proposal: https://github.com/dotnet/csharplang/discussions/130
|
||||||
|
internal static class DynamicCommandBuilder
|
||||||
{
|
{
|
||||||
// This class uses Roslyn to compile commands dynamically.
|
|
||||||
//
|
|
||||||
// It allows us to collocate commands with tests more
|
|
||||||
// easily, which helps a lot when reasoning about them.
|
|
||||||
// Unfortunately, this comes at a cost of static typing,
|
|
||||||
// but this is still a worthwhile trade off.
|
|
||||||
//
|
|
||||||
// Maybe one day C# will allow declaring classes inside
|
|
||||||
// methods and doing this will no longer be necessary.
|
|
||||||
// Language proposal: https://github.com/dotnet/csharplang/discussions/130
|
|
||||||
internal static class DynamicCommandBuilder
|
|
||||||
{
|
|
||||||
public static IReadOnlyList<Type> CompileMany(string sourceCode)
|
public static IReadOnlyList<Type> CompileMany(string sourceCode)
|
||||||
{
|
{
|
||||||
// Get default system namespaces
|
// Get default system namespaces
|
||||||
@@ -60,16 +61,9 @@ namespace CliFx.Tests.Utils
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
new[] {ast},
|
new[] {ast},
|
||||||
new[]
|
ReferenceAssemblies.Net50
|
||||||
{
|
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
||||||
MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location),
|
.Append(MetadataReference.CreateFromFile(typeof(DynamicCommandBuilder).Assembly.Location)),
|
||||||
MetadataReference.CreateFromFile(Assembly.Load("System.Runtime").Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(Console).Assembly.Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
|
|
||||||
MetadataReference.CreateFromFile(typeof(DynamicCommandBuilder).Assembly.Location),
|
|
||||||
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)
|
||||||
);
|
);
|
||||||
@@ -112,13 +106,13 @@ namespace CliFx.Tests.Utils
|
|||||||
// Return all defined commands
|
// Return all defined commands
|
||||||
var commandTypes = generatedAssembly
|
var commandTypes = generatedAssembly
|
||||||
.GetTypes()
|
.GetTypes()
|
||||||
.Where(t => t.IsAssignableTo(typeof(ICommand)))
|
.Where(t => t.IsAssignableTo(typeof(ICommand)) && !t.IsAbstract)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
if (commandTypes.Length <= 0)
|
if (commandTypes.Length <= 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"There are no command definitions in the provide source code."
|
"There are no command definitions in the provided source code."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,11 +126,10 @@ namespace CliFx.Tests.Utils
|
|||||||
if (commandTypes.Count > 1)
|
if (commandTypes.Count > 1)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"There are more than one command definitions in the provide source code."
|
"There are more than one command definitions in the provided source code."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return commandTypes.Single();
|
return commandTypes.Single();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using FluentAssertions.Collections;
|
|
||||||
using FluentAssertions.Execution;
|
using FluentAssertions.Execution;
|
||||||
using FluentAssertions.Primitives;
|
using FluentAssertions.Primitives;
|
||||||
|
|
||||||
namespace CliFx.Tests.Utils.Extensions
|
namespace CliFx.Tests.Utils.Extensions;
|
||||||
|
|
||||||
|
internal static class AssertionExtensions
|
||||||
{
|
{
|
||||||
internal static class AssertionExtensions
|
public static void ConsistOfLines(
|
||||||
{
|
|
||||||
public static AndConstraint<StringCollectionAssertions> ConsistOfLines(
|
|
||||||
this StringAssertions assertions,
|
this StringAssertions assertions,
|
||||||
IEnumerable<string> lines)
|
IEnumerable<string> lines)
|
||||||
{
|
{
|
||||||
var actualLines = assertions.Subject.Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
|
var actualLines = assertions.Subject.Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
actualLines.Should().Equal(lines);
|
||||||
return actualLines.Should().Equal(lines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AndConstraint<StringCollectionAssertions> ConsistOfLines(
|
public static void ConsistOfLines(
|
||||||
this StringAssertions assertions,
|
this StringAssertions assertions,
|
||||||
params string[] lines) =>
|
params string[] lines) =>
|
||||||
assertions.ConsistOfLines((IEnumerable<string>) lines);
|
assertions.ConsistOfLines((IEnumerable<string>) lines);
|
||||||
@@ -50,5 +48,4 @@ namespace CliFx.Tests.Utils.Extensions
|
|||||||
this StringAssertions assertions,
|
this StringAssertions assertions,
|
||||||
params string[] values) =>
|
params string[] values) =>
|
||||||
assertions.ContainAllInOrder((IEnumerable<string>) values);
|
assertions.ContainAllInOrder((IEnumerable<string>) values);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CliFx.Tests.Utils.Extensions
|
namespace CliFx.Tests.Utils.Extensions;
|
||||||
|
|
||||||
|
internal static class ConsoleExtensions
|
||||||
{
|
{
|
||||||
internal static class ConsoleExtensions
|
|
||||||
{
|
|
||||||
public static void DumpToTestOutput(this FakeInMemoryConsole console, ITestOutputHelper testOutputHelper)
|
public static void DumpToTestOutput(this FakeInMemoryConsole console, ITestOutputHelper testOutputHelper)
|
||||||
{
|
{
|
||||||
testOutputHelper.WriteLine("[*] Captured standard output:");
|
testOutputHelper.WriteLine("[*] Captured standard output:");
|
||||||
@@ -13,5 +13,4 @@ namespace CliFx.Tests.Utils.Extensions
|
|||||||
testOutputHelper.WriteLine("[*] Captured standard error:");
|
testOutputHelper.WriteLine("[*] Captured standard error:");
|
||||||
testOutputHelper.WriteLine(console.ReadErrorString());
|
testOutputHelper.WriteLine(console.ReadErrorString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,10 @@
|
|||||||
using CliFx.Attributes;
|
using CliFx.Attributes;
|
||||||
using CliFx.Infrastructure;
|
using CliFx.Infrastructure;
|
||||||
|
|
||||||
namespace CliFx.Tests.Utils
|
namespace CliFx.Tests.Utils;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public class NoOpCommand : ICommand
|
||||||
{
|
{
|
||||||
[Command]
|
|
||||||
public class NoOpCommand : ICommand
|
|
||||||
{
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace CliFx
|
namespace CliFx;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration of an application.
|
||||||
|
/// </summary>
|
||||||
|
public class ApplicationConfiguration
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Configuration of an application.
|
|
||||||
/// </summary>
|
|
||||||
public class ApplicationConfiguration
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command types defined in this application.
|
/// Command types defined in this application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -35,5 +35,4 @@ namespace CliFx
|
|||||||
IsDebugModeAllowed = isDebugModeAllowed;
|
IsDebugModeAllowed = isDebugModeAllowed;
|
||||||
IsPreviewModeAllowed = isPreviewModeAllowed;
|
IsPreviewModeAllowed = isPreviewModeAllowed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace CliFx
|
namespace CliFx;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Metadata associated with an application.
|
||||||
|
/// </summary>
|
||||||
|
public class ApplicationMetadata
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Metadata associated with an application.
|
|
||||||
/// </summary>
|
|
||||||
public class ApplicationMetadata
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Application title.
|
/// Application title.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
public string ExecutableName { get; }
|
public string ExecutableName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Application version text.
|
/// Application version.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Version { get; }
|
public string Version { get; }
|
||||||
|
|
||||||
@@ -39,5 +39,4 @@
|
|||||||
Version = version;
|
Version = version;
|
||||||
Description = description;
|
Description = description;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace CliFx.Attributes
|
namespace CliFx.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Annotates a type that defines a command.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||||
|
public sealed class CommandAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Annotates a type that defines a command.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
|
||||||
public class CommandAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command's name.
|
/// Command's name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -39,5 +39,4 @@ namespace CliFx.Attributes
|
|||||||
public CommandAttribute()
|
public CommandAttribute()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using CliFx.Extensibility;
|
using CliFx.Extensibility;
|
||||||
|
|
||||||
namespace CliFx.Attributes
|
namespace CliFx.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Annotates a property that defines a command option.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public sealed class CommandOptionAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Annotates a property that defines a command option.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class CommandOptionAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Option name.
|
/// Option name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,5 +96,4 @@ namespace CliFx.Attributes
|
|||||||
: this(null, (char?) shortName)
|
: this(null, (char?) shortName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using CliFx.Extensibility;
|
using CliFx.Extensibility;
|
||||||
|
|
||||||
namespace CliFx.Attributes
|
namespace CliFx.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Annotates a property that defines a command parameter.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public sealed class CommandParameterAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Annotates a property that defines a command parameter.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class CommandParameterAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parameter order.
|
/// Parameter order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -63,5 +63,4 @@ namespace CliFx.Attributes
|
|||||||
{
|
{
|
||||||
Order = order;
|
Order = order;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user