2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
8
// See https://swift.org/LICENSE.txt for license information
@@ -14,7 +14,12 @@ import Foundation
14
14
15
15
/// A version number that can be specified in the configuration file, which allows us to change the
16
16
/// format in the future if desired and still support older files.
17
- fileprivate let highestSupportedConfigurationVersion = 1
17
+ ///
18
+ /// Note that *adding* new configuration values is not a version-breaking change; swift-format will
19
+ /// use default values when loading older configurations that don't contain the new settings. This
20
+ /// value only needs to be updated if the configuration changes in a way that would be incompatible
21
+ /// with the previous format.
22
+ internal let highestSupportedConfigurationVersion = 1
18
23
19
24
/// Holds the complete set of configured values and defaults.
20
25
public struct Configuration : Codable , Equatable {
@@ -39,30 +44,36 @@ public struct Configuration: Codable, Equatable {
39
44
case noAssignmentInExpressions
40
45
}
41
46
47
+ /// A dictionary containing the default enabled/disabled states of rules, keyed by the rules'
48
+ /// names.
49
+ ///
50
+ /// This value is generated by `generate-pipeline` based on the `isOptIn` value of each rule.
51
+ public static let defaultRuleEnablements : [ String : Bool ] = RuleRegistry . rules
52
+
42
53
/// The version of this configuration.
43
- private let version : Int
54
+ private var version : Int = highestSupportedConfigurationVersion
44
55
45
56
/// MARK: Common configuration
46
57
47
58
/// The dictionary containing the rule names that we wish to run on. A rule is not used if it is
48
59
/// marked as `false`, or if it is missing from the dictionary.
49
- public var rules : [ String : Bool ] = RuleRegistry . rules
60
+ public var rules : [ String : Bool ]
50
61
51
62
/// The maximum number of consecutive blank lines that may appear in a file.
52
- public var maximumBlankLines = 1
63
+ public var maximumBlankLines : Int
53
64
54
65
/// The maximum length of a line of source code, after which the formatter will break lines.
55
- public var lineLength = 100
66
+ public var lineLength : Int
56
67
57
68
/// The width of the horizontal tab in spaces.
58
69
///
59
70
/// This value is used when converting indentation types (for example, from tabs into spaces).
60
- public var tabWidth = 8
71
+ public var tabWidth : Int
61
72
62
73
/// A value representing a single level of indentation.
63
74
///
64
75
/// All indentation will be conducted in multiples of this configuration.
65
- public var indentation : Indent = . spaces ( 2 )
76
+ public var indentation : Indent
66
77
67
78
/// Indicates that the formatter should try to respect users' discretionary line breaks when
68
79
/// possible.
@@ -71,7 +82,7 @@ public struct Configuration: Codable, Equatable {
71
82
/// line, but for readability the user might break it inside the curly braces. If this setting is
72
83
/// true, those line breaks will be kept. If this setting is false, the formatter will act more
73
84
/// "opinionated" and collapse the statement onto a single line.
74
- public var respectsExistingLineBreaks = true
85
+ public var respectsExistingLineBreaks : Bool
75
86
76
87
/// MARK: Rule-specific configuration
77
88
@@ -81,23 +92,23 @@ public struct Configuration: Codable, Equatable {
81
92
/// If true, a line break will be added before the keyword, forcing it onto its own line. If
82
93
/// false (the default), the keyword will be placed after the closing brace (separated by a
83
94
/// space).
84
- public var lineBreakBeforeControlFlowKeywords = false
95
+ public var lineBreakBeforeControlFlowKeywords : Bool
85
96
86
97
/// Determines the line-breaking behavior for generic arguments and function arguments when a
87
98
/// declaration is wrapped onto multiple lines.
88
99
///
89
100
/// If false (the default), arguments will be laid out horizontally first, with line breaks only
90
101
/// being fired when the line length would be exceeded. If true, a line break will be added before
91
102
/// each argument, forcing the entire argument list to be laid out vertically.
92
- public var lineBreakBeforeEachArgument = false
103
+ public var lineBreakBeforeEachArgument : Bool
93
104
94
105
/// Determines the line-breaking behavior for generic requirements when the requirements list
95
106
/// is wrapped onto multiple lines.
96
107
///
97
108
/// If true, a line break will be added before each requirement, forcing the entire requirements
98
109
/// list to be laid out vertically. If false (the default), requirements will be laid out
99
110
/// horizontally first, with line breaks only being fired when the line length would be exceeded.
100
- public var lineBreakBeforeEachGenericRequirement = false
111
+ public var lineBreakBeforeEachGenericRequirement : Bool
101
112
102
113
/// Determines if function-like declaration outputs should be prioritized to be together with the
103
114
/// function signature right (closing) parenthesis.
@@ -107,21 +118,21 @@ public struct Configuration: Codable, Equatable {
107
118
/// a line break will be fired after the function signature first, indenting the declaration output
108
119
/// one additional level. If true, A line break will be fired further up in the function's
109
120
/// declaration (e.g. generic parameters, parameters) before breaking on the function's output.
110
- public var prioritizeKeepingFunctionOutputTogether = false
121
+ public var prioritizeKeepingFunctionOutputTogether : Bool
111
122
112
123
/// Determines the indentation behavior for `#if`, `#elseif`, and `#else`.
113
- public var indentConditionalCompilationBlocks = true
124
+ public var indentConditionalCompilationBlocks : Bool
114
125
115
126
/// Determines whether line breaks should be forced before and after multiline components of
116
127
/// dot-chained expressions, such as function calls and subscripts chained together through member
117
128
/// access (i.e. "." expressions). When any component is multiline and this option is true, a line
118
129
/// break is forced before the "." of the component and after the component's closing delimiter
119
130
/// (i.e. right paren, right bracket, right brace, etc.).
120
- public var lineBreakAroundMultilineExpressionChainComponents = false
131
+ public var lineBreakAroundMultilineExpressionChainComponents : Bool
121
132
122
133
/// Determines the formal access level (i.e., the level specified in source code) for file-scoped
123
134
/// declarations whose effective access level is private to the containing file.
124
- public var fileScopedDeclarationPrivacy = FileScopedDeclarationPrivacyConfiguration ( )
135
+ public var fileScopedDeclarationPrivacy : FileScopedDeclarationPrivacyConfiguration
125
136
126
137
/// Determines if `case` statements should be indented compared to the containing `switch` block.
127
138
///
@@ -142,19 +153,14 @@ public struct Configuration: Codable, Equatable {
142
153
/// ...
143
154
/// }
144
155
///```
145
- public var indentSwitchCaseLabels = false
156
+ public var indentSwitchCaseLabels : Bool
146
157
147
158
/// Determines whether whitespace should be forced before and after the range formation operators
148
159
/// `...` and `..<`.
149
- public var spacesAroundRangeFormationOperators = false
160
+ public var spacesAroundRangeFormationOperators : Bool
150
161
151
162
/// Contains exceptions for the `NoAssignmentInExpressions` rule.
152
- public var noAssignmentInExpressions = NoAssignmentInExpressionsConfiguration ( )
153
-
154
- /// Constructs a Configuration with all default values.
155
- public init ( ) {
156
- self . version = highestSupportedConfigurationVersion
157
- }
163
+ public var noAssignmentInExpressions : NoAssignmentInExpressionsConfiguration
158
164
159
165
/// Constructs a Configuration by loading it from a configuration file.
160
166
public init ( contentsOf url: URL ) throws {
@@ -165,11 +171,6 @@ public struct Configuration: Codable, Equatable {
165
171
public init ( from decoder: Decoder ) throws {
166
172
let container = try decoder. container ( keyedBy: CodingKeys . self)
167
173
168
- // Unfortunately, to allow the user to leave out configuration options in the JSON, we would
169
- // have to make them optional properties, but that makes using the type in the rest of the code
170
- // more annoying because we'd have to unwrap everything. So, we override this initializer and
171
- // provide the defaults ourselves if needed.
172
-
173
174
// If the version number is not present, assume it is 1.
174
175
self . version = try container. decodeIfPresent ( Int . self, forKey: . version) ?? 1
175
176
guard version <= highestSupportedConfigurationVersion else {
@@ -182,47 +183,70 @@ public struct Configuration: Codable, Equatable {
182
183
// If we ever introduce a new version, this is where we should switch on the decoded version
183
184
// number and dispatch to different decoding methods.
184
185
185
- self . maximumBlankLines
186
- = try container. decodeIfPresent ( Int . self, forKey: . maximumBlankLines) ?? 1
187
- self . lineLength = try container. decodeIfPresent ( Int . self, forKey: . lineLength) ?? 100
188
- self . tabWidth = try container. decodeIfPresent ( Int . self, forKey: . tabWidth) ?? 8
189
- self . indentation
190
- = try container. decodeIfPresent ( Indent . self, forKey: . indentation) ?? . spaces( 2 )
191
- self . respectsExistingLineBreaks
192
- = try container. decodeIfPresent ( Bool . self, forKey: . respectsExistingLineBreaks) ?? true
193
- self . lineBreakBeforeControlFlowKeywords
194
- = try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeControlFlowKeywords) ?? false
195
- self . lineBreakBeforeEachArgument
196
- = try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeEachArgument) ?? false
197
- self . lineBreakBeforeEachGenericRequirement
198
- = try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeEachGenericRequirement) ?? false
199
- self . prioritizeKeepingFunctionOutputTogether
200
- = try container. decodeIfPresent ( Bool . self, forKey: . prioritizeKeepingFunctionOutputTogether) ?? false
201
- self . indentConditionalCompilationBlocks
202
- = try container. decodeIfPresent ( Bool . self, forKey: . indentConditionalCompilationBlocks) ?? true
186
+ // Unfortunately, to allow the user to leave out configuration options in the JSON, we would
187
+ // have to make them optional properties, but that makes using the type in the rest of the code
188
+ // more annoying because we'd have to unwrap everything. So, we override this initializer and
189
+ // provide the defaults ourselves if needed. We get those defaults by pulling them from a
190
+ // default-initialized instance.
191
+ let defaults = Configuration ( )
192
+
193
+ self . maximumBlankLines =
194
+ try container. decodeIfPresent ( Int . self, forKey: . maximumBlankLines)
195
+ ?? defaults. maximumBlankLines
196
+ self . lineLength =
197
+ try container. decodeIfPresent ( Int . self, forKey: . lineLength)
198
+ ?? defaults. lineLength
199
+ self . tabWidth =
200
+ try container. decodeIfPresent ( Int . self, forKey: . tabWidth)
201
+ ?? defaults. tabWidth
202
+ self . indentation =
203
+ try container. decodeIfPresent ( Indent . self, forKey: . indentation)
204
+ ?? defaults. indentation
205
+ self . respectsExistingLineBreaks =
206
+ try container. decodeIfPresent ( Bool . self, forKey: . respectsExistingLineBreaks)
207
+ ?? defaults. respectsExistingLineBreaks
208
+ self . lineBreakBeforeControlFlowKeywords =
209
+ try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeControlFlowKeywords)
210
+ ?? defaults. lineBreakBeforeControlFlowKeywords
211
+ self . lineBreakBeforeEachArgument =
212
+ try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeEachArgument)
213
+ ?? defaults. lineBreakBeforeEachArgument
214
+ self . lineBreakBeforeEachGenericRequirement =
215
+ try container. decodeIfPresent ( Bool . self, forKey: . lineBreakBeforeEachGenericRequirement)
216
+ ?? defaults. lineBreakBeforeEachGenericRequirement
217
+ self . prioritizeKeepingFunctionOutputTogether =
218
+ try container. decodeIfPresent ( Bool . self, forKey: . prioritizeKeepingFunctionOutputTogether)
219
+ ?? defaults. prioritizeKeepingFunctionOutputTogether
220
+ self . indentConditionalCompilationBlocks =
221
+ try container. decodeIfPresent ( Bool . self, forKey: . indentConditionalCompilationBlocks)
222
+ ?? defaults. indentConditionalCompilationBlocks
203
223
self . lineBreakAroundMultilineExpressionChainComponents =
204
224
try container. decodeIfPresent (
205
- Bool . self, forKey: . lineBreakAroundMultilineExpressionChainComponents) ?? false
225
+ Bool . self, forKey: . lineBreakAroundMultilineExpressionChainComponents)
226
+ ?? defaults. lineBreakAroundMultilineExpressionChainComponents
206
227
self . spacesAroundRangeFormationOperators =
207
228
try container. decodeIfPresent (
208
- Bool . self, forKey: . spacesAroundRangeFormationOperators) ?? false
229
+ Bool . self, forKey: . spacesAroundRangeFormationOperators)
230
+ ?? defaults. spacesAroundRangeFormationOperators
209
231
self . fileScopedDeclarationPrivacy =
210
232
try container. decodeIfPresent (
211
233
FileScopedDeclarationPrivacyConfiguration . self, forKey: . fileScopedDeclarationPrivacy)
212
- ?? FileScopedDeclarationPrivacyConfiguration ( )
213
- self . indentSwitchCaseLabels
214
- = try container. decodeIfPresent ( Bool . self, forKey: . indentSwitchCaseLabels) ?? false
234
+ ?? defaults. fileScopedDeclarationPrivacy
235
+ self . indentSwitchCaseLabels =
236
+ try container. decodeIfPresent ( Bool . self, forKey: . indentSwitchCaseLabels)
237
+ ?? defaults. indentSwitchCaseLabels
215
238
self . noAssignmentInExpressions =
216
239
try container. decodeIfPresent (
217
240
NoAssignmentInExpressionsConfiguration . self, forKey: . noAssignmentInExpressions)
218
- ?? NoAssignmentInExpressionsConfiguration ( )
241
+ ?? defaults . noAssignmentInExpressions
219
242
220
243
// If the `rules` key is not present at all, default it to the built-in set
221
244
// so that the behavior is the same as if the configuration had been
222
245
// default-initialized. To get an empty rules dictionary, one can explicitly
223
246
// set the `rules` key to `{}`.
224
- self . rules
225
- = try container. decodeIfPresent ( [ String : Bool ] . self, forKey: . rules) ?? RuleRegistry . rules
247
+ self . rules =
248
+ try container. decodeIfPresent ( [ String : Bool ] . self, forKey: . rules)
249
+ ?? defaults. rules
226
250
}
227
251
228
252
public func encode( to encoder: Encoder ) throws {
@@ -295,6 +319,8 @@ public struct FileScopedDeclarationPrivacyConfiguration: Codable, Equatable {
295
319
/// The formal access level to use when encountering a file-scoped declaration with effective
296
320
/// private access.
297
321
public var accessLevel : AccessLevel = . private
322
+
323
+ public init ( ) { }
298
324
}
299
325
300
326
/// Configuration for the `NoAssignmentInExpressions` rule.
@@ -307,4 +333,6 @@ public struct NoAssignmentInExpressionsConfiguration: Codable, Equatable {
307
333
// in the test.
308
334
" XCTAssertNoThrow "
309
335
]
336
+
337
+ public init ( ) { }
310
338
}
0 commit comments