@@ -26,7 +26,16 @@ import SwiftSyntax
2626public final class OrderedImports : SyntaxFormatRule {
2727
2828 public override func visit( _ node: SourceFileSyntax ) -> SourceFileSyntax {
29- let lines = generateLines ( codeBlockItemList: node. statements, context: context)
29+ var newNode = node
30+ newNode. statements = orderImports ( in: node. statements, atStartOfFile: true )
31+ return newNode
32+ }
33+
34+ private func orderImports(
35+ in codeBlockItemList: CodeBlockItemListSyntax ,
36+ atStartOfFile: Bool
37+ ) -> CodeBlockItemListSyntax {
38+ let lines = generateLines ( codeBlockItemList: codeBlockItemList, context: context)
3039
3140 // Stores the formatted and sorted lines that will be used to reconstruct the list of code block
3241 // items later.
@@ -38,7 +47,7 @@ public final class OrderedImports: SyntaxFormatRule {
3847 var testableImports : [ Line ] = [ ]
3948 var codeBlocks : [ Line ] = [ ]
4049 var fileHeader : [ Line ] = [ ]
41- var atStartOfFile = true
50+ var atStartOfFile = atStartOfFile
4251 var commentBuffer : [ Line ] = [ ]
4352
4453 func formatAndAppend( linesSection: ArraySlice < Line > ) {
@@ -118,6 +127,24 @@ public final class OrderedImports: SyntaxFormatRule {
118127 }
119128 }
120129
130+ if let syntaxNode = line. syntaxNode, case . ifConfigCodeBlock( let ifConfigCodeBlock) = syntaxNode {
131+ var ifConfigDecl = ifConfigCodeBlock. item. cast ( IfConfigDeclSyntax . self)
132+
133+ let newClauses = ifConfigDecl. clauses. map { clause in
134+ guard case . statements( let codeBlockItemList) = clause. elements else {
135+ return clause
136+ }
137+ var newClause = clause
138+ var newCodeBlockItemList = orderImports ( in: codeBlockItemList, atStartOfFile: false )
139+ newCodeBlockItemList. leadingTrivia = . newline + newCodeBlockItemList. leadingTrivia
140+ newClause. elements = . statements( newCodeBlockItemList)
141+ return newClause
142+ }
143+
144+ ifConfigDecl. clauses = IfConfigClauseListSyntax ( newClauses)
145+ line. syntaxNode = . ifConfigCodeBlock( CodeBlockItemSyntax ( item: . decl( DeclSyntax ( ifConfigDecl) ) ) )
146+ }
147+
121148 // Separate lines into different categories along with any associated comments.
122149 switch line. type {
123150 case . regularImport:
@@ -154,9 +181,7 @@ public final class OrderedImports: SyntaxFormatRule {
154181 formatAndAppend ( linesSection: lines [ lastSliceStartIndex..< lines. endIndex] )
155182 }
156183
157- var newNode = node
158- newNode. statements = CodeBlockItemListSyntax ( convertToCodeBlockItems ( lines: formattedLines) )
159- return newNode
184+ return CodeBlockItemListSyntax ( convertToCodeBlockItems ( lines: formattedLines) )
160185 }
161186
162187 /// Raise lint errors if the different import types appear in the wrong order, and if import
@@ -354,11 +379,16 @@ private func generateLines(
354379 var blockWithoutTrailingTrivia = block
355380 blockWithoutTrailingTrivia. trailingTrivia = [ ]
356381 currentLine. syntaxNode = . importCodeBlock( blockWithoutTrailingTrivia, sortable: sortable)
382+ } else if block. item. is ( IfConfigDeclSyntax . self) {
383+ if currentLine. syntaxNode != nil {
384+ appendNewLine ( )
385+ }
386+ currentLine. syntaxNode = . ifConfigCodeBlock( block)
357387 } else {
358388 if let syntaxNode = currentLine. syntaxNode {
359389 // Multiple code blocks can be merged, as long as there isn't an import statement.
360390 switch syntaxNode {
361- case . importCodeBlock:
391+ case . importCodeBlock, . ifConfigCodeBlock :
362392 appendNewLine ( )
363393 currentLine. syntaxNode = . nonImportCodeBlocks( [ block] )
364394 case . nonImportCodeBlocks( let existingCodeBlocks) :
@@ -400,6 +430,8 @@ private func convertToCodeBlockItems(lines: [Line]) -> [CodeBlockItemSyntax] {
400430 switch syntaxNode {
401431 case . importCodeBlock( let codeBlock, _) :
402432 append ( codeBlockItem: codeBlock)
433+ case . ifConfigCodeBlock( let ifConfigCodeBlock) :
434+ append ( codeBlockItem: ifConfigCodeBlock)
403435 case . nonImportCodeBlocks( let codeBlocks) :
404436 codeBlocks. forEach ( append ( codeBlockItem: ) )
405437 }
@@ -458,6 +490,9 @@ private class Line {
458490 case nonImportCodeBlocks( [ CodeBlockItemSyntax ] )
459491 /// A single code block item whose content must be an import decl.
460492 case importCodeBlock( CodeBlockItemSyntax , sortable: Bool )
493+ /// A single code block item whose content must be an if config decl.
494+ /// This is used to sort conditional imports.
495+ case ifConfigCodeBlock( CodeBlockItemSyntax )
461496 }
462497
463498 /// Stores line comments. `syntaxNode` need not be defined, since a comment can exist by itself on
@@ -478,7 +513,7 @@ private class Line {
478513 var type : LineType {
479514 if let syntaxNode = syntaxNode {
480515 switch syntaxNode {
481- case . nonImportCodeBlocks:
516+ case . nonImportCodeBlocks, . ifConfigCodeBlock :
482517 return . codeBlock
483518 case . importCodeBlock( let importCodeBlock, _) :
484519 guard let importDecl = importCodeBlock. item. as ( ImportDeclSyntax . self) else {
@@ -542,6 +577,8 @@ private class Line {
542577 return codeBlock. firstToken ( viewMode: . sourceAccurate)
543578 case . nonImportCodeBlocks( let codeBlocks) :
544579 return codeBlocks. first? . firstToken ( viewMode: . sourceAccurate)
580+ case . ifConfigCodeBlock( let codeBlock) :
581+ return codeBlock. firstToken ( viewMode: . sourceAccurate)
545582 }
546583 }
547584
@@ -592,6 +629,8 @@ extension Line: CustomStringConvertible {
592629 description += " \( codeBlocks. count) code blocks "
593630 case . importCodeBlock( _, let sortable) :
594631 description += " \( sortable ? " sorted " : " unsorted " ) import \( importName) "
632+ case . ifConfigCodeBlock:
633+ description += " if config code block "
595634 }
596635 }
597636
0 commit comments