Files
SwiftFormat/Sources/Rules/ConsistentSwitchCaseSpacing.swift

97 lines
3.5 KiB
Swift

//
// ConsistentSwitchCaseSpacing.swift
// SwiftFormat
//
// Created by Cal Stephens on 2/1/24.
// Copyright © 2024 Nick Lockwood. All rights reserved.
//
import Foundation
public extension FormatRule {
static let consistentSwitchCaseSpacing = FormatRule(
help: "Ensures consistent spacing among all of the cases in a switch statement.",
orderAfter: [.blankLineAfterSwitchCase]
) { formatter in
formatter.forEach(.keyword("switch")) { switchIndex, _ in
guard let switchCases = formatter.switchStatementBranchesWithSpacingInfo(at: switchIndex) else { return }
// When counting the switch cases, exclude the last case (which should never have a trailing blank line).
let countWithTrailingBlankLine = switchCases.filter { $0.isFollowedByBlankLine && !$0.isLastCase }.count
let countWithoutTrailingBlankLine = switchCases.filter { !$0.isFollowedByBlankLine && !$0.isLastCase }.count
// We want the spacing to be consistent for all switch cases,
// so use whichever formatting is used for the majority of cases.
var allCasesShouldHaveBlankLine = countWithTrailingBlankLine >= countWithoutTrailingBlankLine
// When the `blankLinesBetweenChainedFunctions` rule is enabled, and there is a switch case
// that is required to span multiple lines, then all cases must span multiple lines.
// (Since if this rule removed the blank line from that case, it would contradict the other rule)
if formatter.options.enabledRules.contains(FormatRule.blankLineAfterSwitchCase.name),
switchCases.contains(where: { $0.spansMultipleLines && !$0.isLastCase })
{
allCasesShouldHaveBlankLine = true
}
for switchCase in switchCases.reversed() {
if !switchCase.isFollowedByBlankLine, allCasesShouldHaveBlankLine, !switchCase.isLastCase {
switchCase.insertTrailingBlankLine(using: formatter)
}
if switchCase.isFollowedByBlankLine, !allCasesShouldHaveBlankLine || switchCase.isLastCase {
switchCase.removeTrailingBlankLine(using: formatter)
}
}
}
} examples: {
#"""
```diff
func handle(_ action: SpaceshipAction) {
switch action {
case .engageWarpDrive:
navigationComputer.destination = targetedDestination
await warpDrive.spinUp()
warpDrive.activate()
case .enableArtificialGravity:
artificialGravityEngine.enable(strength: .oneG)
+
case let .scanPlanet(planet):
scanner.target = planet
scanner.scanAtmosphere()
scanner.scanBiosphere()
scanner.scanForArtificialLife()
case .handleIncomingEnergyBlast:
energyShields.engage()
}
}
```
```diff
var name: PlanetType {
switch self {
case .mercury:
"Mercury"
-
case .venus:
"Venus"
case .earth:
"Earth"
case .mars:
"Mars"
-
case .jupiter:
"Jupiter"
case .saturn:
"Saturn"
case .uranus:
"Uranus"
case .neptune:
"Neptune"
}
```
"""#
}
}