@@ -19,28 +19,6 @@ internal class RemoveProjectFromSolutionCommand : CommandBase
1919 private readonly string _fileOrDirectory ;
2020 private readonly IReadOnlyCollection < string > _projects ;
2121
22- private int CountNonFolderDescendants (
23- SolutionModel solution ,
24- SolutionFolderModel item ,
25- Dictionary < SolutionFolderModel , SolutionItemModel [ ] > solutionItemsGroupedByParent ,
26- Dictionary < SolutionFolderModel , int > cached )
27- {
28- if ( cached . ContainsKey ( item ) )
29- {
30- return cached [ item ] ;
31- }
32- int count = item . Files ? . Count ?? 0 ;
33- var children = solutionItemsGroupedByParent . TryGetValue ( item , out var items ) ? items : Array . Empty < SolutionItemModel > ( ) ;
34- foreach ( var child in children )
35- {
36- count += child is SolutionFolderModel folderModel
37- ? CountNonFolderDescendants ( solution , folderModel , solutionItemsGroupedByParent , cached )
38- : 1 ;
39- }
40- cached . Add ( item , count ) ;
41- return count ;
42- }
43-
4422 public RemoveProjectFromSolutionCommand ( ParseResult parseResult ) : base ( parseResult )
4523 {
4624 _fileOrDirectory = parseResult . GetValue ( SlnCommandParser . SlnArgument ) ;
@@ -91,7 +69,7 @@ private async Task RemoveProjectsAsync(string solutionFileFullPath, IEnumerable<
9169 ISolutionSerializer serializer = SlnCommandParser . GetSolutionSerializer ( solutionFileFullPath ) ;
9270 SolutionModel solution = await serializer . OpenAsync ( solutionFileFullPath , cancellationToken ) ;
9371
94- // set UTF8 BOM encoding for .sln
72+ // set UTF-8 BOM encoding for .sln
9573 if ( serializer is ISolutionSerializer < SlnV12SerializerSettings > v12Serializer )
9674 {
9775 solution . SerializerExtension = v12Serializer . CreateModelExtension ( new ( )
@@ -114,21 +92,40 @@ private async Task RemoveProjectsAsync(string solutionFileFullPath, IEnumerable<
11492 }
11593 }
11694
117- Dictionary < SolutionFolderModel , SolutionItemModel [ ] > solutionItemsGroupedByParent = solution . SolutionItems
118- . Where ( i => i . Parent != null )
119- . GroupBy ( i => i . Parent )
120- . ToDictionary ( g => g . Key , g => g . ToArray ( ) ) ;
121-
122- Dictionary < SolutionFolderModel , int > nonFolderDescendantsCount = new ( ) ;
123- foreach ( var item in solution . SolutionFolders )
95+ for ( int i = 0 ; i < solution . SolutionFolders . Count ; i ++ )
12496 {
125- CountNonFolderDescendants ( solution , item , solutionItemsGroupedByParent , nonFolderDescendantsCount ) ;
126- }
97+ var folder = solution . SolutionFolders [ i ] ;
98+ int nonFolderDescendants = 0 ;
99+ Stack < SolutionFolderModel > stack = new ( ) ;
100+ stack . Push ( folder ) ;
127101
128- var emptyFolders = nonFolderDescendantsCount . Where ( i => i . Value == 0 ) . Select ( i => i . Key ) ;
129- foreach ( var folder in emptyFolders )
130- {
131- solution . RemoveFolder ( folder ) ;
102+ while ( stack . Count > 0 )
103+ {
104+ var current = stack . Pop ( ) ;
105+
106+ nonFolderDescendants += current . Files ? . Count ?? 0 ;
107+ foreach ( var child in solution . SolutionItems )
108+ {
109+ if ( child is { Parent : var parent } && parent == current )
110+ {
111+ if ( child is SolutionFolderModel childFolder )
112+ {
113+ stack . Push ( childFolder ) ;
114+ }
115+ else
116+ {
117+ nonFolderDescendants ++ ;
118+ }
119+ }
120+ }
121+ }
122+
123+ if ( nonFolderDescendants == 0 )
124+ {
125+ solution . RemoveFolder ( folder ) ;
126+ // After removal, adjust index and continue to avoid skipping folders after removal
127+ i -- ;
128+ }
132129 }
133130
134131 await serializer . SaveAsync ( solutionFileFullPath , solution , cancellationToken ) ;
0 commit comments