Skip to content

Commit a70ac62

Browse files
committed
Merge branch 'main' into bound-case-formatter
2 parents 2d3799b + 8cb0e35 commit a70ac62

27 files changed

+489
-207
lines changed

.pre-commit-hooks.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@
44
language: swift
55
types: [swift]
66
require_serial: true
7+
- id: swift-format-lint
8+
name: swift-format-lint
9+
entry: swift-format lint --strict --recursive --parallel
10+
language: swift
11+
types: [swift]
12+
require_serial: true

Documentation/Configuration.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ top-level keys and values:
113113
### `prioritizeKeepingFunctionOutputTogether`
114114
**type:** boolean
115115

116-
**description:** Determines if function-like declaration outputs should be prioritized to be together with thefunction signature right (closing) parenthesis. If `false`, function output (i.e. throws, return type) is not prioritized to be together with the signature's right parenthesis, and when the line length would be exceeded,a line break will be fired after the function signature first, indenting the declaration output one additional level. If true, A line break will be fired further up in the function's declaration (e.g. generic parameters, parameters) before breaking on the function's output.
116+
**description:** Determines if function-like declaration outputs should be prioritized to be together with the function signature's right (closing) parenthesis. If `false`, function output (i.e. throws, return type) is not prioritized to be together with the signature's right parenthesis, and when the line length would be exceeded, a line break will be fired after the function signature first, indenting the declaration output one additional level. If true, a line break will be fired further up in the function's declaration (e.g. generic parameters, parameters) before breaking on the function's output.
117117

118118
**default:** `false`
119119

