Skip to content

Commit bc6aa7c

Browse files
authored
Add rules for how to wrap attributes on property declarations (#254)
1 parent 013c1b4 commit bc6aa7c

File tree

3 files changed

+170
-3
lines changed

3 files changed

+170
-3
lines changed

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ let package = Package(
4242

4343
.binaryTarget(
4444
name: "SwiftFormat",
45-
url: "https://github.com/calda/SwiftFormat/releases/download/0.53-beta-4/SwiftFormat.artifactbundle.zip",
46-
checksum: "8506e9f6a434127f9eabe62c0a0349ccfd1e12e7cd7a96ba6a0c8f9d4a596099"),
45+
url: "https://github.com/calda/SwiftFormat/releases/download/0.53-beta-8/SwiftFormat.artifactbundle.zip",
46+
checksum: "42b2612305c5bffe57102d6c1a2e137309b5cf246638ff9ff75e3260a6795a19"),
4747

4848
.binaryTarget(
4949
name: "SwiftLintBinary",

README.md

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,26 +655,190 @@ _You can enable the following settings in Xcode by running [this script](resourc
655655

656656
</details>
657657

658-
* <a id='attributes-on-prev-line'></a>(<a href='#attributes-on-prev-line'>link</a>) **Place function/type attributes on the line above the declaration**. [![SwiftFormat: wrapAttributes](https://img.shields.io/badge/SwiftFormat-wrapAttributes-7B0051.svg)](https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md#wrapAttributes)
658+
* <a id='attributes-on-prev-line'></a>(<a href='#attributes-on-prev-line'>link</a>) **Place attributes for functions, types, and computed properties on the line above the declaration**. [![SwiftFormat: wrapAttributes](https://img.shields.io/badge/SwiftFormat-wrapAttributes-7B0051.svg)](https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md#wrapAttributes)
659659

660660
<details>
661661

662662
```swift
663663
// WRONG
664664
@objc class Spaceship {
665665

666+
@ViewBuilder var controlPanel: some View {
667+
// ...
668+
}
669+
666670
@discardableResult func fly() -> Bool {
671+
// ...
667672
}
673+
668674
}
669675

670676
// RIGHT
671677
@objc
672678
class Spaceship {
673679

680+
@ViewBuilder
681+
var controlPanel: some View {
682+
// ...
683+
}
684+
674685
@discardableResult
675686
func fly() -> Bool {
687+
// ...
676688
}
689+
690+
}
691+
```
692+
693+
</details>
694+
695+
* <a id='simple-stored-property-attributes-on-same-line'></a>(<a href='#simple-stored-property-attributes-on-same-line'>link</a>) **Place simple attributes for stored properties on the same line as the rest of the declaration**. Complex attributes with named arguments, or more than one unnamed argument, should be placed on the previous line. [![SwiftFormat: wrapAttributes](https://img.shields.io/badge/SwiftFormat-wrapAttributes-7B0051.svg)](https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md#wrapAttributes)
696+
697+
<details>
698+
699+
```swift
700+
// WRONG. These simple property wrappers should be written on the same line as the declaration.
701+
struct SpaceshipDashboardView {
702+
703+
@State
704+
private var warpDriveEnabled: Bool
705+
706+
@ObservedObject
707+
private var lifeSupportService: LifeSupportService
708+
709+
@Environment(\.controlPanelStyle)
710+
private var controlPanelStyle
711+
712+
}
713+
714+
// RIGHT
715+
struct SpaceshipDashboardView {
716+
717+
@State private var warpDriveEnabled: Bool
718+
719+
@ObservedObject private var lifeSupportService: LifeSupportService
720+
721+
@Environment(\.controlPanelStyle) private var controlPanelStyle
722+
723+
}
724+
```
725+
726+
```swift
727+
// WRONG. These complex attached macros should be written on the previous line.
728+
struct SolarSystemView {
729+
730+
@Query(sort: \.distance) var allPlanets: [Planet]
731+
732+
@Query(sort: \.age, order: .reverse) var moonsByAge: [Moon]
733+
734+
}
735+
736+
// RIGHT
737+
struct SolarSystemView {
738+
739+
@Query(sort: \.distance)
740+
var allPlanets: [Planet]
741+
742+
@Query(sort: \.age, order: .reverse)
743+
var oldestMoons: [Moon]
744+
677745
}
746+
```swift
747+
748+
```
749+
// WRONG. These long, complex attributes should be written on the previous line.
750+
struct RocketFactory {
751+
752+
@available(*, unavailable, message: "No longer in production") var saturn5Builder: Saturn5Builder
753+
754+
@available(*, deprecated, message: "To be retired by 2030") var atlas5Builder: Atlas5Builder
755+
756+
@available(*, iOS 18.0, tvOS 18.0, macOS 15.0, watchOS 11.0) var newGlennBuilder: NewGlennBuilder
757+
758+
}
759+
760+
// RIGHT
761+
struct RocketFactory {
762+
763+
@available(*, unavailable, message: "No longer in production")
764+
var saturn5Builder: Saturn5Builder
765+
766+
@available(*, deprecated, message: "To be retired by 2030")
767+
var atlas5Builder: Atlas5Builder
768+
769+
@available(*, iOS 18.0, tvOS 18.0, macOS 15.0, watchOS 11.0)
770+
var newGlennBuilder: NewGlennBuilder
771+
772+
}
773+
```
774+
775+
#### Why?
776+
777+
Unlike other types of declarations, which have braces and span multiple lines, stored property declarations are often only a single line of code. Stored properties are often written sequentially without any blank lines between them. This makes the code compact without hurting readability, and allows for related properties to be grouped together in blocks:
778+
779+
```swift
780+
struct SpaceshipDashboardView {
781+
@State private var warpDriveEnabled: Bool
782+
@State private var lifeSupportEnabled: Bool
783+
@State private var artificialGravityEnabled: Bool
784+
@State private var tractorBeamEnabled: Bool
785+
786+
@Environment(\.controlPanelStyle) private var controlPanelStyle
787+
@Environment(\.toggleButtonStyle) private var toggleButtonStyle
788+
}
789+
```
790+
791+
If stored property attributes were written on the previous line (like other types of attributes), then the properties start to visually bleed together unless you add blank lines between them:
792+
793+
```swift
794+
struct SpaceshipDashboardView {
795+
@State
796+
private var warpDriveEnabled: Bool
797+
@State
798+
private var lifeSupportEnabled: Bool
799+
@State
800+
private var artificialGravityEnabled: Bool
801+
@State
802+
private var tractorBeamEnabled: Bool
803+
804+
@Environment(\.controlPanelStyle)
805+
private var controlPanelStyle
806+
@Environment(\.toggleButtonStyle)
807+
private var toggleButtonStyle
808+
}
809+
```
810+
811+
If you add blank lines, the list of properties becomes much longer and you lose the ability to group related properties together:
812+
813+
```swift
814+
struct SpaceshipDashboardView {
815+
@State
816+
private var warpDriveEnabled: Bool
817+
818+
@State
819+
private var lifeSupportEnabled: Bool
820+
821+
@State
822+
private var artificialGravityEnabled: Bool
823+
824+
@State
825+
private var tractorBeamEnabled: Bool
826+
827+
@Environment(\.controlPanelStyle)
828+
private var controlPanelStyle
829+
830+
@Environment(\.toggleButtonStyle)
831+
private var toggleButtonStyle
832+
}
833+
```
834+
835+
This doesn't apply to complex attributes with named arguments, or multiple unnamed arguments. These arguments are visually complex and typically encode a lot of information, so feel cramped and difficult to read when written on a single line:
836+
837+
```swift
838+
// Despite being less than 100 characters long, these lines are very complex and feel unnecessarily long:
839+
@available(*, unavailable, message: "No longer in production") var saturn5Builder: Saturn5Builder
840+
@available(*, deprecated, message: "To be retired by 2030") var atlas5Builder: Atlas5Builder
841+
@available(*, iOS 18.0, tvOS 18.0, macOS 15.0, watchOS 11.0) var newGlennBuilder: NewGlennBuilder
678842
```
679843

680844
</details>

Sources/AirbnbSwiftFormatTool/airbnb.swiftformat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
--closingparen same-line # wrapArguments
2020
--wraptypealiases before-first # wrapArguments
2121
--funcattributes prev-line # wrapAttributes
22+
--computedvarattrs prev-line # wrapAttributes
23+
--storedvarattrs same-line # wrapAttributes
24+
--complexattrs prev-line # wrapAttributes
2225
--typeattributes prev-line # wrapAttributes
2326
--wrapternary before-operators # wrap
2427
--structthreshold 20 # organizeDeclarations

0 commit comments

Comments
 (0)