From f689941b2be7bf0b379a71b36f382721ff1824f0 Mon Sep 17 00:00:00 2001 From: JKamsker <11245306+JKamsker@users.noreply.github.com> Date: Fri, 15 Mar 2024 00:51:59 +0100 Subject: [PATCH] Eased requirements for custom type resolvers --- README.md | 2 - ...oolKit.Spectre.AutoCompletion.Tests.csproj | 1 + .../Unit/CommandAppTests.Complete.cs | 35 +++++++++- .../CustomTypeRegistrar.cs | 67 +++++++++++++++++++ .../Completion/Internals/CompleteCommand.cs | 51 +++++++++++--- 5 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 src/JKToolKit.Spectre.AutoCompletion.Tests/Utilities/DependencyInjection/CustomTypeRegistrar.cs diff --git a/README.md b/README.md index c744b4c..9cd905e 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,6 @@ public static void Main(string[] args) } ``` -Hint: If you are using a custom `ITypeRegistrar` or `ITypeResolver`, make sure, that the `ITypeResolver` resolves itself correctly. Or use the [JKToolKit.Spectre.Console.Extensions.Hosting-ng](https://github.com/JKamsker/Spectre.Console.Extensions.Hosting-ng) package - ## Shell integrations 1. [PowerShell](#powershell) 3. More to come... diff --git a/src/JKToolKit.Spectre.AutoCompletion.Tests/JKToolKit.Spectre.AutoCompletion.Tests.csproj b/src/JKToolKit.Spectre.AutoCompletion.Tests/JKToolKit.Spectre.AutoCompletion.Tests.csproj index ccb5123..7c1d291 100644 --- a/src/JKToolKit.Spectre.AutoCompletion.Tests/JKToolKit.Spectre.AutoCompletion.Tests.csproj +++ b/src/JKToolKit.Spectre.AutoCompletion.Tests/JKToolKit.Spectre.AutoCompletion.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/src/JKToolKit.Spectre.AutoCompletion.Tests/Unit/CommandAppTests.Complete.cs b/src/JKToolKit.Spectre.AutoCompletion.Tests/Unit/CommandAppTests.Complete.cs index 30a8ad3..6807232 100644 --- a/src/JKToolKit.Spectre.AutoCompletion.Tests/Unit/CommandAppTests.Complete.cs +++ b/src/JKToolKit.Spectre.AutoCompletion.Tests/Unit/CommandAppTests.Complete.cs @@ -1,3 +1,7 @@ +using JKToolKit.Spectre.AutoCompletion.Tests.Utilities.DependencyInjection; + +using Microsoft.Extensions.DependencyInjection; + using Spectre.Console.Cli; using Spectre.Console.Cli.Tests.Data.Commands; using Spectre.Console.Testing; @@ -5,7 +9,6 @@ namespace Spectre.Console.Tests.Unit.Cli; - public sealed partial class CommandAppTests { [UsesVerify] @@ -1232,5 +1235,35 @@ public void Completion_Should_Suggest_Remaining_Options() // Assert.Equal("dotnet", args.Runtime); // Assert.Equal("C:\\Users\\Tool.dll", args.Command); //} + + [Fact] + public void CustomTypeResolver_Works() + { + var services = new ServiceCollection(); + var customRegistry = new CustomTypeRegistrar(services); + + var fixture = new CommandAppTester(customRegistry); + fixture.Configure(config => + { + config.AddAutoCompletion(); + config.SetApplicationName("myapp"); + config.PropagateExceptions(); + + config.AddBranch("user", feline => + { + feline.AddCommand("add"); + feline.AddCommand("superAdd"); + }); + }); + + var commandToRun = Constants.CompleteCommand + .Append("\"myapp user superAdd Josh --gender male \""); + + // When + var result = fixture.Run(commandToRun.ToArray()); + + // Then + Assert.Equal("--age", result.Output); + } } } \ No newline at end of file diff --git a/src/JKToolKit.Spectre.AutoCompletion.Tests/Utilities/DependencyInjection/CustomTypeRegistrar.cs b/src/JKToolKit.Spectre.AutoCompletion.Tests/Utilities/DependencyInjection/CustomTypeRegistrar.cs new file mode 100644 index 0000000..6e25aa2 --- /dev/null +++ b/src/JKToolKit.Spectre.AutoCompletion.Tests/Utilities/DependencyInjection/CustomTypeRegistrar.cs @@ -0,0 +1,67 @@ +using Microsoft.Extensions.DependencyInjection; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JKToolKit.Spectre.AutoCompletion.Tests.Utilities.DependencyInjection; + +public class CustomTypeRegistrar : ITypeRegistrar +{ + private readonly IServiceCollection _builder; + + public CustomTypeRegistrar(IServiceCollection builder) + { + _builder = builder; + } + + public ITypeResolver Build() + { + return new CustomTypeResolver(_builder.BuildServiceProvider()); + } + + public void Register(Type service, Type implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterInstance(Type service, object implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterLazy(Type service, Func func) + { + if (func is null) + { + throw new ArgumentNullException(nameof(func)); + } + + _builder.AddSingleton(service, _ => func()); + } +} + +public sealed class CustomTypeResolver : ITypeResolver, IDisposable +{ + private readonly IServiceProvider _provider; + + public CustomTypeResolver(IServiceProvider provider) + { + _provider = provider ?? throw new ArgumentNullException(nameof(provider)); + } + + public object? Resolve(Type? type) + { + return type == null ? null : _provider.GetService(type); + } + + public void Dispose() + { + if (_provider is IDisposable disposable) + { + disposable.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/JKToolKit.Spectre.AutoCompletion/Completion/Internals/CompleteCommand.cs b/src/JKToolKit.Spectre.AutoCompletion/Completion/Internals/CompleteCommand.cs index 841fee7..2d11a1f 100644 --- a/src/JKToolKit.Spectre.AutoCompletion/Completion/Internals/CompleteCommand.cs +++ b/src/JKToolKit.Spectre.AutoCompletion/Completion/Internals/CompleteCommand.cs @@ -13,7 +13,6 @@ namespace JKToolKit.Spectre.AutoCompletion.Completion.Internals; - public sealed class CompleteCommandSettings : CommandSettings { [CommandArgument(0, "[commandToComplete]")] @@ -38,7 +37,7 @@ public override ValidationResult Validate() #if NET5_0_OR_GREATER var allowedFormats = new[] { "plain", "json", }; #else - var allowedFormats = new[] { "plain", }; + var allowedFormats = new[] { "plain", }; #endif if (!allowedFormats.Contains(Format, StringComparer.OrdinalIgnoreCase)) { @@ -59,13 +58,17 @@ public sealed partial class CompleteCommand : AsyncCommand ExecuteAsync( CommandContext context, @@ -298,10 +329,10 @@ private async Task> GetCommandArgumentsAsync( continue; } - // var completions = await CompleteCommandOption( - // context.Parent, - // parameter.Parameter, - // parameter.Value); + // var completions = await CompleteCommandOption( + // context.Parent, + // parameter.Parameter, + // parameter.Value); var completions = await CompleteCommandOption(context, parameter); if (completions == null || !completions.Suggestions.Any())