From a65ea804ca7f1debef94d852ec2e609e7ca60d60 Mon Sep 17 00:00:00 2001 From: Cameron Pulsford Date: Wed, 11 Jun 2025 10:37:06 -0400 Subject: [PATCH] Add `--trailingcommas collections-only` option to opt out of Swift 6.1 trailing comma support (#2081) Co-authored-by: Cal Stephens --- PerformanceTests/PerformanceTests.swift | 2 +- Rules.md | 2 +- Sources/Inference.swift | 2 +- Sources/OptionDescriptor.swift | 22 ++- Sources/Options.swift | 10 +- Sources/Rules/TrailingCommas.swift | 47 ++++++- Tests/InferenceTests.swift | 4 +- Tests/Rules/TrailingCommasTests.swift | 175 ++++++++++++++++-------- Tests/Rules/WrapArgumentsTests.swift | 16 +-- 9 files changed, 200 insertions(+), 80 deletions(-) diff --git a/PerformanceTests/PerformanceTests.swift b/PerformanceTests/PerformanceTests.swift index f1814a26..4772be2e 100644 --- a/PerformanceTests/PerformanceTests.swift +++ b/PerformanceTests/PerformanceTests.swift @@ -77,7 +77,7 @@ class PerformanceTests: XCTestCase { spaceAroundOperatorDeclarations: .remove, useVoid: false, indentCase: true, - trailingCommas: false, + trailingCommas: .never, indentComments: false, truncateBlankLines: false, allmanBraces: true, diff --git a/Rules.md b/Rules.md index 5ac3eb95..18ac2bd3 100644 --- a/Rules.md +++ b/Rules.md @@ -3233,7 +3233,7 @@ Add or remove trailing commas in comma-separated lists. Option | Description --- | --- -`--commas` | Commas in collection literals: "always" (default) or "inline" +`--trailingcommas` | Trailing commas: "always" (default), "never", or "collections-only"
Examples diff --git a/Sources/Inference.swift b/Sources/Inference.swift index 279a6552..e4d55ef2 100644 --- a/Sources/Inference.swift +++ b/Sources/Inference.swift @@ -235,7 +235,7 @@ private struct Inference { noTrailing += 1 } } - options.trailingCommas = (trailing >= noTrailing) + options.trailingCommas = (trailing >= noTrailing) ? .always : .never } let truncateBlankLines = OptionInferrer { formatter, options in diff --git a/Sources/OptionDescriptor.swift b/Sources/OptionDescriptor.swift index 9747442f..b7b48ef7 100644 --- a/Sources/OptionDescriptor.swift +++ b/Sources/OptionDescriptor.swift @@ -516,12 +516,10 @@ struct _Descriptors { falseValues: ["false"] ) let trailingCommas = OptionDescriptor( - argumentName: "commas", - displayName: "Commas", - help: "Commas in collection literals: \"always\" (default) or \"inline\"", - keyPath: \.trailingCommas, - trueValues: ["always", "true"], - falseValues: ["inline", "false"] + argumentName: "trailingcommas", + displayName: "Trailing commas", + help: "Trailing commas: \"always\" (default), \"never\", or \"collections-only\"", + keyPath: \.trailingCommas ) let truncateBlankLines = OptionDescriptor( argumentName: "trimwhitespace", @@ -1361,6 +1359,18 @@ struct _Descriptors { deprecationMessage: "Use with `--storedvarattributes` or `--computedvarattributes` instead.", keyPath: \.varAttributes ) + let commas = OptionDescriptor( + argumentName: "commas", + displayName: "Trailing commas", + help: "deprecated", + deprecationMessage: "Use '--trailingcommas' instead", + keyPath: \.trailingCommas, + altOptions: [ + "inline": .never, + "false": .never, + "true": .always, + ] + ) // MARK: - RENAMED diff --git a/Sources/Options.swift b/Sources/Options.swift index 13f4cf74..07d80c25 100644 --- a/Sources/Options.swift +++ b/Sources/Options.swift @@ -178,6 +178,12 @@ public enum ClosureVoidReturn: String, CaseIterable { case preserve } +public enum TrailingCommas: String, CaseIterable { + case never + case always + case collectionsOnly = "collections-only" +} + /// Whether to insert, remove, or preserve spaces around operators public enum OperatorSpacingMode: String, CaseIterable { case insert = "spaced" @@ -651,7 +657,7 @@ public struct FormatOptions: CustomStringConvertible { public var spaceAroundOperatorDeclarations: OperatorSpacingMode public var useVoid: Bool public var indentCase: Bool - public var trailingCommas: Bool + public var trailingCommas: TrailingCommas public var truncateBlankLines: Bool public var insertBlankLines: Bool public var removeBlankLines: Bool @@ -782,7 +788,7 @@ public struct FormatOptions: CustomStringConvertible { spaceAroundOperatorDeclarations: OperatorSpacingMode = .insert, useVoid: Bool = true, indentCase: Bool = false, - trailingCommas: Bool = true, + trailingCommas: TrailingCommas = .always, indentComments: Bool = true, truncateBlankLines: Bool = true, insertBlankLines: Bool = true, diff --git a/Sources/Rules/TrailingCommas.swift b/Sources/Rules/TrailingCommas.swift index 7470786e..90967dc1 100644 --- a/Sources/Rules/TrailingCommas.swift +++ b/Sources/Rules/TrailingCommas.swift @@ -11,7 +11,7 @@ import Foundation public extension FormatRule { static let trailingCommas = FormatRule( help: "Add or remove trailing commas in comma-separated lists.", - options: ["commas"] + options: ["trailingcommas"] ) { formatter in formatter.forEachToken { i, token in switch token { @@ -20,7 +20,18 @@ public extension FormatRule { case .array, .dictionary: formatter.addOrRemoveTrailingComma(before: i, trailingCommaSupported: true) case .subscript, .captureList: - formatter.addOrRemoveTrailingComma(before: i, trailingCommaSupported: formatter.options.swiftVersion >= "6.1") + var trailingCommaSupported = false + + if formatter.options.swiftVersion >= "6.1" { + switch formatter.options.trailingCommas { + case .always: + trailingCommaSupported = true + case .never, .collectionsOnly: + break + } + } + + formatter.addOrRemoveTrailingComma(before: i, trailingCommaSupported: trailingCommaSupported) default: return } @@ -84,6 +95,13 @@ public extension FormatRule { } } + switch formatter.options.trailingCommas { + case .always: + break + case .never, .collectionsOnly: + trailingCommaSupported = false + } + formatter.addOrRemoveTrailingComma(before: i, trailingCommaSupported: trailingCommaSupported) case .endOfScope(">"): @@ -104,6 +122,13 @@ public extension FormatRule { trailingCommaSupported = true } + switch formatter.options.trailingCommas { + case .always: + break + case .never, .collectionsOnly: + trailingCommaSupported = false + } + formatter.addOrRemoveTrailingComma(before: i, trailingCommaSupported: trailingCommaSupported) default: @@ -154,7 +179,8 @@ public extension FormatRule { extension Formatter { /// Adds or removes a trailing comma before the given index that marks the end of a comma-separated list. /// Trailing commas can always be removed. `trailingCommaSupported` indicates whether or not a trailing - /// comma is allowed at this position. + /// comma is allowed at this position. A comma being supported is a combination of language support + /// and enabled options. func addOrRemoveTrailingComma(before endOfListIndex: Int, trailingCommaSupported: Bool) { guard let prevTokenIndex = index(of: .nonSpaceOrComment, before: endOfListIndex) else { return } @@ -169,11 +195,11 @@ extension Formatter { case .startOfScope("["), .delimiter(":"), .startOfScope("("): break // do nothing case .delimiter(","): - if !options.trailingCommas { + if !options.trailingCommas.enabled || !trailingCommaSupported { removeToken(at: prevTokenIndex) } default: - if options.trailingCommas, trailingCommaSupported { + if options.trailingCommas.enabled, trailingCommaSupported { insert(.delimiter(","), at: prevTokenIndex + 1) } } @@ -184,3 +210,14 @@ extension Formatter { } } } + +extension TrailingCommas { + var enabled: Bool { + switch self { + case .never: + return false + case .always, .collectionsOnly: + return true + } + } +} diff --git a/Tests/InferenceTests.swift b/Tests/InferenceTests.swift index fc6f7ca9..7fcd1047 100644 --- a/Tests/InferenceTests.swift +++ b/Tests/InferenceTests.swift @@ -149,13 +149,13 @@ class InferenceTests: XCTestCase { func testInferTrailingCommas() { let input = "let foo = [\nbar,\n]\n let baz = [\nquux\n]" let options = inferFormatOptions(from: tokenize(input)) - XCTAssertTrue(options.trailingCommas) + XCTAssertEqual(options.trailingCommas, .always) } func testInferNoTrailingCommas() { let input = "let foo = [\nbar\n]\n let baz = [\nquux\n]" let options = inferFormatOptions(from: tokenize(input)) - XCTAssertFalse(options.trailingCommas) + XCTAssertEqual(options.trailingCommas, .never) } // MARK: truncateBlankLines diff --git a/Tests/Rules/TrailingCommasTests.swift b/Tests/Rules/TrailingCommasTests.swift index 82d41b0e..5ebf1267 100644 --- a/Tests/Rules/TrailingCommasTests.swift +++ b/Tests/Rules/TrailingCommasTests.swift @@ -22,6 +22,13 @@ class TrailingCommasTests: XCTestCase { testFormatting(for: input, output, rule: .trailingCommas) } + func testCommaAddedToLastItemCollectionsOnly() { + let input = "[\n foo,\n bar\n]" + let output = "[\n foo,\n bar,\n]" + let options = FormatOptions(trailingCommas: .collectionsOnly) + testFormatting(for: input, output, rule: .trailingCommas, options: options) + } + func testCommaAddedToDictionary() { let input = "[\n foo: bar\n]" let output = "[\n foo: bar,\n]" @@ -262,14 +269,14 @@ class TrailingCommasTests: XCTestCase { func testCommaNotAddedToLastItem() { let input = "[\n foo,\n bar\n]" - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, rule: .trailingCommas, options: options) } func testCommaRemovedFromLastItem() { let input = "[\n foo,\n bar,\n]" let output = "[\n foo,\n bar\n]" - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -294,7 +301,7 @@ class TrailingCommasTests: XCTestCase { } } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -304,7 +311,7 @@ class TrailingCommasTests: XCTestCase { bar _: Int ) {} """ - let options = FormatOptions(trailingCommas: true) + let options = FormatOptions(trailingCommas: .always) testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -319,7 +326,7 @@ class TrailingCommasTests: XCTestCase { bar _: Int ) {} """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -336,7 +343,7 @@ class TrailingCommasTests: XCTestCase { baaz _: Int) {} """ - let options = FormatOptions(trailingCommas: false, closingParenPosition: .sameLine) + let options = FormatOptions(trailingCommas: .never, closingParenPosition: .sameLine) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -353,7 +360,7 @@ class TrailingCommasTests: XCTestCase { baaz _: Int) {} """ - let options = FormatOptions(trailingCommas: true, closingParenPosition: .sameLine) + let options = FormatOptions(trailingCommas: .always, closingParenPosition: .sameLine) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -368,7 +375,7 @@ class TrailingCommasTests: XCTestCase { bar _: Int, ) {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -383,7 +390,7 @@ class TrailingCommasTests: XCTestCase { bar _: Int ) {} """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -402,7 +409,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -421,7 +428,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -436,7 +443,7 @@ class TrailingCommasTests: XCTestCase { 1, ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -451,7 +458,7 @@ class TrailingCommasTests: XCTestCase { 1 ) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -478,7 +485,7 @@ class TrailingCommasTests: XCTestCase { baz: 2, ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -513,7 +520,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.redundantReturn]) } @@ -537,7 +544,7 @@ class TrailingCommasTests: XCTestCase { ), ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.redundantReturn]) } @@ -552,7 +559,7 @@ class TrailingCommasTests: XCTestCase { 0, ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options, exclude: [.redundantParens]) } @@ -569,7 +576,7 @@ class TrailingCommasTests: XCTestCase { 1, ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -586,7 +593,7 @@ class TrailingCommasTests: XCTestCase { baz: 1 ) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -600,7 +607,7 @@ class TrailingCommasTests: XCTestCase { ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -619,7 +626,7 @@ class TrailingCommasTests: XCTestCase { )]]() """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options, exclude: [.propertyTypes]) } @@ -638,7 +645,7 @@ class TrailingCommasTests: XCTestCase { )>() """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options, exclude: [.typeSugar, .propertyTypes]) } @@ -654,7 +661,7 @@ class TrailingCommasTests: XCTestCase { ) {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -700,7 +707,7 @@ class TrailingCommasTests: XCTestCase { ) -> Void) {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -715,7 +722,7 @@ class TrailingCommasTests: XCTestCase { )?) {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -743,7 +750,7 @@ class TrailingCommasTests: XCTestCase { )? """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -770,7 +777,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -797,7 +804,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -824,7 +831,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -851,7 +858,7 @@ class TrailingCommasTests: XCTestCase { ) } """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -888,7 +895,7 @@ class TrailingCommasTests: XCTestCase { default: break } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -899,7 +906,7 @@ class TrailingCommasTests: XCTestCase { baz: Int ) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -922,7 +929,7 @@ class TrailingCommasTests: XCTestCase { ): break } """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -939,7 +946,7 @@ class TrailingCommasTests: XCTestCase { bar ) = (0, 1) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -949,7 +956,7 @@ class TrailingCommasTests: XCTestCase { ) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, rule: .trailingCommas, options: options, exclude: [ .blankLinesAtEndOfScope, @@ -974,7 +981,7 @@ class TrailingCommasTests: XCTestCase { ) \""" """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -993,7 +1000,7 @@ class TrailingCommasTests: XCTestCase { ) struct Qux {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1038,7 +1045,7 @@ class TrailingCommasTests: XCTestCase { extension CoreFoundation.CGFloat: Swift.SignedNumeric {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -1057,7 +1064,7 @@ class TrailingCommasTests: XCTestCase { ) struct Qux {} """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1074,7 +1081,7 @@ class TrailingCommasTests: XCTestCase { "baz", ) """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1091,7 +1098,7 @@ class TrailingCommasTests: XCTestCase { "baz" ) """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1130,7 +1137,7 @@ class TrailingCommasTests: XCTestCase { T2, >() -> (T1, T2) {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1170,7 +1177,7 @@ class TrailingCommasTests: XCTestCase { > {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, rule: .trailingCommas, options: options, exclude: [.emptyExtensions, .typeSugar]) } @@ -1189,7 +1196,7 @@ class TrailingCommasTests: XCTestCase { T3 > {} """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1200,7 +1207,7 @@ class TrailingCommasTests: XCTestCase { let output = """ struct S {} """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1219,7 +1226,7 @@ class TrailingCommasTests: XCTestCase { ] in } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1238,7 +1245,7 @@ class TrailingCommasTests: XCTestCase { ] in } """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1253,7 +1260,7 @@ class TrailingCommasTests: XCTestCase { print(capturedValue1, capturedValue2) } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1270,7 +1277,24 @@ class TrailingCommasTests: XCTestCase { y, ] """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") + testFormatting(for: input, output, rule: .trailingCommas, options: options) + } + + func testTrailingCommasRemoveFromSubscriptWhenCollectionsOnly() { + let input = """ + let value = m[ + x, + y, + ] + """ + let output = """ + let value = m[ + x, + y + ] + """ + let options = FormatOptions(trailingCommas: .collectionsOnly, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1287,7 +1311,7 @@ class TrailingCommasTests: XCTestCase { y ] """ - let options = FormatOptions(trailingCommas: false) + let options = FormatOptions(trailingCommas: .never) testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1298,7 +1322,7 @@ class TrailingCommasTests: XCTestCase { let output = """ let value = m[x, y] """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } @@ -1325,10 +1349,22 @@ class TrailingCommasTests: XCTestCase { } """ - let options = FormatOptions(trailingCommas: true, swiftVersion: "6.1") + let options = FormatOptions(trailingCommas: .always, swiftVersion: "6.1") testFormatting(for: input, output, rule: .trailingCommas, options: options) } + func testSingleLineArrayWithMultipleElements() { + let input = """ + for file in files where + file != "build" && !file.hasPrefix(".") && ![ + ".build", ".app", ".framework", ".xcodeproj", ".xcassets", + ].contains(where: { file.hasSuffix($0) }) {} + """ + + let options = FormatOptions(trailingCommas: .always) + testFormatting(for: input, rule: .trailingCommas, options: options) + } + func testSingleLineArrayWithMultipleElementsFollowingNotOperator() { let input = """ for file in files where @@ -1337,7 +1373,7 @@ class TrailingCommasTests: XCTestCase { ].contains(where: { file.hasSuffix($0) }) {} """ - let options = FormatOptions(trailingCommas: true) + let options = FormatOptions(trailingCommas: .always) testFormatting(for: input, rule: .trailingCommas, options: options) } @@ -1352,7 +1388,38 @@ class TrailingCommasTests: XCTestCase { ].throwingOperation() """ - let options = FormatOptions(trailingCommas: true) + let options = FormatOptions(trailingCommas: .always) testFormatting(for: input, rule: .trailingCommas, options: options) } + + func testCollectionsOnlyAddsCollectionCommasAndRemovesNonCollectionCommas() { + let input = """ + let array = [ + 1, + 2 + ] + + func foo( + a: Int, + b: Int, + ) { + print(a, b) + } + """ + let output = """ + let array = [ + 1, + 2, + ] + + func foo( + a: Int, + b: Int + ) { + print(a, b) + } + """ + let options = FormatOptions(trailingCommas: .collectionsOnly, swiftVersion: "6.1") + testFormatting(for: input, output, rule: .trailingCommas, options: options) + } } diff --git a/Tests/Rules/WrapArgumentsTests.swift b/Tests/Rules/WrapArgumentsTests.swift index 77700203..98bf02b9 100644 --- a/Tests/Rules/WrapArgumentsTests.swift +++ b/Tests/Rules/WrapArgumentsTests.swift @@ -1209,7 +1209,7 @@ class WrapArgumentsTests: XCTestCase { func testNoDoubleSpaceAddedToWrappedArray() { let input = "[ foo,\n bar ]" let output = "[\n foo,\n bar\n]" - let options = FormatOptions(trailingCommas: false, wrapCollections: .beforeFirst) + let options = FormatOptions(trailingCommas: .never, wrapCollections: .beforeFirst) testFormatting(for: input, [output], rules: [.wrapArguments, .spaceInsideBrackets], options: options) } @@ -1217,7 +1217,7 @@ class WrapArgumentsTests: XCTestCase { func testTrailingCommasAddedToWrappedArray() { let input = "[foo,\n bar]" let output = "[\n foo,\n bar,\n]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .beforeFirst) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .beforeFirst) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1225,7 +1225,7 @@ class WrapArgumentsTests: XCTestCase { func testTrailingCommasAddedToWrappedNestedDictionary() { let input = "[foo: [bar: baz,\n bar2: baz2]]" let output = "[foo: [\n bar: baz,\n bar2: baz2,\n]]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .beforeFirst) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .beforeFirst) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1233,7 +1233,7 @@ class WrapArgumentsTests: XCTestCase { func testTrailingCommasAddedToSingleLineNestedDictionary() { let input = "[\n foo: [bar: baz, bar2: baz2]]" let output = "[\n foo: [bar: baz, bar2: baz2],\n]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .beforeFirst) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .beforeFirst) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1241,7 +1241,7 @@ class WrapArgumentsTests: XCTestCase { func testTrailingCommasAddedToWrappedNestedDictionaries() { let input = "[foo: [bar: baz,\n bar2: baz2],\n foo2: [bar: baz,\n bar2: baz2]]" let output = "[\n foo: [\n bar: baz,\n bar2: baz2,\n ],\n foo2: [\n bar: baz,\n bar2: baz2,\n ],\n]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .beforeFirst) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .beforeFirst) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1311,7 +1311,7 @@ class WrapArgumentsTests: XCTestCase { func testNoBeforeFirstPreservedAndTrailingCommaIgnoredInMultilineNestedDictionary() { let input = "[foo: [bar: baz,\n bar2: baz2]]" let output = "[foo: [bar: baz,\n bar2: baz2]]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .preserve) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .preserve) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1319,7 +1319,7 @@ class WrapArgumentsTests: XCTestCase { func testBeforeFirstPreservedAndTrailingCommaAddedInSingleLineNestedDictionary() { let input = "[\n foo: [bar: baz, bar2: baz2]]" let output = "[\n foo: [bar: baz, bar2: baz2],\n]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .preserve) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .preserve) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) } @@ -1327,7 +1327,7 @@ class WrapArgumentsTests: XCTestCase { func testBeforeFirstPreservedAndTrailingCommaAddedInSingleLineNestedDictionaryWithOneNestedItem() { let input = "[\n foo: [bar: baz]]" let output = "[\n foo: [bar: baz],\n]" - let options = FormatOptions(trailingCommas: true, wrapCollections: .preserve) + let options = FormatOptions(trailingCommas: .always, wrapCollections: .preserve) testFormatting(for: input, [output], rules: [.wrapArguments, .trailingCommas], options: options) }