mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-06-16 10:34:34 +00:00
Add hoistAwait rule (#1360)
This commit is contained in:
committed by
Nick Lockwood
parent
749d23ec81
commit
9518366da6
@@ -83,6 +83,7 @@
|
||||
* [blankLinesBetweenImports](#blankLinesBetweenImports)
|
||||
* [blockComments](#blockComments)
|
||||
* [docComments](#docComments)
|
||||
* [hoistAwait](#hoistAwait)
|
||||
* [isEmpty](#isEmpty)
|
||||
* [markTypes](#markTypes)
|
||||
* [organizeDeclarations](#organizeDeclarations)
|
||||
@@ -747,6 +748,10 @@ Option | Description
|
||||
</details>
|
||||
<br/>
|
||||
|
||||
## hoistAwait
|
||||
|
||||
Reposition `await` keyword outside of the current scope.
|
||||
|
||||
## hoistPatternLet
|
||||
|
||||
Reposition `let` or `var` bindings within pattern.
|
||||
|
||||
@@ -4171,6 +4171,76 @@ public struct _FormatRules {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reposition `await` keyword outside of the current scope.
|
||||
public let hoistAwait = FormatRule(
|
||||
help: "Reposition `await` keyword outside of the current scope.",
|
||||
disabledByDefault: true,
|
||||
options: []
|
||||
) { formatter in
|
||||
formatter.forEach(.startOfScope("(")) { idx, _ in
|
||||
func insertAwait(at insertIndex: Int) {
|
||||
let awaitIndex = formatter.index(of: .keyword("await"), before: idx)
|
||||
|
||||
guard awaitIndex == nil || formatter.tokens[awaitIndex! ..< idx].contains(
|
||||
where: { $0.isStartOfScope || $0.isLinebreak }
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
formatter.insert([.keyword("await")], at: insertIndex)
|
||||
|
||||
if formatter.token(at: insertIndex + 1)?.isSpace == false {
|
||||
formatter.insertSpace(" ", at: insertIndex + 1)
|
||||
}
|
||||
|
||||
if insertIndex > 0,
|
||||
let previousToken = formatter.token(at: insertIndex - 1),
|
||||
!previousToken.isLinebreak,
|
||||
previousToken.isSpace == false
|
||||
{
|
||||
formatter.insertSpace(" ", at: insertIndex)
|
||||
}
|
||||
}
|
||||
|
||||
guard let endIndex = formatter.index(of: .endOfScope(")"), after: idx),
|
||||
formatter.lastSignificantKeyword(at: idx) != "if"
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
var awaitIndexes: [Int] = []
|
||||
var index = idx
|
||||
while let next = formatter.index(of: .keyword("await"), after: index), index < endIndex {
|
||||
awaitIndexes.append(next)
|
||||
index = next
|
||||
}
|
||||
|
||||
guard !awaitIndexes.isEmpty else { return }
|
||||
|
||||
let prevIndex = formatter.index(before: idx, where: {
|
||||
$0.isSpaceOrLinebreak
|
||||
})
|
||||
|
||||
awaitIndexes.reversed().forEach { awaitIndex in
|
||||
formatter.removeToken(at: awaitIndex)
|
||||
if formatter.tokens[awaitIndex].isSpace == true {
|
||||
formatter.removeToken(at: awaitIndex)
|
||||
}
|
||||
}
|
||||
|
||||
if let prevIndex = prevIndex {
|
||||
let token = formatter.token(at: prevIndex)
|
||||
if token?.isLinebreak == true {
|
||||
return insertAwait(at: prevIndex + 1)
|
||||
} else {
|
||||
return insertAwait(at: prevIndex)
|
||||
}
|
||||
} else {
|
||||
insertAwait(at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move `let` and `var` inside patterns to the beginning
|
||||
public let hoistPatternLet = FormatRule(
|
||||
help: "Reposition `let` or `var` bindings within pattern.",
|
||||
|
||||
@@ -604,6 +604,76 @@ class SyntaxTests: RulesTests {
|
||||
testFormatting(for: input, rule: FormatRules.trailingClosures)
|
||||
}
|
||||
|
||||
// MARK: - hoistAwait
|
||||
|
||||
func testHoistAwait() {
|
||||
let input = "greet(await name, await surname)"
|
||||
let output = "await greet(name, surname)"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitInsideIfDoesNothing() {
|
||||
let input = "if !(await isSomething()) {}"
|
||||
testFormatting(for: input, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitInsideArgument() {
|
||||
let input = """
|
||||
array.append(contentsOf: try await asyncFunction(param1: param1))
|
||||
"""
|
||||
let output = """
|
||||
await array.append(contentsOf: try asyncFunction(param1: param1))
|
||||
"""
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitWithReturn() {
|
||||
let input = "return .enumCase(try await service.greet())"
|
||||
let output = "return await .enumCase(try service.greet())"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitWithInitAssignment() {
|
||||
let input = "let variable = String(try await asyncFunction())"
|
||||
let output = "let variable = await String(try asyncFunction())"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitWithAssignment() {
|
||||
let input = "let variable = (try await asyncFunction())"
|
||||
let output = "let variable = await (try asyncFunction())"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitInRedundantScopePriorToNumber() {
|
||||
let input = """
|
||||
let identifiersTypes = 1
|
||||
(try? await asyncFunction(param1: param1))
|
||||
"""
|
||||
let output = """
|
||||
let identifiersTypes = 1
|
||||
await (try? asyncFunction(param1: param1))
|
||||
"""
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitOnlyOne() {
|
||||
let input = "greet(name, await surname)"
|
||||
let output = "await greet(name, surname)"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitRedundantAwait() {
|
||||
let input = "await greet(await name, await surname)"
|
||||
let output = "await greet(name, surname)"
|
||||
testFormatting(for: input, output, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
func testHoistAwaitDoesNothing() {
|
||||
let input = "await greet(name, surname)"
|
||||
testFormatting(for: input, rule: FormatRules.hoistAwait)
|
||||
}
|
||||
|
||||
// MARK: - hoistPatternLet
|
||||
|
||||
// hoist = true
|
||||
|
||||
Reference in New Issue
Block a user