using Sdt.Config; namespace Sdt.Runner; public static class TargetRunner { /// /// Returns the ordered list of real (non-virtual) steps needed to execute , /// respecting DependsOn chains. Each step appears at most once. /// public static List ResolvePlan( BuildTarget target, IReadOnlyDictionary allTargets) { var visited = new HashSet(StringComparer.OrdinalIgnoreCase); var plan = new List(); Visit(target, allTargets, visited, plan); return plan; } private static void Visit( BuildTarget target, IReadOnlyDictionary allTargets, HashSet visited, List plan) { if (!visited.Add(target.Id)) return; // Recurse into dependencies first (topological order) foreach (var depId in target.DependsOn) { if (allTargets.TryGetValue(depId, out var dep)) Visit(dep, allTargets, visited, plan); } // Virtual aggregator targets (null Command) are just dependency collectors if (target.Command is not null) plan.Add(target); } }