Forge
csharp3407750f
1using AgentForge.Abstractions;
2
3namespace AgentForge.Plugin.Grouping.Core;
4
5public sealed class ForgeGroupingAxisCatalog<TAxis, TItem>
6 where TAxis : IForgeGroupingAxis<TItem>
7{
8 private readonly IReadOnlyList<TAxis> _axes;
9 private readonly Dictionary<string, TAxis> _byId;
10
11 public ForgeGroupingAxisCatalog(IEnumerable<TAxis> axes, string domainLabel)
12 {
13 var list = axes
14 .OrderBy(axis => axis.Order)
15 .ThenBy(axis => axis.Id, StringComparer.OrdinalIgnoreCase)
16 .ToList();
17
18 _byId = new Dictionary<string, TAxis>(StringComparer.OrdinalIgnoreCase);
19 foreach (var axis in list)
20 {
21 if (string.IsNullOrWhiteSpace(axis.Id))
22 throw new InvalidOperationException($"{domainLabel} grouping axis Id is required.");
23
24 if (!_byId.TryAdd(axis.Id.Trim(), axis))
25 {
26 throw new InvalidOperationException(
27 $"Duplicate {domainLabel} grouping axis id '{axis.Id}'.");
28 }
29 }
30
31 _axes = list;
32 }
33
34 public IReadOnlyList<TAxis> Axes => _axes;
35
36 public bool TryGetAxis(string axisId, out TAxis? axis) =>
37 _byId.TryGetValue(axisId, out axis);
38
39 public IReadOnlyList<string> ParseStack(string? groupStackQuery)
40 {
41 if (string.IsNullOrWhiteSpace(groupStackQuery))
42 return [];
43
44 var result = new List<string>();
45 foreach (var part in groupStackQuery.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
46 {
47 if (!_byId.ContainsKey(part))
48 continue;
49 if (result.Contains(part, StringComparer.OrdinalIgnoreCase))
50 continue;
51 if (result.Count >= ForgeGroupingStackOptions.MaxStackDepth)
52 break;
53 result.Add(part);
54 }
55
56 return result;
57 }
58}
59
View only · write via MCP/CIDE