1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
import Foundation
import SwiftParser
import SwiftSyntax
@main struct ImportFormatter {
static func main() {
guard CommandLine.arguments.count == 2 else {
print("Not enough arguments!")
return
}
let filePath = CommandLine.arguments[1]
guard FileManager.default.fileExists(atPath: filePath) else {
print("File doesn't exist at path: \(filePath)")
return
}
guard let file = try? String(contentsOfFile: filePath) else {
print("File at path isn't readable: \(filePath)")
return
}
let formattedFile = ImportFormatter().formatImports(in: file)
print(formattedFile)
}
func formatImports(in file: String) -> SourceFileSyntax {
let sourceFile = Parser.parse(source: file)
var items = classifyItems(in: sourceFile)
let pivotPoint = items.partition { item in
switch item {
case .import(_, _):
return false
case .other(_):
return true
}
}
items[..<pivotPoint]
.sort { lhs, rhs in
guard
case let .import(lhsImport, _) = lhs,
case let .import(rhsImport, _) = rhs
else {
fatalError("Partition must only contain import items!")
}
return lhsImport.path.description < rhsImport.path.description
}
let formattedStatements = items.map { item in
switch item {
case .import(_, let statement):
return statement
case .other(let statement):
return statement
}
}
return
sourceFile
.with(\.statements, CodeBlockItemListSyntax(formattedStatements))
}
enum Item {
case `import`(ImportDeclSyntax, CodeBlockItemSyntax)
case other(CodeBlockItemSyntax)
}
func classifyItems(in file: SourceFileSyntax) -> [Item] {
file
.statements
.map { statement in
if case .decl(let decl) = statement.item,
let `import` = decl.as(ImportDeclSyntax.self)
{
return .import(`import`, statement)
} else {
return .other(statement)
}
}
}
}
|