Skip to content

Commit d718e39

Browse files
committed
Feat: Add dependency injection support for commands
Introduced dependency injection for command creation using `ActivatorUtilities`. Added methods to `ICliParserBuilder` to load commands from assemblies. Enhanced regex in `ParameterDictionary` for improved value parsing and added corresponding unit tests.
1 parent 792a0be commit d718e39

File tree

7 files changed

+62
-3
lines changed

7 files changed

+62
-3
lines changed

src/CodeOfChaos.CliArgsParser.Contracts/ICliParserBuilder.cs

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// ---------------------------------------------------------------------------------------------------------------------
22
// Imports
33
// ---------------------------------------------------------------------------------------------------------------------
4+
using System.Reflection;
5+
46
namespace CodeOfChaos.CliArgsParser;
57

68
// ---------------------------------------------------------------------------------------------------------------------
@@ -9,6 +11,8 @@ namespace CodeOfChaos.CliArgsParser;
911
public interface ICliParserBuilder {
1012
ICliParserBuilder AddServices(IServiceProvider provider);
1113
ICliParserBuilder AddServices(Func<IServiceProvider> provider);
14+
ICliParserBuilder AddCommandsFromAssembly<TEntrypoint>();
15+
ICliParserBuilder AddCommandsFromAssembly(Assembly assembly);
1216

1317
ICliParser Build();
1418
}

src/CodeOfChaos.CliArgsParser/CliParser.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ---------------------------------------------------------------------------------------------------------------------
22
// Imports
33
// ---------------------------------------------------------------------------------------------------------------------
4+
using Microsoft.Extensions.DependencyInjection;
45
using System.Text.RegularExpressions;
56

67
namespace CodeOfChaos.CliArgsParser;
@@ -37,10 +38,11 @@ public async ValueTask ExecuteAsync(string input, CancellationToken ct = default
3738
string parameterInput = string.Join(" ", tokens.Skip(1));
3839

3940
if (!CommandProvider.TryGetCommand(commandName, out Type? commandType)) throw new Exception("no Command found");
40-
41+
4142
ICliCommand? command = ServiceProvider is not null
42-
? Activator.CreateInstance(commandType, ServiceProvider.Value) as ICliCommand
43+
? (ICliCommand?)ActivatorUtilities.CreateInstance(ServiceProvider.Value, commandType)
4344
: Activator.CreateInstance(commandType) as ICliCommand;
45+
4446

4547
if (command is null) throw new Exception("no Command found");
4648

src/CodeOfChaos.CliArgsParser/CodeOfChaos.CliArgsParser.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
<ItemGroup>
3535
<PackageReference Include="CodeOfChaos.Extensions" Version="0.66.1" />
36+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
3637
</ItemGroup>
3738

3839
</Project>

src/CodeOfChaos.CliArgsParser/ParameterDictionary.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public partial class ParameterDictionary : IParameterDictionary {
1313
private uint _quotedStringCounter;
1414

1515
[GeneratedRegex("""
16-
(?<keyValue>(?<key>--[\w\-_]+|-[\w\-_])\s*=\s*(?<value>\\?"[^"]*\\?"))
16+
(?<keyValue>(?<key>--[\w\-_]+|-[\w\-_])\s*=\s*(?<value>\\?"[^"]*\\?"|\w+))
1717
|(?<flag>(?:--[\w\-_]+|-[\w\-_])(?=\s|$))
1818
|(?<quotedString>\\?"(?<quoted>[^"]*)\\?")
1919
|(?<positional>\S+)

tests/Tests.CodeOfChaos.CliArgsParser/CliArgsParserTests.cs

+25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Imports
33
// ---------------------------------------------------------------------------------------------------------------------
44
using CodeOfChaos.CliArgsParser;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using Tests.CodeOfChaos.CliArgsParser.TestCommands;
57

68
namespace Tests.CodeOfChaos.CliArgsParser;
79

@@ -23,4 +25,27 @@ public async Task ExecuteAsync_Test() {
2325
// Assert
2426

2527
}
28+
29+
[Test]
30+
public async Task ExecuteAsync_TestWithServices() {
31+
// Arrange
32+
const string input = "test-service-command --test-required-string=\"something\"";
33+
var services = new ServiceCollection();
34+
services.AddSingleton<IService, Service>();
35+
ServiceProvider provider = services.BuildServiceProvider();
36+
37+
ICliParser parser = CliParser.FromBuilder()
38+
.AddServices(provider)
39+
.AddCommandsFromAssembly(typeof(CliParserTests).Assembly)
40+
.Build();
41+
42+
// Act
43+
await parser.ExecuteAsync(input);
44+
45+
// Assert
46+
var service = provider.GetRequiredService<IService>();
47+
TestCommandParameters? parameters = service.Parameters;
48+
await Assert.That(parameters).IsNotNull();
49+
await Assert.That(parameters!.TestRequiredString).IsEqualTo("something");
50+
}
2651
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
using CodeOfChaos.CliArgsParser;
5+
6+
namespace Tests.CodeOfChaos.CliArgsParser.TestCommands;
7+
8+
// ---------------------------------------------------------------------------------------------------------------------
9+
// Code
10+
// ---------------------------------------------------------------------------------------------------------------------
11+
[CliData, AutoName]
12+
public partial class TestServiceCommand(IService service) : ICliCommand<TestCommandParameters> {
13+
public ValueTask ExecuteAsync(TestCommandParameters parameters, CancellationToken ct = default) {
14+
service.Parameters = parameters;
15+
return ValueTask.CompletedTask;
16+
}
17+
}
18+
19+
20+
public class Service : IService {
21+
public TestCommandParameters? Parameters { get; set; }
22+
}
23+
24+
public interface IService {
25+
TestCommandParameters? Parameters { get; set; }
26+
}

tests/Tests.CodeOfChaos.CliArgsParser/Tests.CodeOfChaos.CliArgsParser.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0"/>
14+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.5" />
1415
<PackageReference Include="Moq" Version="4.20.72"/>
1516
<PackageReference Include="TUnit" Version="0.19.148" />
1617
<PackageReference Include="Bogus" Version="35.6.3" />

0 commit comments

Comments
 (0)