Skip to content

Commit 03ff8cb

Browse files
committed
Add support for tracking remaining arguments in command retrieval.
- Refactor `CliTreeNode`, `CliCommandNode`, and `CliCommandGroupNode` to include parent nodes. - Replace command retrieval methods with `FindCommandNodeResult` to track remaining arguments. - Update `DefaultCliHost` and `CliCommandStore` to align with new structure. - Introduce unit tests for enhanced group and command node retrieval.
1 parent 0daa22d commit 03ff8cb

8 files changed

Lines changed: 276 additions & 72 deletions

File tree

‎source/Cli/CreativeCoders.Cli.Hosting/Commands/Store/CliCommandGroupNode.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
namespace CreativeCoders.Cli.Hosting.Commands.Store;
44

5-
public class CliCommandGroupNode(string groupName) : CliTreeNode(groupName)
5+
public class CliCommandGroupNode(string groupName, CliCommandGroupNode? parent)
6+
: CliTreeNode(groupName, parent)
67
{
78
public IEnumerable<CliCommandNode> GetCommands() => ChildNodes.OfType<CliCommandNode>();
89

‎source/Cli/CreativeCoders.Cli.Hosting/Commands/Store/CliCommandNode.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
namespace CreativeCoders.Cli.Hosting.Commands.Store;
44

5-
public class CliCommandNode(CliCommandInfo commandInfo, string command) : CliTreeNode(command)
5+
public class CliCommandNode(CliCommandInfo commandInfo, string command, CliCommandGroupNode? parent)
6+
: CliTreeNode(command, parent)
67
{
78
public CliCommandInfo CommandInfo { get; } = Ensure.NotNull(commandInfo);
89
}

‎source/Cli/CreativeCoders.Cli.Hosting/Commands/Store/CliCommandStore.cs‎

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,46 @@ public void AddCommands(IEnumerable<CliCommandInfo> commands)
1616
commands.ForEach(AddCommand);
1717
}
1818

19-
public CliCommandInfo? FindCommandForArgs(string[] args)
19+
public FindCommandNodeResult<CliCommandGroupNode>? FindCommandGroupNode(string[] args)
2020
{
21-
return FindCommandForArgs(_treeRootNodes, args);
21+
return FindCommandGroupNode(null, _treeRootNodes, args);
2222
}
2323

