-
Notifications
You must be signed in to change notification settings - Fork 251
.swift-format: Specify an exhaustive configuration #1057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Unexpectedly, an omitted rule tells swift-format to ignore it altogether rather than assume the default setting. This change applies the default configuration, retaining current settings and disabling 3 default-enabled rules: `DoNotUseSemicolons`, `NoAccessLevelOnExtensionDeclaration`, and `DontRepeatTypeInStaticProperties`. The latter is disabled due to undesired effect: ``` warning: [DontRepeatTypeInStaticProperties] remove the suffix 'Paths' from the name of the variable 'envSearchPaths' ```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The configuration decoder explicitly uses decodeIfPresent
and falls back to the default values if the key wasn't in the JSON:
swift-format/Sources/SwiftFormat/API/Configuration.swift
Lines 317 to 432 in 2a1d811
// Unfortunately, to allow the user to leave out configuration options in the JSON, we would | |
// have to make them optional properties, but that makes using the type in the rest of the code | |
// more annoying because we'd have to unwrap everything. So, we override this initializer and | |
// provide the defaults ourselves if needed. We get those defaults by pulling them from a | |
// default-initialized instance. | |
let defaults = Configuration() | |
self.maximumBlankLines = | |
try container.decodeIfPresent(Int.self, forKey: .maximumBlankLines) | |
?? defaults.maximumBlankLines | |
self.lineLength = | |
try container.decodeIfPresent(Int.self, forKey: .lineLength) | |
?? defaults.lineLength | |
self.spacesBeforeEndOfLineComments = | |
try container.decodeIfPresent(Int.self, forKey: .spacesBeforeEndOfLineComments) | |
?? defaults.spacesBeforeEndOfLineComments | |
self.tabWidth = | |
try container.decodeIfPresent(Int.self, forKey: .tabWidth) | |
?? defaults.tabWidth | |
self.indentation = | |
try container.decodeIfPresent(Indent.self, forKey: .indentation) | |
?? defaults.indentation | |
self.respectsExistingLineBreaks = | |
try container.decodeIfPresent(Bool.self, forKey: .respectsExistingLineBreaks) | |
?? defaults.respectsExistingLineBreaks | |
self.lineBreakBeforeControlFlowKeywords = | |
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBeforeControlFlowKeywords) | |
?? defaults.lineBreakBeforeControlFlowKeywords | |
self.lineBreakBeforeEachArgument = | |
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBeforeEachArgument) | |
?? defaults.lineBreakBeforeEachArgument | |
self.lineBreakBeforeEachGenericRequirement = | |
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBeforeEachGenericRequirement) | |
?? defaults.lineBreakBeforeEachGenericRequirement | |
self.lineBreakBetweenDeclarationAttributes = | |
try container.decodeIfPresent(Bool.self, forKey: .lineBreakBetweenDeclarationAttributes) | |
?? defaults.lineBreakBetweenDeclarationAttributes | |
self.prioritizeKeepingFunctionOutputTogether = | |
try container.decodeIfPresent(Bool.self, forKey: .prioritizeKeepingFunctionOutputTogether) | |
?? defaults.prioritizeKeepingFunctionOutputTogether | |
self.indentConditionalCompilationBlocks = | |
try container.decodeIfPresent(Bool.self, forKey: .indentConditionalCompilationBlocks) | |
?? defaults.indentConditionalCompilationBlocks | |
self.lineBreakAroundMultilineExpressionChainComponents = | |
try container.decodeIfPresent( | |
Bool.self, | |
forKey: .lineBreakAroundMultilineExpressionChainComponents | |
) | |
?? defaults.lineBreakAroundMultilineExpressionChainComponents | |
self.spacesAroundRangeFormationOperators = | |
try container.decodeIfPresent( | |
Bool.self, | |
forKey: .spacesAroundRangeFormationOperators | |
) | |
?? defaults.spacesAroundRangeFormationOperators | |
self.fileScopedDeclarationPrivacy = | |
try container.decodeIfPresent( | |
FileScopedDeclarationPrivacyConfiguration.self, | |
forKey: .fileScopedDeclarationPrivacy | |
) | |
?? defaults.fileScopedDeclarationPrivacy | |
self.indentSwitchCaseLabels = | |
try container.decodeIfPresent(Bool.self, forKey: .indentSwitchCaseLabels) | |
?? defaults.indentSwitchCaseLabels | |
self.noAssignmentInExpressions = | |
try container.decodeIfPresent( | |
NoAssignmentInExpressionsConfiguration.self, | |
forKey: .noAssignmentInExpressions | |
) | |
?? defaults.noAssignmentInExpressions | |
self.multiElementCollectionTrailingCommas = | |
try container.decodeIfPresent( | |
Bool.self, | |
forKey: .multiElementCollectionTrailingCommas | |
) | |
?? defaults.multiElementCollectionTrailingCommas | |
self.reflowMultilineStringLiterals = try { | |
// Try to decode `reflowMultilineStringLiterals` as a string | |
// This handles configurations using the String raw value format (e.g. "never"). | |
// If an error occurs, we'll silently bypass it and fall back to the legacy behavior. | |
if let behavior = try? container.decodeIfPresent( | |
MultilineStringReflowBehavior.self, | |
forKey: .reflowMultilineStringLiterals | |
) { | |
return behavior | |
} | |
// If the modern format fails, try to decode as an object with a single key. | |
// This handles configurations from swift-format v601.0.0 (e.g. { "never": {} }). | |
// If an error occurs in this step, we'll propagate it to the caller. | |
if let legacyBehavior = try container.decodeIfPresent( | |
LegacyMultilineStringReflowBehavior.self, | |
forKey: .reflowMultilineStringLiterals | |
) { | |
return legacyBehavior.toMultilineStringReflowBehavior() | |
} | |
// If the key is not present in the configuration at all, use the default value. | |
return defaults.reflowMultilineStringLiterals | |
}() | |
self.indentBlankLines = | |
try container.decodeIfPresent( | |
Bool.self, | |
forKey: .indentBlankLines | |
) | |
?? defaults.indentBlankLines | |
// If the `rules` key is not present at all, default it to the built-in set | |
// so that the behavior is the same as if the configuration had been | |
// default-initialized. To get an empty rules dictionary, one can explicitly | |
// set the `rules` key to `{}`. | |
self.rules = | |
try container.decodeIfPresent([String: Bool].self, forKey: .rules) | |
?? defaults.rules |
...ah, but that still means that any rules
dictionary being present will be used as the entire thing, rather than assuming the default values for any rules not present. We should probably fix that.
In the meantime, no reason to block this PR on that fix.
Indeed. Though it's probably something we need to do under a new "style" given how breaking it could be 😓 |
Mirrors swiftlang/swift-syntax#3117.
Unexpectedly, an omitted rule tells swift-format to ignore it altogether rather than assume the default setting.
This change applies the default configuration, retaining current settings and disabling 3 default-enabled rules:
DoNotUseSemicolons
,NoAccessLevelOnExtensionDeclaration
, andDontRepeatTypeInStaticProperties
. The latter is disabled due to undesired effect: