diff --git a/source/Directory.Build.props b/source/Directory.Build.props
index 90519da..91e1718 100644
--- a/source/Directory.Build.props
+++ b/source/Directory.Build.props
@@ -1,14 +1,30 @@
- 14.0
+ 14.0
+ 10.0
+ 17.13
+
+
+
+ true
+ true
+
+
+
+ enable
+ enable
true
10.0
All
- false
+
+
+
+ true
+ true
true
diff --git a/source/Directory.Packages.props b/source/Directory.Packages.props
index 1e47b24..4dd23bd 100644
--- a/source/Directory.Packages.props
+++ b/source/Directory.Packages.props
@@ -7,6 +7,10 @@
+
+
+
+
diff --git a/source/FlashOWare.CommandLine.slnx b/source/FlashOWare.CommandLine.slnx
index 2378eea..705454d 100644
--- a/source/FlashOWare.CommandLine.slnx
+++ b/source/FlashOWare.CommandLine.slnx
@@ -5,4 +5,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/examples/.globalconfig b/source/examples/.globalconfig
new file mode 100644
index 0000000..80884de
--- /dev/null
+++ b/source/examples/.globalconfig
@@ -0,0 +1,4 @@
+is_global = true
+
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = none
diff --git a/source/examples/Directory.Build.props b/source/examples/Directory.Build.props
new file mode 100644
index 0000000..f485270
--- /dev/null
+++ b/source/examples/Directory.Build.props
@@ -0,0 +1,16 @@
+
+
+
+
+
+ false
+
+
+
+ true
+ true
+ true
+
+
+
diff --git a/source/examples/FlashOWare.CommandLine.Example.CSharp/FlashOWare.CommandLine.Example.CSharp.csproj b/source/examples/FlashOWare.CommandLine.Example.CSharp/FlashOWare.CommandLine.Example.CSharp.csproj
new file mode 100644
index 0000000..1ee3081
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.CSharp/FlashOWare.CommandLine.Example.CSharp.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net10.0
+ FlashOWare.CommandLine.Example.CSharp
+ FlashOWare.CommandLine.Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/examples/FlashOWare.CommandLine.Example.CSharp/Program.cs b/source/examples/FlashOWare.CommandLine.Example.CSharp/Program.cs
new file mode 100644
index 0000000..5b50bb6
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.CSharp/Program.cs
@@ -0,0 +1,111 @@
+using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.CommandLine.Parsing;
+using System.Reflection;
+using Octokit;
+
+RootCommand rootCommand = new("C# sample app.");
+
+Option option = new("--language", ["-l", "--lang"])
+{
+ Description = "Display the .NET language in use.",
+ Arity = ArgumentArity.Zero,
+ Action = new LanguageCommandLineAction(),
+};
+rootCommand.Options.Add(option);
+
+Command command = new("repository", "Display GitHub repository information.");
+command.Aliases.Add("repo");
+Argument argument = new("FULL-NAME")
+{
+ Description = """The full name of the repository in the form of "owner/repo".""",
+ Arity = ArgumentArity.ZeroOrOne,
+ DefaultValueFactory = static string (ArgumentResult argumentResult) => "FlashOWare/command-line-interfaces",
+};
+argument.Validators.Add(void (ArgumentResult argumentResult) =>
+{
+ string value = argumentResult.GetRequiredValue(argument);
+
+ int index = value.IndexOf('/');
+ if (index == -1 || index != value.LastIndexOf('/') || index == 0 || index + 1 == value.Length)
+ {
+ argumentResult.AddError("""The full name of the repository must be in the form of "owner/repo".""");
+ }
+});
+command.Arguments.Add(argument);
+command.SetAction(async Task (ParseResult parseResult, CancellationToken cancellationToken) =>
+{
+ string fullName = parseResult.GetRequiredValue(argument);
+ int index = fullName.IndexOf('/');
+ string owner = fullName[..index];
+ string repo = fullName[(index + 1)..];
+
+ AssemblyName name = typeof(Program).Assembly.GetName();
+ GitHubClient client = new(new ProductHeaderValue(name.Name, name.Version?.ToString()));
+ Repository repository = await client.Repository.Get(owner, repo);
+ RateLimit rateLimit = client.GetLastApiInfo().RateLimit;
+
+ const string TabString = " ";
+ TextWriter output = parseResult.InvocationConfiguration.Output;
+
+ await output.WriteLineAsync($"""
+ Repository
+ {TabString}Full Name: {repository.FullName}
+ {TabString}Stargazers: {repository.StargazersCount}
+ {TabString}Watchers: {repository.SubscribersCount}
+ {TabString}Forks: {repository.ForksCount}
+ {TabString}Open Issues: {repository.OpenIssuesCount}
+ """);
+ await output.WriteLineAsync($"""
+ Rate Limiting
+ {TabString}Requests per hour: {rateLimit.Limit - rateLimit.Remaining} / {rateLimit.Limit}
+ {TabString}Window resets at: {rateLimit.Reset.LocalDateTime:yyyy-MM-dd HH:mm:ss.fffffff}
+ """);
+
+ return 0;
+});
+rootCommand.Subcommands.Add(command);
+
+Directive directive = new("config")
+{
+ Description = "Show the command-line configuration that would have been used if the given command line were run.",
+ Action = new ConfigCommandLineAction(),
+};
+rootCommand.Directives.Add(directive);
+
+ParseResult parseResult = rootCommand.Parse(args);
+return await parseResult.InvokeAsync();
+
+internal sealed class LanguageCommandLineAction : SynchronousCommandLineAction
+{
+ public override int Invoke(ParseResult parseResult)
+ {
+ TextWriter output = parseResult.InvocationConfiguration.Output;
+ output.WriteLine("C#");
+ return 0;
+ }
+}
+
+internal sealed class ConfigCommandLineAction : SynchronousCommandLineAction
+{
+ public override int Invoke(ParseResult parseResult)
+ {
+ const string TabString = " ";
+ TextWriter output = parseResult.InvocationConfiguration.Output;
+
+ output.WriteLine($"""
+ Configuration
+ {TabString}EnablePosixBundling: {parseResult.Configuration.EnablePosixBundling}
+ """);
+
+ output.WriteLine($"""
+ Invocation
+ {TabString}EnableDefaultExceptionHandler: {parseResult.InvocationConfiguration.EnableDefaultExceptionHandler}
+ {TabString}ProcessTerminationTimeout: {(parseResult.InvocationConfiguration.ProcessTerminationTimeout is { } timeout ? timeout.ToString("c") : "")}
+ {TabString}Output: {parseResult.InvocationConfiguration.Output}
+ {TabString}Error: {parseResult.InvocationConfiguration.Error}
+ """);
+
+ return 0;
+ }
+}
diff --git a/source/examples/FlashOWare.CommandLine.Example.CSharp/Properties/AssemblyInfo.cs b/source/examples/FlashOWare.CommandLine.Example.CSharp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..476abce
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.CSharp/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Reflection;
+
+[assembly: AssemblyCopyright("Copyright © FlashOWare 2026")]
diff --git a/source/examples/FlashOWare.CommandLine.Example.FSharp/FlashOWare.CommandLine.Example.FSharp.fsproj b/source/examples/FlashOWare.CommandLine.Example.FSharp/FlashOWare.CommandLine.Example.FSharp.fsproj
new file mode 100644
index 0000000..cc23b19
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.FSharp/FlashOWare.CommandLine.Example.FSharp.fsproj
@@ -0,0 +1,30 @@
+
+
+
+ Exe
+ net10.0
+ FlashOWare.CommandLine.Example.FSharp
+ FlashOWare.CommandLine.Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/examples/FlashOWare.CommandLine.Example.FSharp/Program.fs b/source/examples/FlashOWare.CommandLine.Example.FSharp/Program.fs
new file mode 100644
index 0000000..051c9ff
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.FSharp/Program.fs
@@ -0,0 +1,99 @@
+open System
+open System.CommandLine
+open System.CommandLine.Invocation
+open System.CommandLine.Parsing
+open System.Reflection
+open System.Threading
+open System.Threading.Tasks
+open Octokit
+
+[]
+type private LanguageCommandLineAction() =
+ inherit SynchronousCommandLineAction()
+
+ override this.Invoke(parseResult: ParseResult) : int =
+ let output = parseResult.InvocationConfiguration.Output
+ output.WriteLine("F#")
+ 0
+
+[]
+type private ConfigCommandLineAction() =
+ inherit SynchronousCommandLineAction()
+
+ override this.Invoke(parseResult: ParseResult) : int =
+ let tabString = " "
+ let output = parseResult.InvocationConfiguration.Output
+
+ output.WriteLine("Configuration")
+ output.WriteLine($"{tabString}EnablePosixBundling: %b{parseResult.Configuration.EnablePosixBundling}")
+
+ output.WriteLine("Invocation")
+ output.WriteLine($"{tabString}EnableDefaultExceptionHandler: %b{parseResult.InvocationConfiguration.EnableDefaultExceptionHandler}")
+ output.WriteLine($"""{tabString}ProcessTerminationTimeout: {(if parseResult.InvocationConfiguration.ProcessTerminationTimeout.HasValue then parseResult.InvocationConfiguration.ProcessTerminationTimeout.Value.ToString("c") else "")}""")
+ output.WriteLine($"{tabString}Output: {parseResult.InvocationConfiguration.Output}")
+ output.WriteLine($"{tabString}Error: {parseResult.InvocationConfiguration.Error}")
+
+ 0
+
+let rootCommand = RootCommand("F# sample app.")
+
+let option = Option("--language", [| "-l"; "--lang" |],
+ Description = "Display the .NET language in use.",
+ Arity = ArgumentArity.Zero,
+ Action = LanguageCommandLineAction()
+)
+rootCommand.Options.Add(option)
+
+let command = Command("repository", "Display GitHub repository information.")
+command.Aliases.Add("repo")
+let argument = Argument("FULL-NAME",
+ Description = """The full name of the repository in the form of "owner/repo".""",
+ Arity = ArgumentArity.ZeroOrOne,
+ DefaultValueFactory = fun (argumentResult: ArgumentResult) -> "FlashOWare/command-line-interfaces"
+)
+argument.Validators.Add(fun (argumentResult : ArgumentResult) ->
+ let value = argumentResult.GetRequiredValue(argument)
+
+ let index = value.IndexOf('/')
+ if index = -1 || index <> value.LastIndexOf('/') || index = 0 || index + 1 = value.Length then
+ argumentResult.AddError("""The full name of the repository must be in the form of "owner/repo".""")
+)
+command.Arguments.Add(argument)
+command.SetAction(fun (parseResult: ParseResult) (cancellationToken: CancellationToken) -> (task {
+ let fullName = parseResult.GetRequiredValue(argument)
+ let index = fullName.IndexOf('/')
+ let owner = fullName.Substring(0, index)
+ let repo = fullName.Substring(index + 1)
+
+ let name = Assembly.GetExecutingAssembly().GetName()
+ let client = GitHubClient(ProductHeaderValue(name.Name, match name.Version with | null -> null | version -> version.ToString()))
+ let! repository = client.Repository.Get(owner, repo)
+ let rateLimit = client.GetLastApiInfo().RateLimit
+
+ let tabString = " "
+ let output = parseResult.InvocationConfiguration.Output
+
+ do! output.WriteLineAsync("Repository")
+ do! output.WriteLineAsync($"{tabString}Full Name: {repository.FullName}")
+ do! output.WriteLineAsync($"{tabString}Stargazers: {repository.StargazersCount}")
+ do! output.WriteLineAsync($"{tabString}Watchers: {repository.SubscribersCount}")
+ do! output.WriteLineAsync($"{tabString}Forks: {repository.ForksCount}")
+ do! output.WriteLineAsync($"{tabString}Open Issues: {repository.OpenIssuesCount}")
+
+ do! output.WriteLineAsync("Rate Limiting")
+ do! output.WriteLineAsync($"{tabString}Requests per hour: {rateLimit.Limit - rateLimit.Remaining} / {rateLimit.Limit}")
+ do! output.WriteLineAsync($"""{tabString}Window resets at: {rateLimit.Reset.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}""")
+
+ return 0
+} : Task))
+rootCommand.Subcommands.Add(command)
+
+let directive = Directive("config",
+ Description = "Show the command-line configuration that would have been used if the given command line were run.",
+ Action = ConfigCommandLineAction()
+)
+rootCommand.Directives.Add(directive)
+
+let parseResult = rootCommand.Parse(Environment.GetCommandLineArgs() |> Array.skip 1)
+let exitCode = parseResult.Invoke()
+exit exitCode
diff --git a/source/examples/FlashOWare.CommandLine.Example.VisualBasic/FlashOWare.CommandLine.Example.VisualBasic.vbproj b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/FlashOWare.CommandLine.Example.VisualBasic.vbproj
new file mode 100644
index 0000000..0f10238
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/FlashOWare.CommandLine.Example.VisualBasic.vbproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net10.0
+ FlashOWare.CommandLine.Example.VisualBasic
+ FlashOWare.CommandLine.Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Program.vb b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Program.vb
new file mode 100644
index 0000000..a95df87
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Program.vb
@@ -0,0 +1,108 @@
+Imports System.CommandLine
+Imports System.CommandLine.Invocation
+Imports System.CommandLine.Parsing
+Imports System.IO
+Imports System.Reflection
+Imports System.Threading
+Imports Octokit
+
+Friend Module Program
+ Friend Function Main(args As String()) As Integer
+ Dim rootCommand As New RootCommand("Visual Basic sample app.")
+
+ Dim [option] As New [Option](Of Boolean)("--language", New String() {"-l", "--lang"}) With {
+ .Description = "Display the .NET language in use.",
+ .Arity = ArgumentArity.Zero,
+ .Action = New LanguageCommandLineAction()
+ }
+ rootCommand.Options.Add([option])
+
+ Dim command As New Command("repository", "Display GitHub repository information.")
+ command.Aliases.Add("repo")
+ Dim argument As New Argument(Of String)("FULL-NAME") With {
+ .Description = "The full name of the repository in the form of ""owner/repo"".",
+ .Arity = ArgumentArity.ZeroOrOne,
+ .DefaultValueFactory = Function(argumentResult As ArgumentResult) "FlashOWare/command-line-interfaces"
+ }
+ argument.Validators.Add(
+ Sub(argumentResult As ArgumentResult)
+ Dim value As String = argumentResult.GetRequiredValue(argument)
+
+ Dim index As Integer = value.IndexOf("/"c)
+ If index = -1 OrElse index <> value.LastIndexOf("/"c) OrElse index = 0 OrElse index + 1 = value.Length Then
+ argumentResult.AddError("The full name of the repository must be in the form of ""owner/repo"".")
+ End If
+ End Sub)
+ command.Arguments.Add(argument)
+ command.SetAction(
+ Async Function(parseResult As ParseResult, cancellationToken As CancellationToken) As Task(Of Integer)
+ Dim fullName As String = parseResult.GetRequiredValue(argument)
+ Dim index As Integer = fullName.IndexOf("/"c)
+ Dim owner As String = fullName.Substring(0, index)
+ Dim repo As String = fullName.Substring(index + 1)
+
+ Dim name As AssemblyName = GetType(Program).Assembly.GetName()
+ Dim client As New GitHubClient(New ProductHeaderValue(name.Name, name.Version?.ToString()))
+ Dim repository As Repository = Await client.Repository.Get(owner, repo)
+ Dim rateLimit As RateLimit = client.GetLastApiInfo().RateLimit
+
+ Const TabString As String = " "
+ Dim output As TextWriter = parseResult.InvocationConfiguration.Output
+
+ Await output.WriteLineAsync("Repository")
+ Await output.WriteLineAsync($"{TabString}Full Name: {repository.FullName}")
+ Await output.WriteLineAsync($"{TabString}Stargazers: {repository.StargazersCount}")
+ Await output.WriteLineAsync($"{TabString}Watchers: {repository.SubscribersCount}")
+ Await output.WriteLineAsync($"{TabString}Forks: {repository.ForksCount}")
+ Await output.WriteLineAsync($"{TabString}Open Issues: {repository.OpenIssuesCount}")
+
+ Await output.WriteLineAsync("Rate Limiting")
+ Await output.WriteLineAsync($"{TabString}Requests per hour: {rateLimit.Limit - rateLimit.Remaining} / {rateLimit.Limit}")
+ Await output.WriteLineAsync($"{TabString}Window resets at: {rateLimit.Reset.LocalDateTime:yyyy-MM-dd HH:mm:ss.fffffff}")
+
+ Return 0
+ End Function)
+ rootCommand.Subcommands.Add(command)
+
+ Dim directive As New Directive("config") With {
+ .Description = "Show the command-line configuration that would have been used if the given command line were run.",
+ .Action = New ConfigCommandLineAction()
+ }
+ rootCommand.Directives.Add(directive)
+
+ Dim result As ParseResult = rootCommand.Parse(args)
+ Return result.Invoke()
+ End Function
+End Module
+
+Friend NotInheritable Class LanguageCommandLineAction
+ Inherits SynchronousCommandLineAction
+
+ Public Overrides Function Invoke(parseResult As ParseResult) As Integer
+ Dim output As TextWriter = parseResult.InvocationConfiguration.Output
+ output.WriteLine("Visual Basic")
+ Return 0
+ End Function
+End Class
+
+Friend NotInheritable Class ConfigCommandLineAction
+ Inherits SynchronousCommandLineAction
+
+ Public Overrides Function Invoke(parseResult As ParseResult) As Integer
+ Const TabString As String = " "
+ Dim output As TextWriter = parseResult.InvocationConfiguration.Output
+
+ output.WriteLine("Configuration")
+ output.WriteLine($"{TabString}EnablePosixBundling: {parseResult.Configuration.EnablePosixBundling}")
+
+ output.WriteLine("Invocation")
+ output.WriteLine($"{TabString}EnableDefaultExceptionHandler: {parseResult.InvocationConfiguration.EnableDefaultExceptionHandler}")
+ output.WriteLine($"{TabString}ProcessTerminationTimeout: {If(parseResult.InvocationConfiguration.ProcessTerminationTimeout.HasValue,
+ parseResult.InvocationConfiguration.ProcessTerminationTimeout.Value.ToString("c"),
+ "")}")
+ output.WriteLine($"{TabString}Output: {parseResult.InvocationConfiguration.Output}")
+ output.WriteLine($"{TabString}Error: {parseResult.InvocationConfiguration.Error}")
+
+ Return 0
+ End Function
+End Class
diff --git a/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/AssemblyInfo.vb b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/AssemblyInfo.vb
new file mode 100644
index 0000000..661b034
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/AssemblyInfo.vb
@@ -0,0 +1,3 @@
+Imports System.Reflection
+
+
diff --git a/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/GlobalSuppressions.vb b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/GlobalSuppressions.vb
new file mode 100644
index 0000000..e5be563
--- /dev/null
+++ b/source/examples/FlashOWare.CommandLine.Example.VisualBasic/Properties/GlobalSuppressions.vb
@@ -0,0 +1,5 @@
+' Global Suppressions
+
+Imports System.Diagnostics.CodeAnalysis
+
+
diff --git a/source/lib/.globalconfig b/source/lib/.globalconfig
new file mode 100644
index 0000000..7874532
--- /dev/null
+++ b/source/lib/.globalconfig
@@ -0,0 +1 @@
+is_global = true
diff --git a/source/lib/Directory.Build.props b/source/lib/Directory.Build.props
new file mode 100644
index 0000000..05eca01
--- /dev/null
+++ b/source/lib/Directory.Build.props
@@ -0,0 +1,26 @@
+
+
+
+
+
+ true
+
+
+
+ true
+
+
+
+
+ true
+ true
+
+
+
+
+ true
+ true
+
+
+
diff --git a/source/lib/FlashOWare.CommandLine.CliSchema/FlashOWare.CommandLine.CliSchema.csproj b/source/lib/FlashOWare.CommandLine.CliSchema/FlashOWare.CommandLine.CliSchema.csproj
new file mode 100644
index 0000000..cdb55a5
--- /dev/null
+++ b/source/lib/FlashOWare.CommandLine.CliSchema/FlashOWare.CommandLine.CliSchema.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Library
+ net10.0
+ FlashOWare.CommandLine.CliSchema
+ FlashOWare.CommandLine
+
+
+
diff --git a/source/lib/FlashOWare.CommandLine.CliSchema/Properties/AssemblyInfo.cs b/source/lib/FlashOWare.CommandLine.CliSchema/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c0d560e
--- /dev/null
+++ b/source/lib/FlashOWare.CommandLine.CliSchema/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+[assembly: CLSCompliant(true)]
diff --git a/source/lib/FlashOWare.CommandLine.OpenCli/FlashOWare.CommandLine.OpenCli.csproj b/source/lib/FlashOWare.CommandLine.OpenCli/FlashOWare.CommandLine.OpenCli.csproj
new file mode 100644
index 0000000..386e7c2
--- /dev/null
+++ b/source/lib/FlashOWare.CommandLine.OpenCli/FlashOWare.CommandLine.OpenCli.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Library
+ net10.0
+ FlashOWare.CommandLine.OpenCli
+ FlashOWare.CommandLine
+
+
+
diff --git a/source/lib/FlashOWare.CommandLine.OpenCli/Properties/AssemblyInfo.cs b/source/lib/FlashOWare.CommandLine.OpenCli/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c0d560e
--- /dev/null
+++ b/source/lib/FlashOWare.CommandLine.OpenCli/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+[assembly: CLSCompliant(true)]
diff --git a/source/perf/.globalconfig b/source/perf/.globalconfig
new file mode 100644
index 0000000..c290eca
--- /dev/null
+++ b/source/perf/.globalconfig
@@ -0,0 +1,13 @@
+is_global = true
+
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+
+# CA1515: Consider making public types internal
+dotnet_diagnostic.CA1515.severity = none
+
+# CA1822: Mark members as static
+dotnet_diagnostic.CA1822.severity = none
+
+# CA1852: Seal internal types
+dotnet_diagnostic.CA1852.severity = none
diff --git a/source/perf/Directory.Build.props b/source/perf/Directory.Build.props
new file mode 100644
index 0000000..4a05b80
--- /dev/null
+++ b/source/perf/Directory.Build.props
@@ -0,0 +1,14 @@
+
+
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/FlashOWare.CommandLine.CliSchema.Benchmarks.csproj b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/FlashOWare.CommandLine.CliSchema.Benchmarks.csproj
new file mode 100644
index 0000000..b7f9d1c
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/FlashOWare.CommandLine.CliSchema.Benchmarks.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net10.0
+ FlashOWare.CommandLine.CliSchema.Benchmarks
+ FlashOWare.CommandLine.Benchmarks
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Program.cs b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Program.cs
new file mode 100644
index 0000000..a7eb5e7
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Program.cs
@@ -0,0 +1,20 @@
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Diagnosers;
+using BenchmarkDotNet.Reports;
+using BenchmarkDotNet.Running;
+
+#if DEBUG
+IConfig config = new DebugInProcessConfig();
+#else
+IConfig config = ManualConfig.Create(DefaultConfig.Instance)
+ .WithOptions(ConfigOptions.DisableLogFile)
+ .AddDiagnoser(MemoryDiagnoser.Default);
+#endif
+
+IEnumerable summaries = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
+
+Console.WriteLine("Summaries:");
+foreach (Summary summary in summaries)
+{
+ Console.WriteLine($"- Ran {summary.Title} with {summary.ValidationErrors.Length} validation errors.");
+}
diff --git a/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Properties/AssemblyInfo.cs b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..476abce
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.CliSchema.Benchmarks/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Reflection;
+
+[assembly: AssemblyCopyright("Copyright © FlashOWare 2026")]
diff --git a/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/FlashOWare.CommandLine.OpenCli.Benchmarks.csproj b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/FlashOWare.CommandLine.OpenCli.Benchmarks.csproj
new file mode 100644
index 0000000..73e8aca
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/FlashOWare.CommandLine.OpenCli.Benchmarks.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net10.0
+ FlashOWare.CommandLine.OpenCli.Benchmarks
+ FlashOWare.CommandLine.Benchmarks
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Program.cs b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Program.cs
new file mode 100644
index 0000000..a7eb5e7
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Program.cs
@@ -0,0 +1,20 @@
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Diagnosers;
+using BenchmarkDotNet.Reports;
+using BenchmarkDotNet.Running;
+
+#if DEBUG
+IConfig config = new DebugInProcessConfig();
+#else
+IConfig config = ManualConfig.Create(DefaultConfig.Instance)
+ .WithOptions(ConfigOptions.DisableLogFile)
+ .AddDiagnoser(MemoryDiagnoser.Default);
+#endif
+
+IEnumerable summaries = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
+
+Console.WriteLine("Summaries:");
+foreach (Summary summary in summaries)
+{
+ Console.WriteLine($"- Ran {summary.Title} with {summary.ValidationErrors.Length} validation errors.");
+}
diff --git a/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Properties/AssemblyInfo.cs b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..476abce
--- /dev/null
+++ b/source/perf/FlashOWare.CommandLine.OpenCli.Benchmarks/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Reflection;
+
+[assembly: AssemblyCopyright("Copyright © FlashOWare 2026")]
diff --git a/source/tests/.globalconfig b/source/tests/.globalconfig
new file mode 100644
index 0000000..06dfdf7
--- /dev/null
+++ b/source/tests/.globalconfig
@@ -0,0 +1,11 @@
+is_global = true
+
+# CA1515: Consider making public types internal
+dotnet_diagnostic.CA1515.severity = none
+
+# https://learn.microsoft.com/dotnet/core/testing/mstest-analyzers/overview
+dotnet_diagnostic.MSTEST0015.severity = warning
+dotnet_diagnostic.MSTEST0019.severity = none
+dotnet_diagnostic.MSTEST0020.severity = warning
+dotnet_diagnostic.MSTEST0021.severity = warning
+dotnet_diagnostic.MSTEST0022.severity = none
diff --git a/source/tests/Directory.Build.props b/source/tests/Directory.Build.props
new file mode 100644
index 0000000..9229631
--- /dev/null
+++ b/source/tests/Directory.Build.props
@@ -0,0 +1,18 @@
+
+
+
+
+
+ false
+
+
+
+ true
+
+
+
+
+
+
+
diff --git a/source/tests/FlashOWare.CommandLine.CliSchema.Tests/FlashOWare.CommandLine.CliSchema.Tests.csproj b/source/tests/FlashOWare.CommandLine.CliSchema.Tests/FlashOWare.CommandLine.CliSchema.Tests.csproj
new file mode 100644
index 0000000..4a6c213
--- /dev/null
+++ b/source/tests/FlashOWare.CommandLine.CliSchema.Tests/FlashOWare.CommandLine.CliSchema.Tests.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net10.0
+ FlashOWare.CommandLine.CliSchema.Tests
+ FlashOWare.CommandLine.Tests
+
+
+
+
+
+
+
diff --git a/source/tests/FlashOWare.CommandLine.CliSchema.Tests/Properties/AssemblyInfo.cs b/source/tests/FlashOWare.CommandLine.CliSchema.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..300f5b1
--- /dev/null
+++ b/source/tests/FlashOWare.CommandLine.CliSchema.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
diff --git a/source/tests/FlashOWare.CommandLine.OpenCli.Tests/FlashOWare.CommandLine.OpenCli.Tests.csproj b/source/tests/FlashOWare.CommandLine.OpenCli.Tests/FlashOWare.CommandLine.OpenCli.Tests.csproj
new file mode 100644
index 0000000..b6b144f
--- /dev/null
+++ b/source/tests/FlashOWare.CommandLine.OpenCli.Tests/FlashOWare.CommandLine.OpenCli.Tests.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net10.0
+ FlashOWare.CommandLine.OpenCli.Tests
+ FlashOWare.CommandLine.Tests
+
+
+
+
+
+
+
diff --git a/source/tests/FlashOWare.CommandLine.OpenCli.Tests/Properties/AssemblyInfo.cs b/source/tests/FlashOWare.CommandLine.OpenCli.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..300f5b1
--- /dev/null
+++ b/source/tests/FlashOWare.CommandLine.OpenCli.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1 @@
+[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]