mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Merge branch 'master' into aot
This commit is contained in:
@@ -9,15 +9,15 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.7.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="6.0.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||||
<PackageReference Include="xunit" Version="2.6.1" />
|
<PackageReference Include="xunit" Version="2.8.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ public class GeneralSpecs
|
|||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var analyzers = typeof(AnalyzerBase)
|
var analyzers = typeof(AnalyzerBase)
|
||||||
.Assembly
|
.Assembly.GetTypes()
|
||||||
.GetTypes()
|
|
||||||
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
|
.Where(t => !t.IsAbstract && t.IsAssignableTo(typeof(DiagnosticAnalyzer)))
|
||||||
.Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!)
|
.Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption(null)]
|
[CommandOption(null)]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -40,7 +40,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -60,7 +60,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -79,7 +79,7 @@ public class OptionMustHaveNameOrShortNameAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Bar { get; init; }
|
public string? Bar { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -42,10 +42,10 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
[CommandOption("bar")]
|
[CommandOption("bar")]
|
||||||
public string? Bar { get; init; }
|
public string? Bar { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -65,7 +65,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -84,7 +84,7 @@ public class OptionMustHaveUniqueNameAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Bar { get; init; }
|
public string? Bar { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -43,10 +43,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
[CommandOption('b')]
|
[CommandOption('b')]
|
||||||
public string? Bar { get; init; }
|
public string? Bar { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -66,10 +66,10 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
[CommandOption('F')]
|
[CommandOption('F')]
|
||||||
public string? Bar { get; init; }
|
public string? Bar { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -89,7 +89,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -108,7 +108,7 @@ public class OptionMustHaveUniqueShortNameAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("f")]
|
[CommandOption("f")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -39,7 +39,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("1foo")]
|
[CommandOption("1foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -59,7 +59,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -79,7 +79,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -98,7 +98,7 @@ public class OptionMustHaveValidNameAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('1')]
|
[CommandOption('1')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -40,7 +40,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption('f')]
|
[CommandOption('f')]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -60,7 +60,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -79,7 +79,7 @@ public class OptionMustHaveValidShortNameAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
public void Validate(string value) {}
|
public void Validate(string value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -44,13 +44,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
public override BindingValidationError Validate(int value) => Ok();
|
public override BindingValidationError Validate(int value) => Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -69,13 +69,13 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
public override BindingValidationError Validate(string value) => Ok();
|
public override BindingValidationError Validate(string value) => Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
[CommandOption("foo", Validators = new[] { typeof(MyValidator) })]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -95,7 +95,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
{
|
{
|
||||||
[CommandOption("foo")]
|
[CommandOption("foo")]
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
@@ -114,7 +114,7 @@ public class OptionMustHaveValidValidatorsAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public string? Foo { get; init; }
|
public string? Foo { get; init; }
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzerSpecs
|
|||||||
public class MyCommand : ICommand
|
public class MyCommand : ICommand
|
||||||
{
|
{
|
||||||
public void SomeOtherMethod() => Console.WriteLine("Test");
|
public void SomeOtherMethod() => Console.WriteLine("Test");
|
||||||
|
|
||||||
public ValueTask ExecuteAsync(IConsole console) => default;
|
public ValueTask ExecuteAsync(IConsole console) => default;
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
|||||||
|
|
||||||
// Get default CliFx namespaces
|
// Get default CliFx namespaces
|
||||||
var defaultCliFxNamespaces = typeof(ICommand)
|
var defaultCliFxNamespaces = typeof(ICommand)
|
||||||
.Assembly
|
.Assembly.GetTypes()
|
||||||
.GetTypes()
|
|
||||||
.Where(t => t.IsPublic)
|
.Where(t => t.IsPublic)
|
||||||
.Select(t => t.Namespace)
|
.Select(t => t.Namespace)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
@@ -54,10 +53,9 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
|||||||
var compilation = CSharpCompilation.Create(
|
var compilation = CSharpCompilation.Create(
|
||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
[ast],
|
[ast],
|
||||||
Net80
|
Net80.References.All.Append(
|
||||||
.References
|
MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)
|
||||||
.All
|
),
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)),
|
|
||||||
// DLL to avoid having to define the Main() method
|
// DLL to avoid having to define the Main() method
|
||||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
|
||||||
);
|
);
|
||||||
@@ -105,8 +103,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
|||||||
== expectedDiagnosticIds.Length;
|
== expectedDiagnosticIds.Length;
|
||||||
|
|
||||||
Execute
|
Execute
|
||||||
.Assertion
|
.Assertion.ForCondition(isSuccessfulAssertion)
|
||||||
.ForCondition(isSuccessfulAssertion)
|
|
||||||
.FailWith(() =>
|
.FailWith(() =>
|
||||||
{
|
{
|
||||||
var buffer = new StringBuilder();
|
var buffer = new StringBuilder();
|
||||||
@@ -150,8 +147,7 @@ internal class AnalyzerAssertions(DiagnosticAnalyzer analyzer)
|
|||||||
var isSuccessfulAssertion = !producedDiagnostics.Any();
|
var isSuccessfulAssertion = !producedDiagnostics.Any();
|
||||||
|
|
||||||
Execute
|
Execute
|
||||||
.Assertion
|
.Assertion.ForCondition(isSuccessfulAssertion)
|
||||||
.ForCondition(isSuccessfulAssertion)
|
|
||||||
.FailWith(() =>
|
.FailWith(() =>
|
||||||
{
|
{
|
||||||
var buffer = new StringBuilder();
|
var buffer = new StringBuilder();
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<!-- Make sure to target the lowest possible version of the compiler for wider support -->
|
<!-- Make sure to target the lowest possible version of the compiler for wider support -->
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="PolyShim" Version="1.8.0" PrivateAssets="all" />
|
<PackageReference Include="PolyShim" Version="1.10.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -26,8 +26,8 @@ public class CommandMustBeAnnotatedAnalyzer()
|
|||||||
if (type.IsAbstract)
|
if (type.IsAbstract)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var implementsCommandInterface = type.AllInterfaces.Any(
|
var implementsCommandInterface = type.AllInterfaces.Any(i =>
|
||||||
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
);
|
);
|
||||||
|
|
||||||
var hasCommandAttribute = type.GetAttributes()
|
var hasCommandAttribute = type.GetAttributes()
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ public class CommandMustImplementInterfaceAnalyzer()
|
|||||||
.Select(a => a.AttributeClass)
|
.Select(a => a.AttributeClass)
|
||||||
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
.Any(c => c.DisplayNameMatches(SymbolNames.CliFxCommandAttribute));
|
||||||
|
|
||||||
var implementsCommandInterface = type.AllInterfaces.Any(
|
var implementsCommandInterface = type.AllInterfaces.Any(i =>
|
||||||
i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the attribute is present, but the interface is not implemented,
|
// If the attribute is present, but the interface is not implemented,
|
||||||
|
|||||||
@@ -32,10 +32,9 @@ internal partial class CommandOptionSymbol
|
|||||||
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
|
private static AttributeData? TryGetOptionAttribute(IPropertySymbol property) =>
|
||||||
property
|
property
|
||||||
.GetAttributes()
|
.GetAttributes()
|
||||||
.FirstOrDefault(
|
.FirstOrDefault(a =>
|
||||||
a =>
|
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute)
|
||||||
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandOptionAttribute)
|
== true
|
||||||
== true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
|
public static CommandOptionSymbol? TryResolve(IPropertySymbol property)
|
||||||
@@ -46,35 +45,30 @@ internal partial class CommandOptionSymbol
|
|||||||
|
|
||||||
var name =
|
var name =
|
||||||
attribute
|
attribute
|
||||||
.ConstructorArguments
|
.ConstructorArguments.Where(a => a.Type?.SpecialType == SpecialType.System_String)
|
||||||
.Where(a => a.Type?.SpecialType == SpecialType.System_String)
|
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.FirstOrDefault() as string;
|
.FirstOrDefault() as string;
|
||||||
|
|
||||||
var shortName =
|
var shortName =
|
||||||
attribute
|
attribute
|
||||||
.ConstructorArguments
|
.ConstructorArguments.Where(a => a.Type?.SpecialType == SpecialType.System_Char)
|
||||||
.Where(a => a.Type?.SpecialType == SpecialType.System_Char)
|
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.FirstOrDefault() as char?;
|
.FirstOrDefault() as char?;
|
||||||
|
|
||||||
var isRequired =
|
var isRequired =
|
||||||
attribute
|
attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "IsRequired")
|
||||||
.Where(a => a.Key == "IsRequired")
|
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as bool?;
|
.FirstOrDefault() as bool?;
|
||||||
|
|
||||||
var converter = attribute
|
var converter = attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "Converter")
|
||||||
.Where(a => a.Key == "Converter")
|
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.Cast<ITypeSymbol?>()
|
.Cast<ITypeSymbol?>()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var validators = attribute
|
var validators = attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "Validators")
|
||||||
.Where(a => a.Key == "Validators")
|
|
||||||
.SelectMany(a => a.Value.Values)
|
.SelectMany(a => a.Value.Values)
|
||||||
.Select(c => c.Value)
|
.Select(c => c.Value)
|
||||||
.Cast<ITypeSymbol>()
|
.Cast<ITypeSymbol>()
|
||||||
|
|||||||
@@ -32,10 +32,9 @@ internal partial class CommandParameterSymbol
|
|||||||
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
|
private static AttributeData? TryGetParameterAttribute(IPropertySymbol property) =>
|
||||||
property
|
property
|
||||||
.GetAttributes()
|
.GetAttributes()
|
||||||
.FirstOrDefault(
|
.FirstOrDefault(a =>
|
||||||
a =>
|
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute)
|
||||||
a.AttributeClass?.DisplayNameMatches(SymbolNames.CliFxCommandParameterAttribute)
|
== true
|
||||||
== true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
|
public static CommandParameterSymbol? TryResolve(IPropertySymbol property)
|
||||||
@@ -48,28 +47,24 @@ internal partial class CommandParameterSymbol
|
|||||||
|
|
||||||
var name =
|
var name =
|
||||||
attribute
|
attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "Name")
|
||||||
.Where(a => a.Key == "Name")
|
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as string;
|
.FirstOrDefault() as string;
|
||||||
|
|
||||||
var isRequired =
|
var isRequired =
|
||||||
attribute
|
attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "IsRequired")
|
||||||
.Where(a => a.Key == "IsRequired")
|
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.FirstOrDefault() as bool?;
|
.FirstOrDefault() as bool?;
|
||||||
|
|
||||||
var converter = attribute
|
var converter = attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "Converter")
|
||||||
.Where(a => a.Key == "Converter")
|
|
||||||
.Select(a => a.Value.Value)
|
.Select(a => a.Value.Value)
|
||||||
.Cast<ITypeSymbol?>()
|
.Cast<ITypeSymbol?>()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var validators = attribute
|
var validators = attribute
|
||||||
.NamedArguments
|
.NamedArguments.Where(a => a.Key == "Validators")
|
||||||
.Where(a => a.Key == "Validators")
|
|
||||||
.SelectMany(a => a.Value.Values)
|
.SelectMany(a => a.Value.Values)
|
||||||
.Select(c => c.Value)
|
.Select(c => c.Value)
|
||||||
.Cast<ITypeSymbol>()
|
.Cast<ITypeSymbol>()
|
||||||
|
|||||||
@@ -29,10 +29,9 @@ public class OptionMustBeInsideCommandAnalyzer()
|
|||||||
if (!CommandOptionSymbol.IsOptionProperty(property))
|
if (!CommandOptionSymbol.IsOptionProperty(property))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isInsideCommand = property
|
var isInsideCommand = property.ContainingType.AllInterfaces.Any(i =>
|
||||||
.ContainingType
|
i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.AllInterfaces
|
);
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
|
||||||
|
|
||||||
if (!isInsideCommand)
|
if (!isInsideCommand)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ public class OptionMustHaveUniqueNameAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ public class OptionMustHaveUniqueShortNameAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -28,13 +28,11 @@ public class OptionMustHaveValidConverterAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var converterValueType = option
|
var converterValueType = option
|
||||||
.ConverterType
|
.ConverterType.GetBaseTypes()
|
||||||
.GetBaseTypes()
|
.FirstOrDefault(t =>
|
||||||
.FirstOrDefault(
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
||||||
t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
|
||||||
)
|
)
|
||||||
?.TypeArguments
|
?.TypeArguments.FirstOrDefault();
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
// Value returned by the converter must be assignable to the property type
|
// Value returned by the converter must be assignable to the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
@@ -45,9 +43,10 @@ public class OptionMustHaveValidConverterAnalyzer()
|
|||||||
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
||||||
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
||||||
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
||||||
&& context
|
&& context.Compilation.IsAssignable(
|
||||||
.Compilation
|
converterValueType,
|
||||||
.IsAssignable(converterValueType, enumerableUnderlyingType)
|
enumerableUnderlyingType
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
|
|||||||
@@ -28,12 +28,10 @@ public class OptionMustHaveValidValidatorsAnalyzer()
|
|||||||
{
|
{
|
||||||
var validatorValueType = validatorType
|
var validatorValueType = validatorType
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(
|
.FirstOrDefault(t =>
|
||||||
t =>
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
||||||
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
|
||||||
)
|
)
|
||||||
?.TypeArguments
|
?.TypeArguments.FirstOrDefault();
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
// Value passed to the validator must be assignable from the property type
|
// Value passed to the validator must be assignable from the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
|
|||||||
@@ -29,10 +29,9 @@ public class ParameterMustBeInsideCommandAnalyzer()
|
|||||||
if (!CommandParameterSymbol.IsParameterProperty(property))
|
if (!CommandParameterSymbol.IsParameterProperty(property))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isInsideCommand = property
|
var isInsideCommand = property.ContainingType.AllInterfaces.Any(i =>
|
||||||
.ContainingType
|
i.DisplayNameMatches(SymbolNames.CliFxCommandInterface)
|
||||||
.AllInterfaces
|
);
|
||||||
.Any(i => i.DisplayNameMatches(SymbolNames.CliFxCommandInterface));
|
|
||||||
|
|
||||||
if (!isInsideCommand)
|
if (!isInsideCommand)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class ParameterMustBeLastIfNonRequiredAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class ParameterMustBeLastIfNonScalarAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class ParameterMustBeSingleIfNonRequiredAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class ParameterMustBeSingleIfNonScalarAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ public class ParameterMustHaveUniqueNameAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ public class ParameterMustHaveUniqueOrderAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var otherProperties = property
|
var otherProperties = property
|
||||||
.ContainingType
|
.ContainingType.GetMembers()
|
||||||
.GetMembers()
|
|
||||||
.OfType<IPropertySymbol>()
|
.OfType<IPropertySymbol>()
|
||||||
.Where(m => !m.Equals(property))
|
.Where(m => !m.Equals(property))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -28,13 +28,11 @@ public class ParameterMustHaveValidConverterAnalyzer()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var converterValueType = parameter
|
var converterValueType = parameter
|
||||||
.ConverterType
|
.ConverterType.GetBaseTypes()
|
||||||
.GetBaseTypes()
|
.FirstOrDefault(t =>
|
||||||
.FirstOrDefault(
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
||||||
t => t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingConverterClass)
|
|
||||||
)
|
)
|
||||||
?.TypeArguments
|
?.TypeArguments.FirstOrDefault();
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
// Value returned by the converter must be assignable to the property type
|
// Value returned by the converter must be assignable to the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
@@ -45,9 +43,10 @@ public class ParameterMustHaveValidConverterAnalyzer()
|
|||||||
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
? context.Compilation.IsAssignable(converterValueType, property.Type)
|
||||||
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
// Non-scalar (assume we can handle all IEnumerable types for simplicity)
|
||||||
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
: property.Type.TryGetEnumerableUnderlyingType() is { } enumerableUnderlyingType
|
||||||
&& context
|
&& context.Compilation.IsAssignable(
|
||||||
.Compilation
|
converterValueType,
|
||||||
.IsAssignable(converterValueType, enumerableUnderlyingType)
|
enumerableUnderlyingType
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isCompatible)
|
if (!isCompatible)
|
||||||
|
|||||||
@@ -28,12 +28,10 @@ public class ParameterMustHaveValidValidatorsAnalyzer()
|
|||||||
{
|
{
|
||||||
var validatorValueType = validatorType
|
var validatorValueType = validatorType
|
||||||
.GetBaseTypes()
|
.GetBaseTypes()
|
||||||
.FirstOrDefault(
|
.FirstOrDefault(t =>
|
||||||
t =>
|
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
||||||
t.ConstructedFrom.DisplayNameMatches(SymbolNames.CliFxBindingValidatorClass)
|
|
||||||
)
|
)
|
||||||
?.TypeArguments
|
?.TypeArguments.FirstOrDefault();
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
// Value passed to the validator must be assignable from the property type
|
// Value passed to the validator must be assignable from the property type
|
||||||
var isCompatible =
|
var isCompatible =
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ public class SystemConsoleShouldBeAvoidedAnalyzer()
|
|||||||
|
|
||||||
// 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
|
var isConsoleInterfaceAvailable = context
|
||||||
.Node
|
.Node.Ancestors()
|
||||||
.Ancestors()
|
|
||||||
.OfType<MethodDeclarationSyntax>()
|
.OfType<MethodDeclarationSyntax>()
|
||||||
.SelectMany(m => m.ParameterList.Parameters)
|
.SelectMany(m => m.ParameterList.Parameters)
|
||||||
.Select(p => p.Type)
|
.Select(p => p.Type)
|
||||||
|
|||||||
@@ -30,11 +30,10 @@ internal static class RoslynExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) =>
|
public static ITypeSymbol? TryGetEnumerableUnderlyingType(this ITypeSymbol type) =>
|
||||||
type.AllInterfaces
|
type
|
||||||
.FirstOrDefault(
|
.AllInterfaces.FirstOrDefault(i =>
|
||||||
i =>
|
i.ConstructedFrom.SpecialType
|
||||||
i.ConstructedFrom.SpecialType
|
== SpecialType.System_Collections_Generic_IEnumerable_T
|
||||||
== SpecialType.System_Collections_Generic_IEnumerable_T
|
|
||||||
)
|
)
|
||||||
?.TypeArguments[0];
|
?.TypeArguments[0];
|
||||||
|
|
||||||
@@ -44,8 +43,7 @@ internal static class RoslynExtensions
|
|||||||
property
|
property
|
||||||
// Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user,
|
// Can't rely on the RequiredMemberAttribute because it's generated by the compiler, not added by the user,
|
||||||
// so we have to check for the presence of the `required` modifier in the syntax tree instead.
|
// so we have to check for the presence of the `required` modifier in the syntax tree instead.
|
||||||
.DeclaringSyntaxReferences
|
.DeclaringSyntaxReferences.Select(r => r.GetSyntax())
|
||||||
.Select(r => r.GetSyntax())
|
|
||||||
.OfType<PropertyDeclarationSyntax>()
|
.OfType<PropertyDeclarationSyntax>()
|
||||||
.SelectMany(p => p.Modifiers)
|
.SelectMany(p => p.Modifiers)
|
||||||
.Any(m => m.IsKind((SyntaxKind)8447));
|
.Any(m => m.IsKind((SyntaxKind)8447));
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.11" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
|
||||||
<PackageReference Include="clipr" Version="1.6.1" />
|
<PackageReference Include="clipr" Version="1.6.1" />
|
||||||
<PackageReference Include="Cocona" Version="2.2.0" />
|
<PackageReference Include="Cocona" Version="2.2.0" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.0" />
|
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
|
||||||
<PackageReference Include="PowerArgs" Version="4.0.3" />
|
<PackageReference Include="PowerArgs" Version="4.0.3" />
|
||||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,18 +9,18 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.4.5" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net80" Version="1.7.2" />
|
||||||
<PackageReference Include="CliWrap" Version="3.6.4" />
|
<PackageReference Include="CliWrap" Version="3.6.6" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" PrivateAssets="all" />
|
<PackageReference Include="coverlet.collector" Version="6.0.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="PolyShim" Version="1.8.0" PrivateAssets="all" />
|
<PackageReference Include="PolyShim" Version="1.10.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="xunit" Version="2.6.3" />
|
<PackageReference Include="xunit" Version="2.8.0" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5" PrivateAssets="all" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ internal static class DynamicCommandBuilder
|
|||||||
|
|
||||||
// Get default CliFx namespaces
|
// Get default CliFx namespaces
|
||||||
var defaultCliFxNamespaces = typeof(ICommand)
|
var defaultCliFxNamespaces = typeof(ICommand)
|
||||||
.Assembly
|
.Assembly.GetTypes()
|
||||||
.GetTypes()
|
|
||||||
.Where(t => t.IsPublic)
|
.Where(t => t.IsPublic)
|
||||||
.Select(t => t.Namespace)
|
.Select(t => t.Namespace)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
@@ -57,9 +56,9 @@ internal static class DynamicCommandBuilder
|
|||||||
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
"CliFxTests_DynamicAssembly_" + Guid.NewGuid(),
|
||||||
[ast],
|
[ast],
|
||||||
Net80
|
Net80
|
||||||
.References
|
.References.All.Append(
|
||||||
.All
|
MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location)
|
||||||
.Append(MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location))
|
)
|
||||||
.Append(
|
.Append(
|
||||||
MetadataReference.CreateFromFile(
|
MetadataReference.CreateFromFile(
|
||||||
typeof(DynamicCommandBuilder).Assembly.Location
|
typeof(DynamicCommandBuilder).Assembly.Location
|
||||||
@@ -88,8 +87,8 @@ internal static class DynamicCommandBuilder
|
|||||||
using var buffer = new MemoryStream();
|
using var buffer = new MemoryStream();
|
||||||
var emit = compilation.Emit(buffer);
|
var emit = compilation.Emit(buffer);
|
||||||
|
|
||||||
var emitErrors = emit.Diagnostics
|
var emitErrors = emit
|
||||||
.Where(d => d.Severity >= DiagnosticSeverity.Error)
|
.Diagnostics.Where(d => d.Severity >= DiagnosticSeverity.Error)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
if (emitErrors.Any())
|
if (emitErrors.Any())
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ internal static class AssertionExtensions
|
|||||||
IEnumerable<string> lines
|
IEnumerable<string> lines
|
||||||
) =>
|
) =>
|
||||||
assertions
|
assertions
|
||||||
.Subject
|
.Subject.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Should()
|
.Should()
|
||||||
.Equal(lines);
|
.Equal(lines);
|
||||||
|
|
||||||
@@ -34,11 +33,9 @@ internal static class AssertionExtensions
|
|||||||
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
Execute
|
Execute.Assertion.FailWith(
|
||||||
.Assertion
|
$"Expected string '{assertions.Subject}' to contain '{value}' after position {lastIndex}."
|
||||||
.FailWith(
|
);
|
||||||
$"Expected string '{assertions.Subject}' to contain '{value}' after position {lastIndex}."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastIndex = index;
|
lastIndex = index;
|
||||||
|
|||||||
@@ -56,11 +56,9 @@ public class CliApplication(
|
|||||||
{
|
{
|
||||||
using (console.WithForegroundColor(ConsoleColor.Green))
|
using (console.WithForegroundColor(ConsoleColor.Green))
|
||||||
{
|
{
|
||||||
console
|
console.Output.WriteLine(
|
||||||
.Output
|
$"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue."
|
||||||
.WriteLine(
|
);
|
||||||
$"Attach the debugger to process with ID {ProcessEx.GetCurrentProcessId()} to continue."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to also launch the debugger ourselves (only works with Visual Studio)
|
// Try to also launch the debugger ourselves (only works with Visual Studio)
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ public partial class CliApplicationBuilder
|
|||||||
/// Configures the application to use the specified service provider for activating types.
|
/// Configures the application to use the specified service provider for activating types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CliApplicationBuilder UseTypeActivator(IServiceProvider serviceProvider) =>
|
public CliApplicationBuilder UseTypeActivator(IServiceProvider serviceProvider) =>
|
||||||
UseTypeActivator(serviceProvider.GetService);
|
// Null returns are handled by DelegateTypeActivator
|
||||||
|
UseTypeActivator(serviceProvider.GetService!);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the application to use the specified service provider for activating types.
|
/// Configures the application to use the specified service provider for activating types.
|
||||||
|
|||||||
@@ -23,9 +23,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CSharpier.MsBuild" Version="0.26.5" PrivateAssets="all" />
|
<PackageReference Include="CSharpier.MsBuild" Version="0.28.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="PolyShim" Version="1.8.0" PrivateAssets="all" />
|
<PackageReference Include="PolyShim" Version="1.10.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -42,13 +42,15 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
// Special case for DateTimeOffset
|
// Special case for DateTimeOffset
|
||||||
if (targetType == typeof(DateTimeOffset))
|
if (targetType == typeof(DateTimeOffset))
|
||||||
{
|
{
|
||||||
return DateTimeOffset.Parse(rawValue, _formatProvider);
|
// Null reference exception will be handled upstream
|
||||||
|
return DateTimeOffset.Parse(rawValue!, _formatProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for TimeSpan
|
// Special case for TimeSpan
|
||||||
if (targetType == typeof(TimeSpan))
|
if (targetType == typeof(TimeSpan))
|
||||||
{
|
{
|
||||||
return TimeSpan.Parse(rawValue, _formatProvider);
|
// Null reference exception will be handled upstream
|
||||||
|
return TimeSpan.Parse(rawValue!, _formatProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum
|
// Enum
|
||||||
@@ -143,10 +145,8 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Non-scalar
|
// Non-scalar
|
||||||
var enumerableUnderlyingType = memberSchema
|
var enumerableUnderlyingType =
|
||||||
.Property
|
memberSchema.Property.Type.TryGetEnumerableUnderlyingType();
|
||||||
.Type
|
|
||||||
.TryGetEnumerableUnderlyingType();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
enumerableUnderlyingType is not null
|
enumerableUnderlyingType is not null
|
||||||
@@ -244,8 +244,7 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
// Ensure there are no unexpected parameters and that all parameters are provided
|
// Ensure there are no unexpected parameters and that all parameters are provided
|
||||||
var remainingParameterInputs = commandInput.Parameters.ToList();
|
var remainingParameterInputs = commandInput.Parameters.ToList();
|
||||||
var remainingRequiredParameterSchemas = commandSchema
|
var remainingRequiredParameterSchemas = commandSchema
|
||||||
.Parameters
|
.Parameters.Where(p => p.IsRequired)
|
||||||
.Where(p => p.IsRequired)
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var position = 0;
|
var position = 0;
|
||||||
@@ -298,7 +297,9 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"""
|
$"""
|
||||||
Missing required parameter(s):
|
Missing required parameter(s):
|
||||||
{remainingRequiredParameterSchemas.Select(p => p.GetFormattedIdentifier()).JoinToString(" ")}
|
{remainingRequiredParameterSchemas
|
||||||
|
.Select(p => p.GetFormattedIdentifier())
|
||||||
|
.JoinToString(" ")}
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -313,20 +314,18 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
// Ensure there are no unrecognized options and that all required options are set
|
// Ensure there are no unrecognized options and that all required options are set
|
||||||
var remainingOptionInputs = commandInput.Options.ToList();
|
var remainingOptionInputs = commandInput.Options.ToList();
|
||||||
var remainingRequiredOptionSchemas = commandSchema
|
var remainingRequiredOptionSchemas = commandSchema
|
||||||
.Options
|
.Options.Where(o => o.IsRequired)
|
||||||
.Where(o => o.IsRequired)
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
foreach (var optionSchema in commandSchema.Options)
|
foreach (var optionSchema in commandSchema.Options)
|
||||||
{
|
{
|
||||||
var optionInputs = commandInput
|
var optionInputs = commandInput
|
||||||
.Options
|
.Options.Where(o => optionSchema.MatchesIdentifier(o.Identifier))
|
||||||
.Where(o => optionSchema.MatchesIdentifier(o.Identifier))
|
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var environmentVariableInput = commandInput
|
var environmentVariableInput = commandInput.EnvironmentVariables.FirstOrDefault(e =>
|
||||||
.EnvironmentVariables
|
optionSchema.MatchesEnvironmentVariable(e.Name)
|
||||||
.FirstOrDefault(e => optionSchema.MatchesEnvironmentVariable(e.Name));
|
);
|
||||||
|
|
||||||
// Direct input
|
// Direct input
|
||||||
if (optionInputs.Any())
|
if (optionInputs.Any())
|
||||||
@@ -376,7 +375,9 @@ internal class CommandBinder(ITypeActivator typeActivator)
|
|||||||
throw CliFxException.UserError(
|
throw CliFxException.UserError(
|
||||||
$"""
|
$"""
|
||||||
Missing required option(s):
|
Missing required option(s):
|
||||||
{remainingRequiredOptionSchemas.Select(o => o.GetFormattedIdentifier()).JoinToString(", ")}
|
{remainingRequiredOptionSchemas
|
||||||
|
.Select(o => o.GetFormattedIdentifier())
|
||||||
|
.JoinToString(", ")}
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Child command usage
|
// Child command usage
|
||||||
var childCommandSchemas = context
|
var childCommandSchemas = context.ApplicationSchema.GetChildCommands(
|
||||||
.ApplicationSchema
|
context.CommandSchema.Name
|
||||||
.GetChildCommands(context.CommandSchema.Name);
|
);
|
||||||
|
|
||||||
if (childCommandSchemas.Any())
|
if (childCommandSchemas.Any())
|
||||||
{
|
{
|
||||||
@@ -359,8 +359,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con
|
|||||||
private void WriteCommandChildren()
|
private void WriteCommandChildren()
|
||||||
{
|
{
|
||||||
var childCommandSchemas = context
|
var childCommandSchemas = context
|
||||||
.ApplicationSchema
|
.ApplicationSchema.GetChildCommands(context.CommandSchema.Name)
|
||||||
.GetChildCommands(context.CommandSchema.Name)
|
|
||||||
.OrderBy(a => a.Name, StringComparer.Ordinal)
|
.OrderBy(a => a.Name, StringComparer.Ordinal)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -393,8 +392,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con
|
|||||||
|
|
||||||
// Child commands of child command
|
// Child commands of child command
|
||||||
var grandChildCommandSchemas = context
|
var grandChildCommandSchemas = context
|
||||||
.ApplicationSchema
|
.ApplicationSchema.GetChildCommands(childCommandSchema.Name)
|
||||||
.GetChildCommands(childCommandSchema.Name)
|
|
||||||
.OrderBy(c => c.Name, StringComparer.Ordinal)
|
.OrderBy(c => c.Name, StringComparer.Ordinal)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
@@ -418,8 +416,7 @@ internal class HelpConsoleFormatter(ConsoleWriter consoleWriter, HelpContext con
|
|||||||
ConsoleColor.Cyan,
|
ConsoleColor.Cyan,
|
||||||
// Relative to current command (not the parent)
|
// Relative to current command (not the parent)
|
||||||
grandChildCommandSchema
|
grandChildCommandSchema
|
||||||
.Name
|
.Name?.Substring(context.CommandSchema.Name?.Length ?? 0)
|
||||||
?.Substring(context.CommandSchema.Name?.Length ?? 0)
|
|
||||||
.Trim()
|
.Trim()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class ConsoleWriter : StreamWriter
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
public override void Write(char[] buffer) => base.Write(buffer);
|
public override void Write(char[]? buffer) => base.Write(buffer);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
@@ -147,7 +147,7 @@ public class ConsoleWriter : StreamWriter
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
public override void WriteLine(char[] buffer) => base.WriteLine(buffer);
|
public override void WriteLine(char[]? buffer) => base.WriteLine(buffer);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
[ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)]
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ public class DefaultTypeActivator : ITypeActivator
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Activator.CreateInstance(type);
|
return Activator.CreateInstance(type)
|
||||||
|
?? throw CliFxException.InternalError(
|
||||||
|
$"""
|
||||||
|
Failed to create an instance of type `{type.FullName}`, received <null> instead.
|
||||||
|
This may be caused by the type's constructor being trimmed away.
|
||||||
|
"""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Only catch MemberAccessException because the constructor can throw for its own reasons too
|
// Only catch MemberAccessException because the constructor can throw for its own reasons too
|
||||||
catch (MemberAccessException ex)
|
catch (MemberAccessException ex)
|
||||||
|
|||||||
@@ -9,21 +9,13 @@ namespace CliFx.Infrastructure;
|
|||||||
public class DelegateTypeActivator(Func<Type, object> createInstance) : ITypeActivator
|
public class DelegateTypeActivator(Func<Type, object> createInstance) : ITypeActivator
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object CreateInstance(Type type)
|
public object CreateInstance(Type type) =>
|
||||||
{
|
createInstance(type)
|
||||||
var instance = createInstance(type);
|
?? throw CliFxException.InternalError(
|
||||||
|
$"""
|
||||||
if (instance is null)
|
Failed to create an instance of type `{type.FullName}`, received <null> instead.
|
||||||
{
|
To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return <null>.
|
||||||
throw CliFxException.InternalError(
|
If you are relying on a dependency container, this error may indicate that the specified type has not been registered.
|
||||||
$"""
|
"""
|
||||||
Failed to create an instance of type `{type.FullName}`, received <null> instead.
|
);
|
||||||
To fix this, ensure that the provided type activator is configured correctly, as it's not expected to return <null>.
|
|
||||||
If you are relying on a dependency container, this error may indicate that the specified type has not been registered.
|
|
||||||
"""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ internal partial class ApplicationSchema(IReadOnlyList<CommandSchema> commands)
|
|||||||
string.IsNullOrWhiteSpace(parentCommandName)
|
string.IsNullOrWhiteSpace(parentCommandName)
|
||||||
||
|
||
|
||||||
// Otherwise a command is a descendant if it starts with the same name segments
|
// Otherwise a command is a descendant if it starts with the same name segments
|
||||||
potentialParentCommandSchema
|
potentialParentCommandSchema.Name.StartsWith(
|
||||||
.Name
|
parentCommandName + ' ',
|
||||||
.StartsWith(parentCommandName + ' ', StringComparison.OrdinalIgnoreCase);
|
StringComparison.OrdinalIgnoreCase
|
||||||
|
);
|
||||||
|
|
||||||
if (isDescendant)
|
if (isDescendant)
|
||||||
result.Add(potentialParentCommandSchema);
|
result.Add(potentialParentCommandSchema);
|
||||||
|
|||||||
@@ -86,10 +86,14 @@ internal partial class CommandSchema
|
|||||||
type.GetInterfaces()
|
type.GetInterfaces()
|
||||||
// Only interfaces implementing ICommand for explicitness
|
// Only interfaces implementing ICommand for explicitness
|
||||||
.Where(i => i != typeof(ICommand) && i.IsAssignableTo(typeof(ICommand)))
|
.Where(i => i != typeof(ICommand) && i.IsAssignableTo(typeof(ICommand)))
|
||||||
.SelectMany(
|
.SelectMany(i =>
|
||||||
i =>
|
i.GetProperties()
|
||||||
i.GetProperties()
|
.Where(p =>
|
||||||
.Where(p => !p.GetMethod.IsAbstract && !p.SetMethod.IsAbstract)
|
p.GetMethod is not null
|
||||||
|
&& !p.GetMethod.IsAbstract
|
||||||
|
&& p.SetMethod is not null
|
||||||
|
&& !p.SetMethod.IsAbstract
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|||||||
@@ -42,10 +42,11 @@ internal static class CollectionExtensions
|
|||||||
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
|
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
|
||||||
this IDictionary dictionary,
|
this IDictionary dictionary,
|
||||||
IEqualityComparer<TKey> comparer
|
IEqualityComparer<TKey> comparer
|
||||||
) =>
|
)
|
||||||
|
where TKey : notnull =>
|
||||||
dictionary
|
dictionary
|
||||||
.Cast<DictionaryEntry>()
|
.Cast<DictionaryEntry>()
|
||||||
.ToDictionary(entry => (TKey)entry.Key, entry => (TValue)entry.Value, comparer);
|
.ToDictionary(entry => (TKey)entry.Key, entry => (TValue)entry.Value!, comparer);
|
||||||
|
|
||||||
public static Array ToNonGenericArray<T>(this IEnumerable<T> source, Type elementType)
|
public static Array ToNonGenericArray<T>(this IEnumerable<T> source, Type elementType)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ internal static class PropertyExtensions
|
|||||||
// Match attribute by name to avoid depending on .NET 7.0+ and to allow polyfilling
|
// Match attribute by name to avoid depending on .NET 7.0+ and to allow polyfilling
|
||||||
propertyInfo
|
propertyInfo
|
||||||
.GetCustomAttributes()
|
.GetCustomAttributes()
|
||||||
.Any(
|
.Any(a =>
|
||||||
a =>
|
string.Equals(
|
||||||
string.Equals(
|
a.GetType().FullName,
|
||||||
a.GetType().FullName,
|
"System.Runtime.CompilerServices.RequiredMemberAttribute",
|
||||||
"System.Runtime.CompilerServices.RequiredMemberAttribute",
|
StringComparison.Ordinal
|
||||||
StringComparison.Ordinal
|
)
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ internal static class StringExtensions
|
|||||||
public static string JoinToString<T>(this IEnumerable<T> source, string separator) =>
|
public static string JoinToString<T>(this IEnumerable<T> source, string separator) =>
|
||||||
string.Join(separator, source);
|
string.Join(separator, source);
|
||||||
|
|
||||||
public static string ToString(
|
public static string? ToString(
|
||||||
this object obj,
|
this object obj,
|
||||||
IFormatProvider? formatProvider = null,
|
IFormatProvider? formatProvider = null,
|
||||||
string? format = null
|
string? format = null
|
||||||
|
|||||||
@@ -41,33 +41,33 @@ internal partial class StackFrame
|
|||||||
private static readonly Regex Pattern =
|
private static readonly Regex Pattern =
|
||||||
new(
|
new(
|
||||||
$$"""
|
$$"""
|
||||||
^
|
^
|
||||||
{{Space}}*
|
{{Space}}*
|
||||||
\w+ {{Space}}+
|
\w+ {{Space}}+
|
||||||
(?<frame>
|
(?<frame>
|
||||||
(?<type> {{NotSpace}}+ ) \.
|
(?<type> {{NotSpace}}+ ) \.
|
||||||
(?<method> {{NotSpace}}+? ) {{Space}}*
|
(?<method> {{NotSpace}}+? ) {{Space}}*
|
||||||
(?<params> \( ( {{Space}}* \)
|
(?<params> \( ( {{Space}}* \)
|
||||||
| (?<pt> .+?) {{Space}}+ (?<pn> .+?)
|
| (?<pt> .+?) {{Space}}+ (?<pn> .+?)
|
||||||
(, {{Space}}* (?<pt> .+?) {{Space}}+ (?<pn> .+?) )* \) ) )
|
(, {{Space}}* (?<pt> .+?) {{Space}}+ (?<pn> .+?) )* \) ) )
|
||||||
( {{Space}}+
|
( {{Space}}+
|
||||||
( # Microsoft .NET stack traces
|
( # Microsoft .NET stack traces
|
||||||
\w+ {{Space}}+
|
\w+ {{Space}}+
|
||||||
(?<file> ( [a-z] \: # Windows rooted path starting with a drive letter
|
(?<file> ( [a-z] \: # Windows rooted path starting with a drive letter
|
||||||
| / ) # Unix rooted path starting with a forward-slash
|
| / ) # Unix rooted path starting with a forward-slash
|
||||||
.+? )
|
.+? )
|
||||||
\: \w+ {{Space}}+
|
\: \w+ {{Space}}+
|
||||||
(?<line> [0-9]+ ) \p{P}?
|
(?<line> [0-9]+ ) \p{P}?
|
||||||
| # Mono stack traces
|
| # Mono stack traces
|
||||||
\[0x[0-9a-f]+\] {{Space}}+ \w+ {{Space}}+
|
\[0x[0-9a-f]+\] {{Space}}+ \w+ {{Space}}+
|
||||||
<(?<file> [^>]+ )>
|
<(?<file> [^>]+ )>
|
||||||
:(?<line> [0-9]+ )
|
:(?<line> [0-9]+ )
|
||||||
)
|
)
|
||||||
)?
|
)?
|
||||||
)
|
)
|
||||||
\s*
|
\s*
|
||||||
$
|
$
|
||||||
""",
|
""",
|
||||||
RegexOptions.IgnoreCase
|
RegexOptions.IgnoreCase
|
||||||
| RegexOptions.Multiline
|
| RegexOptions.Multiline
|
||||||
| RegexOptions.ExplicitCapture
|
| RegexOptions.ExplicitCapture
|
||||||
|
|||||||
Reference in New Issue
Block a user