File: Formatter.step10.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (79 lines) | stat: -rw-r--r-- 2,069 bytes parent folder | download
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)
        }
      }
  }
}