Skip to content

Commit d80c57c

Browse files
committed
Allow to customize Rule severity
In order to customize the severity of rules, I added the possibility to do so via the configuration files. If no severity is specified, we use the one pre-determined by the Rule itself. Example: ``` { "rules": { "AlwaysUseLowerCamelCase": "warning", "AmbiguousTrailingClosureOverload": "error", "UseLetInEveryBoundCaseVariable": "true", // use rule default "UseWhereClausesInForLoops": "false", // disabled } } ``` In addition, one can now control how pretty-print violations should be treated in the same way Example: ``` { "rules": { "TrailingComma": "warning", "LineLength": "error", "Indentation": "true", // use rule default "TrailingWhitespace": "false", // disabled } } ``` Issue: #879
1 parent 923f1b9 commit d80c57c

27 files changed

+572
-154
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
.swiftpm/
33
swift-format.xcodeproj/
44
Package.resolved
5-
5+
.index-build

Documentation/RuleDocumentation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Use the rules below in the `rules` block of your `.swift-format`
66
configuration file, as described in
7-
[Configuration](Configuration.md). All of these rules can be
7+
[Configuration](Documentation/Configuration.md). All of these rules can be
88
applied in the linter, but only some of them can format your source code
99
automatically.
1010

Sources/SwiftFormat/API/Configuration+Default.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ extension Configuration {
2222
/// the JSON will be populated from this default configuration.
2323
public init() {
2424
self.rules = Self.defaultRuleEnablements
25-
self.ruleSeverity = [:]
2625
self.maximumBlankLines = 1
2726
self.lineLength = 100
2827
self.tabWidth = 8

Sources/SwiftFormat/API/Configuration.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public struct Configuration: Codable, Equatable {
2727
public enum RuleSeverity: String, Codable, CaseIterable, Equatable, Sendable {
2828
case warning = "warning"
2929
case error = "error"
30+
case ruleDefault = "true"
31+
case disabled = "false"
3032
}
3133

3234
private enum CodingKeys: CodingKey {
@@ -59,7 +61,7 @@ public struct Configuration: Codable, Equatable {
5961
/// names.
6062
///
6163
/// This value is generated by `generate-swift-format` based on the `isOptIn` value of each rule.
62-
public static let defaultRuleEnablements: [String: Bool] = RuleRegistry.rules
64+
public static let defaultRuleEnablements: [String: Configuration.RuleSeverity] = RuleRegistry.rules
6365

6466
/// The version of this configuration.
6567
private var version: Int = highestSupportedConfigurationVersion
@@ -68,11 +70,7 @@ public struct Configuration: Codable, Equatable {
6870

6971
/// The dictionary containing the rule names that we wish to run on. A rule is not used if it is
7072
/// marked as `false`, or if it is missing from the dictionary.
71-
public var rules: [String: Bool]
72-
73-
/// The dictionary containing the severities for the rule names that we wish to run on. If a rule
74-
/// is not listed here, the default severity is used.
75-
public var ruleSeverity: [String: RuleSeverity]
73+
public var rules: [String: Configuration.RuleSeverity]
7674

7775
/// The maximum number of consecutive blank lines that may appear in a file.
7876
public var maximumBlankLines: Int
@@ -398,11 +396,8 @@ public struct Configuration: Codable, Equatable {
398396
// default-initialized. To get an empty rules dictionary, one can explicitly
399397
// set the `rules` key to `{}`.
400398
self.rules =
401-
try container.decodeIfPresent([String: Bool].self, forKey: .rules)
399+
try container.decodeIfPresent([String: Configuration.RuleSeverity].self, forKey: .rules)
402400
?? defaults.rules
403-
404-
self.ruleSeverity =
405-
try container.decodeIfPresent([String: RuleSeverity].self, forKey: .ruleSeverity) ?? [:]
406401
}
407402

408403
public func encode(to encoder: Encoder) throws {
@@ -499,3 +494,16 @@ public struct NoAssignmentInExpressionsConfiguration: Codable, Equatable {
499494

500495
public init() {}
501496
}
497+
498+
extension Configuration.RuleSeverity {
499+
func findingSeverity(ruleDefault: Finding.Severity) -> Finding.Severity {
500+
switch self {
501+
case .warning: return .warning
502+
case .error: return .error
503+
case .ruleDefault:
504+
return ruleDefault
505+
case .disabled:
506+
return .disabled
507+
}
508+
}
509+
}

Sources/SwiftFormat/API/Finding.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public struct Finding {
1818
case error
1919
case refactoring
2020
case convention
21+
case disabled
2122
}
2223

2324
/// The file path and location in that file where a finding was encountered.

Sources/SwiftFormat/API/FindingCategorizing.swift

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,8 @@ public protocol FindingCategorizing: CustomStringConvertible {
2121
///
2222
/// By default, all findings are warnings. Individual categories or configuration may choose to override this to
2323
/// make the findings in those categories more severe.
24-
func severity(configuration: Configuration) -> Finding.Severity
24+
var severity: Finding.Severity { get }
2525

2626
/// The name of the category.
27-
var name: String {get}
28-
}
29-
30-
extension FindingCategorizing {
31-
func severity(configuration: Configuration) -> Finding.Severity {
32-
return severityFromConfig(configuration: configuration)
33-
}
34-
35-
func severityFromConfig(configuration: Configuration) -> Finding.Severity {
36-
guard let customSeverity = configuration.ruleSeverity[self.name] else { return .warning }
37-
return customSeverity.findingSeverity
38-
}
27+
var name: String { get }
3928
}

Sources/SwiftFormat/Core/Context.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,12 @@ public final class Context {
108108
let ruleName = ruleNameCache[ObjectIdentifier(rule)] ?? R.ruleName
109109
switch ruleMask.ruleState(ruleName, at: loc) {
110110
case .default:
111-
return configuration.rules[ruleName] ?? false
111+
guard let configSeverity = configuration.rules[ruleName] else { return false }
112+
if case .disabled = configSeverity {
113+
return false
114+
} else {
115+
return true
116+
}
112117
case .disabled:
113118
return false
114119
}

Sources/SwiftFormat/Core/FindingEmitter.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final class FindingEmitter {
5555
Finding(
5656
category: category,
5757
message: message,
58-
severity: category.severity(configuration: context.configuration),
58+
severity: category.severity,
5959
location: location,
6060
notes: notes
6161
)

Sources/SwiftFormat/Core/Rule.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ extension Rule {
8686
syntaxLocation = nil
8787
}
8888

89-
let severity: Finding.Severity? = severity ?? context.configuration.findingSeverity(for: type(of: self))
89+
let severity: Finding.Severity =
90+
severity ?? context.configuration.findingSeverity(for: type(of: self), defaultSeverity: .warning)
9091

9192
let category = RuleBasedFindingCategory(ruleType: type(of: self), severity: severity)
9293
context.findingEmitter.emit(
@@ -100,8 +101,8 @@ extension Rule {
100101
}
101102

102103
extension Configuration {
103-
func findingSeverity(for rule: any Rule.Type) -> Finding.Severity? {
104-
guard let severity = self.ruleSeverity[rule.ruleName] else { return nil }
105-
return severity.findingSeverity
104+
func findingSeverity(for rule: any Rule.Type, defaultSeverity: Finding.Severity) -> Finding.Severity {
105+
guard let severity = self.rules[rule.ruleName] else { return defaultSeverity }
106+
return severity.findingSeverity(ruleDefault: defaultSeverity)
106107
}
107108
}

Sources/SwiftFormat/Core/RuleBasedFindingCategory.swift

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,15 @@ struct RuleBasedFindingCategory: FindingCategorizing {
2222

2323
var description: String { ruleType.ruleName }
2424

25-
var severity: Finding.Severity?
25+
var severity: Finding.Severity
2626

2727
var name: String {
2828
return description
2929
}
3030

3131
/// Creates a finding category that wraps the given rule type.
32-
init(ruleType: Rule.Type, severity: Finding.Severity? = nil) {
32+
init(ruleType: Rule.Type, severity: Finding.Severity) {
3333
self.ruleType = ruleType
3434
self.severity = severity
3535
}
36-
37-
func severity(configuration: Configuration) -> Finding.Severity {
38-
if let severity = severity {
39-
return severity
40-
}
41-
return severityFromConfig(configuration: configuration)
42-
}
4336
}

0 commit comments

Comments
 (0)