@@ -186,7 +186,7 @@ switch someValue {
186186
### `noAssignmentInExpressions`
187187
**type:** object
188188

189-
**description:** Assignment expressions must be their own statements. Assignment should not be used in an expression context that expects a `Void` value. For example, assigning a variable within a `return` statement existing a `Void` function is prohibited.
189+
**description:** Assignment expressions must be their own statements. Assignment should not be used in an expression context that expects a `Void` value. For example, assigning a variable within a `return` statement exiting a `Void` function is prohibited.
190190

191191
- `allowedFunctions` _(strings array)_: A list of function names where assignments are allowed to be embedded in expressions that are passed as parameters to that function.
192192

@@ -221,7 +221,7 @@ a hard line break
221221
will be formatted as:
222222
```swift
223223
"""
224-
an esacpe\
224+
an escape\
225225
line break
226226
a hard \
227227
line break

Documentation/RuleDocumentation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ Format: The access level is removed from the extension declaration and is added
243243
Assignment expressions must be their own statements.
244244

245245
Assignment should not be used in an expression context that expects a `Void` value. For example,
246-
assigning a variable within a `return` statement existing a `Void` function is prohibited.
246+
assigning a variable within a `return` statement exiting a `Void` function is prohibited.
247247

248248
Lint: If an assignment expression is found in a position other than a standalone statement, a
249249
lint finding is emitted.

README.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,19 @@ settings in the default configuration can be viewed by running
210210
`swift-format dump-configuration`, which will dump it to standard
211211
output.
212212

213-
If the `--configuration <file>` option is passed to `swift-format`, then that
214-
configuration will be used unconditionally and the file system will not be
215-
searched.
213+
If the `--configuration <configuration>` option is passed to `swift-format`,
214+
then that configuration will be used unconditionally and the file system will
215+
not be searched.
216216

217217
See [Documentation/Configuration.md](Documentation/Configuration.md) for a
218-
description of the configuration file format and the settings that are
219-
available.
218+
description of the configuration format and the settings that are available.
219+
220+
#### Viewing the Effective Configuration
221+
222+
The `dump-configuration` subcommand accepts a `--effective` flag. If set, it
223+
dumps the configuration that would be used if `swift-format` was executed from
224+
the current working directory, and accounts for `.swift-format` files or
225+
`--configuration` options as outlined above.
220226

221227
### Miscellaneous
222228

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
extension Configuration {
16+
/// Return the configuration as a JSON string.
17+
public func asJsonString() throws -> String {
18+
let data: Data
19+
20+
do {
21+
let encoder = JSONEncoder()
22+
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
23+
data = try encoder.encode(self)
24+
} catch {
25+
throw SwiftFormatError.configurationDumpFailed("\(error)")
26+
}
27+
28+
guard let jsonString = String(data: data, encoding: .utf8) else {
29+
// This should never happen, but let's make sure we fail more gracefully than crashing, just in case.
30+
throw SwiftFormatError.configurationDumpFailed("The JSON was not valid UTF-8")
31+
}
32+
33+
return jsonString
34+
}
35+
}

Sources/SwiftFormat/API/Configuration.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,12 @@ public struct Configuration: Codable, Equatable {
122122
public var lineBreakBetweenDeclarationAttributes: Bool
123123

124124
/// Determines if function-like declaration outputs should be prioritized to be together with the
125-
/// function signature right (closing) parenthesis.
125+
/// function signature's right (closing) parenthesis.
126126
///
127127
/// If false (the default), function output (i.e. throws, return type) is not prioritized to be
128128
/// together with the signature's right parenthesis, and when the line length would be exceeded,
129129
/// a line break will be fired after the function signature first, indenting the declaration output
130-
/// one additional level. If true, A line break will be fired further up in the function's
130+
/// one additional level. If true, a line break will be fired further up in the function's
131131
/// declaration (e.g. generic parameters, parameters) before breaking on the function's output.
132132
public var prioritizeKeepingFunctionOutputTogether: Bool
133133

@@ -211,7 +211,7 @@ public struct Configuration: Codable, Equatable {
211211
/// will be formatted as:
212212
/// ```swift
213213
/// """
214-
/// an esacpe\
214+
/// an escape\
215215
/// line break
216216
/// a hard \
217217
/// line break
@@ -285,11 +285,9 @@ public struct Configuration: Codable, Equatable {
285285
// If the version number is not present, assume it is 1.
286286
self.version = try container.decodeIfPresent(Int.self, forKey: .version) ?? 1
287287
guard version <= highestSupportedConfigurationVersion else {
288-
throw DecodingError.dataCorruptedError(
289-
forKey: .version,
290-
in: container,
291-
debugDescription:
292-
"This version of the formatter does not support configuration version \(version)."
288+
throw SwiftFormatError.unsupportedConfigurationVersion(
289+
version,
290+
highestSupported: highestSupportedConfigurationVersion
293291
)
294292
}
295293

Sources/SwiftFormat/API/SwiftFormatError.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public enum SwiftFormatError: LocalizedError {
2828
/// The requested experimental feature name was not recognized by the parser.
2929
case unrecognizedExperimentalFeature(String)
3030

31+
/// An error happened while dumping the tool's configuration.
32+
case configurationDumpFailed(String)
33+
34+
/// The provided configuration version is not supported by this version of the formatter.
35+
case unsupportedConfigurationVersion(Int, highestSupported: Int)
36+
3137
public var errorDescription: String? {
3238
switch self {
3339
case .fileNotReadable:
@@ -38,6 +44,11 @@ public enum SwiftFormatError: LocalizedError {
3844
return "file contains invalid Swift syntax"
3945
case .unrecognizedExperimentalFeature(let name):
4046
return "experimental feature '\(name)' was not recognized by the Swift parser"
47+
case .configurationDumpFailed(let message):
48+
return "dumping configuration failed: \(message)"
49+
case .unsupportedConfigurationVersion(let version, let highestSupported):
50+
return
51+
"This version of the formatter does not support configuration version \(version). The highest supported version is \(highestSupported)."
4152
}
4253
}
4354
}

Sources/SwiftFormat/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#[[
22
This source file is part of the swift-format open source project
33
4-
Copyright (c) 2024 Apple Inc. and the swift-format project authors
4+
Copyright (c) 2024 - 2025 Apple Inc. and the swift-format project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66
77
See https://swift.org/LICENSE.txt for license information
88
#]]
99

1010
add_library(SwiftFormat
1111
API/Configuration+Default.swift
12+
API/Configuration+Dump.swift
1213
API/Configuration.swift
1314
API/DebugOptions.swift
1415
API/Finding.swift

Sources/SwiftFormat/PrettyPrint/PrettyPrint.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ public class PrettyPrinter {
819819
context.findingEmitter.emit(
820820
message,
821821
category: category,
822-
location: Finding.Location(file: context.fileURL.path, line: outputBuffer.lineNumber, column: column)
822+
location: Finding.Location(file: context.fileURL.relativePath, line: outputBuffer.lineNumber, column: column)
823823
)
824824
}
825825
}

Sources/SwiftFormat/Rules/BeginDocumentationCommentWithOneLineSummary.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Foundation
14+
import Markdown
1415
import SwiftSyntax
1516

1617
#if os(macOS)
@@ -91,14 +92,20 @@ public final class BeginDocumentationCommentWithOneLineSummary: SyntaxLintRule {
9192

9293
/// Diagnose documentation comments that don't start with one sentence summary.
9394
private func diagnoseDocComments(in decl: DeclSyntax) {
95+
// Extract the summary from a documentation comment, if it exists, and strip
96+
// out any inline code segments (which shouldn't be considered when looking
97+
// for the end of a sentence).
98+
var inlineCodeRemover = InlineCodeRemover()
9499
guard
95100
let docComment = DocumentationComment(extractedFrom: decl),
96-
let briefSummary = docComment.briefSummary
101+
let briefSummary = docComment.briefSummary,
102+
let noInlineCodeSummary = inlineCodeRemover.visit(briefSummary) as? Paragraph
97103
else { return }
98104

99105
// For the purposes of checking the sentence structure of the comment, we can operate on the
100106
// plain text; we don't need any of the styling.
101-
let trimmedText = briefSummary.plainText.trimmingCharacters(in: .whitespacesAndNewlines)
107+
let trimmedText = noInlineCodeSummary.plainText
108+
.trimmingCharacters(in: .whitespacesAndNewlines)
102109
let (commentSentences, trailingText) = sentences(in: trimmedText)
103110
if commentSentences.count == 0 {
104111
diagnose(.terminateSentenceWithPeriod(trimmedText), on: decl)
@@ -231,3 +238,9 @@ extension Finding.Message {
231238
"add a blank comment line after this sentence: \"\(text)\""
232239
}
233240
}
241+
242+
struct InlineCodeRemover: MarkupRewriter {
243+
mutating func visitInlineCode(_ inlineCode: InlineCode) -> Markup? {
244+
nil
245+
}
246+
}

0 commit comments

Comments
 (0)