1- using System . Text ;
21using ModularPipelines . Models ;
2+ using Spectre . Console ;
33
44namespace ModularPipelines . Engine ;
55
66/// <summary>
7- /// Formats dependency trees as text with visual tree structure .
8- /// Creates a hierarchical representation using box-drawing characters .
7+ /// Formats dependency trees using Spectre.Console Tree widget .
8+ /// Creates a visual hierarchy with proper connectors, colors, and DAG support .
99/// </summary>
1010/// <example>
1111/// <code>
1212/// // Example output:
13- /// // ▶ RootModule
14- /// // └─ DependentModule1
15- /// // └─ DependentModule2
16- /// // └─ DependentModule3
13+ /// // Module Dependencies
14+ /// // ├── BuildModule
15+ /// // │ └── CompileModule
16+ /// // │ └── TestModule
17+ /// // └── DeployModule
18+ /// // └── TestModule (↑)
1719/// //
1820/// var formatter = new DependencyTreeFormatter();
1921/// var tree = formatter.FormatTree(rootModules);
20- /// Console.WriteLine (tree);
22+ /// AnsiConsole.Write (tree);
2123/// </code>
2224/// </example>
2325internal class DependencyTreeFormatter : IDependencyTreeFormatter
2426{
25- public string FormatTree ( IEnumerable < ModuleDependencyModel > rootModules )
27+ public Tree FormatTree ( IEnumerable < ModuleDependencyModel > rootModules )
2628 {
27- var stringBuilder = new StringBuilder ( ) ;
29+ var tree = new Tree ( "[bold]Module Dependencies[/]" ) ;
2830 var alreadyPrinted = new HashSet < ModuleDependencyModel > ( ) ;
2931
3032 foreach ( var rootModule in rootModules . OrderBy ( m => m . AllDescendantDependencies ( ) . Count ( ) ) )
@@ -34,27 +36,31 @@ public string FormatTree(IEnumerable<ModuleDependencyModel> rootModules)
3436 continue ;
3537 }
3638
37- stringBuilder . AppendLine ( ) ;
38- AppendNode ( stringBuilder , rootModule , 1 , alreadyPrinted ) ;
39+ AddNode ( tree , rootModule , alreadyPrinted ) ;
3940 }
4041
41- return stringBuilder . ToString ( ) ;
42+ return tree ;
4243 }
4344
44- private void AppendNode ( StringBuilder sb , ModuleDependencyModel node , int depth , ISet < ModuleDependencyModel > alreadyPrinted )
45+ private void AddNode ( IHasTreeNodes parent , ModuleDependencyModel node , HashSet < ModuleDependencyModel > alreadyPrinted )
4546 {
47+ var isReference = alreadyPrinted . Contains ( node ) ;
4648 alreadyPrinted . Add ( node ) ;
4749
48- var indent = new string ( ' ' , ( depth - 1 ) * 2 ) ;
49- var prefix = depth == 1 ? "▶ " : "└─ " ;
50+ var moduleName = node . Module . GetType ( ) . Name ;
51+ var label = isReference
52+ ? $ "[dim italic]{ moduleName } [/] [grey](↑)[/]"
53+ : $ "[blue]{ moduleName } [/]";
5054
51- sb . Append ( indent ) ;
52- sb . Append ( prefix ) ;
53- sb . AppendLine ( node . Module . GetType ( ) . Name ) ;
55+ var treeNode = parent . AddNode ( label ) ;
5456
55- foreach ( var dependent in node . IsDependencyFor )
57+ // Don't recurse into references - their children are shown elsewhere
58+ if ( ! isReference )
5659 {
57- AppendNode ( sb , dependent , depth + 1 , alreadyPrinted ) ;
60+ foreach ( var dependent in node . IsDependencyFor )
61+ {
62+ AddNode ( treeNode , dependent , alreadyPrinted ) ;
63+ }
5864 }
5965 }
6066}
@@ -65,9 +71,9 @@ private void AppendNode(StringBuilder sb, ModuleDependencyModel node, int depth,
6571internal interface IDependencyTreeFormatter
6672{
6773 /// <summary>
68- /// Formats a collection of root dependency modules as a tree structure .
74+ /// Formats a collection of root dependency modules as a Spectre.Console tree .
6975 /// </summary>
7076 /// <param name="rootModules">The root modules to format.</param>
71- /// <returns>A formatted string representation of the dependency tree .</returns>
72- string FormatTree ( IEnumerable < ModuleDependencyModel > rootModules ) ;
77+ /// <returns>A Spectre.Console Tree representing the dependency hierarchy .</returns>
78+ Tree FormatTree ( IEnumerable < ModuleDependencyModel > rootModules ) ;
7379}
0 commit comments