|
| 1 | +import Foundation |
| 2 | +import SwiftSyntax |
| 3 | +import SwiftParser |
| 4 | + |
| 5 | +/// MigrateToNewIfLetSyntax will visit each `if` statement in the syntax tree |
| 6 | +/// replacing all "old style" optional bindings by the new shorter syntax available |
| 7 | +/// since Swift 5.7. |
| 8 | +/// |
| 9 | +/// For example, it will turn: |
| 10 | +/// ``` |
| 11 | +/// if let foo = foo { |
| 12 | +/// ... |
| 13 | +/// } |
| 14 | +/// ``` |
| 15 | +/// into: |
| 16 | +/// ``` |
| 17 | +/// if let foo { |
| 18 | +/// ... |
| 19 | +/// } |
| 20 | +class MigrateToNewIfLetSyntax: SyntaxRewriter { |
| 21 | + // Visit all `if` statements. |
| 22 | + override func visit(_ node: IfStmtSyntax) -> StmtSyntax { |
| 23 | + // Visit all conditions in the node. |
| 24 | + let newConditions = node.conditions.enumerated().map { (index, condition) in |
| 25 | + var conditionCopy = condition |
| 26 | + // Check if the condition is an optional binding ... |
| 27 | + if var binding = condition.condition.as(OptionalBindingConditionSyntax.self), |
| 28 | + // ... and has an initializer ... |
| 29 | + let initializer = binding.initializer, |
| 30 | + // ... and both sides of the assignment are the same identifiers. |
| 31 | + binding.pattern.withoutTrivia().description == initializer.value.withoutTrivia().description { |
| 32 | + // Remove the initializer ... |
| 33 | + binding.initializer = nil |
| 34 | + // ... and remove whitespace before the comma (in `if` statements with multiple conditions). |
| 35 | + if index != node.conditions.count - 1 { |
| 36 | + binding.pattern = binding.pattern.withoutTrailingTrivia() |
| 37 | + } |
| 38 | + conditionCopy.condition = Syntax(binding) |
| 39 | + } |
| 40 | + return conditionCopy |
| 41 | + } |
| 42 | + return StmtSyntax(node.withConditions(ConditionElementListSyntax(newConditions))) |
| 43 | + } |
| 44 | + |
| 45 | + /// Utility function to migrate all swift files in a folder and its subfolders |
| 46 | + static func migrate(folderPath: String) { |
| 47 | + for case let fileURL as String in FileManager.default.enumerator(atPath: folderPath)! { |
| 48 | + if fileURL.hasSuffix("swift") { |
| 49 | + print("Rewriting", fileURL) |
| 50 | + let fullPath = folderPath + "/" + fileURL |
| 51 | + let tree = try! Parser.parse(source: String(data: FileManager.default.contents(atPath: fullPath)!, encoding: .utf8 )!) |
| 52 | + let newTree = MigrateToNewIfLetSyntax().visit(tree) |
| 53 | + try! newTree.description.write(toFile: fullPath, atomically: true, encoding: .utf8) |
| 54 | + } |
| 55 | + } |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +MigrateToNewIfLetSyntax.migrate(folderPath: "/path/to/folder") |
0 commit comments