24-
public CliCommandGroupNode? FindGroupNodeForArgs(string[] args)
25-
{
26-
return FindGroupNodeForArgs(null, _treeRootNodes, args);
27-
}
28-
29-
public CliCommandGroupNode? FindGroupNodeForArgs(CliCommandGroupNode? lastGroupNode,
24+
private FindCommandNodeResult<CliCommandGroupNode>? FindCommandGroupNode(
25+
CliCommandGroupNode? lastGroupNode,
3026
IEnumerable<CliTreeNode> nodes, string[] args)
3127
{
3228
if (args.Length == 0)
3329
{
34-
return null;
30+
return lastGroupNode == null
31+
? null
32+
: new FindCommandNodeResult<CliCommandGroupNode>(lastGroupNode, []);
3533
}
3634

3735
var node = nodes.FirstOrDefault(x => x.Name == args[0]);
3836

37+
var remainingArgs = args.Skip(1).ToArray();
38+
3939
return node switch
4040
{
41-
null => lastGroupNode,
42-
CliCommandNode commandNode => commandNode.Parent,
43-
CliCommandGroupNode groupNode => FindGroupNodeForArgs(groupNode, groupNode.ChildNodes,
44-
args.Skip(1).ToArray()),
41+
null => lastGroupNode == null
42+
? null
43+
: new FindCommandNodeResult<CliCommandGroupNode>(lastGroupNode, args),
44+
CliCommandNode commandNode => new FindCommandNodeResult<CliCommandGroupNode>(commandNode.Parent,
45+
args),
46+
CliCommandGroupNode groupNode => FindCommandGroupNode(groupNode, groupNode.ChildNodes,
47+
remainingArgs),
4548
_ => null
4649
};
4750
}
4851

49-
private CliCommandInfo? FindCommandForArgs(IEnumerable<CliTreeNode> nodes, string[] args)
52+
public FindCommandNodeResult<CliCommandNode>? FindCommandNode(string[] args)
53+
{
54+
return FindCommandNode(_treeRootNodes, args);
55+
}
56+
57+
private static FindCommandNodeResult<CliCommandNode>? FindCommandNode(IEnumerable<CliTreeNode> nodes,
58+
string[] args)
5059
{
5160
if (args.Length == 0)
5261
{
@@ -58,8 +67,10 @@ public void AddCommands(IEnumerable<CliCommandInfo> commands)
5867
return node switch
5968
{
6069
null => null,
61-
CliCommandNode commandNode => commandNode.CommandInfo,
62-
CliCommandGroupNode groupNode => FindCommandForArgs(groupNode.ChildNodes, args.Skip(1).ToArray()),
70+
CliCommandNode commandNode => new FindCommandNodeResult<CliCommandNode>(commandNode,
71+
args.Skip(1).ToArray()),
72+
CliCommandGroupNode groupNode => FindCommandNode(groupNode.ChildNodes,
73+
args.Skip(1).ToArray()),
6374
_ => null
6475
};
6576
}
@@ -79,7 +90,7 @@ private void AddCommand(CliCommandInfo command, string[] commands)
7990
case 0:
8091
throw new InvalidOperationException("Commands must not be empty");
8192
case 1:
82-
_treeRootNodes.Add(new CliCommandNode(command, commands[0]));
93+
_treeRootNodes.Add(new CliCommandNode(command, commands[0], null));
8394
break;
8495
default:
8596
{
@@ -92,7 +103,7 @@ private void AddCommand(CliCommandInfo command, string[] commands)
92103

93104
_treeRootNodes.Add(groupNode);
94105

95-
groupNode.ChildNodes.Add(new CliCommandNode(command, commands[^1]));
106+
groupNode.ChildNodes.Add(new CliCommandNode(command, commands[^1], groupNode));
96107

97108
break;
98109
}
@@ -101,10 +112,11 @@ private void AddCommand(CliCommandInfo command, string[] commands)
101112

102113
private CliCommandGroupNode? GetGroupNode(string[] commands)
103114
{
104-
return GetGroupNode(_treeRootNodes, commands);
115+
return GetGroupNode(null, _treeRootNodes, commands);
105116
}
106117

107-
private static CliCommandGroupNode? GetGroupNode(List<CliTreeNode> nodes, string[] cmds)
118+
private static CliCommandGroupNode? GetGroupNode(CliCommandGroupNode? parent, List<CliTreeNode> nodes,
119+
string[] cmds)
108120
{
109121
var childNode = nodes
110122
.OfType<CliCommandGroupNode>()
@@ -118,16 +130,16 @@ private void AddCommand(CliCommandInfo command, string[] commands)
118130

119131
if (childNode != null)
120132
{
121-
return GetGroupNode(childNode.ChildNodes, cmds.Skip(1).ToArray());
133+
return GetGroupNode(childNode, childNode.ChildNodes, cmds.Skip(1).ToArray());
122134
}
123135

124-
var groupNode = new CliCommandGroupNode(cmds[0]);
136+
var groupNode = new CliCommandGroupNode(cmds[0], parent);
125137

126138
nodes.Add(groupNode);
127139

128140
return cmds.Length == 1
129141
? groupNode
130-
: GetGroupNode(groupNode.ChildNodes, cmds.Skip(1).ToArray());
142+
: GetGroupNode(groupNode, groupNode.ChildNodes, cmds.Skip(1).ToArray());
131143
}
132144

133145
public IEnumerable<CliTreeNode> TreeRootNodes => _treeRootNodes;

‎source/Cli/CreativeCoders.Cli.Hosting/Commands/Store/CliTreeNode.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
namespace CreativeCoders.Cli.Hosting.Commands.Store;
44

5-
public class CliTreeNode(string name)
5+
public class CliTreeNode(string name, CliCommandGroupNode? parent)
66
{
77
public List<CliTreeNode> ChildNodes { get; } = new List<CliTreeNode>();
88

9-
public CliCommandGroupNode? Parent { get; set; }
9+
public CliCommandGroupNode? Parent { get; } = parent;
1010

1111
public string Name { get; } = Ensure.IsNotNullOrWhitespace(name);
1212
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using CreativeCoders.Core;
2+
3+
namespace CreativeCoders.Cli.Hosting.Commands.Store;
4+
5+
public class FindCommandNodeResult<TNode>(TNode? node, string[] remainingArgs)
6+
where TNode : CliTreeNode
7+
{
8+
public TNode? Node { get; } = Ensure.NotNull(node);
9+
10+
public string[] RemainingArgs { get; } = Ensure.NotNull(remainingArgs);
11+
}

‎source/Cli/CreativeCoders.Cli.Hosting/Commands/Store/ICliCommandStore.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ public interface ICliCommandStore
44
{
55
void AddCommands(IEnumerable<CliCommandInfo> commands);
66

7-
CliCommandInfo? FindCommandForArgs(string[] args);
7+
FindCommandNodeResult<CliCommandGroupNode>? FindCommandGroupNode(string[] args);
88

9-
CliCommandGroupNode? FindGroupNodeForArgs(string[] args);
9+
FindCommandNodeResult<CliCommandNode>? FindCommandNode(string[] args);
1010

1111
IEnumerable<CliTreeNode> TreeRootNodes { get; }
1212

‎source/Cli/CreativeCoders.Cli.Hosting/DefaultCliHost.cs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ public DefaultCliHost(ICliCommandStore commandStore, IServiceProvider servicePro
2020

2121
public async Task<CliResult> RunAsync(string[] args)
2222
{
23-
var commandInfo = _commandStore.FindCommandForArgs(args);
24-
if (commandInfo != null)
23+
var commandInfo = _commandStore.FindCommandNode(args);
24+
if (commandInfo?.Node?.CommandInfo != null)
2525
{
26-
var command = commandInfo.CommandType.CreateInstance<ICliCommand>(_serviceProvider);
26+
var command =
27+
commandInfo.Node?.CommandInfo.CommandType.CreateInstance<ICliCommand>(_serviceProvider);
2728

2829
if (command != null)
2930
{

0 commit comments

Comments
 (0)