Skip to content

Commit ff93f49

Browse files
committed
Add option to disable trailing commas on multi-line collections
Extends the configuration options to allow disabling the addtion of trailing commas on multi-line collections.
1 parent 23cbb8e commit ff93f49

File tree

6 files changed

+160
-1
lines changed

6 files changed

+160
-1
lines changed

Documentation/Configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ top-level keys and values:
8282
* `spacesAroundRangeFormationOperators` _(boolean)_: Determines whether whitespace should be forced
8383
before and after the range formation operators `...` and `..<`.
8484

85+
* `multilineCollectionTrailingCommas` _(boolean)_: Determines whether multi-line collections should have trailing commas.
86+
Defaults to `true`.
87+
8588
> TODO: Add support for enabling/disabling specific syntax transformations in
8689
> the pipeline.
8790

Sources/SwiftFormat/API/Configuration+Default.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ extension Configuration {
3737
self.indentSwitchCaseLabels = false
3838
self.spacesAroundRangeFormationOperators = false
3939
self.noAssignmentInExpressions = NoAssignmentInExpressionsConfiguration()
40+
self.multilineCollectionTrailingCommas = true
4041
}
4142
}

Sources/SwiftFormat/API/Configuration.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public struct Configuration: Codable, Equatable {
4242
case rules
4343
case spacesAroundRangeFormationOperators
4444
case noAssignmentInExpressions
45+
case multilineCollectionTrailingCommas
4546
}
4647

4748
/// A dictionary containing the default enabled/disabled states of rules, keyed by the rules'
@@ -162,6 +163,9 @@ public struct Configuration: Codable, Equatable {
162163
/// Contains exceptions for the `NoAssignmentInExpressions` rule.
163164
public var noAssignmentInExpressions: NoAssignmentInExpressionsConfiguration
164165

166+
/// Determines whether multi-line list initializers should have trailing commas
167+
public var multilineCollectionTrailingCommas: Bool
168+
165169
/// Constructs a Configuration by loading it from a configuration file.
166170
public init(contentsOf url: URL) throws {
167171
let data = try Data(contentsOf: url)
@@ -239,6 +243,10 @@ public struct Configuration: Codable, Equatable {
239243
try container.decodeIfPresent(
240244
NoAssignmentInExpressionsConfiguration.self, forKey: .noAssignmentInExpressions)
241245
?? defaults.noAssignmentInExpressions
246+
self.multilineCollectionTrailingCommas =
247+
try container.decodeIfPresent(
248+
Bool.self, forKey: .multilineCollectionTrailingCommas)
249+
?? defaults.multilineCollectionTrailingCommas
242250

243251
// If the `rules` key is not present at all, default it to the built-in set
244252
// so that the behavior is the same as if the configuration had been
@@ -271,6 +279,7 @@ public struct Configuration: Codable, Equatable {
271279
try container.encode(fileScopedDeclarationPrivacy, forKey: .fileScopedDeclarationPrivacy)
272280
try container.encode(indentSwitchCaseLabels, forKey: .indentSwitchCaseLabels)
273281
try container.encode(noAssignmentInExpressions, forKey: .noAssignmentInExpressions)
282+
try container.encode(multilineCollectionTrailingCommas, forKey: .multilineCollectionTrailingCommas)
274283
try container.encode(rules, forKey: .rules)
275284
}
276285

Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ public class PrettyPrinter {
557557
// We never want to add a trailing comma in an initializer so we disable trailing commas on
558558
// single element collections.
559559
let shouldHaveTrailingComma =
560-
startLineNumber != openCloseBreakCompensatingLineNumber && !isSingleElement
560+
startLineNumber != openCloseBreakCompensatingLineNumber && !isSingleElement && configuration.multilineCollectionTrailingCommas
561561
if shouldHaveTrailingComma && !hasTrailingComma {
562562
diagnose(.addTrailingComma, category: .trailingComma)
563563
} else if !shouldHaveTrailingComma && hasTrailingComma {

Sources/_SwiftFormatTestSupport/Configuration+Testing.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ extension Configuration {
4040
config.indentSwitchCaseLabels = false
4141
config.spacesAroundRangeFormationOperators = false
4242
config.noAssignmentInExpressions = NoAssignmentInExpressionsConfiguration()
43+
config.multilineCollectionTrailingCommas = true
4344
return config
4445
}
4546
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import SwiftFormat
2+
3+
final class CommaTests: PrettyPrintTestCase {
4+
func testCommasAbsentEnabled() {
5+
let input =
6+
"""
7+
let MyList = [
8+
1,
9+
2,
10+
3
11+
]
12+
13+
"""
14+
15+
let expected =
16+
"""
17+
let MyList = [
18+
1,
19+
2,
20+
3,
21+
]
22+
23+
"""
24+
25+
var configuration = Configuration.forTesting
26+
configuration.multilineCollectionTrailingCommas = true
27+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20, configuration: configuration)
28+
}
29+
30+
func testCommasAbsentDisabled() {
31+
let input =
32+
"""
33+
let MyList = [
34+
1,
35+
2,
36+
3
37+
]
38+
39+
"""
40+
41+
let expected =
42+
"""
43+
let MyList = [
44+
1,
45+
2,
46+
3
47+
]
48+
49+
"""
50+
51+
var configuration = Configuration.forTesting
52+
configuration.multilineCollectionTrailingCommas = false
53+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20, configuration: configuration)
54+
}
55+
56+
func testCommasPresentEnabled() {
57+
let input =
58+
"""
59+
let MyList = [
60+
1,
61+
2,
62+
3,
63+
]
64+
65+
"""
66+
67+
let expected =
68+
"""
69+
let MyList = [
70+
1,
71+
2,
72+
3,
73+
]
74+
75+
"""
76+
77+
var configuration = Configuration.forTesting
78+
configuration.multilineCollectionTrailingCommas = true
79+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20, configuration: configuration)
80+
}
81+
82+
func testCommasPresentDisabled() {
83+
let input =
84+
"""
85+
let MyList = [
86+
1,
87+
2,
88+
3,
89+
]
90+
91+
"""
92+
93+
let expected =
94+
"""
95+
let MyList = [
96+
1,
97+
2,
98+
3
99+
]
100+
101+
"""
102+
103+
var configuration = Configuration.forTesting
104+
configuration.multilineCollectionTrailingCommas = false
105+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 20, configuration: configuration)
106+
}
107+
108+
func testCommasPresentSingleLineDisabled() {
109+
let input =
110+
"""
111+
let MyList = [1, 2, 3,]
112+
113+
"""
114+
115+
// no effect expected
116+
let expected =
117+
"""
118+
let MyList = [1, 2, 3]
119+
120+
"""
121+
122+
var configuration = Configuration.forTesting
123+
configuration.multilineCollectionTrailingCommas = true
124+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40, configuration: configuration)
125+
}
126+
127+
func testCommasPresentSingleLineEnabled() {
128+
let input =
129+
"""
130+
let MyList = [1, 2, 3,]
131+
132+
"""
133+
134+
// no effect expected
135+
let expected =
136+
"""
137+
let MyList = [1, 2, 3]
138+
139+
"""
140+
141+
var configuration = Configuration.forTesting
142+
configuration.multilineCollectionTrailingCommas = false
143+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40, configuration: configuration)
144+
}
145+
}

0 commit comments

Comments
 (0)