mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-05-17 10:30:35 +00:00
90 lines
3.5 KiB
Swift
90 lines
3.5 KiB
Swift
//
|
|
// PreferKeyPath.swift
|
|
// SwiftFormat
|
|
//
|
|
// Created by Nick Lockwood on 7/29/20.
|
|
// Copyright © 2024 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public extension FormatRule {
|
|
static let preferKeyPath = FormatRule(
|
|
help: "Convert trivial `map { $0.foo }` closures to keyPath-based syntax."
|
|
) { formatter in
|
|
formatter.forEach(.startOfScope("{")) { i, _ in
|
|
guard formatter.options.swiftVersion >= "5.2",
|
|
var prevIndex = formatter.index(of: .nonSpaceOrLinebreak, before: i)
|
|
else {
|
|
return
|
|
}
|
|
var prevToken = formatter.tokens[prevIndex]
|
|
var label: String?
|
|
if prevToken == .delimiter(":"),
|
|
let labelIndex = formatter.index(of: .nonSpace, before: prevIndex),
|
|
case let .identifier(name) = formatter.tokens[labelIndex],
|
|
let prevIndex2 = formatter.index(of: .nonSpaceOrLinebreak, before: labelIndex)
|
|
{
|
|
label = name
|
|
prevToken = formatter.tokens[prevIndex2]
|
|
prevIndex = prevIndex2
|
|
}
|
|
let parenthesized = prevToken == .startOfScope("(")
|
|
if parenthesized {
|
|
prevToken = formatter.last(.nonSpaceOrLinebreak, before: prevIndex) ?? prevToken
|
|
}
|
|
guard case let .identifier(name) = prevToken,
|
|
["map", "flatMap", "compactMap", "allSatisfy", "filter", "contains"].contains(name),
|
|
let nextIndex = formatter.index(of: .nonSpaceOrLinebreak, after: i, if: {
|
|
$0 == .identifier("$0")
|
|
}),
|
|
let endIndex = formatter.endOfScope(at: i),
|
|
let lastIndex = formatter.index(of: .nonSpaceOrLinebreak, before: endIndex)
|
|
else {
|
|
return
|
|
}
|
|
if let nextIndex = formatter.index(of: .nonSpaceOrCommentOrLinebreak, after: endIndex),
|
|
formatter.isLabel(at: nextIndex)
|
|
{
|
|
return
|
|
}
|
|
if name == "contains" {
|
|
if label != "where" {
|
|
return
|
|
}
|
|
} else if label != nil {
|
|
return
|
|
}
|
|
var replacementTokens: [Token]
|
|
if nextIndex == lastIndex {
|
|
// https://bugs.swift.org/browse/SR-12897
|
|
guard formatter.options.swiftVersion >= "6" else { return }
|
|
replacementTokens = tokenize("\\.self")
|
|
} else {
|
|
let tokens = formatter.tokens[nextIndex + 1 ... lastIndex]
|
|
guard tokens.allSatisfy({ $0.isSpace || $0.isIdentifier || $0.isOperator(".") }) else {
|
|
return
|
|
}
|
|
replacementTokens = [.operator("\\", .prefix)] + tokens
|
|
}
|
|
if let label {
|
|
replacementTokens = [.identifier(label), .delimiter(":"), .space(" ")] + replacementTokens
|
|
}
|
|
if !parenthesized {
|
|
replacementTokens = [.startOfScope("(")] + replacementTokens + [.endOfScope(")")]
|
|
}
|
|
formatter.replaceTokens(in: prevIndex + 1 ... endIndex, with: replacementTokens)
|
|
}
|
|
} examples: {
|
|
"""
|
|
```diff
|
|
- let barArray = fooArray.map { $0.bar }
|
|
+ let barArray = fooArray.map(\\.bar)
|
|
|
|
- let barArray = fooArray.compactMap { $0.optionalBar }
|
|
+ let barArray = fooArray.compactMap(\\.optionalBar)
|
|
```
|
|
"""
|
|
}
|
|
}
|