From cf0a6881d4260a17706ebae78298e10df5395b55 Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 16 Jan 2025 10:48:52 +0900 Subject: [PATCH 01/31] emit ConsoleApp.g.cs --- src/ConsoleAppFramework/ConsoleAppGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index dedef6e1..f03c2139 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -182,7 +182,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) static void EmitConsoleAppTemplateSource(IncrementalGeneratorPostInitializationContext context) { - context.AddSource("ConsoleApp.cs", ConsoleAppBaseCode.InitializationCode); + context.AddSource("ConsoleApp.g.cs", ConsoleAppBaseCode.InitializationCode); } static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, CommanContext commandContext) From a123d48a15de204ffee3dd004bb821d9f0e76274 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:53:18 +0900 Subject: [PATCH 02/31] chore: fix spelling issues --- ConsoleAppFramework.sln | 2 +- ReadMe.md | 6 +-- exclusion.dic | 41 +++++++++++++++++++ sandbox/GeneratorSandbox/Filters.cs | 2 +- .../ConsoleAppGenerator.cs | 12 +++--- .../DiagnosticDescriptors.cs | 4 +- src/ConsoleAppFramework/Emitter.cs | 8 ++-- src/ConsoleAppFramework/Parser.cs | 12 +++--- src/ConsoleAppFramework/RoslynExtensions.cs | 4 +- .../{ArrayPraseTest.cs => ArrayParseTest.cs} | 2 +- .../NameConverterTest.cs | 2 +- 11 files changed, 68 insertions(+), 27 deletions(-) create mode 100644 exclusion.dic rename tests/ConsoleAppFramework.GeneratorTests/{ArrayPraseTest.cs => ArrayParseTest.cs} (97%) diff --git a/ConsoleAppFramework.sln b/ConsoleAppFramework.sln index 124388f5..e02ebe20 100644 --- a/ConsoleAppFramework.sln +++ b/ConsoleAppFramework.sln @@ -13,9 +13,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .dockerignore = .dockerignore .gitignore = .gitignore - .circleci\config.yml = .circleci\config.yml Directory.Build.props = Directory.Build.props ReadMe.md = ReadMe.md + exclusion.dic = exclusion.dic EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppFramework", "src\ConsoleAppFramework\ConsoleAppFramework.csproj", "{09BEEA7B-B6D3-4011-BCAB-6DF976713695}" diff --git a/ReadMe.md b/ReadMe.md index 8c12d031..f373d5a9 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -670,7 +670,7 @@ The field secondArg must be between 0 and 2. By default, the ExitCode is set to 1 in this case. -Filter(Middleware) Pipline / ConsoleAppContext +Filter(Middleware) Pipeline / ConsoleAppContext --- Filters are provided as a mechanism to hook into the execution before and after. To use filters, define an `internal class` that implements `ConsoleAppFilter`. @@ -1022,7 +1022,7 @@ When `Microsoft.Extensions.Configuration` is imported, `ConfigureEmptyConfigurat Furthermore, overloads of `Action configure` and `Action configure` are added to `ConfigureServices` and `ConfigureLogging`, allowing you to retrieve the Configuration when executing the delegate. -without Hosting dependency, I've prefere these import packages. +without Hosting dependency, I've preferred these import packages. ```xml @@ -1106,7 +1106,7 @@ ConsoleApp.ServiceProvider = scope.ServiceProvider; * `app.AddAllCommandType` -> `NotSupported`(use `Add` manually) * `[Option(int index)]` -> `[Argument]` * `[Option(string shortName, string description)]` -> `Xml Document Comment` -* `ConsoleAppFilter.Order` -> `NotSupported`(global -> class -> method declrative order) +* `ConsoleAppFilter.Order` -> `NotSupported`(global -> class -> method declarative order) * `ConsoleAppOptions.GlobalFilters` -> `app.UseFilter` * `ConsoleAppBase` -> inject `ConsoleAppContext`, `CancellationToken` to method diff --git a/exclusion.dic b/exclusion.dic new file mode 100644 index 00000000..ea77d898 --- /dev/null +++ b/exclusion.dic @@ -0,0 +1,41 @@ +abcd +abcde +abcdefg +aiueo +appsettings +args +authed +awaitable +Awaiter +Binded +Clipr +Cysharp +Decr +dest +Equatable +fooa +foobarbaz +generatortest +hoge +ignorecase +Impl +Incr +Kabayaki +Kokuban +Lamda +Moge +nomsg +nomunomu +Numerics +Parsable +posix +saas +Spectre +stackalloc +stdout +Tacommands +tako +takoyaki +Withargs +Yaki +Zeroargs diff --git a/sandbox/GeneratorSandbox/Filters.cs b/sandbox/GeneratorSandbox/Filters.cs index a05c887d..ee6be4bd 100644 --- a/sandbox/GeneratorSandbox/Filters.cs +++ b/sandbox/GeneratorSandbox/Filters.cs @@ -54,7 +54,7 @@ async Task GetUserIdAsync() } } -record class ApplicationContext(Guid RequiestId, int UserId); +record class ApplicationContext(Guid RequestId, int UserId); internal class LogRunningTimeFilter(ConsoleAppFilter next) : ConsoleAppFilter(next) { diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index f03c2139..133bdb8f 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -15,7 +15,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Emit ConsoleApp.g.cs context.RegisterPostInitializationOutput(EmitConsoleAppTemplateSource); - // Emti ConfigureConfiguration/Logging/Services and Host.AsConsoleApp + // Emit ConfigureConfiguration/Logging/Services and Host.AsConsoleApp var hasReferences = context.MetadataReferencesProvider .Collect() .Select((xs, _) => @@ -118,7 +118,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var isRunAsync = (node.Expression as MemberAccessExpressionSyntax)?.Name.Identifier.Text == "RunAsync"; var command = parser.ParseAndValidateForRun(); - return new CommanContext(command, isRunAsync, reporter, node); + return new CommandContext(command, isRunAsync, reporter, node); }) .WithTrackingName("ConsoleApp.Run.0_CreateSyntaxProvider"); // annotate for IncrementalGeneratorTest @@ -185,7 +185,7 @@ static void EmitConsoleAppTemplateSource(IncrementalGeneratorPostInitializationC context.AddSource("ConsoleApp.g.cs", ConsoleAppBaseCode.InitializationCode); } - static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, CommanContext commandContext) + static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, CommandContext commandContext) { if (commandContext.DiagnosticReporter.HasDiagnostics) { @@ -324,14 +324,14 @@ static void EmitConsoleAppConfigure(SourceProductionContext sourceProductionCont sourceProductionContext.AddSource("ConsoleApp.Builder.Configure.g.cs", sb.ToString()); } - class CommanContext(Command? command, bool isAsync, DiagnosticReporter diagnosticReporter, InvocationExpressionSyntax node) : IEquatable + class CommandContext(Command? command, bool isAsync, DiagnosticReporter diagnosticReporter, InvocationExpressionSyntax node) : IEquatable { public Command? Command => command; public DiagnosticReporter DiagnosticReporter => diagnosticReporter; public InvocationExpressionSyntax Node => node; public bool IsAsync => isAsync; - public bool Equals(CommanContext other) + public bool Equals(CommandContext other) { // has diagnostics, always go to modified(don't cache) if (diagnosticReporter.HasDiagnostics || other.DiagnosticReporter.HasDiagnostics) return false; @@ -396,7 +396,7 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption if (filter == null) { - DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConsturtor, genericType.GetLocation()); + DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConstructor, genericType.GetLocation()); return null!; } diff --git a/src/ConsoleAppFramework/DiagnosticDescriptors.cs b/src/ConsoleAppFramework/DiagnosticDescriptors.cs index 0c54422f..6eb8b870 100644 --- a/src/ConsoleAppFramework/DiagnosticDescriptors.cs +++ b/src/ConsoleAppFramework/DiagnosticDescriptors.cs @@ -95,11 +95,11 @@ public static DiagnosticDescriptor Create(int id, string title, string messageFo 9, "ConsoleApp.Run does not allow the use of filters, but the function has a filter attribute."); - public static DiagnosticDescriptor FilterMultipleConsturtor { get; } = Create( + public static DiagnosticDescriptor FilterMultipleConstructor { get; } = Create( 10, "ConsoleAppFilter class does not allow multiple constructors."); - public static DiagnosticDescriptor ClassMultipleConsturtor { get; } = Create( + public static DiagnosticDescriptor ClassMultipleConstructor { get; } = Create( 11, "ConsoleAppBuilder.Add class does not allow multiple constructors."); diff --git a/src/ConsoleAppFramework/Emitter.cs b/src/ConsoleAppFramework/Emitter.cs index fc4e38ea..435cd4c2 100644 --- a/src/ConsoleAppFramework/Emitter.cs +++ b/src/ConsoleAppFramework/Emitter.cs @@ -470,16 +470,16 @@ public void EmitBuilder(SourceBuilder sb, CommandWithId[] commandIds, bool emitS void EmitRunBody(ILookup groupedCommands, int depth, bool isRunAsync) { var leafCommand = groupedCommands[""].FirstOrDefault(); - IDisposable? ifBlcok = null; + IDisposable? ifBlock = null; if (!(groupedCommands.Count == 1 && leafCommand != null)) { - ifBlcok = sb.BeginBlock($"if (args.Length == {depth})"); + ifBlock = sb.BeginBlock($"if (args.Length == {depth})"); } EmitLeafCommand(leafCommand); - if (ifBlcok != null) + if (ifBlock != null) { sb.AppendLine("return;"); - ifBlcok.Dispose(); + ifBlock.Dispose(); } else { diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index be1320ef..c1bbd83d 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -25,7 +25,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag public Command? ParseAndValidateForBuilderDelegateRegistration() // for ConsoleAppBuilder.Add { - // Add(string commandName, Delgate command) + // Add(string commandName, Delegate command) var args = (node as InvocationExpressionSyntax)!.ArgumentList.Arguments; if (args.Count == 2) // 0 = string command, 1 = lambda { @@ -112,7 +112,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag if (publicConstructors.Length != 1) { - context.ReportDiagnostic(DiagnosticDescriptors.ClassMultipleConsturtor, node.GetLocation()); + context.ReportDiagnostic(DiagnosticDescriptors.ClassMultipleConstructor, node.GetLocation()); return []; } @@ -128,7 +128,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag if (filter == null) { - context.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConsturtor, x.ApplicationSyntaxReference!.GetSyntax().GetLocation()); + context.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConstructor, x.ApplicationSyntaxReference!.GetSyntax().GetLocation()); return null!; } @@ -146,7 +146,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag IsIDisposable = hasIDisposable, IsIAsyncDisposable = hasIAsyncDisposable, ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbol(x.Type)).ToArray(), - MethodName = "", // without methodname + MethodName = "", // without method name }; return publicMethods @@ -481,7 +481,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag if (filter == null) { - context.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConsturtor, x.ApplicationSyntaxReference!.GetSyntax().GetLocation()); + context.ReportDiagnostic(DiagnosticDescriptors.FilterMultipleConstructor, x.ApplicationSyntaxReference!.GetSyntax().GetLocation()); return null!; } @@ -493,7 +493,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag return null; } - // validate parametersymbols + // validate parameter symbols if (parameterDescriptions != null) { foreach (var item in parameterDescriptions) diff --git a/src/ConsoleAppFramework/RoslynExtensions.cs b/src/ConsoleAppFramework/RoslynExtensions.cs index 53f937cc..8c4f2f99 100644 --- a/src/ConsoleAppFramework/RoslynExtensions.cs +++ b/src/ConsoleAppFramework/RoslynExtensions.cs @@ -92,9 +92,9 @@ public static Location Clone(this Location location) public static DocumentationCommentTriviaSyntax? GetDocumentationCommentTriviaSyntax(this SyntaxNode node) { // Hack note: - // ISymbol.GetDocumentationCommtentXml requirestrue. + // ISymbol.GetDocumentationCommentXml requirestrue. // However, getting the DocumentationCommentTrivia of a SyntaxNode also requires the same condition. - // It can only be obtained when DocumentationMode is Parse or Diagnostic, but whenfalse, + // It can only be obtained when DocumentationMode is Parse or Diagnostic, but whenfalse, // it becomes None, and the necessary Trivia cannot be obtained. // Therefore, we will attempt to reparse and retrieve it. diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArrayPraseTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs similarity index 97% rename from tests/ConsoleAppFramework.GeneratorTests/ArrayPraseTest.cs rename to tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs index b5d932e7..3f3a307e 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArrayPraseTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs @@ -2,7 +2,7 @@ namespace ConsoleAppFramework.GeneratorTests { - public class ArrayPraseTest(ITestOutputHelper output) + public class ArrayParseTest(ITestOutputHelper output) { VerifyHelper verifier = new VerifyHelper(output, "CAF"); diff --git a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs index 550d8197..bdf26a98 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs @@ -30,7 +30,7 @@ public void KebabCase() } [Fact] - public void CommmandName() + public void CommandName() { verifier.Execute(""" var builder = ConsoleApp.Create(); From 9fa08db81b271aaec5721e66a1b123683e326767 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Thu, 6 Feb 2025 18:38:04 +0900 Subject: [PATCH 03/31] chore: update benchmarks --- .../CliFrameworkBenchmark.csproj | 5 +-- .../Commands/SystemCommandLineCommand.cs | 32 ++++--------------- sandbox/CliFrameworkBenchmark/Program.cs | 2 +- .../Properties/launchSettings.json | 12 +++++++ 4 files changed, 23 insertions(+), 28 deletions(-) create mode 100644 sandbox/CliFrameworkBenchmark/Properties/launchSettings.json diff --git a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj index 2acf4fe7..fb299f6f 100644 --- a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj +++ b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj @@ -15,7 +15,7 @@ - + @@ -26,7 +26,8 @@ - + + diff --git a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs index ca5a114d..41003b55 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs @@ -1,5 +1,5 @@ using System.CommandLine; -using System.CommandLine.Invocation; +using System.CommandLine.NamingConventionBinder; namespace Cocona.Benchmark.External.Commands; @@ -11,18 +11,9 @@ public static int Execute(string[] args) { var command = new RootCommand { - new Option(new[] {"--str", "-s"}) - { - Argument = new Argument() - }, - new Option(new[] {"--int", "-i"}) - { - Argument = new Argument() - }, - new Option(new[] {"--bool", "-b"}) - { - Argument = new Argument() - } + new Option(new[] {"--str", "-s"}), + new Option(new[] {"--int", "-i"}), + new Option(new[] {"--bool", "-b"}), }; command.Handler = CommandHandler.Create(ExecuteHandler); @@ -33,18 +24,9 @@ public static Task ExecuteAsync(string[] args) { var command = new RootCommand { - new Option(new[] {"--str", "-s"}) - { - Argument = new Argument() - }, - new Option(new[] {"--int", "-i"}) - { - Argument = new Argument() - }, - new Option(new[] {"--bool", "-b"}) - { - Argument = new Argument() - } + new Option(new[] {"--str", "-s"}), + new Option(new[] {"--int", "-i"}), + new Option(new[] {"--bool", "-b"}), }; command.Handler = CommandHandler.Create(ExecuteHandler); diff --git a/sandbox/CliFrameworkBenchmark/Program.cs b/sandbox/CliFrameworkBenchmark/Program.cs index f71dd38e..5ee4add9 100644 --- a/sandbox/CliFrameworkBenchmark/Program.cs +++ b/sandbox/CliFrameworkBenchmark/Program.cs @@ -12,6 +12,6 @@ class Program { static void Main(string[] args) { - BenchmarkRunner.Run(DefaultConfig.Instance.WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(TimeUnit.Millisecond))); + BenchmarkRunner.Run(DefaultConfig.Instance.WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(TimeUnit.Millisecond)), args); } } diff --git a/sandbox/CliFrameworkBenchmark/Properties/launchSettings.json b/sandbox/CliFrameworkBenchmark/Properties/launchSettings.json new file mode 100644 index 00000000..f56b87d6 --- /dev/null +++ b/sandbox/CliFrameworkBenchmark/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Default": { + "commandName": "Project", + "commandLineArgs": "" + }, + "Measure": { + "commandName": "Project", + "commandLineArgs": "--launchCount 20" + } + } +} From 9224bb116e96dbccb9552d78c2f0600498d1f33d Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 6 Feb 2025 19:11:32 +0900 Subject: [PATCH 04/31] support double-dash escape --- ReadMe.md | 31 +++++++++- .../GeneratorSandbox/GeneratorSandbox.csproj | 4 +- sandbox/GeneratorSandbox/Program.cs | 49 ++++++++------- .../ConsoleApp.Abstractions.cs | 45 +++++++++++++- src/ConsoleAppFramework/Command.cs | 20 +++--- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 41 ++++++++++++- src/ConsoleAppFramework/Emitter.cs | 43 ++++++++----- .../CSharpGeneratorRunner.cs | 6 +- .../ConsoleAppContextTest.cs | 61 +++++++++++++++++++ .../ConsoleAppFramework.GeneratorTests.csproj | 4 +- 10 files changed, 246 insertions(+), 58 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index f373d5a9..46bbf00b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -2,7 +2,7 @@ ConsoleAppFramework === [![GitHub Actions](https://github.com/Cysharp/ConsoleAppFramework/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/ConsoleAppFramework/actions) [![Releases](https://img.shields.io/github/release/Cysharp/ConsoleAppFramework.svg)](https://github.com/Cysharp/ConsoleAppFramework/releases) -ConsoleAppFramework v5 is Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation, AOT Safe CLI Framework powered by C# Source Generator; achieves exceptionally high performance, fastest start-up time(with NativeAOT) and minimal binary size. Leveraging the latest features of .NET 8 and C# 12 ([IncrementalGenerator](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md), [managed function pointer](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers#function-pointers-1), [params arrays and default values lambda expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#input-parameters-of-a-lambda-expression), [`ISpanParsable`](https://learn.microsoft.com/en-us/dotnet/api/system.ispanparsable-1), [`PosixSignalRegistration`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.posixsignalregistration), etc.), this library ensures maximum performance while maintaining flexibility and extensibility. +ConsoleAppFramework v5 is Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation, AOT Safe CLI Framework powered by C# Source Generator; achieves exceptionally high performance, fastest start-up time(with NativeAOT) and minimal binary size. Leveraging the latest features of .NET 8 and C# 13 ([IncrementalGenerator](https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md), [managed function pointer](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers#function-pointers-1), [params arrays and default values lambda expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#input-parameters-of-a-lambda-expression), [`ISpanParsable`](https://learn.microsoft.com/en-us/dotnet/api/system.ispanparsable-1), [`PosixSignalRegistration`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.posixsignalregistration), etc.), this library ensures maximum performance while maintaining flexibility and extensibility. ![image](https://github.com/Cysharp/ConsoleAppFramework/assets/46207/db4bf599-9fe0-4ce4-801f-0003f44d5628) > Set `RunStrategy=ColdStart WarmupCount=0` to calculate the cold start benchmark, which is suitable for CLI application. @@ -147,6 +147,7 @@ ConsoleAppFramework offers a rich set of features as a framework. The Source Gen * High performance value parsing via `ISpanParsable` * Parsing of params arrays * Parsing of JSON arguments +* Double-dash escape arguments * Help(`-h|--help`) option builder * Default show version(`--version`) option @@ -154,7 +155,7 @@ As you can see from the generated output, the help display is also fast. In typi Getting Started -- -This library is distributed via NuGet, minimal requirement is .NET 8 and C# 12. +This library is distributed via NuGet, minimal requirement is .NET 8 and C# 13. > dotnet add package [ConsoleAppFramework](https://www.nuget.org/packages/ConsoleAppFramework) @@ -168,6 +169,13 @@ using ConsoleAppFramework; ConsoleApp.Run(args, (string name) => Console.WriteLine($"Hello {name}")); ``` +> When using .NET 8, you need to explicitly set LangVersion to 13 or above. +> ```xml +> +> net8.0 +> 13 +> + > The latest Visual Studio changed the execution timing of Source Generators to either during save or at compile time. If you encounter unexpected behavior, try compiling once or change the option to "Automatic" under TextEditor -> C# -> Advanced -> Source Generators. You can execute command like `sampletool --name "foo"`. @@ -605,6 +613,25 @@ By setting this attribute on a parameter, the custom parser will be called when ConsoleApp.Run(args, ([Vector3Parser] Vector3 position) => Console.WriteLine(position)); ``` +### Double-dash escaping + +Arguments after double-dash (`--`) can be received as escaped arguments without being parsed. This is useful when creating commands like `dotnet run`. +```csharp +// dotnet run --project foo.csproj -- --foo 100 --bar bazbaz +var app = ConsoleApp.Create(); +app.Add("run", (string project, ConsoleAppContext context) => +{ + // run --project foo.csproj -- --foo 100 --bar bazbaz + Console.WriteLine(string.Join(" ", context.Arguments)); + // --project foo.csproj + Console.WriteLine(string.Join(" ", context.CommandArguments!)); + // --foo 100 --bar bazbaz + Console.WriteLine(string.Join(" ", context.EscapedArguments!)); +}); +app.Run(args); +``` +You can get the escaped arguments using `ConsoleAppContext.EscapedArguments`. From `ConsoleAppContext`, you can also get `Arguments` which contains all arguments passed to `Run/RunAsync`, and `CommandArguments` which contains the arguments used for command execution. + ### Syntax Parsing Policy and Performance While there are some standards for command-line arguments, such as UNIX tools and POSIX, there is no absolute specification. The [Command-line syntax overview for System.CommandLine](https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax) provides an explanation of the specifications adopted by System.CommandLine. However, ConsoleAppFramework, while referring to these specifications to some extent, does not necessarily aim to fully comply with them. diff --git a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj index 89c2ed5a..641e3f91 100644 --- a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj +++ b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj @@ -2,7 +2,9 @@ Exe - net8.0 + net9.0 + 13 + enable disable true diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 2c0db53f..34b0cde4 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -1,7 +1,9 @@ #nullable enable using ConsoleAppFramework; +using GeneratorSandbox; using Microsoft.Extensions.DependencyInjection; +using System.Linq; using System.Text.Json; //using Microsoft.Extensions.Configuration; //using Microsoft.Extensions.DependencyInjection; @@ -29,14 +31,30 @@ // services.Configure(configuration.GetSection("Position")); // }); -//app.Add(); -//app.Run(args); -// sc.BuildServiceProvider() -//IServiceProvider ser; -//ser.CreateScope() +args = ["run", "--project", "foo.csproj", "--", "--foo", "100", "--bar", "bazbaz"]; -ConsoleApp.Run(args, () => { }); +// dotnet run --project foo.csproj -- --foo 100 --bar bazbaz + +var app = ConsoleApp.Create(); + +app.Add("run", (string project, ConsoleAppContext context) => +{ + // run --project foo.csproj -- --foo 100 --bar bazbaz + Console.WriteLine(string.Join(" ", context.Arguments)); + + // --project foo.csproj + Console.WriteLine(string.Join(" ", context.CommandArguments!)); + + // --foo 100 --bar bazbaz + Console.WriteLine(string.Join(" ", context.EscapedArguments!)); +}); + +app.Run(args); + + + +//ConsoleApp.Run(args, (ConsoleAppContext ctx) => { }); // inject options //public class MyCommand(IOptions options) @@ -115,24 +133,13 @@ public class MyService public class MyCommands { - /// - /// - /// - /// foobarbaz! - [Command("Error1")] - public void Error1(string msg = @"\") + public void Cmd1(int x, int y, ConsoleAppContext ctx) { - Console.WriteLine(msg); } - [Command("Error2")] - public void Error2(string msg = "\\") - { - Console.WriteLine(msg); - } - [Command("Output")] - public void Output(string msg = @"\\") + + public Task Cmd2(int x, int y) { - Console.WriteLine(msg); // 「\」 + return Task.CompletedTask; } } diff --git a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs index be56be9f..a67a49d7 100644 --- a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs +++ b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs @@ -1,11 +1,52 @@ -namespace ConsoleAppFramework; +using System.ComponentModel; + +namespace ConsoleAppFramework; public interface IArgumentParser { static abstract bool TryParse(ReadOnlySpan s, out T result); } -public record class ConsoleAppContext(string CommandName, string[] Arguments, object? State); +public record ConsoleAppContext +{ + public string CommandName { get; init; } + public string[] Arguments { get; init; } + public object? State { get; init; } + + [EditorBrowsable(EditorBrowsableState.Never)] + public int CommandDepth { get; } + + [EditorBrowsable(EditorBrowsableState.Never)] + public int EscapeIndex { get; } + + public ReadOnlySpan CommandArguments + { + get => (EscapeIndex == -1) + ? Arguments.AsSpan(CommandDepth) + : Arguments.AsSpan(CommandDepth, EscapeIndex - CommandDepth); + } + + public ReadOnlySpan EscapedArguments + { + get => (EscapeIndex == -1) + ? Array.Empty() + : Arguments.AsSpan(EscapeIndex + 1); + } + + public ConsoleAppContext(string commandName, string[] arguments, object? state, int commandDepth, int escapeIndex) + { + this.CommandName = commandName; + this.Arguments = arguments; + this.State = state; + this.CommandDepth = commandDepth; + this.EscapeIndex = escapeIndex; + } + + public override string ToString() + { + return string.Join(" ", Arguments); + } +} public abstract class ConsoleAppFilter(ConsoleAppFilter next) { diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index 1f74ddf6..da0842d0 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -173,7 +173,7 @@ public record class CommandParameter // increment = false when passed from [Argument] public string BuildParseMethod(int argCount, string argumentName, bool increment) { - var incrementIndex = increment ? "!TryIncrementIndex(ref i, args.Length) || " : ""; + var incrementIndex = increment ? "!TryIncrementIndex(ref i, commandArgs.Length) || " : ""; return Core(Type.TypeSymbol, false); string Core(ITypeSymbol type, bool nullable) @@ -193,7 +193,7 @@ string Core(ITypeSymbol type, bool nullable) if (CustomParserType != null) { - return $"if ({incrementIndex}!{CustomParserType.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{CustomParserType.ToFullyQualifiedFormatDisplayString()}.TryParse(commandArgs[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } switch (type.SpecialType) @@ -202,11 +202,11 @@ string Core(ITypeSymbol type, bool nullable) // no parse if (increment) { - return $"if (!TryIncrementIndex(ref i, args.Length)) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }} else {{ arg{argCount} = args[i]; }}"; + return $"if (!TryIncrementIndex(ref i, commandArgs.Length)) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }} else {{ arg{argCount} = commandArgs[i]; }}"; } else { - return $"arg{argCount} = args[i];"; + return $"arg{argCount} = commandArgs[i];"; } case SpecialType.System_Boolean: @@ -230,13 +230,13 @@ string Core(ITypeSymbol type, bool nullable) // Enum if (type.TypeKind == TypeKind.Enum) { - return $"if ({incrementIndex}!Enum.TryParse<{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>(args[i], true, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!Enum.TryParse<{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>(commandArgs[i], true, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } // ParamsArray if (IsParams) { - return $"{(increment ? "i++; " : "")}if (!TryParseParamsArray(args, ref arg{argCount}, ref i)) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"{(increment ? "i++; " : "")}if (!TryParseParamsArray(commandArgs, ref arg{argCount}, ref i)) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } // Array @@ -248,7 +248,7 @@ string Core(ITypeSymbol type, bool nullable) { if (elementType.AllInterfaces.Any(x => x.EqualsUnconstructedGenericType(parsable))) { - return $"if ({incrementIndex}!TrySplitParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!TrySplitParse(commandArgs[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } } break; @@ -272,15 +272,15 @@ string Core(ITypeSymbol type, bool nullable) if (tryParseKnownPrimitive) { - return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(commandArgs[i], {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } else if (tryParseIParsable) { - return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(args[i], null, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}{elseExpr}"; + return $"if ({incrementIndex}!{type.ToFullyQualifiedFormatDisplayString()}.TryParse(commandArgs[i], null, {outArgVar})) {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}{elseExpr}"; } else { - return $"try {{ arg{argCount} = System.Text.Json.JsonSerializer.Deserialize<{type.ToFullyQualifiedFormatDisplayString()}>(args[{(increment ? "++i" : "i")}], JsonSerializerOptions); }} catch {{ ThrowArgumentParseFailed(\"{argumentName}\", args[i]); }}"; + return $"try {{ arg{argCount} = System.Text.Json.JsonSerializer.Deserialize<{type.ToFullyQualifiedFormatDisplayString()}>(commandArgs[{(increment ? "++i" : "i")}], JsonSerializerOptions); }} catch {{ ThrowArgumentParseFailed(\"{argumentName}\", commandArgs[i]); }}"; } } } diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index f69f1548..cfc8d82c 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -45,7 +45,42 @@ internal interface IArgumentParser static abstract bool TryParse(ReadOnlySpan s, out T result); } -internal record class ConsoleAppContext(string CommandName, string[] Arguments, object? State); +internal record ConsoleAppContext +{ + public string CommandName { get; init; } + public string[] Arguments { get; init; } + public object? State { get; init; } + internal int CommandDepth { get; } + internal int EscapeIndex { get; } + + public ReadOnlySpan CommandArguments + { + get => (EscapeIndex == -1) + ? Arguments.AsSpan(CommandDepth) + : Arguments.AsSpan(CommandDepth, EscapeIndex - CommandDepth); + } + + public ReadOnlySpan EscapedArguments + { + get => (EscapeIndex == -1) + ? Array.Empty() + : Arguments.AsSpan(EscapeIndex + 1); + } + + public ConsoleAppContext(string commandName, string[] arguments, object? state, int commandDepth, int escapeIndex) + { + this.CommandName = commandName; + this.Arguments = arguments; + this.State = state; + this.CommandDepth = commandDepth; + this.EscapeIndex = escapeIndex; + } + + public override string ToString() + { + return string.Join(" ", Arguments); + } +} internal abstract class ConsoleAppFilter(ConsoleAppFilter next) { @@ -329,12 +364,12 @@ static void ShowVersion() static partial void ShowHelp(int helpId); - static async Task RunWithFilterAsync(string commandName, string[] args, ConsoleAppFilter invoker) + static async Task RunWithFilterAsync(string commandName, string[] args, int commandDepth, int escapeIndex, ConsoleAppFilter invoker) { using var posixSignalHandler = PosixSignalHandler.Register(Timeout); try { - await Task.Run(() => invoker.InvokeAsync(new ConsoleAppContext(commandName, args, null), posixSignalHandler.Token)).WaitAsync(posixSignalHandler.TimeoutToken); + await Task.Run(() => invoker.InvokeAsync(new ConsoleAppContext(commandName, args, null, commandDepth, escapeIndex), posixSignalHandler.Token)).WaitAsync(posixSignalHandler.TimeoutToken); } catch (Exception ex) { diff --git a/src/ConsoleAppFramework/Emitter.cs b/src/ConsoleAppFramework/Emitter.cs index 435cd4c2..77331d74 100644 --- a/src/ConsoleAppFramework/Emitter.cs +++ b/src/ConsoleAppFramework/Emitter.cs @@ -25,7 +25,6 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy } var returnType = isRunAsync ? "async Task" : "void"; var accessibility = !emitForBuilder ? "public" : "private"; - var argsType = !emitForBuilder ? "string[]" : (isRunAsync ? "string[]" : "ReadOnlySpan"); // NOTE: C# 13 will allow Span in async methods so can change to ReadOnlyMemory(and store .Span in local var) methodName = methodName ?? (isRunAsync ? "RunAsync" : "Run"); var unsafeCode = (command.MethodKind == MethodKind.FunctionPointer) ? "unsafe " : ""; @@ -42,8 +41,8 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy sb.AppendLine(); } + var commandDepthEscapeIndex = emitForBuilder ? ", int commandDepth, int escapeIndex" : ""; var filterCancellationToken = command.HasFilter ? ", ConsoleAppContext context, CancellationToken cancellationToken" : ""; - var rawArgs = !emitForBuilder ? "" : "string[] rawArgs, "; if (!emitForBuilder) { @@ -59,9 +58,26 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy } // method signature - using (sb.BeginBlock($"{accessibility} static {unsafeCode}{returnType} {methodName}({rawArgs}{argsType} args{commandMethodType}{filterCancellationToken})")) + using (sb.BeginBlock($"{accessibility} static {unsafeCode}{returnType} {methodName}(string[] args{commandDepthEscapeIndex}{commandMethodType}{filterCancellationToken})")) { - sb.AppendLine($"if (TryShowHelpOrVersion(args, {requiredParsableParameterCount}, {commandWithId.Id})) return;"); + if (emitForBuilder) + { + sb.AppendLine("var commandArgs = (escapeIndex == -1) ? args.AsSpan(commandDepth) : args.AsSpan(commandDepth, escapeIndex - commandDepth);"); + } + else + { + if (hasConsoleAppContext) + { + sb.AppendLine("var escapeIndex = args.AsSpan().IndexOf(\"--\");"); + sb.AppendLine("var commandArgs = (escapeIndex == -1) ? args.AsSpan() : args.AsSpan(0, escapeIndex);"); + } + else + { + sb.AppendLine("var commandArgs = args.AsSpan();"); + } + } + + sb.AppendLine($"if (TryShowHelpOrVersion(commandArgs, {requiredParsableParameterCount}, {commandWithId.Id})) return;"); sb.AppendLine(); // prepare argument variables @@ -71,8 +87,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy } if (hasConsoleAppContext) { - var rawArgsName = !emitForBuilder ? "args" : "rawArgs"; - sb.AppendLine($"var context = new ConsoleAppContext(\"{command.Name}\", {rawArgsName}, null);"); + sb.AppendLine($"var context = new ConsoleAppContext(\"{command.Name}\", args, null, {(emitForBuilder ? "commandDepth" : "0")}, escapeIndex);"); } for (var i = 0; i < command.Parameters.Length; i++) { @@ -113,7 +128,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy using (command.HasFilter ? sb.Nop : sb.BeginBlock("try")) { - using (sb.BeginBlock("for (int i = 0; i < args.Length; i++)")) + using (sb.BeginBlock("for (int i = 0; i < commandArgs.Length; i++)")) { // parse indexed argument([Argument] parameter) if (hasArgument) @@ -137,7 +152,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy sb.AppendLine(); } - sb.AppendLine("var name = args[i];"); + sb.AppendLine("var name = commandArgs[i];"); sb.AppendLine(); using (sb.BeginBlock("switch (name)")) @@ -538,16 +553,16 @@ void EmitLeafCommand(CommandWithId? command) { if (!isRunAsync) { - sb.AppendLine($"RunCommand{command.Id}(args, args.AsSpan({depth}){commandArgs});"); + sb.AppendLine($"RunCommand{command.Id}(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs});"); } else { - sb.AppendLine($"result = RunCommand{command.Id}Async(args, args[{depth}..]{commandArgs});"); + sb.AppendLine($"result = RunCommand{command.Id}Async(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs});"); } } else { - var invokeCode = $"RunWithFilterAsync(\"{command.Command.Name}\", args, new Command{command.Id}Invoker(args[{depth}..]{commandArgs}).BuildFilter())"; + var invokeCode = $"RunWithFilterAsync(\"{command.Command.Name}\", args, {depth}, args.AsSpan().IndexOf(\"--\"), new Command{command.Id}Invoker({commandArgs.TrimStart(',', ' ')}).BuildFilter())"; if (!isRunAsync) { sb.AppendLine($"{invokeCode}.GetAwaiter().GetResult();"); @@ -565,9 +580,9 @@ void EmitFilterInvoker(CommandWithId command) { var commandType = command.Command.BuildDelegateSignature(command.BuildCustomDelegateTypeName(), out _); var needsCommand = commandType != null; - if (needsCommand) commandType = $", {commandType} command"; + if (needsCommand) commandType = $"{commandType} command"; - using (sb.BeginBlock($"sealed class Command{command.Id}Invoker(string[] args{commandType}) : ConsoleAppFilter(null!)")) + using (sb.BeginBlock($"sealed class Command{command.Id}Invoker({commandType}) : ConsoleAppFilter(null!)")) { using (sb.BeginBlock($"public ConsoleAppFilter BuildFilter()")) { @@ -584,7 +599,7 @@ void EmitFilterInvoker(CommandWithId command) using (sb.BeginBlock($"public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)")) { var cmdArgs = needsCommand ? ", command" : ""; - sb.AppendLine($"return RunCommand{command.Id}Async(context.Arguments, args{cmdArgs}, context, cancellationToken);"); + sb.AppendLine($"return RunCommand{command.Id}Async(context.Arguments, context.CommandDepth, context.EscapeIndex{cmdArgs}, context, cancellationToken);"); } } } diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index 441bfdd2..5571fa95 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -41,7 +41,7 @@ public static (Compilation, ImmutableArray) RunGenerator([StringSynt { preprocessorSymbols = new[] { "NET8_0_OR_GREATER" }; } - var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp12, preprocessorSymbols: preprocessorSymbols); // 12 + var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp13, preprocessorSymbols: preprocessorSymbols); // 13 var driver = CSharpGeneratorDriver.Create(new ConsoleAppGenerator()).WithUpdatedParseOptions(parseOptions); if (options != null) @@ -94,7 +94,7 @@ public static (Compilation, ImmutableArray, string) CompileAndExecut public static (string Key, string Reasons)[][] GetIncrementalGeneratorTrackedStepsReasons(string keyPrefixFilter, params string[] sources) { - var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp12); // 12 + var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp13); // 13 var driver = CSharpGeneratorDriver.Create( [new ConsoleAppGenerator().AsSourceGenerator()], driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)) @@ -185,7 +185,7 @@ public void Verify(int id, [StringSyntax("C#-test")] string code, string diagnos // Execute and check stdout result - public void Execute([StringSyntax("C#-test")]string code, string args, string expected, [CallerArgumentExpression("code")] string? codeExpr = null) + public void Execute([StringSyntax("C#-test")] string code, string args, string expected, [CallerArgumentExpression("code")] string? codeExpr = null) { output.WriteLine(codeExpr); diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs index 674270cc..c0438efc 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs @@ -40,4 +40,65 @@ public override Task InvokeAsync(ConsoleAppContext context,CancellationToken can } """, args: "", expected: "12"); } + + [Theory] + [InlineData("--x 1 --y 2", "", "--x 1 --y 2", "")] // no command, no espace + [InlineData("foo --x 1 --y 2", "foo", "--x 1 --y 2", "")] // command, no espace + [InlineData("foo bar --x 1 --y 2", "foo bar", "--x 1 --y 2", "")] // nested command, no espace + [InlineData("--x 1 --y 2 -- abc", "", "--x 1 --y 2", "abc")] // no command, espace + [InlineData("--x 1 --y 2 -- abc def", "", "--x 1 --y 2", "abc def")] // no command, espace2 + [InlineData("foo --x 1 --y 2 -- abc", "foo", "--x 1 --y 2", "abc")] // command, espace + [InlineData("foo --x 1 --y 2 -- abc def", "foo", "--x 1 --y 2", "abc def")] // command, espace2 + [InlineData("foo bar --x 1 --y 2 -- abc", "foo bar", "--x 1 --y 2", "abc")] // nested command, espace + [InlineData("foo bar --x 1 --y 2 -- abc def", "foo bar", "--x 1 --y 2", "abc def")] // nested command, espace2 + public void ArgumentsParseTest(string args, string commandName, string expectedCommandArguments, string expectedEscapedArguments) + { + var argsSpan = args.Split(' ').AsSpan(); + var commandDepth = (commandName == "") ? 0 : (argsSpan.Length - args.Replace(commandName, "").Split(' ', StringSplitOptions.RemoveEmptyEntries).Length); + var escapeIndex = argsSpan.IndexOf("--"); + + var ctx = new ConsoleAppContext2(commandName, argsSpan.ToArray(), null, commandDepth, escapeIndex); + + string.Join(" ", ctx.CommandArguments!).ShouldBe(expectedCommandArguments); + string.Join(" ", ctx.EscapedArguments!).ShouldBe(expectedEscapedArguments); + } + + public class ConsoleAppContext2 + { + public string CommandName { get; } + public string[] Arguments { get; } + public object? State { get; } + + int commandDepth; + int escapeIndex; + + public ReadOnlySpan CommandArguments + { + get => (escapeIndex == -1) + ? Arguments.AsSpan(commandDepth) + : Arguments.AsSpan(commandDepth, escapeIndex - commandDepth); + } + + public ReadOnlySpan EscapedArguments + { + get => (escapeIndex == -1) + ? Array.Empty() + : Arguments.AsSpan(escapeIndex + 1); + } + + public ConsoleAppContext2(string commandName, string[] arguments, object? state, int commandDepth, int escapeIndex) + { + this.CommandName = commandName; + this.Arguments = arguments; + this.State = state; + + this.commandDepth = commandDepth; + this.escapeIndex = escapeIndex; + } + + public override string ToString() + { + return string.Join(" ", Arguments); + } + } } diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj index 68335771..65abe8e4 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable false @@ -11,7 +11,7 @@ - + From 2a3881614532d4909bf78eeecb862e27b00725bb Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 7 Feb 2025 00:53:52 +0900 Subject: [PATCH 05/31] chore: add .editorconfig setting file --- .editorconfig | 47 +++++++++++++++++++++++++++++++++++++++++ ConsoleAppFramework.sln | 3 ++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..c77f7be5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,47 @@ +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline=true +trim_trailing_whitespace=true + +# Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker) +spelling_exclusion_path = ./exclusion.dic + +# Solution files +[*.{sln,slnx}] +indent_size = 2 + +# MSBuild project files +[*.{csproj,props,targets}] +indent_size = 2 + +# Xml config files +[*.{ruleset,config,nuspec,resx,runsettings,DotSettings}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# YAML files +[*.{yml] +indent_size = 2 + +# PowerShell files +[*.ps1] +indent_size = 2 + +# Markdown files +[*.md] +charset = utf-8-bom +trim_trailing_whitespace = false + +# C# code style settings +[*.{cs}] + +## TODO: Define custom settings diff --git a/ConsoleAppFramework.sln b/ConsoleAppFramework.sln index e02ebe20..3d30c478 100644 --- a/ConsoleAppFramework.sln +++ b/ConsoleAppFramework.sln @@ -12,10 +12,11 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DF6534A-0F9D-44A4-BF89-AE1F3B243914}" ProjectSection(SolutionItems) = preProject .dockerignore = .dockerignore + .editorconfig = .editorconfig .gitignore = .gitignore Directory.Build.props = Directory.Build.props ReadMe.md = ReadMe.md - exclusion.dic = exclusion.dic + exclusion.dic = exclusion.dic EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppFramework", "src\ConsoleAppFramework\ConsoleAppFramework.csproj", "{09BEEA7B-B6D3-4011-BCAB-6DF976713695}" From cf0629b6422c3bd6a5864536512febeeef58e3b7 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 7 Feb 2025 00:54:33 +0900 Subject: [PATCH 06/31] chore: apply `dotnet format` command --- sandbox/CliFrameworkBenchmark/Benchmark.cs | 2 +- sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs | 2 +- sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs | 2 +- .../CliFrameworkBenchmark/Commands/CoconaCommand.cs | 2 +- .../Commands/CommandLineParserCommand.cs | 2 +- .../Commands/ConsoleAppFrameworkCommand.cs | 2 +- .../CliFrameworkBenchmark/Commands/McMasterCommand.cs | 2 +- .../CliFrameworkBenchmark/Commands/PowerArgsCommand.cs | 2 +- .../Commands/SpectreConsoleCliCommand.cs | 4 ++-- .../Commands/SystemCommandLineCommand.cs | 2 +- sandbox/FilterShareProject/Class1.cs | 4 ++-- sandbox/GeneratorSandbox/Filters.cs | 4 ++-- sandbox/GeneratorSandbox/Program.cs | 4 ++-- sandbox/NativeAot/Program.cs | 2 +- .../ConsoleApp.Abstractions.cs | 4 ++-- src/ConsoleAppFramework/Command.cs | 4 ++-- src/ConsoleAppFramework/CommandHelpBuilder.cs | 4 ++-- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 2 +- src/ConsoleAppFramework/ConsoleAppGenerator.cs | 2 +- src/ConsoleAppFramework/DiagnosticDescriptors.cs | 2 +- src/ConsoleAppFramework/Emitter.cs | 2 +- src/ConsoleAppFramework/EquatableArray.cs | 2 +- src/ConsoleAppFramework/EquatableTypeSymbol.cs | 4 ++-- src/ConsoleAppFramework/IgnoreEquality.cs | 2 +- src/ConsoleAppFramework/NameConverter.cs | 2 +- src/ConsoleAppFramework/Parser.cs | 2 +- src/ConsoleAppFramework/PooledStringWriter.cs | 2 +- src/ConsoleAppFramework/RoslynExtensions.cs | 2 +- src/ConsoleAppFramework/SourceBuilder.cs | 4 ++-- src/ConsoleAppFramework/SourceGeneratorContexts.cs | 4 ++-- .../SyntaxNodeTextEqualityComparer.cs | 2 +- src/ConsoleAppFramework/WellKnownTypes.cs | 2 +- .../ArgumentParserTest.cs | 2 +- .../ArrayParseTest.cs | 2 +- .../BuildCustomDelegateTest.cs | 2 +- .../CSharpGeneratorRunner.cs | 2 +- .../ConfigureTest.cs | 2 +- .../ConsoleAppBuilderTest.cs | 6 +++--- .../ConsoleAppContextTest.cs | 2 +- tests/ConsoleAppFramework.GeneratorTests/DITest.cs | 4 ++-- .../DiagnosticsTest.cs | 2 +- tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs | 2 +- .../GeneratorOptionsTest.cs | 2 +- .../ConsoleAppFramework.GeneratorTests/GlobalUsings.cs | 2 +- tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs | 2 +- .../IncrementalGeneratorTest.cs | 4 ++-- .../NameConverterTest.cs | 2 +- .../PooledStringWriterTest.cs | 2 +- .../RegisterCommandsTest.cs | 2 +- tests/ConsoleAppFramework.GeneratorTests/RunTest.cs | 4 ++-- .../SubCommandTest.cs | 10 +++++----- 51 files changed, 70 insertions(+), 70 deletions(-) diff --git a/sandbox/CliFrameworkBenchmark/Benchmark.cs b/sandbox/CliFrameworkBenchmark/Benchmark.cs index 0a7fc0ca..1e3e9b1c 100644 --- a/sandbox/CliFrameworkBenchmark/Benchmark.cs +++ b/sandbox/CliFrameworkBenchmark/Benchmark.cs @@ -124,4 +124,4 @@ public void ExecuteSpectreConsoleCli() // app.Add("", ConsoleAppFrameworkCommand.Execute); // app.Run(Arguments); //} -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs index 6d73e063..e7371805 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs @@ -14,6 +14,6 @@ public class CliFxCommand : CliFx.ICommand [CommandOption("bool", 'b')] public bool BoolOption { get; set; } - + public ValueTask ExecuteAsync(IConsole console) => ValueTask.CompletedTask; } diff --git a/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs index 3a5b9ceb..c55f4175 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs @@ -16,4 +16,4 @@ public class CliprCommand public void Execute() { } -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs index 4e299f03..6b491158 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs @@ -11,4 +11,4 @@ public void Execute( bool boolOption) { } -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs index b15dc2f2..d5036398 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs @@ -14,4 +14,4 @@ public class CommandLineParserCommand public void Execute() { } -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs index 8a5fb9af..04c3369a 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs @@ -51,4 +51,4 @@ public static void Execute(string? str, int intOption, bool boolOption, Cancella // { // return Next.InvokeAsync(cancellationToken); // } -//} \ No newline at end of file +//} diff --git a/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs index d9ff0d74..5a576a3a 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs @@ -12,4 +12,4 @@ public class McMasterCommand public bool BoolOption { get; set; } public int OnExecute() => 0; -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs index 33d14c29..a52fc034 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs @@ -16,4 +16,4 @@ namespace Cocona.Benchmark.External.Commands; // public void Main() // { // } -//} \ No newline at end of file +//} diff --git a/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs index 0a8d4c28..e96c824b 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs @@ -1,4 +1,4 @@ -using Spectre.Console.Cli; +using Spectre.Console.Cli; using System.ComponentModel; namespace Cocona.Benchmark.External.Commands; @@ -21,4 +21,4 @@ public override int Execute(CommandContext context, Settings settings) { return 0; } -} \ No newline at end of file +} diff --git a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs index 41003b55..c37a45d3 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs @@ -32,4 +32,4 @@ public static Task ExecuteAsync(string[] args) command.Handler = CommandHandler.Create(ExecuteHandler); return command.InvokeAsync(args); } -} \ No newline at end of file +} diff --git a/sandbox/FilterShareProject/Class1.cs b/sandbox/FilterShareProject/Class1.cs index 8a619b7d..1f285396 100644 --- a/sandbox/FilterShareProject/Class1.cs +++ b/sandbox/FilterShareProject/Class1.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; namespace FilterShareProject; @@ -17,4 +17,4 @@ public void Execute(int x) { Console.WriteLine("Hello?"); } -} \ No newline at end of file +} diff --git a/sandbox/GeneratorSandbox/Filters.cs b/sandbox/GeneratorSandbox/Filters.cs index ee6be4bd..228206f0 100644 --- a/sandbox/GeneratorSandbox/Filters.cs +++ b/sandbox/GeneratorSandbox/Filters.cs @@ -1,4 +1,4 @@ - + using ConsoleAppFramework; using System.ComponentModel.DataAnnotations; @@ -119,4 +119,4 @@ public override async Task InvokeAsync(ConsoleAppContext context, CancellationTo // await using var scope = serviceProvider.CreateAsyncScope(); // await Next.InvokeAsync(context, cancellationToken); // } -//} \ No newline at end of file +//} diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 34b0cde4..85662959 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using ConsoleAppFramework; using GeneratorSandbox; @@ -272,4 +272,4 @@ public class Batch2Attribute : BatchAttribute } -} \ No newline at end of file +} diff --git a/sandbox/NativeAot/Program.cs b/sandbox/NativeAot/Program.cs index 400798ea..5af0f8c5 100644 --- a/sandbox/NativeAot/Program.cs +++ b/sandbox/NativeAot/Program.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json; diff --git a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs index a67a49d7..945467a8 100644 --- a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs +++ b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; namespace ConsoleAppFramework; @@ -63,4 +63,4 @@ public sealed class ConsoleAppFilterAttribute : Attribute public sealed class ArgumentParseFailedException(string message) : Exception(message) { -} \ No newline at end of file +} diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index da0842d0..7d763ae6 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Text; namespace ConsoleAppFramework; @@ -418,4 +418,4 @@ public string BuildNew(string nextFilterName) return $"new {TypeFullName}({string.Join(", ", p)})"; } -} \ No newline at end of file +} diff --git a/src/ConsoleAppFramework/CommandHelpBuilder.cs b/src/ConsoleAppFramework/CommandHelpBuilder.cs index 0e7a73e7..a8b6fb85 100644 --- a/src/ConsoleAppFramework/CommandHelpBuilder.cs +++ b/src/ConsoleAppFramework/CommandHelpBuilder.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Text; namespace ConsoleAppFramework; @@ -349,4 +349,4 @@ public CommandOptionHelpDefinition(string[] options, string description, string IsParams = isParams; } } -} \ No newline at end of file +} diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index cfc8d82c..675ce7dd 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; public static class ConsoleAppBaseCode { diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index 133bdb8f..af6cbd55 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Immutable; diff --git a/src/ConsoleAppFramework/DiagnosticDescriptors.cs b/src/ConsoleAppFramework/DiagnosticDescriptors.cs index 6eb8b870..e18b72d7 100644 --- a/src/ConsoleAppFramework/DiagnosticDescriptors.cs +++ b/src/ConsoleAppFramework/DiagnosticDescriptors.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/Emitter.cs b/src/ConsoleAppFramework/Emitter.cs index 77331d74..718112c6 100644 --- a/src/ConsoleAppFramework/Emitter.cs +++ b/src/ConsoleAppFramework/Emitter.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Reflection.Metadata; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/EquatableArray.cs b/src/ConsoleAppFramework/EquatableArray.cs index c9bd85b8..cbf71cae 100644 --- a/src/ConsoleAppFramework/EquatableArray.cs +++ b/src/ConsoleAppFramework/EquatableArray.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Runtime.CompilerServices; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/EquatableTypeSymbol.cs b/src/ConsoleAppFramework/EquatableTypeSymbol.cs index a9f67745..0e99bcb0 100644 --- a/src/ConsoleAppFramework/EquatableTypeSymbol.cs +++ b/src/ConsoleAppFramework/EquatableTypeSymbol.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Collections.Immutable; namespace ConsoleAppFramework; @@ -30,4 +30,4 @@ public bool Equals(EquatableTypeSymbol other) static class EquatableTypeSymbolExtensions { public static EquatableTypeSymbol ToEquatable(this ITypeSymbol typeSymbol) => new(typeSymbol); -} \ No newline at end of file +} diff --git a/src/ConsoleAppFramework/IgnoreEquality.cs b/src/ConsoleAppFramework/IgnoreEquality.cs index 72942880..784e5d64 100644 --- a/src/ConsoleAppFramework/IgnoreEquality.cs +++ b/src/ConsoleAppFramework/IgnoreEquality.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; public readonly struct IgnoreEquality(T value) : IEquatable> { diff --git a/src/ConsoleAppFramework/NameConverter.cs b/src/ConsoleAppFramework/NameConverter.cs index c5702c02..ec61d4b4 100644 --- a/src/ConsoleAppFramework/NameConverter.cs +++ b/src/ConsoleAppFramework/NameConverter.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index c1bbd83d..006ae696 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/ConsoleAppFramework/PooledStringWriter.cs b/src/ConsoleAppFramework/PooledStringWriter.cs index 2e3d5b5b..07686a6b 100644 --- a/src/ConsoleAppFramework/PooledStringWriter.cs +++ b/src/ConsoleAppFramework/PooledStringWriter.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/RoslynExtensions.cs b/src/ConsoleAppFramework/RoslynExtensions.cs index 8c4f2f99..0007fe3d 100644 --- a/src/ConsoleAppFramework/RoslynExtensions.cs +++ b/src/ConsoleAppFramework/RoslynExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/ConsoleAppFramework/SourceBuilder.cs b/src/ConsoleAppFramework/SourceBuilder.cs index e3fb8b9f..2514ddb4 100644 --- a/src/ConsoleAppFramework/SourceBuilder.cs +++ b/src/ConsoleAppFramework/SourceBuilder.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; namespace ConsoleAppFramework; @@ -115,4 +115,4 @@ public void Dispose() { } } -} \ No newline at end of file +} diff --git a/src/ConsoleAppFramework/SourceGeneratorContexts.cs b/src/ConsoleAppFramework/SourceGeneratorContexts.cs index c1cbba0c..678fb76e 100644 --- a/src/ConsoleAppFramework/SourceGeneratorContexts.cs +++ b/src/ConsoleAppFramework/SourceGeneratorContexts.cs @@ -1,5 +1,5 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; readonly record struct ConsoleAppFrameworkGeneratorOptions(bool DisableNamingConversion); -readonly record struct DllReference(bool HasDependencyInjection, bool HasLogging, bool HasConfiguration, bool HasJsonConfiguration, bool HasHost); \ No newline at end of file +readonly record struct DllReference(bool HasDependencyInjection, bool HasLogging, bool HasConfiguration, bool HasJsonConfiguration, bool HasHost); diff --git a/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs b/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs index d3ffd196..21067c6f 100644 --- a/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs +++ b/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/WellKnownTypes.cs b/src/ConsoleAppFramework/WellKnownTypes.cs index c758e531..15e5b0bd 100644 --- a/src/ConsoleAppFramework/WellKnownTypes.cs +++ b/src/ConsoleAppFramework/WellKnownTypes.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs index 3f27ff86..6cf26b13 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace ConsoleAppFramework.GeneratorTests; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs index 3f3a307e..5943998f 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs @@ -1,4 +1,4 @@ -using Xunit.Abstractions; +using Xunit.Abstractions; namespace ConsoleAppFramework.GeneratorTests { diff --git a/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs b/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs index be347f3b..d2488c99 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index 5571fa95..2356adf8 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -241,4 +241,4 @@ void OutputGeneratedCode(Compilation compilation) output.WriteLine(syntaxTree.ToString()); } } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs index 79d67dd9..c56e03d4 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs index 311416d1..893cae76 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs @@ -1,4 +1,4 @@ -using Microsoft.VisualStudio.TestPlatform.Utilities; +using Microsoft.VisualStudio.TestPlatform.Utilities; using System; using System.Collections.Generic; using System.Linq; @@ -242,7 +242,7 @@ public void Do() verifier.Execute(code, "nomunomu", "yeah"); } - [Fact] + [Fact] public void CommandAttrWithFilter() { var code = """ @@ -283,4 +283,4 @@ public override Task InvokeAsync(ConsoleAppContext context,CancellationToken can verifier.Execute(code, "nomunomu", "filter1-filter2-command"); } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs index c0438efc..1dd139fb 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class ConsoleAppContextTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/DITest.cs b/tests/ConsoleAppFramework.GeneratorTests/DITest.cs index 76ab4530..760d7233 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/DITest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/DITest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class DITest(ITestOutputHelper output) { @@ -38,4 +38,4 @@ class MyClass(string name) } """, args: "--x 10 --y 20", expected: "foo:10:20"); } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs index 9facc174..c6b8b027 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs @@ -1,4 +1,4 @@ -using Xunit.Abstractions; +using Xunit.Abstractions; namespace ConsoleAppFramework.GeneratorTests; diff --git a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs index 46cbcfaf..ecf45a38 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs index 646f4dd8..6f442a4f 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs b/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs index 5ad8c783..24acf1e8 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs @@ -1,3 +1,3 @@ // CSharpGeneratorRunner.CompileAndExecute uses stdout hook(replace Console.Out) // so can not work in parallel test -[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs index 552a584d..7f2c2fce 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; diff --git a/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs b/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs index 86fa2edb..8d5c0f55 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; using System.Linq; @@ -677,4 +677,4 @@ public void IncrDual() var reasons = CSharpGeneratorRunner.GetIncrementalGeneratorTrackedStepsReasons("ConsoleApp.Builder.", step1, step2); } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs index bdf26a98..1bdd6fa1 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs index a8812bf8..d5e826c6 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs index a119c190..2313e822 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs index b470bbf7..79d4aa46 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -167,4 +167,4 @@ public void Output(string msg = @"\\") ConsoleApp.Run(args, (string msg = @"\\") => Console.Write(msg)); """, "", @"\\"); } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs index 13acb27e..ce75dc06 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -29,7 +29,7 @@ public void Zeroargs() builder.Run(args); """; - verifier.Execute(code, "", "root"); + verifier.Execute(code, "", "root"); verifier.Execute(code, "a", "a"); verifier.Execute(code, "a b1", "a b1"); verifier.Execute(code, "a b2", "a b2"); @@ -57,7 +57,7 @@ public void Withargs() builder.Run(args); """; - verifier.Execute(code, "--x 10 --y 20", "root 10 20"); + verifier.Execute(code, "--x 10 --y 20", "root 10 20"); verifier.Execute(code, "a --x 10 --y 20", "a 10 20"); verifier.Execute(code, "a b1 --x 10 --y 20", "a b1 10 20"); verifier.Execute(code, "a b2 --x 10 --y 20", "a b2 10 20"); @@ -85,7 +85,7 @@ public void ZeroargsAsync() await builder.RunAsync(args); """; - verifier.Execute(code, "", "root"); + verifier.Execute(code, "", "root"); verifier.Execute(code, "a", "a"); verifier.Execute(code, "a b1", "a b1"); verifier.Execute(code, "a b2", "a b2"); @@ -113,7 +113,7 @@ public void WithargsAsync() await builder.RunAsync(args); """; - verifier.Execute(code, "--x 10 --y 20", "root 10 20"); + verifier.Execute(code, "--x 10 --y 20", "root 10 20"); verifier.Execute(code, "a --x 10 --y 20", "a 10 20"); verifier.Execute(code, "a b1 --x 10 --y 20", "a b1 10 20"); verifier.Execute(code, "a b2 --x 10 --y 20", "a b2 10 20"); From 25834f386f7a3555d9ed0e691e0772e51c19162a Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 7 Feb 2025 01:02:21 +0900 Subject: [PATCH 07/31] chore: apply editorconfig settings manually --- ReadMe.md | 2 +- exclusion.dic | 2 +- .../CliFrameworkBenchmark.csproj | 66 ++++++------- sandbox/CliFrameworkBenchmark/README.md | 2 +- .../FilterShareProject.csproj | 6 +- .../GeneratorSandbox/GeneratorSandbox.csproj | 66 ++++++------- sandbox/NativeAot/NativeAot.csproj | 32 +++---- .../ConsoleAppFramework.Abstractions.csproj | 26 +++--- .../ConsoleAppFramework.Abstractions.props | 10 +- .../ConsoleAppFramework.csproj | 92 +++++++++---------- .../Properties/launchSettings.json | 2 +- .../ConsoleAppFramework.GeneratorTests.csproj | 52 +++++------ 12 files changed, 179 insertions(+), 179 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 46bbf00b..243ddd02 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,4 +1,4 @@ -ConsoleAppFramework +ConsoleAppFramework === [![GitHub Actions](https://github.com/Cysharp/ConsoleAppFramework/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/ConsoleAppFramework/actions) [![Releases](https://img.shields.io/github/release/Cysharp/ConsoleAppFramework.svg)](https://github.com/Cysharp/ConsoleAppFramework/releases) diff --git a/exclusion.dic b/exclusion.dic index ea77d898..4d216395 100644 --- a/exclusion.dic +++ b/exclusion.dic @@ -1,4 +1,4 @@ -abcd +abcd abcde abcdefg aiueo diff --git a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj index fb299f6f..0af9c640 100644 --- a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj +++ b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj @@ -1,41 +1,41 @@  - - Exe - net8.0 - enable - annotations - true - false - Debug;Release - + + Exe + net8.0 + enable + annotations + true + false + Debug;Release + - - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - Analyzer - false - - + + + Analyzer + false + + diff --git a/sandbox/CliFrameworkBenchmark/README.md b/sandbox/CliFrameworkBenchmark/README.md index 9c8ed355..7fe449f2 100644 --- a/sandbox/CliFrameworkBenchmark/README.md +++ b/sandbox/CliFrameworkBenchmark/README.md @@ -2,4 +2,4 @@ https://github.com/Tyrrrz/CliFx/tree/master/CliFx.Benchmarks/ -https://github.com/mayuki/Cocona/tree/master/perf/Cocona.Benchmark.External \ No newline at end of file +https://github.com/mayuki/Cocona/tree/master/perf/Cocona.Benchmark.External diff --git a/sandbox/FilterShareProject/FilterShareProject.csproj b/sandbox/FilterShareProject/FilterShareProject.csproj index 181c71e4..e7bdf612 100644 --- a/sandbox/FilterShareProject/FilterShareProject.csproj +++ b/sandbox/FilterShareProject/FilterShareProject.csproj @@ -3,9 +3,9 @@ net8.0 enable - false - enable - Debug;Release + false + enable + Debug;Release diff --git a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj index 641e3f91..ff2d53f9 100644 --- a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj +++ b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj @@ -1,42 +1,42 @@  - - Exe - net9.0 - 13 + + Exe + net9.0 + 13 - enable - disable - true - 1701;1702;CS8321 - false + enable + disable + true + 1701;1702;CS8321 + false - USE_EXTERNAL_CONSOLEAPP_ABSTRACTIONS + USE_EXTERNAL_CONSOLEAPP_ABSTRACTIONS - Debug;Release - + Debug;Release + - - - - - - - - - - - Analyzer - false - - - - - - - PreserveNewest - - + + + + + + + + + Analyzer + false + + + + + + + PreserveNewest + + diff --git a/sandbox/NativeAot/NativeAot.csproj b/sandbox/NativeAot/NativeAot.csproj index b44e82cb..f5fd1b81 100644 --- a/sandbox/NativeAot/NativeAot.csproj +++ b/sandbox/NativeAot/NativeAot.csproj @@ -1,22 +1,22 @@  - - Exe - net9.0 - enable - enable - false + + Exe + net9.0 + enable + enable + false - true - true - Debug;Release - + true + true + Debug;Release + - - - Analyzer - false - - + + + Analyzer + false + + diff --git a/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.csproj b/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.csproj index 80cabfef..f767a6c2 100644 --- a/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.csproj +++ b/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.csproj @@ -1,19 +1,19 @@  - - net8.0 - enable - enable + + net8.0 + enable + enable - - ConsoleAppFramework.Abstractions - ConsoleAppFramework external abstractions library. - Debug;Release - + + ConsoleAppFramework.Abstractions + ConsoleAppFramework external abstractions library. + Debug;Release + - - - - + + + + diff --git a/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.props b/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.props index 1019de1d..658c0320 100644 --- a/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.props +++ b/src/ConsoleAppFramework.Abstractions/ConsoleAppFramework.Abstractions.props @@ -1,5 +1,5 @@ - - - USE_EXTERNAL_CONSOLEAPP_ABSTRACTIONS - - \ No newline at end of file + + + USE_EXTERNAL_CONSOLEAPP_ABSTRACTIONS + + diff --git a/src/ConsoleAppFramework/ConsoleAppFramework.csproj b/src/ConsoleAppFramework/ConsoleAppFramework.csproj index 8f33a205..7e06a5b2 100644 --- a/src/ConsoleAppFramework/ConsoleAppFramework.csproj +++ b/src/ConsoleAppFramework/ConsoleAppFramework.csproj @@ -1,50 +1,50 @@  - - netstandard2.0 - 12 - enable - enable - ConsoleAppFramework - true - cs - - - false - true - false - true - true - - - ConsoleAppFramework - Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation, AOT Safe CLI Framework powered by C# Source Generator. - Debug;Release - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - + + netstandard2.0 + 12 + enable + enable + ConsoleAppFramework + true + cs + + + false + true + false + true + true + + + ConsoleAppFramework + Zero Dependency, Zero Overhead, Zero Reflection, Zero Allocation, AOT Safe CLI Framework powered by C# Source Generator. + Debug;Release + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + diff --git a/src/ConsoleAppFramework/Properties/launchSettings.json b/src/ConsoleAppFramework/Properties/launchSettings.json index 7f7a5b05..11e8a667 100644 --- a/src/ConsoleAppFramework/Properties/launchSettings.json +++ b/src/ConsoleAppFramework/Properties/launchSettings.json @@ -5,4 +5,4 @@ "targetProject": "..\\..\\sandbox\\GeneratorSandbox\\GeneratorSandbox.csproj" } } -} \ No newline at end of file +} diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj index 65abe8e4..e9b01886 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj @@ -1,32 +1,32 @@  - - net9.0 - enable - enable - false - true - Debug;Release - + + net9.0 + enable + enable + false + true + Debug;Release + - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + + - - - - - + + + + + From 4fdde6a1bf6bfa484f4624986721365d0843e692 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 7 Feb 2025 17:59:22 +0900 Subject: [PATCH 08/31] chore: remove `end_of_line = lf` setting --- .editorconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index c77f7be5..64803749 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,7 +3,6 @@ root = true [*] charset = utf-8 -end_of_line = lf indent_style = space indent_size = 4 insert_final_newline=true From b042191ae38161af220ccd4f8a5fd605b7808f67 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:12:04 +0900 Subject: [PATCH 09/31] fix: tests failed when disable autocrlf --- .../ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index 5571fa95..84138c85 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -196,7 +196,7 @@ public void Execute([StringSyntax("C#-test")] string code, string args, string e } OutputGeneratedCode(compilation); - stdout.ShouldBe(expected); + stdout.ShouldBe(expected, StringCompareShould.IgnoreLineEndings); } public string Error([StringSyntax("C#-test")] string code, string args, [CallerArgumentExpression("code")] string? codeExpr = null) From 2a82c0af88e9733d89c3a4033f56c17865d827d3 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:33:57 +0900 Subject: [PATCH 10/31] chore: remove extra spaces --- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index cfc8d82c..18456f41 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -8,7 +8,7 @@ public static class ConsoleAppBaseCode #pragma warning disable namespace ConsoleAppFramework; - + using System; using System.Text; using System.Reflection; @@ -307,7 +307,7 @@ static bool TryShowHelpOrVersion(ReadOnlySpan args, int requiredParamete if (args.Length == 0) { if (requiredParameterCount == 0) return false; - + ShowHelp(helpId); return true; } @@ -531,7 +531,7 @@ static bool TryShowHelpOrVersion(ReadOnlySpan args, int requiredParamete if (args.Length == 0) { if (requiredParameterCount == 0) return false; - + ShowHelp(helpId); return true; } From ccb9abddc02a89898287b084df82f16431bfa0e4 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Sun, 16 Feb 2025 10:45:00 +0900 Subject: [PATCH 11/31] fix: replace line endings of generated code --- .../ConsoleAppGenerator.cs | 14 +++++------ src/ConsoleAppFramework/StringExtensions.cs | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/ConsoleAppFramework/StringExtensions.cs diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index af6cbd55..30b1d4a7 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -182,7 +182,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) static void EmitConsoleAppTemplateSource(IncrementalGeneratorPostInitializationContext context) { - context.AddSource("ConsoleApp.g.cs", ConsoleAppBaseCode.InitializationCode); + context.AddSource("ConsoleApp.g.cs", ConsoleAppBaseCode.InitializationCode.ReplaceLineEndings()); } static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, CommandContext commandContext) @@ -209,7 +209,7 @@ static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, C var withId = new Emitter.CommandWithId(null, command, -1); emitter.EmitRun(sb, withId, command.IsAsync); } - sourceProductionContext.AddSource("ConsoleApp.Run.g.cs", sb.ToString()); + sourceProductionContext.AddSource("ConsoleApp.Run.g.cs", sb.ToString().ReplaceLineEndings()); var help = new SourceBuilder(0); help.AppendLine(ConsoleAppBaseCode.GeneratedCodeHeader); @@ -218,7 +218,7 @@ static void EmitConsoleAppRun(SourceProductionContext sourceProductionContext, C var emitter = new Emitter(); emitter.EmitHelp(help, command); } - sourceProductionContext.AddSource("ConsoleApp.Run.Help.g.cs", help.ToString()); + sourceProductionContext.AddSource("ConsoleApp.Run.Help.g.cs", help.ToString().ReplaceLineEndings()); } static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContext, CollectBuilderContext collectBuilderContext) @@ -267,7 +267,7 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex var emitter = new Emitter(); emitter.EmitBuilder(sb, commandIds, hasRun, hasRunAsync); } - sourceProductionContext.AddSource("ConsoleApp.Builder.g.cs", sb.ToString()); + sourceProductionContext.AddSource("ConsoleApp.Builder.g.cs", sb.ToString().ReplaceLineEndings()); // Build Help @@ -279,7 +279,7 @@ static void EmitConsoleAppBuilder(SourceProductionContext sourceProductionContex var emitter = new Emitter(); emitter.EmitHelp(help, commandIds!); } - sourceProductionContext.AddSource("ConsoleApp.Builder.Help.g.cs", help.ToString()); + sourceProductionContext.AddSource("ConsoleApp.Builder.Help.g.cs", help.ToString().ReplaceLineEndings()); } static void EmitConsoleAppConfigure(SourceProductionContext sourceProductionContext, DllReference dllReference) @@ -311,7 +311,7 @@ static void EmitConsoleAppConfigure(SourceProductionContext sourceProductionCont sb2.AppendLine("using Microsoft.Extensions.Hosting;"); var emitter = new Emitter(); emitter.EmitAsConsoleAppBuilder(sb2, dllReference); - sourceProductionContext.AddSource("ConsoleAppHostBuilderExtensions.g.cs", sb2.ToString()); + sourceProductionContext.AddSource("ConsoleAppHostBuilderExtensions.g.cs", sb2.ToString().ReplaceLineEndings()); } using (sb.BeginBlock("internal static partial class ConsoleApp")) @@ -321,7 +321,7 @@ static void EmitConsoleAppConfigure(SourceProductionContext sourceProductionCont emitter.EmitConfigure(sb, dllReference); } - sourceProductionContext.AddSource("ConsoleApp.Builder.Configure.g.cs", sb.ToString()); + sourceProductionContext.AddSource("ConsoleApp.Builder.Configure.g.cs", sb.ToString().ReplaceLineEndings()); } class CommandContext(Command? command, bool isAsync, DiagnosticReporter diagnosticReporter, InvocationExpressionSyntax node) : IEquatable diff --git a/src/ConsoleAppFramework/StringExtensions.cs b/src/ConsoleAppFramework/StringExtensions.cs new file mode 100644 index 00000000..2e104065 --- /dev/null +++ b/src/ConsoleAppFramework/StringExtensions.cs @@ -0,0 +1,23 @@ +namespace ConsoleAppFramework; + +internal static class StringExtensions +{ +#if NETSTANDARD2_0 + public static string ReplaceLineEndings(this string input) + { +#pragma warning disable RS1035 + return ReplaceLineEndings(input, Environment.NewLine); +#pragma warning restore RS1035 + } + + public static string ReplaceLineEndings(this string text, string replacementText) + { + text = text.Replace("\r\n", "\n"); + + if (replacementText != "\n") + text = text.Replace("\n", replacementText); + + return text; + } +#endif +} From 52478721e7b6d97e9a085e41e71fe53fee82895c Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Mon, 17 Feb 2025 11:17:03 +0900 Subject: [PATCH 12/31] chore: update xunit version to v3 --- .../ArrayParseTest.cs | 2 -- .../CSharpGeneratorRunner.cs | 11 +++++------ .../ConsoleAppBuilderTest.cs | 8 -------- .../ConsoleAppFramework.GeneratorTests.csproj | 10 +++++----- .../DiagnosticsTest.cs | 2 -- .../ConsoleAppFramework.GeneratorTests/FilterTest.cs | 7 ------- tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs | 1 - .../NameConverterTest.cs | 7 ------- tests/ConsoleAppFramework.GeneratorTests/RunTest.cs | 9 --------- .../SubCommandTest.cs | 7 ------- 10 files changed, 10 insertions(+), 54 deletions(-) diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs index 5943998f..df421b58 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs @@ -1,5 +1,3 @@ -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests { public class ArrayParseTest(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index 6b21cae9..f8fa8e44 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Loader; -using Xunit.Abstractions; public static class CSharpGeneratorRunner { @@ -144,7 +143,7 @@ public class VerifyHelper(ITestOutputHelper output, string idPrefix) public void Ok([StringSyntax("C#-test")] string code, [CallerArgumentExpression("code")] string? codeExpr = null) { - output.WriteLine(codeExpr); + output.WriteLine(codeExpr!); var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code); foreach (var item in diagnostics) @@ -158,7 +157,7 @@ public void Ok([StringSyntax("C#-test")] string code, [CallerArgumentExpression( public void Verify(int id, [StringSyntax("C#-test")] string code, string diagnosticsCodeSpan, [CallerArgumentExpression("code")] string? codeExpr = null) { - output.WriteLine(codeExpr); + output.WriteLine(codeExpr!); var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code); foreach (var item in diagnostics) @@ -176,7 +175,7 @@ public void Verify(int id, [StringSyntax("C#-test")] string code, string diagnos public (string, string)[] Verify([StringSyntax("C#-test")] string code, [CallerArgumentExpression("code")] string? codeExpr = null) { - output.WriteLine(codeExpr); + output.WriteLine(codeExpr!); var (compilation, diagnostics) = CSharpGeneratorRunner.RunGenerator(code); OutputGeneratedCode(compilation); @@ -187,7 +186,7 @@ public void Verify(int id, [StringSyntax("C#-test")] string code, string diagnos public void Execute([StringSyntax("C#-test")] string code, string args, string expected, [CallerArgumentExpression("code")] string? codeExpr = null) { - output.WriteLine(codeExpr); + output.WriteLine(codeExpr!); var (compilation, diagnostics, stdout) = CSharpGeneratorRunner.CompileAndExecute(code, args == "" ? [] : args.Split(' ')); foreach (var item in diagnostics) @@ -201,7 +200,7 @@ public void Execute([StringSyntax("C#-test")] string code, string args, string e public string Error([StringSyntax("C#-test")] string code, string args, [CallerArgumentExpression("code")] string? codeExpr = null) { - output.WriteLine(codeExpr); + output.WriteLine(codeExpr!); var (compilation, diagnostics, stdout) = CSharpGeneratorRunner.CompileAndExecute(code, args == "" ? [] : args.Split(' ')); foreach (var item in diagnostics) diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs index 893cae76..46509ffa 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs @@ -1,11 +1,3 @@ -using Microsoft.VisualStudio.TestPlatform.Utilities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class ConsoleAppBuilderTest(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj index e9b01886..4ac531e4 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj @@ -1,6 +1,7 @@  + Exe net9.0 enable enable @@ -10,11 +11,11 @@ - + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -26,7 +27,6 @@ - diff --git a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs index c6b8b027..f59c0e28 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs @@ -1,5 +1,3 @@ -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class DiagnosticsTest(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs index ecf45a38..eff7b99d 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class FilterTest(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs index 7f2c2fce..61f5a010 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs @@ -4,7 +4,6 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -using Xunit.Abstractions; namespace ConsoleAppFramework.GeneratorTests; diff --git a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs index 1bdd6fa1..2d154e52 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class NameConverterTest(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs index 79d4aa46..71f11094 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs @@ -1,12 +1,3 @@ -using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class Test(ITestOutputHelper output) diff --git a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs index ce75dc06..369e909e 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Xunit.Abstractions; - namespace ConsoleAppFramework.GeneratorTests; public class SubCommandTest(ITestOutputHelper output) From 0259c36f37fcd77b1a6348e2a566064b0bf20fb8 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Mon, 17 Feb 2025 11:40:43 +0900 Subject: [PATCH 13/31] chore: fix test codes --- ConsoleAppFramework.sln | 3 +++ .../CSharpGeneratorRunner.cs | 8 +++++- .../ConsoleAppBuilderTest.cs | 6 +++-- .../HelpTest.cs | 21 ++++++++++++++-- .../RunTest.cs | 4 ++- tests/Directory.Build.props | 25 +++++++++++++++++++ 6 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/Directory.Build.props diff --git a/ConsoleAppFramework.sln b/ConsoleAppFramework.sln index 3d30c478..b36345cd 100644 --- a/ConsoleAppFramework.sln +++ b/ConsoleAppFramework.sln @@ -8,6 +8,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandbox", "sandbox", "{A2CF2984-E8E2-48FC-B5A1-58D74A2467E6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AAD2D900-C305-4449-A9FC-6C7696FFEDFA}" + ProjectSection(SolutionItems) = preProject + tests\Directory.Build.props = tests\Directory.Build.props + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6DF6534A-0F9D-44A4-BF89-AE1F3B243914}" ProjectSection(SolutionItems) = preProject diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index f8fa8e44..8e515eb6 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -24,7 +24,13 @@ public static void InitializeCompilation() var references = AppDomain.CurrentDomain.GetAssemblies() .Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location)) - .Select(x => MetadataReference.CreateFromFile(x.Location)); + .Select(x => MetadataReference.CreateFromFile(x.Location)) + .Concat([ + MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), // System.Console.dll + MetadataReference.CreateFromFile(typeof(IServiceProvider).Assembly.Location), // System.ComponentModel.dll + MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute).Assembly.Location), // System.ComponentModel.DataAnnotations + MetadataReference.CreateFromFile(typeof(System.Text.Json.JsonDocument).Assembly.Location), // System.Text.Json.dll + ]); var compilation = CSharpCompilation.Create("generatortest", references: references, diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs index 46509ffa..071628ce 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs @@ -1,8 +1,10 @@ namespace ConsoleAppFramework.GeneratorTests; -public class ConsoleAppBuilderTest(ITestOutputHelper output) +public class ConsoleAppBuilderTest(ITestOutputHelper output) : IDisposable { - VerifyHelper verifier = new VerifyHelper(output, "CAF"); + VerifyHelper verifier = new VerifyHelper(output, "CAF"); + + public void Dispose() => Environment.ExitCode = 0; [Fact] public void BuilderRun() diff --git a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs index 61f5a010..663be080 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs @@ -14,7 +14,7 @@ public class HelpTest(ITestOutputHelper output) [Fact] public void Version() { - var version = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion ?? "1.0.0"; + var version = GetEntryAssemblyVersion(); verifier.Execute(code: $$""" ConsoleApp.Run(args, (int x, int y) => { }); @@ -39,7 +39,7 @@ public void Version() [Fact] public void VersionOnBuilder() { - var version = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion ?? "1.0.0"; + var version = GetEntryAssemblyVersion(); verifier.Execute(code: """ var app = ConsoleApp.Create(); @@ -320,4 +320,21 @@ hello my world. """); } + + private static string GetEntryAssemblyVersion() + { + var version = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.InformationalVersion; + + if (version == null) + return "1.0.0"; + + // Trim SourceRevisionId (SourceLink feature is enabled by default when using .NET SDK 8 or later) + var i = version.IndexOf('+'); + if (i != -1) + { + version = version.Substring(0, i); + } + + return version; + } } diff --git a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs index 71f11094..4ef2ce5b 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs @@ -1,9 +1,11 @@ namespace ConsoleAppFramework.GeneratorTests; -public class Test(ITestOutputHelper output) +public class Test(ITestOutputHelper output) : IDisposable { VerifyHelper verifier = new VerifyHelper(output, "CAF"); + public void Dispose() => Environment.ExitCode = 0; + [Fact] public void SyncRun() { diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 00000000..25e06788 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,25 @@ + + + + + + true + + + true + + + false + + + + + $(TestingPlatformCommandLineArguments) --xunit-info + + + $(TestingPlatformCommandLineArguments) --results-directory "$(MSBuildThisFileDirectory)TestResults" + + + $(TestingPlatformCommandLineArguments) --ignore-exit-code 8 + + From c4a86c0ec035c328c3d9848bdee37cc98df135e3 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Mon, 17 Feb 2025 12:03:35 +0900 Subject: [PATCH 14/31] chore: modify GeneratorSandbox project launch settings --- sandbox/GeneratorSandbox/Program.cs | 4 ++-- .../Properties/launchSettings.json | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sandbox/GeneratorSandbox/Properties/launchSettings.json diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 85662959..845a276e 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -31,8 +31,8 @@ // services.Configure(configuration.GetSection("Position")); // }); - -args = ["run", "--project", "foo.csproj", "--", "--foo", "100", "--bar", "bazbaz"]; +//// Uncomment following line to overwrite args. +// args = ["run", "--project", "foo.csproj", "--", "--foo", "100", "--bar", "bazbaz"]; // dotnet run --project foo.csproj -- --foo 100 --bar bazbaz diff --git a/sandbox/GeneratorSandbox/Properties/launchSettings.json b/sandbox/GeneratorSandbox/Properties/launchSettings.json new file mode 100644 index 00000000..91cb9250 --- /dev/null +++ b/sandbox/GeneratorSandbox/Properties/launchSettings.json @@ -0,0 +1,20 @@ +{ + "profiles": { + "Default": { + "commandName": "Project", + "commandLineArgs": "run --project foo.csproj -- --foo 100 --bar bazbaz" + }, + "ShowVersion": { + "commandName": "Project", + "commandLineArgs": "--version" + }, + "ShowRootCommandHelp": { + "commandName": "Project", + "commandLineArgs": "--help" + }, + "ShowRunCommandHelp": { + "commandName": "Project", + "commandLineArgs": "run --help" + } + } +} From 00f299597e3ba5bfde6f28a01b0ca3230633824d Mon Sep 17 00:00:00 2001 From: neuecc Date: Wed, 5 Mar 2025 17:51:37 +0900 Subject: [PATCH 15/31] log --- ReadMe.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReadMe.md b/ReadMe.md index 243ddd02..0b40fb4f 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -993,6 +993,9 @@ internal sealed class ReplaceLogFilter(ConsoleAppFilter next, ILogger l } ``` +> I don't recommend using `ConsoleApp.Log` and `ConsoleApp.LogError` directly as an application logging method, as they are intended to be used as output destinations for internal framework output. +> For error handling, it would be better to define your own custom filters for error handling, which would allow you to record more details when handling errors. + DI can also be effectively used when reading application configuration from `appsettings.json`. For example, suppose you have the following JSON file. ```json From 31a2e5deca0f1aa223b46024de6c3e60445a612c Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Mon, 10 Mar 2025 18:50:33 +0900 Subject: [PATCH 16/31] feat: Add HiddenAttribute to hide specific command/parameter --- src/ConsoleAppFramework/Command.cs | 2 + src/ConsoleAppFramework/CommandHelpBuilder.cs | 15 ++- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 5 + src/ConsoleAppFramework/Parser.cs | 13 +- .../HiddenAttributeTest.cs | 121 ++++++++++++++++++ 5 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index 7d763ae6..25869b8b 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -18,6 +18,7 @@ public record class Command { public required bool IsAsync { get; init; } // Task or Task public required bool IsVoid { get; init; } // void or int + public required bool IsHidden { get; init; } // Hide help from command list public bool IsRootCommand => Name == ""; public required string Name { get; init; } @@ -153,6 +154,7 @@ public record class CommandParameter public required IgnoreEquality WellKnownTypes { get; init; } public required bool IsNullableReference { get; init; } public required bool IsParams { get; init; } + public required bool IsHidden { get; init; } // Hide command parameter help public required string Name { get; init; } public required string OriginalParameterName { get; init; } public required bool HasDefaultValue { get; init; } diff --git a/src/ConsoleAppFramework/CommandHelpBuilder.cs b/src/ConsoleAppFramework/CommandHelpBuilder.cs index a8b6fb85..d3bd9825 100644 --- a/src/ConsoleAppFramework/CommandHelpBuilder.cs +++ b/src/ConsoleAppFramework/CommandHelpBuilder.cs @@ -64,7 +64,7 @@ static string BuildHelpMessageCore(Command command, bool showCommandName, bool s if (definition.Options.Any()) { var hasArgument = definition.Options.Any(x => x.Index.HasValue); - var hasOptions = definition.Options.Any(x => !x.Index.HasValue); + var hasNoHiddenOptions = definition.Options.Any(x => !x.Index.HasValue && !x.IsHidden); if (hasArgument) { @@ -72,7 +72,7 @@ static string BuildHelpMessageCore(Command command, bool showCommandName, bool s sb.AppendLine(BuildArgumentsMessage(definition)); } - if (hasOptions) + if (hasNoHiddenOptions) { sb.AppendLine(); sb.AppendLine(BuildOptionsMessage(definition)); @@ -102,7 +102,7 @@ static string BuildUsageMessage(CommandHelpDefinition definition, bool showComma sb.Append(" [arguments...]"); } - if (definition.Options.Any(x => !x.Index.HasValue)) + if (definition.Options.Any(x => !x.Index.HasValue && !x.IsHidden)) { sb.Append(" [options...]"); } @@ -160,6 +160,7 @@ static string BuildOptionsMessage(CommandHelpDefinition definition) { var optionsFormatted = definition.Options .Where(x => !x.Index.HasValue) + .Where(x => !x.IsHidden) .Select(x => (Options: string.Join("|", x.Options) + (x.IsFlag ? string.Empty : $" {x.FormattedValueTypeName}{(x.IsParams ? "..." : "")}"), x.Description, x.IsRequired, x.IsFlag, x.DefaultValue)) .ToArray(); @@ -215,6 +216,7 @@ static string BuildOptionsMessage(CommandHelpDefinition definition) static string BuildMethodListMessage(IEnumerable commands, out int maxWidth) { var formatted = commands + .Where(x => !x.IsHidden) .Select(x => { return (Command: x.Name, x.Description); @@ -279,6 +281,7 @@ static CommandHelpDefinition CreateCommandHelpDefinition(Command descriptor) var description = item.Description; var isFlag = item.Type.SpecialType == Microsoft.CodeAnalysis.SpecialType.System_Boolean; var isParams = item.IsParams; + var isHidden = item.IsHidden; var defaultValue = default(string); if (item.HasDefaultValue) @@ -300,7 +303,7 @@ static CommandHelpDefinition CreateCommandHelpDefinition(Command descriptor) } var paramTypeName = item.ToTypeShortString(); - parameterDefinitions.Add(new CommandOptionHelpDefinition(options.Distinct().ToArray(), description, paramTypeName, defaultValue, index, isFlag, isParams)); + parameterDefinitions.Add(new CommandOptionHelpDefinition(options.Distinct().ToArray(), description, paramTypeName, defaultValue, index, isFlag, isParams, isHidden)); } var commandName = descriptor.Name; @@ -336,9 +339,10 @@ class CommandOptionHelpDefinition public bool IsRequired => DefaultValue == null && !IsParams; public bool IsFlag { get; } public bool IsParams { get; } + public bool IsHidden { get; } public string FormattedValueTypeName => "<" + ValueTypeName + ">"; - public CommandOptionHelpDefinition(string[] options, string description, string valueTypeName, string? defaultValue, int? index, bool isFlag, bool isParams) + public CommandOptionHelpDefinition(string[] options, string description, string valueTypeName, string? defaultValue, int? index, bool isFlag, bool isParams, bool isHidden) { Options = options; Description = description; @@ -347,6 +351,7 @@ public CommandOptionHelpDefinition(string[] options, string description, string Index = index; IsFlag = isFlag; IsParams = isParams; + IsHidden = isHidden; } } } diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index f6b16cb4..a3520406 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -122,6 +122,11 @@ public CommandAttribute(string command) } } +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] +internal sealed class HiddenAttribute : Attribute +{ +} + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] internal sealed class RegisterCommandsAttribute : Attribute { diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index 006ae696..932d599b 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -283,7 +283,11 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag } } - var hasParams = x.Modifiers.Any(x => x.IsKind(SyntaxKind.ParamsKeyword)); + var hasParams = x.Modifiers.Any(x => x.IsKind(SyntaxKind.ParamsKeyword)); + + var isHidden = x.AttributeLists + .SelectMany(x => x.Attributes) + .Any(x => model.GetTypeInfo(x).Type?.Name == "HiddenAttribute"); var customParserType = x.AttributeLists.SelectMany(x => x.Attributes) .Select(x => @@ -360,6 +364,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag IsNullableReference = isNullableReference, IsConsoleAppContext = isConsoleAppContext, IsParams = hasParams, + IsHidden = isHidden, Type = new EquatableTypeSymbol(type.Type!), Location = x.GetLocation(), HasDefaultValue = hasDefault, @@ -381,6 +386,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag Name = commandName, IsAsync = isAsync, IsVoid = isVoid, + IsHidden = false, // Anonymous lambda don't support attribute. Parameters = parameters, MethodKind = MethodKind.Lambda, Description = "", @@ -472,6 +478,8 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag return null; } + var isHiddenCommand = methodSymbol.GetAttributes().Any(x => x.AttributeClass?.Name == "HiddenAttribute"); + var methodFilters = methodSymbol.GetAttributes() .Where(x => x.AttributeClass?.Name == "ConsoleAppFilterAttribute") .Select(x => @@ -516,6 +524,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag var hasValidation = x.GetAttributes().Any(x => x.AttributeClass?.GetBaseTypes().Any(y => y.Name == "ValidationAttribute") ?? false); var isCancellationToken = SymbolEqualityComparer.Default.Equals(x.Type, wellKnownTypes.CancellationToken); var isConsoleAppContext = x.Type!.Name == "ConsoleAppContext"; + var isHiddenParameter = x.GetAttributes().Any(x => x.AttributeClass?.Name == "HiddenAttribute"); string description = ""; string[] aliases = []; @@ -547,6 +556,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag IsNullableReference = isNullableReference, IsConsoleAppContext = isConsoleAppContext, IsParams = x.IsParams, + IsHidden = isHiddenParameter, Location = x.DeclaringSyntaxReferences[0].GetSyntax().GetLocation(), Type = new EquatableTypeSymbol(x.Type), HasDefaultValue = x.HasExplicitDefaultValue, @@ -567,6 +577,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag Name = commandName, IsAsync = isAsync, IsVoid = isVoid, + IsHidden = isHiddenCommand, Parameters = parameters, MethodKind = addressOf ? MethodKind.FunctionPointer : MethodKind.Method, Description = summary, diff --git a/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs new file mode 100644 index 00000000..e3090483 --- /dev/null +++ b/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs @@ -0,0 +1,121 @@ +namespace ConsoleAppFramework.GeneratorTests; + +public class HiddenAtttributeTest(ITestOutputHelper output) +{ + VerifyHelper verifier = new(output, "CAF"); + + [Fact] + public void VerifyHiddenOptions_Lambda() + { + var code = + """ + ConsoleApp.Run(args, (int x, [Hidden]int y) => { }); + """; + + // Verify Hidden options is not shown on command help. + verifier.Execute(code, args: "--help", expected: + """ + Usage: [options...] [-h|--help] [--version] + + Options: + --x (Required) + + """); + } + + [Fact] + public void VerifyHiddenCommands_Class() + { + var code = + """ + var builder = ConsoleApp.Create(); + builder.Add(); + await builder.RunAsync(args); + + public class Commands + { + [Hidden] + public void Command1() { Console.Write("command1"); } + + public void Command2() { Console.Write("command2"); } + + [Hidden] + public void Command3(int x, [Hidden]int y) { Console.Write($"command3: x={x} y={y}"); } + } + """; + + // Verify hidden command is not shown on root help commands. + verifier.Execute(code, args: "--help", expected: + """ + Usage: [command] [-h|--help] [--version] + + Commands: + command2 + + """); + + // Verify Hidden command help is shown when explicitly specify command name. + verifier.Execute(code, args: "command1 --help", expected: + """ + Usage: command1 [-h|--help] [--version] + + """); + + verifier.Execute(code, args: "command2 --help", expected: + """ + Usage: command2 [-h|--help] [--version] + + """); + + verifier.Execute(code, args: "command3 --help", expected: + """ + Usage: command3 [options...] [-h|--help] [--version] + + Options: + --x (Required) + + """); + + // Verify commands involations + verifier.Execute(code, args: "command1", "command1"); + verifier.Execute(code, args: "command2", "command2"); + verifier.Execute(code, args: "command3 --x 1 --y 2", expected: "command3: x=1 y=2"); + } + + [Fact] + public void VerifyHiddenCommands_LocalFunctions() + { + var code = + """ + var builder = ConsoleApp.Create(); + + builder.Add("", () => { Console.Write("root"); }); + builder.Add("command1", Command1); + builder.Add("command2", Command2); + builder.Add("command3", Command3); + builder.Run(args); + + [Hidden] + static void Command1() { Console.Write("command1"); } + + static void Command2() { Console.Write("command2"); } + + [Hidden] + static void Command3(int x, [Hidden]int y) { Console.Write($"command3: x={x} y={y}"); } + """; + + verifier.Execute(code, args: "--help", expected: + """ + Usage: [command] [-h|--help] [--version] + + Commands: + command2 + + """); + + // Verify commands can be invoked. + verifier.Execute(code, args: "command1", expected: "command1"); + verifier.Execute(code, args: "command2", expected: "command2"); + verifier.Execute(code, args: "command3 --x 1 --y 2", expected: "command3: x=1 y=2"); + } +} From e0667b6883effc919209a1e0b7151307fa99a699 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Tue, 11 Mar 2025 09:46:09 +0900 Subject: [PATCH 17/31] chore: add docfs of HiddenAttribute --- ReadMe.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ReadMe.md b/ReadMe.md index 0b40fb4f..588cad46 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -697,6 +697,13 @@ The field secondArg must be between 0 and 2. By default, the ExitCode is set to 1 in this case. +Hide command/parameter help +--- +`ConsoleAppFramework` supports `HiddenAttribute` which is used to hide specific help for a command/parameter. + +- When`HiddenAttribute` is set to command, it hides command from command list. +- When`HiddenAttribute` is set to parameter, it hides parameter from command help. + Filter(Middleware) Pipeline / ConsoleAppContext --- Filters are provided as a mechanism to hook into the execution before and after. To use filters, define an `internal class` that implements `ConsoleAppFilter`. From eb44968c83ab9cc747d188651be52640d8c6a89b Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:27:48 +0900 Subject: [PATCH 18/31] ci: Pinning third party GitHub Actions sha --- .github/workflows/build-debug.yml | 2 +- .github/workflows/build-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml index 1f1949b2..ebe8372b 100644 --- a/.github/workflows/build-debug.yml +++ b/.github/workflows/build-debug.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: Cysharp/Actions/.github/actions/setup-dotnet@main - run: dotnet build -c Debug - run: dotnet test -c Debug --no-build diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 3017b072..8bce6036 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: Cysharp/Actions/.github/actions/setup-dotnet@main # pack nuget - run: dotnet build -c Release -p:Version=${{ inputs.tag }} From 5ce0eb91e39595c16dbea654096225401005f83f Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:34:54 +0900 Subject: [PATCH 19/31] ci: dependabot ignore for patch --- .github/dependabot.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 00aea0a7..63b36f3d 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -5,3 +5,8 @@ updates: directory: "/" schedule: interval: "weekly" # Check for updates to GitHub Actions every week + ignore: + # I just want update action when major/minor version is updated. patch updates are too noisy. + - dependency-name: '*' + update-types: + - version-update:semver-patch From 5d33e4a98b9c1ac5f9901c75835667a2c182736e Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Wed, 19 Mar 2025 15:28:21 +0900 Subject: [PATCH 20/31] ci: use Cysharp/Actions checkout instead of 3rd party directly --- .github/workflows/build-debug.yml | 2 +- .github/workflows/build-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml index ebe8372b..319096dc 100644 --- a/.github/workflows/build-debug.yml +++ b/.github/workflows/build-debug.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: Cysharp/Actions/.github/actions/checkout@main - uses: Cysharp/Actions/.github/actions/setup-dotnet@main - run: dotnet build -c Debug - run: dotnet test -c Debug --no-build diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 8bce6036..2942debe 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: Cysharp/Actions/.github/actions/checkout@main - uses: Cysharp/Actions/.github/actions/setup-dotnet@main # pack nuget - run: dotnet build -c Release -p:Version=${{ inputs.tag }} From 8a983bfaa62044fb4736c9be1fa9656bfeeb61e4 Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Wed, 7 May 2025 20:09:54 +0900 Subject: [PATCH 21/31] ci: fix ghalint --- .editorconfig | 2 +- .github/workflows/build-debug.yml | 2 ++ .github/workflows/build-release.yml | 4 ++++ .github/workflows/stale.yml | 4 ++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 64803749..c4aab4fd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -28,7 +28,7 @@ indent_size = 2 indent_size = 2 # YAML files -[*.{yml] +[*.{yml,yaml}] indent_size = 2 # PowerShell files diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml index 319096dc..13de325f 100644 --- a/.github/workflows/build-debug.yml +++ b/.github/workflows/build-debug.yml @@ -11,6 +11,8 @@ on: jobs: build-dotnet: + permissions: + contents: read runs-on: ubuntu-latest timeout-minutes: 10 steps: diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 2942debe..0c7578d6 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -14,6 +14,8 @@ on: jobs: build-dotnet: + permissions: + contents: read runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -32,6 +34,8 @@ jobs: # release create-release: needs: [build-dotnet] + permissions: + contents: write uses: Cysharp/Actions/.github/workflows/create-release.yaml@main with: commit-id: ${{ github.sha }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b480c3e3..c333a85b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,4 +7,8 @@ on: jobs: stale: + permissions: + contents: read + pull-requests: write + issues: write uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main From 123fc4389e3fbad6c5dc3da0377f8ab49ca83cd2 Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Wed, 7 May 2025 20:30:04 +0900 Subject: [PATCH 22/31] ci: ubuntu-24.04 --- .github/workflows/build-debug.yml | 2 +- .github/workflows/build-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml index 13de325f..9d5952bb 100644 --- a/.github/workflows/build-debug.yml +++ b/.github/workflows/build-debug.yml @@ -13,7 +13,7 @@ jobs: build-dotnet: permissions: contents: read - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - uses: Cysharp/Actions/.github/actions/checkout@main diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 0c7578d6..e1d8984c 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -16,7 +16,7 @@ jobs: build-dotnet: permissions: contents: read - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - uses: Cysharp/Actions/.github/actions/checkout@main From a07efbd60625e0f7b09b1b5240ed9acd3695dbfc Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Wed, 7 May 2025 20:38:56 +0900 Subject: [PATCH 23/31] ci: yml -> yaml --- .github/workflows/{build-debug.yml => build-debug.yaml} | 0 .github/workflows/{build-release.yml => build-release.yaml} | 0 .github/workflows/{stale.yml => stale.yaml} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{build-debug.yml => build-debug.yaml} (100%) rename .github/workflows/{build-release.yml => build-release.yaml} (100%) rename .github/workflows/{stale.yml => stale.yaml} (100%) diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yaml similarity index 100% rename from .github/workflows/build-debug.yml rename to .github/workflows/build-debug.yaml diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yaml similarity index 100% rename from .github/workflows/build-release.yml rename to .github/workflows/build-release.yaml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yaml similarity index 100% rename from .github/workflows/stale.yml rename to .github/workflows/stale.yaml From 9b4a4f88d5bdba9e15d1a26a118ef2d7190c9b44 Mon Sep 17 00:00:00 2001 From: Ikiru Yoshizaki <3856350+guitarrapc@users.noreply.github.com> Date: Tue, 13 May 2025 18:11:44 +0900 Subject: [PATCH 24/31] chore: update .editorconfig --- .editorconfig | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/.editorconfig b/.editorconfig index c4aab4fd..c9e08409 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,44 +3,36 @@ root = true [*] charset = utf-8 +end_of_line = lf indent_style = space -indent_size = 4 -insert_final_newline=true -trim_trailing_whitespace=true +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true # Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker) spelling_exclusion_path = ./exclusion.dic +[*.cs] +indent_size = 4 +charset = utf-8-bom +end_of_line = unset + # Solution files [*.{sln,slnx}] -indent_size = 2 +end_of_line = unset # MSBuild project files [*.{csproj,props,targets}] -indent_size = 2 +end_of_line = unset # Xml config files [*.{ruleset,config,nuspec,resx,runsettings,DotSettings}] -indent_size = 2 - -# JSON files -[*.json] -indent_size = 2 - -# YAML files -[*.{yml,yaml}] -indent_size = 2 - -# PowerShell files -[*.ps1] -indent_size = 2 - -# Markdown files -[*.md] -charset = utf-8-bom -trim_trailing_whitespace = false +end_of_line = unset # C# code style settings [*.{cs}] +dotnet_diagnostic.IDE0044.severity = none # IDE0044: Make field readonly -## TODO: Define custom settings +# https://stackoverflow.com/questions/79195382/how-to-disable-fading-unused-methods-in-visual-studio-2022-17-12-0 +dotnet_diagnostic.IDE0051.severity = none # IDE0051: Remove unused private member +dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure From 9aaa85cbe2db6967dc1602fcd720d1ad88b27e65 Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 19 Jun 2025 16:44:44 +0900 Subject: [PATCH 25/31] WIP FromKeyedServices --- sandbox/CliFrameworkBenchmark/Program.cs | 2 +- sandbox/GeneratorSandbox/Program.cs | 10 +++- src/ConsoleAppFramework/Command.cs | 14 +++++- .../ConsoleAppGenerator.cs | 4 +- src/ConsoleAppFramework/Emitter.cs | 8 +++- src/ConsoleAppFramework/Parser.cs | 47 ++++++++++++++++++- 6 files changed, 76 insertions(+), 9 deletions(-) diff --git a/sandbox/CliFrameworkBenchmark/Program.cs b/sandbox/CliFrameworkBenchmark/Program.cs index 5ee4add9..c2b78ea2 100644 --- a/sandbox/CliFrameworkBenchmark/Program.cs +++ b/sandbox/CliFrameworkBenchmark/Program.cs @@ -1,4 +1,4 @@ -// This benchmark project is based on CliFx.Benchmarks. +// This benchmark project is based on CliFx.Benchmarks. // https://github.com/Tyrrrz/CliFx/tree/master/CliFx.Benchmarks/ using BenchmarkDotNet.Configs; diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 845a276e..7fd65d44 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using ConsoleAppFramework; using GeneratorSandbox; @@ -38,7 +38,7 @@ var app = ConsoleApp.Create(); -app.Add("run", (string project, ConsoleAppContext context) => +app.Add("run", ([FromKeyedServices("takoyaki")] List testList, string project, ConsoleAppContext context) => { // run --project foo.csproj -- --foo 100 --bar bazbaz Console.WriteLine(string.Join(" ", context.Arguments)); @@ -46,6 +46,12 @@ // --project foo.csproj Console.WriteLine(string.Join(" ", context.CommandArguments!)); + //IServiceProvider ServiceProvider = null!; + // ((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(Type, ""); + + // FromKeyedServicesAttribute + // IKeyedServiceProvider + // --foo 100 --bar bazbaz Console.WriteLine(string.Join(" ", context.EscapedArguments!)); }); diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index 7d763ae6..0163356c 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Text; namespace ConsoleAppFramework; @@ -159,9 +159,11 @@ public record class CommandParameter public object? DefaultValue { get; init; } public required EquatableTypeSymbol? CustomParserType { get; init; } public required bool IsFromServices { get; init; } + public required bool IsFromKeyedServices { get; init; } + public required object? KeyedServiceKey { get; init; } public required bool IsConsoleAppContext { get; init; } public required bool IsCancellationToken { get; init; } - public bool IsParsable => !(IsFromServices || IsCancellationToken || IsConsoleAppContext); + public bool IsParsable => !(IsFromServices || IsFromKeyedServices || IsCancellationToken || IsConsoleAppContext); public bool IsFlag => Type.SpecialType == SpecialType.System_Boolean; public required bool HasValidation { get; init; } public required int ArgumentIndex { get; init; } // -1 is not Argument, other than marked as [Argument] @@ -330,6 +332,14 @@ public string ToTypeShortString() return IsNullableReference ? $"{t}?" : t; } + public string GetFormattedKeyedServiceKey() + { + if (KeyedServiceKey == null) return "null"; + + if (KeyedServiceKey is string) return $"\"{KeyedServiceKey}\""; + return $"({KeyedServiceKey.GetType().FullName}){KeyedServiceKey.ToString()}"; + } + public override string ToString() { var sb = new StringBuilder(); diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index 30b1d4a7..2f900b60 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Immutable; @@ -31,7 +31,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var name = x.Display; if (name == null) continue; - if (!hasDependencyInjection && name.EndsWith("Microsoft.Extensions.DependencyInjection.dll")) // BuildServiceProvider + if (!hasDependencyInjection && name.EndsWith("Microsoft.Extensions.DependencyInjection.dll")) // BuildServiceProvider, IKeyedServiceProvider { hasDependencyInjection = true; continue; diff --git a/src/ConsoleAppFramework/Emitter.cs b/src/ConsoleAppFramework/Emitter.cs index 718112c6..02a24e3c 100644 --- a/src/ConsoleAppFramework/Emitter.cs +++ b/src/ConsoleAppFramework/Emitter.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Reflection.Metadata; namespace ConsoleAppFramework; @@ -123,6 +123,12 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy var type = parameter.Type.ToFullyQualifiedFormatDisplayString(); sb.AppendLine($"var arg{i} = ({type})ServiceProvider!.GetService(typeof({type}))!;"); } + else if (parameter.IsFromKeyedServices) + { + var type = parameter.Type.ToFullyQualifiedFormatDisplayString(); + var line = $"var arg{i} = ({type})((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(typeof({type}), {parameter.GetFormattedKeyedServiceKey()})!;"; + sb.AppendLine(line); + } } sb.AppendLineIfExists(command.Parameters.AsSpan()); diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index 006ae696..82cbb4e4 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -321,6 +321,40 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag return identifier is "FromServices" or "FromServicesAttribute"; }); + object? keyedServiceKey = null; + var isFromKeyedServices = x.AttributeLists.SelectMany(x => x.Attributes) + .Any(x => + { + var name = x.Name; + if (x.Name is QualifiedNameSyntax qns) + { + name = qns.Right; + } + + var identifier = name.ToString(); + var result = identifier is "FromKeyedServices" or "FromKeyedServicesAttribute"; + if (result) + { + SemanticModel semanticModel = model; // we can use SemanticModel + if (x.ArgumentList?.Arguments.Count > 0) + { + var argumentExpression = x.ArgumentList.Arguments[0].Expression; + + var constantValue = semanticModel.GetConstantValue(argumentExpression); + if (constantValue.HasValue) + { + keyedServiceKey = constantValue.Value; + } + else if (argumentExpression is TypeOfExpressionSyntax typeOf) + { + var typeInfo = semanticModel.GetTypeInfo(typeOf.Type); + keyedServiceKey = typeInfo.Type; + } + } + } + return result; + }); + var hasArgument = x.AttributeLists.SelectMany(x => x.Attributes) .Any(x => { @@ -368,6 +402,8 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag HasValidation = hasValidation, IsCancellationToken = isCancellationToken, IsFromServices = isFromServices, + IsFromKeyedServices = isFromKeyedServices, + KeyedServiceKey = keyedServiceKey, Aliases = [], Description = "", ArgumentIndex = argumentIndex, @@ -512,11 +548,18 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag { var customParserType = x.GetAttributes().FirstOrDefault(x => x.AttributeClass?.AllInterfaces.Any(y => y.Name == "IArgumentParser") ?? false); var hasFromServices = x.GetAttributes().Any(x => x.AttributeClass?.Name == "FromServicesAttribute"); + var hasFromKeyedServices = x.GetAttributes().Any(x => x.AttributeClass?.Name == "FromKeyedServicesAttribute"); var hasArgument = x.GetAttributes().Any(x => x.AttributeClass?.Name == "ArgumentAttribute"); var hasValidation = x.GetAttributes().Any(x => x.AttributeClass?.GetBaseTypes().Any(y => y.Name == "ValidationAttribute") ?? false); var isCancellationToken = SymbolEqualityComparer.Default.Equals(x.Type, wellKnownTypes.CancellationToken); var isConsoleAppContext = x.Type!.Name == "ConsoleAppContext"; + object? keyedServiceKey = null; + if (hasFromKeyedServices) + { + // TODO: try to get keyedservicekey + } + string description = ""; string[] aliases = []; if (parameterDescriptions != null && parameterDescriptions.TryGetValue(x.Name, out var desc)) @@ -554,6 +597,8 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag CustomParserType = customParserType?.AttributeClass?.ToEquatable(), IsCancellationToken = isCancellationToken, IsFromServices = hasFromServices, + IsFromKeyedServices = hasFromKeyedServices, + KeyedServiceKey = keyedServiceKey, HasValidation = hasValidation, Aliases = aliases, ArgumentIndex = argumentIndex, From 629b9d6e4972b0027cfd6c088f9c666286ded35a Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 20 Jun 2025 09:16:41 +0900 Subject: [PATCH 26/31] chore: update benchmarks --- sandbox/CliFrameworkBenchmark/Benchmark.cs | 10 +----- .../CliFrameworkBenchmark.csproj | 10 +++--- .../Commands/SystemCommandLineCommand.cs | 32 +++++++++++++------ sandbox/CliFrameworkBenchmark/Program.cs | 22 ++++++++++++- .../GeneratorSandbox/GeneratorSandbox.csproj | 4 +-- .../ConsoleAppFramework.csproj | 2 +- .../ConsoleAppFramework.GeneratorTests.csproj | 12 ++++--- 7 files changed, 60 insertions(+), 32 deletions(-) diff --git a/sandbox/CliFrameworkBenchmark/Benchmark.cs b/sandbox/CliFrameworkBenchmark/Benchmark.cs index 1e3e9b1c..c78de1c8 100644 --- a/sandbox/CliFrameworkBenchmark/Benchmark.cs +++ b/sandbox/CliFrameworkBenchmark/Benchmark.cs @@ -1,23 +1,15 @@ -// This benchmark project is based on CliFx.Benchmarks. +// This benchmark project is based on CliFx.Benchmarks. // https://github.com/Tyrrrz/CliFx/tree/master/CliFx.Benchmarks/ using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Engines; using BenchmarkDotNet.Order; using CliFx; using Cocona.Benchmark.External.Commands; -using CommandLine; using ConsoleAppFramework; -using PowerArgs; using Spectre.Console.Cli; -using System.ComponentModel.DataAnnotations.Schema; -using BenchmarkDotNet.Columns; namespace Cocona.Benchmark.External; -// use ColdStart strategy to measure startup time evaluation -[SimpleJob(RunStrategy.ColdStart, launchCount: 1, warmupCount: 0, iterationCount: 1, invocationCount: 1)] -[MemoryDiagnoser] [Orderer(SummaryOrderPolicy.FastestToSlowest)] public class Benchmark { diff --git a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj index 0af9c640..8cc59763 100644 --- a/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj +++ b/sandbox/CliFrameworkBenchmark/CliFrameworkBenchmark.csproj @@ -15,8 +15,8 @@ - - + + @@ -25,9 +25,9 @@ - - - + + + diff --git a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs index c37a45d3..a536ceb6 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs @@ -11,25 +11,37 @@ public static int Execute(string[] args) { var command = new RootCommand { - new Option(new[] {"--str", "-s"}), - new Option(new[] {"--int", "-i"}), - new Option(new[] {"--bool", "-b"}), + new Option("--str", ["-s"]), + new Option("--int", ["-i"]), + new Option("--bool", ["-b"]), }; - command.Handler = CommandHandler.Create(ExecuteHandler); - return command.Invoke(args); + command.SetAction(parseResult => + { + var handler = CommandHandler.Create(ExecuteHandler); + return handler.InvokeAsync(parseResult); + }); + + ParseResult parseResult = command.Parse(args); + return parseResult.Invoke(); } public static Task ExecuteAsync(string[] args) { var command = new RootCommand { - new Option(new[] {"--str", "-s"}), - new Option(new[] {"--int", "-i"}), - new Option(new[] {"--bool", "-b"}), + new Option("--str", ["-s"]), + new Option("--int", ["-i"]), + new Option("--bool", ["-b"]), }; - command.Handler = CommandHandler.Create(ExecuteHandler); - return command.InvokeAsync(args); + command.SetAction((parseResult, cancellationToken) => + { + var handler = CommandHandler.Create(ExecuteHandler); + return handler.InvokeAsync(parseResult); + }); + + ParseResult parseResult = command.Parse(args); + return parseResult.InvokeAsync(); } } diff --git a/sandbox/CliFrameworkBenchmark/Program.cs b/sandbox/CliFrameworkBenchmark/Program.cs index 5ee4add9..2183dbce 100644 --- a/sandbox/CliFrameworkBenchmark/Program.cs +++ b/sandbox/CliFrameworkBenchmark/Program.cs @@ -2,8 +2,12 @@ // https://github.com/Tyrrrz/CliFx/tree/master/CliFx.Benchmarks/ using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Engines; +using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Reports; using BenchmarkDotNet.Running; +using BenchmarkDotNet.Toolchains.CsProj; using Perfolizer.Horology; namespace Cocona.Benchmark.External; @@ -12,6 +16,22 @@ class Program { static void Main(string[] args) { - BenchmarkRunner.Run(DefaultConfig.Instance.WithSummaryStyle(SummaryStyle.Default.WithTimeUnit(TimeUnit.Millisecond)), args); + var config = DefaultConfig.Instance + .WithSummaryStyle(SummaryStyle.Default + .WithTimeUnit(TimeUnit.Millisecond)); + + config.AddDiagnoser(MemoryDiagnoser.Default); + config.AddDiagnoser(ThreadingDiagnoser.Default); + + config.AddJob(Job.Default + .WithStrategy(RunStrategy.ColdStart) + .WithLaunchCount(1) + .WithWarmupCount(0) + .WithIterationCount(1) + .WithInvocationCount(1) + .WithToolchain(CsProjCoreToolchain.NetCoreApp80) + .DontEnforcePowerPlan()); + + BenchmarkRunner.Run(config, args); } } diff --git a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj index ff2d53f9..8ba7778a 100644 --- a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj +++ b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj @@ -18,8 +18,8 @@ - + --> + diff --git a/src/ConsoleAppFramework/ConsoleAppFramework.csproj b/src/ConsoleAppFramework/ConsoleAppFramework.csproj index 7e06a5b2..363e1b74 100644 --- a/src/ConsoleAppFramework/ConsoleAppFramework.csproj +++ b/src/ConsoleAppFramework/ConsoleAppFramework.csproj @@ -32,7 +32,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj index 4ac531e4..32d7b249 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppFramework.GeneratorTests.csproj @@ -12,10 +12,14 @@ - - - - + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all From 0593a97407b5626cbcf176df946423b29b6bc850 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Fri, 20 Jun 2025 09:27:21 +0900 Subject: [PATCH 27/31] chore: add settings to suppress unused columns --- sandbox/CliFrameworkBenchmark/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sandbox/CliFrameworkBenchmark/Program.cs b/sandbox/CliFrameworkBenchmark/Program.cs index 2183dbce..560f93c3 100644 --- a/sandbox/CliFrameworkBenchmark/Program.cs +++ b/sandbox/CliFrameworkBenchmark/Program.cs @@ -21,7 +21,7 @@ static void Main(string[] args) .WithTimeUnit(TimeUnit.Millisecond)); config.AddDiagnoser(MemoryDiagnoser.Default); - config.AddDiagnoser(ThreadingDiagnoser.Default); + config.AddDiagnoser(new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayLockContentionWhenZero: false, displayCompletedWorkItemCountWhenZero: false))); config.AddJob(Job.Default .WithStrategy(RunStrategy.ColdStart) From 3cf59f121c1c9ede0448bc4eff20ffa5fd743c7b Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 20 Jun 2025 15:57:12 +0900 Subject: [PATCH 28/31] impl done --- ReadMe.md | 2 +- sandbox/GeneratorSandbox/Program.cs | 464 ++++++++++-------- src/ConsoleAppFramework/Command.cs | 46 +- src/ConsoleAppFramework/Emitter.cs | 12 +- .../EquatableTypeSymbol.cs | 33 +- src/ConsoleAppFramework/Parser.cs | 7 +- 6 files changed, 349 insertions(+), 215 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 0b40fb4f..e2b1eeb7 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -930,7 +930,7 @@ app.Add("", ([FromServices] MyService service, int x, int y) => Console.WriteLin app.Run(args); ``` -When passing to a lambda expression or method, the `[FromServices]` attribute is used to distinguish it from command parameters. When passing a class, Constructor Injection can be used, resulting in a simpler appearance. +When passing to a lambda expression or method, the `[FromServices]` attribute is used to distinguish it from command parameters. When passing a class, Constructor Injection can be used, resulting in a simpler appearance. Lambda, method, constructor, filter, etc, all DI supported parameter also supports `[FromKeyedServices]`. Let's try injecting a logger and enabling output to a file. The libraries used are Microsoft.Extensions.Logging and [Cysharp/ZLogger](https://github.com/Cysharp/ZLogger/) (a high-performance logger built on top of MS.E.Logging). If you are referencing `Microsoft.Extensions.Logging`, you can call `ConfigureLogging` from `ConsoleAppBuilder`. diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index 7fd65d44..a2ec580e 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -1,16 +1,47 @@ #nullable enable using ConsoleAppFramework; -using GeneratorSandbox; using Microsoft.Extensions.DependencyInjection; -using System.Linq; -using System.Text.Json; -//using Microsoft.Extensions.Configuration; -//using Microsoft.Extensions.DependencyInjection; -//// using Microsoft.Extensions.Hosting; -//using Microsoft.Extensions.Logging; -//using Microsoft.Extensions.Options; -//using ZLogger; +using Microsoft.Extensions.Hosting; + +[assembly: ConsoleAppFrameworkGeneratorOptions(DisableNamingConversion = true)] + +args = ["TestCommand", "Run"]; + +var builder = Host.CreateApplicationBuilder(args); +var services = builder.Services; + +services.AddSingleton(); +services.AddKeyedSingleton("Key"); + +var app = builder.ToConsoleAppBuilder(); +app.Run(args); + +interface ITest +{ + int Value { get; set; } +} + +class Test : ITest +{ + public int Value { get; set; } = 1; +} + +class KeyedTest : ITest +{ + public int Value { get; set; } = 2; +} + +[RegisterCommands(nameof(TestCommand))] +class TestCommand([FromKeyedServices("Key")] ITest test) +{ + public void Run() + { + // This value should be 2 but 1 displayed + Console.WriteLine(test.Value); + } +} + @@ -36,246 +67,277 @@ // dotnet run --project foo.csproj -- --foo 100 --bar bazbaz -var app = ConsoleApp.Create(); - -app.Add("run", ([FromKeyedServices("takoyaki")] List testList, string project, ConsoleAppContext context) => -{ - // run --project foo.csproj -- --foo 100 --bar bazbaz - Console.WriteLine(string.Join(" ", context.Arguments)); - - // --project foo.csproj - Console.WriteLine(string.Join(" ", context.CommandArguments!)); +//var app = ConsoleApp.Create(); - //IServiceProvider ServiceProvider = null!; - // ((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(Type, ""); +//app.Add("run", ([FromKeyedServices("takoyaki")] List testList, string project, ConsoleAppContext context) => +//{ +// // run --project foo.csproj -- --foo 100 --bar bazbaz +// Console.WriteLine(string.Join(" ", context.Arguments)); - // FromKeyedServicesAttribute - // IKeyedServiceProvider +// // --project foo.csproj +// Console.WriteLine(string.Join(" ", context.CommandArguments!)); - // --foo 100 --bar bazbaz - Console.WriteLine(string.Join(" ", context.EscapedArguments!)); -}); +// //IServiceProvider ServiceProvider = null!; +// // ((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(Type, ""); -app.Run(args); +// // FromKeyedServicesAttribute +// // IKeyedServiceProvider +// // --foo 100 --bar bazbaz +// Console.WriteLine(string.Join(" ", context.EscapedArguments!)); +//}); +//app.Add("foo"); -//ConsoleApp.Run(args, (ConsoleAppContext ctx) => { }); +//app.UseFilter(); -// inject options -//public class MyCommand(IOptions options) -//{ -// public void Echo(string msg) -// { -// ConsoleApp.Log($"Binded Option: {options.Value.Title} {options.Value.Name}"); -// } -//} +//app.Run(args); -//public class PositionOptions -//{ -// public string Title { get; set; } = ""; -// public string Name { get; set; } = ""; -//} -//internal class ServiceProviderScopeFilter(IServiceProvider serviceProvider, ConsoleAppFilter next) : ConsoleAppFilter(next) +//internal class NopFilter2([FromKeyedServices("mykey")] List xxxx, ConsoleAppFilter next) : ConsoleAppFilter(next) //{ // public override async Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken) // { -// // create Microsoft.Extensions.DependencyInjection scope -// await using var scope = serviceProvider.CreateAsyncScope(); - -// var originalServiceProvider = ConsoleApp.ServiceProvider; -// ConsoleApp.ServiceProvider = scope.ServiceProvider; // try // { -// await Next.InvokeAsync(context, cancellationToken); +// /* on before */ +// await Next.InvokeAsync(context, cancellationToken); // next +// /* on after */ +// } +// catch +// { +// /* on error */ +// throw; // } // finally // { -// ConsoleApp.ServiceProvider = originalServiceProvider; +// /* on finally */ // } // } //} -// JsonSerializer.Deserialize("foo"); -//// inject logger to filter -//internal class ReplaceLogFilter(ConsoleAppFilter next, ILogger logger) -// : ConsoleAppFilter(next) +////ConsoleApp.Run(args, (ConsoleAppContext ctx) => { }); + +//// inject options +////public class MyCommand(IOptions options) +////{ +//// public void Echo(string msg) +//// { +//// ConsoleApp.Log($"Binded Option: {options.Value.Title} {options.Value.Name}"); +//// } +////} + +////public class PositionOptions +////{ +//// public string Title { get; set; } = ""; +//// public string Name { get; set; } = ""; +////} + +////internal class ServiceProviderScopeFilter(IServiceProvider serviceProvider, ConsoleAppFilter next) : ConsoleAppFilter(next) +////{ +//// public override async Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken) +//// { +//// // create Microsoft.Extensions.DependencyInjection scope +//// await using var scope = serviceProvider.CreateAsyncScope(); + +//// var originalServiceProvider = ConsoleApp.ServiceProvider; +//// ConsoleApp.ServiceProvider = scope.ServiceProvider; +//// try +//// { +//// await Next.InvokeAsync(context, cancellationToken); +//// } +//// finally +//// { +//// ConsoleApp.ServiceProvider = originalServiceProvider; +//// } +//// } +////} + +//// JsonSerializer.Deserialize("foo"); + +////// inject logger to filter +////internal class ReplaceLogFilter(ConsoleAppFilter next, ILogger logger) +//// : ConsoleAppFilter(next) +////{ +//// public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken) +//// { +//// ConsoleApp.Log = msg => logger.LogInformation(msg); +//// ConsoleApp.LogError = msg => logger.LogError(msg); + +//// return Next.InvokeAsync(context, cancellationToken); +//// } +////} + +//class MyProvider : IServiceProvider, IAsyncDisposable //{ -// public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken) +// public void Dispose() +// { +// Console.WriteLine("disposed"); +// } + +// public ValueTask DisposeAsync() // { -// ConsoleApp.Log = msg => logger.LogInformation(msg); -// ConsoleApp.LogError = msg => logger.LogError(msg); +// Console.WriteLine("dispose async"); +// return default; +// } -// return Next.InvokeAsync(context, cancellationToken); +// public object? GetService(Type serviceType) +// { +// return null; // } //} -class MyProvider : IServiceProvider, IAsyncDisposable -{ - public void Dispose() - { - Console.WriteLine("disposed"); - } +//public class MyService +//{ - public ValueTask DisposeAsync() - { - Console.WriteLine("dispose async"); - return default; - } +//} - public object? GetService(Type serviceType) - { - return null; - } -} -public class MyService -{ +//public class MyCommands +//{ +// public MyCommands([FromKeyedServices(10.9)] float kokonimo) +// { -} +// } +// public void Cmd1(int x, int y, ConsoleAppContext ctx) +// { +// } -public class MyCommands -{ - public void Cmd1(int x, int y, ConsoleAppContext ctx) - { - } +// public Task Cmd2([FromKeyedServices(typeof(int))] List l, int x, int y) +// { +// return Task.CompletedTask; +// } +//} - public Task Cmd2(int x, int y) - { - return Task.CompletedTask; - } -} +//public class Tacommands +//{ +// public void HelloWorld(int hogeMoge) +// { +// } +//} -public class Tacommands -{ - public void HelloWorld(int hogeMoge) - { - } -} +//namespace ConsoleAppFramework +//{ +// internal static partial class ConsoleApp +// { +// static void Foo() +// { +// var options = JsonSerializerOptions ?? System.Text.Json.JsonSerializerOptions.Default; +// } -namespace ConsoleAppFramework -{ - internal static partial class ConsoleApp - { - static void Foo() - { - var options = JsonSerializerOptions ?? System.Text.Json.JsonSerializerOptions.Default; - } - - //public static ConsoleAppBuilder Create(IServiceProvider serviceProvider) - //{ - // ConsoleApp.ServiceProvider = serviceProvider; - // return ConsoleApp.Create(); - //} - - //public static ConsoleAppBuilder Create(Action configure) - //{ - // var services = new ServiceCollection(); - // configure(services); - // ConsoleApp.ServiceProvider = services.BuildServiceProvider(); - // return ConsoleApp.Create(); - //} - - - - //internal partial class ConsoleAppBuilder - //{ - // bool requireConfiguration; - // IConfiguration? configuration; - // Action? configureServices; - // Action? configureLogging; - - // /// Create configuration with SetBasePath(Directory.GetCurrentDirectory()) and AddJsonFile("appsettings.json"). - // public void ConfigureDefaultConfiguration(Action configure) - // { - // var config = new ConfigurationBuilder(); - // config.SetBasePath(System.IO.Directory.GetCurrentDirectory()); - // config.AddJsonFile("appsettings.json", optional: true); - // configure(config); - // configuration = config.Build(); - // } - - // public void ConfigureEmptyConfiguration(Action configure) - // { - // var config = new ConfigurationBuilder(); - // configure(config); - // configuration = config.Build(); - // } - - // public void ConfigureServices(Action configure) - // { - // this.configureServices = (_, services) => configure(services); - // } - - // public void ConfigureServices(Action configure) - // { - // this.requireConfiguration = true; - // this.configureServices = configure; - // } - - // public void ConfigureLogging(Action configure) - // { - // this.configureLogging = (_, builder) => configure(builder); - // } - - // public void ConfigureLogging(Action configure) - // { - // this.requireConfiguration = true; - // this.configureLogging = configure; - // } - - // public void BuildAndSetServiceProvider() - // { - // if (configureServices == null && configureLogging == null) return; - - // if (configureServices != null) - // { - // var services = new ServiceCollection(); - // configureServices?.Invoke(configuration!, services); - - // if (configureLogging != null) - // { - // var config = configuration; - // if (requireConfiguration && config == null) - // { - // config = new ConfigurationRoot(Array.Empty()); - // } - - // var configure = configureLogging; - // services.AddLogging(logging => - // { - // configure!(config!, logging); - // }); - // } - - // ConsoleApp.ServiceProvider = services.BuildServiceProvider(); - // } - // } - //} - } +// //public static ConsoleAppBuilder Create(IServiceProvider serviceProvider) +// //{ +// // ConsoleApp.ServiceProvider = serviceProvider; +// // return ConsoleApp.Create(); +// //} + +// //public static ConsoleAppBuilder Create(Action configure) +// //{ +// // var services = new ServiceCollection(); +// // configure(services); +// // ConsoleApp.ServiceProvider = services.BuildServiceProvider(); +// // return ConsoleApp.Create(); +// //} + + + +// //internal partial class ConsoleAppBuilder +// //{ +// // bool requireConfiguration; +// // IConfiguration? configuration; +// // Action? configureServices; +// // Action? configureLogging; + +// // /// Create configuration with SetBasePath(Directory.GetCurrentDirectory()) and AddJsonFile("appsettings.json"). +// // public void ConfigureDefaultConfiguration(Action configure) +// // { +// // var config = new ConfigurationBuilder(); +// // config.SetBasePath(System.IO.Directory.GetCurrentDirectory()); +// // config.AddJsonFile("appsettings.json", optional: true); +// // configure(config); +// // configuration = config.Build(); +// // } + +// // public void ConfigureEmptyConfiguration(Action configure) +// // { +// // var config = new ConfigurationBuilder(); +// // configure(config); +// // configuration = config.Build(); +// // } + +// // public void ConfigureServices(Action configure) +// // { +// // this.configureServices = (_, services) => configure(services); +// // } + +// // public void ConfigureServices(Action configure) +// // { +// // this.requireConfiguration = true; +// // this.configureServices = configure; +// // } + +// // public void ConfigureLogging(Action configure) +// // { +// // this.configureLogging = (_, builder) => configure(builder); +// // } + +// // public void ConfigureLogging(Action configure) +// // { +// // this.requireConfiguration = true; +// // this.configureLogging = configure; +// // } + +// // public void BuildAndSetServiceProvider() +// // { +// // if (configureServices == null && configureLogging == null) return; + +// // if (configureServices != null) +// // { +// // var services = new ServiceCollection(); +// // configureServices?.Invoke(configuration!, services); + +// // if (configureLogging != null) +// // { +// // var config = configuration; +// // if (requireConfiguration && config == null) +// // { +// // config = new ConfigurationRoot(Array.Empty()); +// // } + +// // var configure = configureLogging; +// // services.AddLogging(logging => +// // { +// // configure!(config!, logging); +// // }); +// // } + +// // ConsoleApp.ServiceProvider = services.BuildServiceProvider(); +// // } +// // } +// //} +// } -} +//} -namespace HogeHoge -{ +//namespace HogeHoge +//{ - public class BatchAttribute : Attribute - { - } +// public class BatchAttribute : Attribute +// { +// } - public class Batch2Attribute : BatchAttribute - { - } +// public class Batch2Attribute : BatchAttribute +// { +// } -} +//} diff --git a/src/ConsoleAppFramework/Command.cs b/src/ConsoleAppFramework/Command.cs index 0163356c..c36ba736 100644 --- a/src/ConsoleAppFramework/Command.cs +++ b/src/ConsoleAppFramework/Command.cs @@ -334,10 +334,21 @@ public string ToTypeShortString() public string GetFormattedKeyedServiceKey() { - if (KeyedServiceKey == null) return "null"; + return GetFormattedKeyedServiceKey(KeyedServiceKey); + } + + public static string GetFormattedKeyedServiceKey(object? keyedServiceKey) + { + if (keyedServiceKey == null) return "null"; + + if (keyedServiceKey is string) return $"\"{keyedServiceKey}\""; + + if (keyedServiceKey is ITypeSymbol type) + { + return $"typeof({type.ToFullyQualifiedFormatDisplayString()})"; + } - if (KeyedServiceKey is string) return $"\"{KeyedServiceKey}\""; - return $"({KeyedServiceKey.GetType().FullName}){KeyedServiceKey.ToString()}"; + return $"({keyedServiceKey.GetType().FullName}){keyedServiceKey.ToString()}"; } public override string ToString() @@ -364,7 +375,7 @@ public record class CommandMethodInfo { public required string TypeFullName { get; init; } public required string MethodName { get; init; } - public required EquatableArray ConstructorParameterTypes { get; init; } + public required EquatableArray ConstructorParameterTypes { get; init; } public required bool IsIDisposable { get; init; } public required bool IsIAsyncDisposable { get; init; } @@ -373,7 +384,14 @@ public string BuildNew() var p = ConstructorParameterTypes.Select(parameter => { var type = parameter.ToFullyQualifiedFormatDisplayString(); - return $"({type})ServiceProvider!.GetService(typeof({type}))!"; + if (!parameter.IsKeyedService) + { + return $"({type})ServiceProvider!.GetService(typeof({type}))!"; + } + else + { + return $"({type})((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(typeof({type}), {parameter.FormattedKeyedServiceKey})!"; + } }); return $"new {TypeFullName}({string.Join(", ", p)})"; @@ -383,7 +401,7 @@ public string BuildNew() public record class FilterInfo { public required string TypeFullName { get; init; } - public required EquatableArray ConstructorParameterTypes { get; init; } + public required EquatableArray ConstructorParameterTypes { get; init; } FilterInfo() { @@ -405,7 +423,12 @@ public record class FilterInfo var filter = new FilterInfo { TypeFullName = type.ToFullyQualifiedFormatDisplayString(), - ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbol(x.Type)).ToArray() + ConstructorParameterTypes = publicConstructors[0].Parameters + .Select(x => + { + return new EquatableTypeSymbolWithKeyedServiceKey(x); + }) + .ToArray() }; return filter; @@ -422,7 +445,14 @@ public string BuildNew(string nextFilterName) } else { - return $"({type})ServiceProvider!.GetService(typeof({type}))!"; + if (!parameter.IsKeyedService) + { + return $"({type})ServiceProvider!.GetService(typeof({type}))!"; + } + else + { + return $"({type})((Microsoft.Extensions.DependencyInjection.IKeyedServiceProvider)ServiceProvider).GetKeyedService(typeof({type}), {parameter.FormattedKeyedServiceKey})!"; + } } }); diff --git a/src/ConsoleAppFramework/Emitter.cs b/src/ConsoleAppFramework/Emitter.cs index 02a24e3c..83b48e15 100644 --- a/src/ConsoleAppFramework/Emitter.cs +++ b/src/ConsoleAppFramework/Emitter.cs @@ -838,13 +838,23 @@ public void EmitAsConsoleAppBuilder(SourceBuilder sb, DllReference dllReference) internal static class ConsoleAppHostBuilderExtensions { class CompositeDisposableServiceProvider(IDisposable host, IServiceProvider serviceServiceProvider, IDisposable scope, IServiceProvider serviceProvider) - : IServiceProvider, IDisposable + : IServiceProvider, IKeyedServiceProvider, IDisposable { public object? GetService(Type serviceType) { return serviceProvider.GetService(serviceType); } + public object? GetKeyedService(Type serviceType, object? serviceKey) + { + return ((IKeyedServiceProvider)serviceProvider).GetKeyedService(serviceType, serviceKey); + } + + public object GetRequiredKeyedService(Type serviceType, object? serviceKey) + { + return ((IKeyedServiceProvider)serviceProvider).GetRequiredKeyedService(serviceType, serviceKey); + } + public void Dispose() { if (serviceProvider is IDisposable d) diff --git a/src/ConsoleAppFramework/EquatableTypeSymbol.cs b/src/ConsoleAppFramework/EquatableTypeSymbol.cs index 0e99bcb0..308c381d 100644 --- a/src/ConsoleAppFramework/EquatableTypeSymbol.cs +++ b/src/ConsoleAppFramework/EquatableTypeSymbol.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Collections.Immutable; namespace ConsoleAppFramework; @@ -27,6 +27,37 @@ public bool Equals(EquatableTypeSymbol other) } } +// for filter +public class EquatableTypeSymbolWithKeyedServiceKey + : EquatableTypeSymbol, IEquatable +{ + public bool IsKeyedService { get; } + public string? FormattedKeyedServiceKey { get; } + + public EquatableTypeSymbolWithKeyedServiceKey(IParameterSymbol symbol) + : base(symbol.Type) + { + var keyedServciesAttr = symbol.GetAttributes().FirstOrDefault(x => x.AttributeClass?.Name == "FromKeyedServicesAttribute"); + if (keyedServciesAttr != null) + { + this.IsKeyedService = true; + this.FormattedKeyedServiceKey = CommandParameter.GetFormattedKeyedServiceKey(keyedServciesAttr.ConstructorArguments[0].Value); + } + } + + public bool Equals(EquatableTypeSymbolWithKeyedServiceKey other) + { + if (base.Equals(other)) + { + if (IsKeyedService != other.IsKeyedService) return false; + if (FormattedKeyedServiceKey != other.FormattedKeyedServiceKey) return false; + return true; + } + + return false; + } +} + static class EquatableTypeSymbolExtensions { public static EquatableTypeSymbol ToEquatable(this ITypeSymbol typeSymbol) => new(typeSymbol); diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index 82cbb4e4..705ac3d3 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -145,7 +145,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag TypeFullName = type.ToFullyQualifiedFormatDisplayString(), IsIDisposable = hasIDisposable, IsIAsyncDisposable = hasIAsyncDisposable, - ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbol(x.Type)).ToArray(), + ConstructorParameterTypes = publicConstructors[0].Parameters.Select(x => new EquatableTypeSymbolWithKeyedServiceKey(x)).ToArray(), MethodName = "", // without method name }; @@ -330,7 +330,7 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag { name = qns.Right; } - + var identifier = name.ToString(); var result = identifier is "FromKeyedServices" or "FromKeyedServicesAttribute"; if (result) @@ -557,7 +557,8 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag object? keyedServiceKey = null; if (hasFromKeyedServices) { - // TODO: try to get keyedservicekey + var attr = x.GetAttributes().First(x => x.AttributeClass?.Name == "FromKeyedServicesAttribute"); + keyedServiceKey = attr.ConstructorArguments[0].Value; } string description = ""; From dee656db6330e87ab7fbbb88d9bb264ac22f3e27 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Mon, 23 Jun 2025 17:41:29 +0900 Subject: [PATCH 29/31] chore: apply dotnet format command --- .../Commands/CliFxCommand.cs | 2 +- .../Commands/CliprCommand.cs | 2 +- .../Commands/CoconaCommand.cs | 2 +- .../Commands/CommandLineParserCommand.cs | 2 +- .../Commands/ConsoleAppFrameworkCommand.cs | 2 +- .../Commands/McMasterCommand.cs | 2 +- .../Commands/PowerArgsCommand.cs | 2 +- .../Commands/SpectreConsoleCliCommand.cs | 2 +- .../Commands/SystemCommandLineCommand.cs | 2 +- sandbox/FilterShareProject/Class1.cs | 2 +- sandbox/GeneratorSandbox/Filters.cs | 2 +- sandbox/NativeAot/Program.cs | 2 +- .../ConsoleApp.Abstractions.cs | 2 +- src/ConsoleAppFramework/CommandHelpBuilder.cs | 2 +- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 2 +- .../DiagnosticDescriptors.cs | 2 +- src/ConsoleAppFramework/EquatableArray.cs | 2 +- src/ConsoleAppFramework/IgnoreEquality.cs | 2 +- src/ConsoleAppFramework/NameConverter.cs | 2 +- src/ConsoleAppFramework/Parser.cs | 8 +- src/ConsoleAppFramework/PooledStringWriter.cs | 2 +- src/ConsoleAppFramework/RoslynExtensions.cs | 2 +- src/ConsoleAppFramework/SourceBuilder.cs | 2 +- .../SourceGeneratorContexts.cs | 2 +- src/ConsoleAppFramework/StringExtensions.cs | 34 ++--- .../SyntaxNodeTextEqualityComparer.cs | 2 +- src/ConsoleAppFramework/WellKnownTypes.cs | 2 +- .../ArgumentParserTest.cs | 2 +- .../ArrayParseTest.cs | 2 +- .../BuildCustomDelegateTest.cs | 2 +- .../CSharpGeneratorRunner.cs | 2 +- .../ConfigureTest.cs | 2 +- .../ConsoleAppBuilderTest.cs | 6 +- .../ConsoleAppContextTest.cs | 2 +- .../DITest.cs | 2 +- .../DiagnosticsTest.cs | 2 +- .../FilterTest.cs | 2 +- .../GeneratorOptionsTest.cs | 2 +- .../GlobalUsings.cs | 2 +- .../HelpTest.cs | 2 +- .../HiddenAttributeTest.cs | 128 +++++++++--------- .../IncrementalGeneratorTest.cs | 2 +- .../NameConverterTest.cs | 2 +- .../PooledStringWriterTest.cs | 2 +- .../RegisterCommandsTest.cs | 2 +- .../RunTest.cs | 2 +- .../SubCommandTest.cs | 2 +- 47 files changed, 131 insertions(+), 131 deletions(-) diff --git a/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs index e7371805..d3c48dae 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CliFxCommand.cs @@ -1,4 +1,4 @@ -using CliFx.Attributes; +using CliFx.Attributes; using CliFx.Infrastructure; namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs index c55f4175..34872d3b 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CliprCommand.cs @@ -1,4 +1,4 @@ -using clipr; +using clipr; namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs index 6b491158..37f39977 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CoconaCommand.cs @@ -1,4 +1,4 @@ -namespace Cocona.Benchmark.External.Commands; +namespace Cocona.Benchmark.External.Commands; public class CoconaCommand { diff --git a/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs index d5036398..2ab1d58a 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/CommandLineParserCommand.cs @@ -1,4 +1,4 @@ -namespace Cocona.Benchmark.External.Commands; +namespace Cocona.Benchmark.External.Commands; public class CommandLineParserCommand { diff --git a/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs index 04c3369a..ad7adcbd 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/ConsoleAppFrameworkCommand.cs @@ -1,4 +1,4 @@ -//using ConsoleAppFramework; +//using ConsoleAppFramework; //namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs index 5a576a3a..ae6b2b4c 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/McMasterCommand.cs @@ -1,4 +1,4 @@ -namespace Cocona.Benchmark.External.Commands; +namespace Cocona.Benchmark.External.Commands; public class McMasterCommand { diff --git a/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs index a52fc034..c9d0e72e 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/PowerArgsCommand.cs @@ -1,4 +1,4 @@ -using PowerArgs; +using PowerArgs; namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs index e96c824b..411ecc25 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SpectreConsoleCliCommand.cs @@ -1,4 +1,4 @@ -using Spectre.Console.Cli; +using Spectre.Console.Cli; using System.ComponentModel; namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs index a536ceb6..3a7f72b5 100644 --- a/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs +++ b/sandbox/CliFrameworkBenchmark/Commands/SystemCommandLineCommand.cs @@ -1,4 +1,4 @@ -using System.CommandLine; +using System.CommandLine; using System.CommandLine.NamingConventionBinder; namespace Cocona.Benchmark.External.Commands; diff --git a/sandbox/FilterShareProject/Class1.cs b/sandbox/FilterShareProject/Class1.cs index 1f285396..dc62a25a 100644 --- a/sandbox/FilterShareProject/Class1.cs +++ b/sandbox/FilterShareProject/Class1.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; namespace FilterShareProject; diff --git a/sandbox/GeneratorSandbox/Filters.cs b/sandbox/GeneratorSandbox/Filters.cs index 228206f0..4917f95b 100644 --- a/sandbox/GeneratorSandbox/Filters.cs +++ b/sandbox/GeneratorSandbox/Filters.cs @@ -1,4 +1,4 @@ - + using ConsoleAppFramework; using System.ComponentModel.DataAnnotations; diff --git a/sandbox/NativeAot/Program.cs b/sandbox/NativeAot/Program.cs index 5af0f8c5..400798ea 100644 --- a/sandbox/NativeAot/Program.cs +++ b/sandbox/NativeAot/Program.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json; diff --git a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs index 945467a8..69d28e32 100644 --- a/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs +++ b/src/ConsoleAppFramework.Abstractions/ConsoleApp.Abstractions.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/CommandHelpBuilder.cs b/src/ConsoleAppFramework/CommandHelpBuilder.cs index d3bd9825..b6b44386 100644 --- a/src/ConsoleAppFramework/CommandHelpBuilder.cs +++ b/src/ConsoleAppFramework/CommandHelpBuilder.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index a3520406..f73de146 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; public static class ConsoleAppBaseCode { diff --git a/src/ConsoleAppFramework/DiagnosticDescriptors.cs b/src/ConsoleAppFramework/DiagnosticDescriptors.cs index e18b72d7..6eb8b870 100644 --- a/src/ConsoleAppFramework/DiagnosticDescriptors.cs +++ b/src/ConsoleAppFramework/DiagnosticDescriptors.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/EquatableArray.cs b/src/ConsoleAppFramework/EquatableArray.cs index cbf71cae..c9bd85b8 100644 --- a/src/ConsoleAppFramework/EquatableArray.cs +++ b/src/ConsoleAppFramework/EquatableArray.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Runtime.CompilerServices; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/IgnoreEquality.cs b/src/ConsoleAppFramework/IgnoreEquality.cs index 784e5d64..72942880 100644 --- a/src/ConsoleAppFramework/IgnoreEquality.cs +++ b/src/ConsoleAppFramework/IgnoreEquality.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; public readonly struct IgnoreEquality(T value) : IEquatable> { diff --git a/src/ConsoleAppFramework/NameConverter.cs b/src/ConsoleAppFramework/NameConverter.cs index ec61d4b4..c5702c02 100644 --- a/src/ConsoleAppFramework/NameConverter.cs +++ b/src/ConsoleAppFramework/NameConverter.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/Parser.cs b/src/ConsoleAppFramework/Parser.cs index 38d3dfd9..3e024ea8 100644 --- a/src/ConsoleAppFramework/Parser.cs +++ b/src/ConsoleAppFramework/Parser.cs @@ -283,10 +283,10 @@ internal class Parser(ConsoleAppFrameworkGeneratorOptions generatorOptions, Diag } } - var hasParams = x.Modifiers.Any(x => x.IsKind(SyntaxKind.ParamsKeyword)); - - var isHidden = x.AttributeLists - .SelectMany(x => x.Attributes) + var hasParams = x.Modifiers.Any(x => x.IsKind(SyntaxKind.ParamsKeyword)); + + var isHidden = x.AttributeLists + .SelectMany(x => x.Attributes) .Any(x => model.GetTypeInfo(x).Type?.Name == "HiddenAttribute"); var customParserType = x.AttributeLists.SelectMany(x => x.Attributes) diff --git a/src/ConsoleAppFramework/PooledStringWriter.cs b/src/ConsoleAppFramework/PooledStringWriter.cs index 07686a6b..2e3d5b5b 100644 --- a/src/ConsoleAppFramework/PooledStringWriter.cs +++ b/src/ConsoleAppFramework/PooledStringWriter.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/RoslynExtensions.cs b/src/ConsoleAppFramework/RoslynExtensions.cs index 0007fe3d..8c4f2f99 100644 --- a/src/ConsoleAppFramework/RoslynExtensions.cs +++ b/src/ConsoleAppFramework/RoslynExtensions.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/ConsoleAppFramework/SourceBuilder.cs b/src/ConsoleAppFramework/SourceBuilder.cs index 2514ddb4..478ca34b 100644 --- a/src/ConsoleAppFramework/SourceBuilder.cs +++ b/src/ConsoleAppFramework/SourceBuilder.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/SourceGeneratorContexts.cs b/src/ConsoleAppFramework/SourceGeneratorContexts.cs index 678fb76e..45258410 100644 --- a/src/ConsoleAppFramework/SourceGeneratorContexts.cs +++ b/src/ConsoleAppFramework/SourceGeneratorContexts.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; readonly record struct ConsoleAppFrameworkGeneratorOptions(bool DisableNamingConversion); diff --git a/src/ConsoleAppFramework/StringExtensions.cs b/src/ConsoleAppFramework/StringExtensions.cs index 2e104065..7d1473f4 100644 --- a/src/ConsoleAppFramework/StringExtensions.cs +++ b/src/ConsoleAppFramework/StringExtensions.cs @@ -1,23 +1,23 @@ -namespace ConsoleAppFramework; - -internal static class StringExtensions -{ +namespace ConsoleAppFramework; + +internal static class StringExtensions +{ #if NETSTANDARD2_0 - public static string ReplaceLineEndings(this string input) - { + public static string ReplaceLineEndings(this string input) + { #pragma warning disable RS1035 - return ReplaceLineEndings(input, Environment.NewLine); + return ReplaceLineEndings(input, Environment.NewLine); #pragma warning restore RS1035 - } - - public static string ReplaceLineEndings(this string text, string replacementText) - { - text = text.Replace("\r\n", "\n"); - - if (replacementText != "\n") - text = text.Replace("\n", replacementText); + } + + public static string ReplaceLineEndings(this string text, string replacementText) + { + text = text.Replace("\r\n", "\n"); + + if (replacementText != "\n") + text = text.Replace("\n", replacementText); - return text; - } + return text; + } #endif } diff --git a/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs b/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs index 21067c6f..d3ffd196 100644 --- a/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs +++ b/src/ConsoleAppFramework/SyntaxNodeTextEqualityComparer.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/src/ConsoleAppFramework/WellKnownTypes.cs b/src/ConsoleAppFramework/WellKnownTypes.cs index 15e5b0bd..c758e531 100644 --- a/src/ConsoleAppFramework/WellKnownTypes.cs +++ b/src/ConsoleAppFramework/WellKnownTypes.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace ConsoleAppFramework; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs index 6cf26b13..3f27ff86 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArgumentParserTest.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; namespace ConsoleAppFramework.GeneratorTests; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs index df421b58..4483ea88 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ArrayParseTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests +namespace ConsoleAppFramework.GeneratorTests { public class ArrayParseTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs b/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs index d2488c99..be347f3b 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/BuildCustomDelegateTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs index 8e515eb6..06e1ad2b 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/CSharpGeneratorRunner.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs index c56e03d4..79d67dd9 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConfigureTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs index 071628ce..b32e38c5 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppBuilderTest.cs @@ -1,9 +1,9 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class ConsoleAppBuilderTest(ITestOutputHelper output) : IDisposable { - VerifyHelper verifier = new VerifyHelper(output, "CAF"); - + VerifyHelper verifier = new VerifyHelper(output, "CAF"); + public void Dispose() => Environment.ExitCode = 0; [Fact] diff --git a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs index 1dd139fb..c0438efc 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/ConsoleAppContextTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class ConsoleAppContextTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/DITest.cs b/tests/ConsoleAppFramework.GeneratorTests/DITest.cs index 760d7233..375b8990 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/DITest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/DITest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class DITest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs index f59c0e28..0b145f69 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/DiagnosticsTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class DiagnosticsTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs index eff7b99d..ab26b3bf 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/FilterTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class FilterTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs index 6f442a4f..646f4dd8 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/GeneratorOptionsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs b/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs index 24acf1e8..3df5f4b4 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/GlobalUsings.cs @@ -1,3 +1,3 @@ -// CSharpGeneratorRunner.CompileAndExecute uses stdout hook(replace Console.Out) +// CSharpGeneratorRunner.CompileAndExecute uses stdout hook(replace Console.Out) // so can not work in parallel test [assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs index 663be080..3bd24446 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/HelpTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; diff --git a/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs b/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs index e3090483..7a2c074a 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/HiddenAttributeTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class HiddenAtttributeTest(ITestOutputHelper output) { @@ -7,26 +7,26 @@ public class HiddenAtttributeTest(ITestOutputHelper output) [Fact] public void VerifyHiddenOptions_Lambda() { - var code = - """ - ConsoleApp.Run(args, (int x, [Hidden]int y) => { }); + var code = + """ + ConsoleApp.Run(args, (int x, [Hidden]int y) => { }); """; // Verify Hidden options is not shown on command help. - verifier.Execute(code, args: "--help", expected: + verifier.Execute(code, args: "--help", expected: """ Usage: [options...] [-h|--help] [--version] Options: --x (Required) - + """); - } - + } + [Fact] public void VerifyHiddenCommands_Class() { - var code = + var code = """ var builder = ConsoleApp.Create(); builder.Add(); @@ -41,51 +41,51 @@ public class Commands [Hidden] public void Command3(int x, [Hidden]int y) { Console.Write($"command3: x={x} y={y}"); } - } + } """; // Verify hidden command is not shown on root help commands. - verifier.Execute(code, args: "--help", expected: - """ - Usage: [command] [-h|--help] [--version] - + verifier.Execute(code, args: "--help", expected: + """ + Usage: [command] [-h|--help] [--version] + Commands: - command2 - - """); - - // Verify Hidden command help is shown when explicitly specify command name. - verifier.Execute(code, args: "command1 --help", expected: - """ - Usage: command1 [-h|--help] [--version] - - """); - - verifier.Execute(code, args: "command2 --help", expected: - """ - Usage: command2 [-h|--help] [--version] - - """); - - verifier.Execute(code, args: "command3 --help", expected: - """ - Usage: command3 [options...] [-h|--help] [--version] - - Options: - --x (Required) - - """); - - // Verify commands involations - verifier.Execute(code, args: "command1", "command1"); - verifier.Execute(code, args: "command2", "command2"); - verifier.Execute(code, args: "command3 --x 1 --y 2", expected: "command3: x=1 y=2"); + command2 + + """); + + // Verify Hidden command help is shown when explicitly specify command name. + verifier.Execute(code, args: "command1 --help", expected: + """ + Usage: command1 [-h|--help] [--version] + + """); + + verifier.Execute(code, args: "command2 --help", expected: + """ + Usage: command2 [-h|--help] [--version] + + """); + + verifier.Execute(code, args: "command3 --help", expected: + """ + Usage: command3 [options...] [-h|--help] [--version] + + Options: + --x (Required) + + """); + + // Verify commands involations + verifier.Execute(code, args: "command1", "command1"); + verifier.Execute(code, args: "command2", "command2"); + verifier.Execute(code, args: "command3 --x 1 --y 2", expected: "command3: x=1 y=2"); } [Fact] public void VerifyHiddenCommands_LocalFunctions() - { - var code = + { + var code = """ var builder = ConsoleApp.Create(); @@ -93,27 +93,27 @@ public void VerifyHiddenCommands_LocalFunctions() builder.Add("command1", Command1); builder.Add("command2", Command2); builder.Add("command3", Command3); - builder.Run(args); - - [Hidden] - static void Command1() { Console.Write("command1"); } - - static void Command2() { Console.Write("command2"); } - - [Hidden] - static void Command3(int x, [Hidden]int y) { Console.Write($"command3: x={x} y={y}"); } + builder.Run(args); + + [Hidden] + static void Command1() { Console.Write("command1"); } + + static void Command2() { Console.Write("command2"); } + + [Hidden] + static void Command3(int x, [Hidden]int y) { Console.Write($"command3: x={x} y={y}"); } """; verifier.Execute(code, args: "--help", expected: - """ - Usage: [command] [-h|--help] [--version] - - Commands: - command2 - - """); - - // Verify commands can be invoked. + """ + Usage: [command] [-h|--help] [--version] + + Commands: + command2 + + """); + + // Verify commands can be invoked. verifier.Execute(code, args: "command1", expected: "command1"); verifier.Execute(code, args: "command2", expected: "command2"); verifier.Execute(code, args: "command3 --x 1 --y 2", expected: "command3: x=1 y=2"); diff --git a/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs b/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs index 8d5c0f55..3b27c70d 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/IncrementalGeneratorTest.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; using System.Linq; diff --git a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs index 2d154e52..534cafa0 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/NameConverterTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class NameConverterTest(ITestOutputHelper output) { diff --git a/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs b/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs index d5e826c6..a8812bf8 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/PooledStringWriterTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs index 2313e822..a119c190 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RegisterCommandsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs index 4ef2ce5b..7c3caabe 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/RunTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class Test(ITestOutputHelper output) : IDisposable { diff --git a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs index 369e909e..9130658d 100644 --- a/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs +++ b/tests/ConsoleAppFramework.GeneratorTests/SubCommandTest.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework.GeneratorTests; +namespace ConsoleAppFramework.GeneratorTests; public class SubCommandTest(ITestOutputHelper output) { From 082a4bf8696e68f4778eb1b4d9db5b5ff3075e79 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 23 Jun 2025 18:13:12 +0900 Subject: [PATCH 30/31] suppress IL2026, IL3050 warning for NativeAOT publish --- sandbox/NativeAot/NativeAot.csproj | 4 ++++ sandbox/NativeAot/Program.cs | 3 ++- src/ConsoleAppFramework/ConsoleAppBaseCode.cs | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sandbox/NativeAot/NativeAot.csproj b/sandbox/NativeAot/NativeAot.csproj index f5fd1b81..6c599b38 100644 --- a/sandbox/NativeAot/NativeAot.csproj +++ b/sandbox/NativeAot/NativeAot.csproj @@ -9,6 +9,10 @@ true true + true + true + true + Debug;Release diff --git a/sandbox/NativeAot/Program.cs b/sandbox/NativeAot/Program.cs index 5af0f8c5..4251bd79 100644 --- a/sandbox/NativeAot/Program.cs +++ b/sandbox/NativeAot/Program.cs @@ -1,4 +1,4 @@ -using ConsoleAppFramework; +using ConsoleAppFramework; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json; @@ -8,6 +8,7 @@ ConsoleApp.Run(args, (int x, Kabayaki y) => Console.WriteLine(x + y.MyProperty)); app.Run(args); + public class Kabayaki { public int MyProperty { get; set; } diff --git a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs index a3520406..576cb6b1 100644 --- a/src/ConsoleAppFramework/ConsoleAppBaseCode.cs +++ b/src/ConsoleAppFramework/ConsoleAppBaseCode.cs @@ -1,4 +1,4 @@ -namespace ConsoleAppFramework; +namespace ConsoleAppFramework; public static class ConsoleAppBaseCode { @@ -149,6 +149,8 @@ public class ConsoleAppFrameworkGeneratorOptionsAttribute : Attribute public bool DisableNamingConversion { get; set; } } +[UnconditionalSuppressMessage("Trimming", "IL2026")] +[UnconditionalSuppressMessage("AOT", "IL3050")] internal static partial class ConsoleApp { public static IServiceProvider? ServiceProvider { get; set; } From 24f5271404257db05b616bd27dd46aefae77bf25 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 23 Jun 2025 19:32:26 +0900 Subject: [PATCH 31/31] don't report CAF008 error on CommunityToolkit.Mvvm.ObservableProperty "Add" calls --- .../GeneratorSandbox/GeneratorSandbox.csproj | 1 + sandbox/GeneratorSandbox/Program.cs | 20 +++++++++++++++- .../ConsoleAppGenerator.cs | 23 +++++++++++++------ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj index ff2d53f9..1d156d64 100644 --- a/sandbox/GeneratorSandbox/GeneratorSandbox.csproj +++ b/sandbox/GeneratorSandbox/GeneratorSandbox.csproj @@ -19,6 +19,7 @@ + diff --git a/sandbox/GeneratorSandbox/Program.cs b/sandbox/GeneratorSandbox/Program.cs index a2ec580e..fbfdcc8c 100644 --- a/sandbox/GeneratorSandbox/Program.cs +++ b/sandbox/GeneratorSandbox/Program.cs @@ -1,5 +1,6 @@ #nullable enable +using CommunityToolkit.Mvvm.ComponentModel; using ConsoleAppFramework; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -14,7 +15,20 @@ services.AddSingleton(); services.AddKeyedSingleton("Key"); + +MyObj obj = new(); +while (obj.Data.Count < 1) +{ + obj.Data.Add(0); // <-- CAF008 error here +} + var app = builder.ToConsoleAppBuilder(); +// var app = ConsoleApp.Create(); +//for (int i = 0; i < 10; i++) +//{ +// app.Add("foo", (int x) => { }); +//} + app.Run(args); interface ITest @@ -42,7 +56,11 @@ public void Run() } } - +public partial class MyObj : ObservableObject +{ + [ObservableProperty] + private List data = []; +} //args = ["echo", "--msg", "zzzz"]; diff --git a/src/ConsoleAppFramework/ConsoleAppGenerator.cs b/src/ConsoleAppFramework/ConsoleAppGenerator.cs index 2f900b60..5cc1bb8c 100644 --- a/src/ConsoleAppFramework/ConsoleAppGenerator.cs +++ b/src/ConsoleAppFramework/ConsoleAppGenerator.cs @@ -151,11 +151,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.SemanticModel, ct)) .WithTrackingName("ConsoleApp.Builder.0_CreateSyntaxProvider") - .Where(x => + .Select((x, ct) => { var model = x.Model.GetTypeInfo((x.Node.Expression as MemberAccessExpressionSyntax)!.Expression, x.CancellationToken); - return model.Type?.Name is "ConsoleAppBuilder" or "IHostBuilder" || model.Type?.Kind == SymbolKind.ErrorType; // allow ErrorType(ConsoleAppBuilder from Configure***(Source Generator generated method) is unknown in Source Generator) + return (x, model.Type?.Name, model.Type?.Kind); }) + .Where(x => x.Name is "ConsoleAppBuilder" or "IHostBuilder" || x.Kind == SymbolKind.ErrorType) // allow ErrorType(ConsoleAppBuilder from Configure***(Source Generator generated method) is unknown in Source Generator) .WithTrackingName("ConsoleApp.Builder.1_Where") .Collect() .Combine(generatorOptions) @@ -353,7 +354,7 @@ class CollectBuilderContext : IEquatable FilterInfo[]? globalFilters { get; } ConsoleAppFrameworkGeneratorOptions generatorOptions { get; } - public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOptions, ImmutableArray contexts, CancellationToken cancellationToken) + public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOptions, ImmutableArray<(BuilderContext, string?, SymbolKind?)> contexts, CancellationToken cancellationToken) { this.DiagnosticReporter = new DiagnosticReporter(); this.CancellationToken = cancellationToken; @@ -362,19 +363,24 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption // validation, invoke in loop is not allowed. foreach (var item in contexts) { - if (item.Name is "Run" or "RunAsync") continue; - foreach (var n in item.Node.Ancestors()) + var (ctx, name, kind) = item; + if (kind == SymbolKind.ErrorType) continue; // ErrorType can't distinguished from ConsoleAppFramework or others so ignore all. + + if (ctx.Name is "Run" or "RunAsync") continue; + foreach (var n in ctx.Node.Ancestors()) { if (n.Kind() is SyntaxKind.WhileStatement or SyntaxKind.DoStatement or SyntaxKind.ForStatement or SyntaxKind.ForEachStatement) { - DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.AddInLoopIsNotAllowed, item.Node.GetLocation()); + DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.AddInLoopIsNotAllowed, ctx.Node.GetLocation()); return; } } } - var methodGroup = contexts.ToLookup(x => + var methodGroup = contexts.ToLookup(ctx => { + var x = ctx.Item1; + if (x.Name == "Add" && ((x.Node.Expression as MemberAccessExpressionSyntax)?.Name.IsKind(SyntaxKind.GenericName) ?? false)) { return "Add"; @@ -384,6 +390,7 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption }); globalFilters = methodGroup["UseFilter"] + .Select(x => x.Item1) .OrderBy(x => x.Node.GetLocation().SourceSpan) // sort by line number .Select(x => { @@ -413,6 +420,7 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption var names = new HashSet(); var commands1 = methodGroup["Add"] + .Select(x => x.Item1) .Select(x => { var wellKnownTypes = new WellKnownTypes(x.Model.Compilation); @@ -432,6 +440,7 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption .ToArray(); // evaluate first. var commands2 = methodGroup["Add"] + .Select(x => x.Item1) .SelectMany(x => { var wellKnownTypes = new WellKnownTypes(x.Model.Compilation);