@@ -11,5 +11,89 @@ import SwiftSyntax
1111///
1212/// - SeeAlso: https://google.github.io/swift#enum-cases
1313public final class OneCasePerLine : SyntaxFormatRule {
14+
15+ public override func visit( _ node: EnumDeclSyntax ) -> DeclSyntax {
16+ let enumMembers = node. members. members
17+ var newMembers : [ MemberDeclListItemSyntax ] = [ ]
18+ var newIndx = 0
19+
20+ for member in enumMembers {
21+ var numNewMembers = 0
22+ if let caseMember = member. decl as? EnumCaseDeclSyntax {
23+ var otherDecl : EnumCaseDeclSyntax ? = caseMember
24+ // Add and skip single element case declarations
25+ guard caseMember. elements. count > 1 else {
26+ let newMember = SyntaxFactory . makeMemberDeclListItem ( decl: caseMember, semicolon: nil )
27+ newMembers. append ( newMember)
28+ newIndx += 1
29+ continue
30+ }
31+ // Move all cases with associated/raw values to new declarations
32+ for element in caseMember. elements {
33+ if element. associatedValue != nil || element. rawValue != nil {
34+ diagnose ( . moveAssociatedOrRawValueCase( name: element. identifier. text) , on: element)
35+ let newRemovedDecl = createAssociateOrRawCaseDecl ( fullDecl: caseMember,
36+ removedElement: element)
37+ otherDecl = removeAssociateOrRawCaseDecl ( fullDecl: otherDecl)
38+ let newMember = SyntaxFactory . makeMemberDeclListItem ( decl: newRemovedDecl,
39+ semicolon: nil )
40+ newMembers. append ( newMember)
41+ numNewMembers += 1
42+ }
43+ }
44+ // Add case declaration of remaining elements without associated/raw values, if any
45+ if let otherDecl = otherDecl {
46+ let newMember = SyntaxFactory . makeMemberDeclListItem ( decl: otherDecl, semicolon: nil )
47+ newMembers. insert ( newMember, at: newIndx)
48+ newIndx += 1
49+ }
50+ // Add any member that isn't an enum case declaration
51+ } else {
52+ newMembers. append ( member)
53+ newIndx += 1
54+ }
55+ newIndx += numNewMembers
56+ }
1457
58+ let newDeclList = SyntaxFactory . makeMemberDeclList ( newMembers)
59+ let newMemberBlock = SyntaxFactory . makeMemberDeclBlock ( leftBrace: node. members. leftBrace,
60+ members: newDeclList,
61+ rightBrace: node. members. rightBrace)
62+ return node. withMembers ( newMemberBlock)
63+ }
64+
65+ func createAssociateOrRawCaseDecl( fullDecl: EnumCaseDeclSyntax ,
66+ removedElement: EnumCaseElementSyntax ) -> EnumCaseDeclSyntax {
67+ let formattedElement = removedElement. withTrailingComma ( nil )
68+ let newElementList = SyntaxFactory . makeEnumCaseElementList ( [ formattedElement] )
69+ let newDecl = SyntaxFactory . makeEnumCaseDecl ( attributes: fullDecl. attributes,
70+ modifiers: fullDecl. modifiers,
71+ caseKeyword: fullDecl. caseKeyword,
72+ elements: newElementList)
73+ return newDecl
74+ }
75+
76+ // Returns formatted declaration of cases without associated/raw values, or nil if all cases had
77+ // a raw or associate value
78+ func removeAssociateOrRawCaseDecl( fullDecl: EnumCaseDeclSyntax ? ) -> EnumCaseDeclSyntax ? {
79+ guard let fullDecl = fullDecl else { return nil }
80+ var newList : [ EnumCaseElementSyntax ] = [ ]
81+
82+ for element in fullDecl. elements {
83+ if element. associatedValue == nil && element. rawValue == nil { newList. append ( element) }
84+ }
85+
86+ guard newList. count > 0 else { return nil }
87+ let ( last, indx) = ( newList [ newList. count - 1 ] , newList. count - 1 )
88+ if last. trailingComma != nil {
89+ newList [ indx] = last. withTrailingComma ( nil )
90+ }
91+ return fullDecl. withElements ( SyntaxFactory . makeEnumCaseElementList ( newList) )
92+ }
93+ }
94+
95+ extension Diagnostic . Message {
96+ static func moveAssociatedOrRawValueCase( name: String ) -> Diagnostic . Message {
97+ return . init( . warning, " move \( name) case to a new line " )
98+ }
1599}
0 commit comments