Make postprocessors non-throwing (#5539)

Failing immediately when a property is invalid is too strict. It feels
sufficient to allow to report an issue but otherwise continue with a default
value instead of stopping execution completely.
This commit is contained in:
Danny Mösch
2024-04-23 22:45:59 +02:00
committed by GitHub
parent 3276266716
commit 1b7fbc4bcd
5 changed files with 26 additions and 28 deletions
@@ -4,11 +4,18 @@ import SwiftLintCore
struct IndentationWidthConfiguration: SeverityBasedRuleConfiguration {
typealias Parent = IndentationWidthRule
private static let defaultIndentationWidth = 4
@ConfigurationElement(key: "severity")
private(set) var severityConfiguration = SeverityConfiguration<Parent>.warning
@ConfigurationElement(
key: "indentation_width",
postprocessor: { if $0 < 1 { throw Issue.invalidConfiguration(ruleID: Parent.identifier) } }
postprocessor: {
if $0 < 1 {
Issue.invalidConfiguration(ruleID: Parent.identifier).print()
$0 = Self.defaultIndentationWidth
}
}
)
private(set) var indentationWidth = 4
@ConfigurationElement(key: "include_comments")
@@ -416,7 +416,13 @@ public protocol InlinableOptionType: AcceptableByConfigurationElement {}
@propertyWrapper
public struct ConfigurationElement<T: AcceptableByConfigurationElement & Equatable>: Equatable {
/// Wrapped option value.
public var wrappedValue: T
public var wrappedValue: T {
didSet {
if wrappedValue != oldValue {
postprocessor(&wrappedValue)
}
}
}
/// The wrapper itself providing access to all its data. This field can only be accessed by the
/// element's name prefixed with a `$`.
@@ -431,7 +437,7 @@ public struct ConfigurationElement<T: AcceptableByConfigurationElement & Equatab
/// Whether this configuration element will be inlined into its description.
public let inline: Bool
private let postprocessor: (inout T) throws -> Void
private let postprocessor: (inout T) -> Void
/// Default constructor.
///
@@ -441,11 +447,11 @@ public struct ConfigurationElement<T: AcceptableByConfigurationElement & Equatab
/// - postprocessor: Function to be applied to the wrapped value after parsing to validate and modify it.
public init(wrappedValue value: T,
key: String,
postprocessor: @escaping (inout T) throws -> Void = { _ in }) {
postprocessor: @escaping (inout T) -> Void = { _ in }) {
self.init(wrappedValue: value, key: key, inline: false, postprocessor: postprocessor)
// Validate and modify the set value immediately. An exception means invalid defaults.
try! performAfterParseOperations() // swiftlint:disable:this force_try
// Modify the set value immediately.
postprocessor(&wrappedValue)
}
/// Constructor for optional values.
@@ -482,18 +488,13 @@ public struct ConfigurationElement<T: AcceptableByConfigurationElement & Equatab
private init(wrappedValue: T,
key: String,
inline: Bool,
postprocessor: @escaping (inout T) throws -> Void = { _ in }) {
postprocessor: @escaping (inout T) -> Void = { _ in }) {
self.wrappedValue = wrappedValue
self.key = key
self.inline = inline
self.postprocessor = postprocessor
}
/// Run operations to validate and modify the parsed value.
public mutating func performAfterParseOperations() throws {
try postprocessor(&wrappedValue)
}
public static func == (lhs: ConfigurationElement, rhs: ConfigurationElement) -> Bool {
lhs.wrappedValue == rhs.wrappedValue && lhs.key == rhs.key
}
@@ -60,7 +60,6 @@ enum AutoApply: MemberMacro {
"""
do {
try \(raw: option).apply(configuration, ruleID: Parent.identifier)
try $\(raw: option).performAfterParseOperations()
} catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) {
// Acceptable. Continue.
}
@@ -77,9 +76,6 @@ enum AutoApply: MemberMacro {
"""
try \(raw: option).apply(configuration[$\(raw: option).key], ruleID: Parent.identifier)
"""
"""
try $\(raw: option).performAfterParseOperations()
"""
}
"""
if !supportedKeys.isSuperset(of: configuration.keys) {
-8
View File
@@ -81,9 +81,7 @@ final class AutoApplyTests: XCTestCase {
throw Issue.invalidConfiguration(ruleID: Parent.identifier)
}
try eA.apply(configuration[$eA.key], ruleID: Parent.identifier)
try $eA.performAfterParseOperations()
try eB.apply(configuration[$eB.key], ruleID: Parent.identifier)
try $eB.performAfterParseOperations()
if !supportedKeys.isSuperset(of: configuration.keys) {
let unknownKeys = Set(configuration.keys).subtracting(supportedKeys)
throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys)
@@ -127,7 +125,6 @@ final class AutoApplyTests: XCTestCase {
}
do {
try eB.apply(configuration, ruleID: Parent.identifier)
try $eB.performAfterParseOperations()
} catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) {
// Acceptable. Continue.
}
@@ -135,9 +132,7 @@ final class AutoApplyTests: XCTestCase {
return
}
try eA.apply(configuration[$eA.key], ruleID: Parent.identifier)
try $eA.performAfterParseOperations()
try eC.apply(configuration[$eC.key], ruleID: Parent.identifier)
try $eC.performAfterParseOperations()
if !supportedKeys.isSuperset(of: configuration.keys) {
let unknownKeys = Set(configuration.keys).subtracting(supportedKeys)
throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys)
@@ -210,7 +205,6 @@ final class AutoApplyTests: XCTestCase {
}
do {
try severityConfiguration.apply(configuration, ruleID: Parent.identifier)
try $severityConfiguration.performAfterParseOperations()
} catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) {
// Acceptable. Continue.
}
@@ -218,9 +212,7 @@ final class AutoApplyTests: XCTestCase {
return
}
try severityConfiguration.apply(configuration[$severityConfiguration.key], ruleID: Parent.identifier)
try $severityConfiguration.performAfterParseOperations()
try foo.apply(configuration[$foo.key], ruleID: Parent.identifier)
try $foo.performAfterParseOperations()
if !supportedKeys.isSuperset(of: configuration.keys) {
let unknownKeys = Set(configuration.keys).subtracting(supportedKeys)
throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys)
@@ -3,12 +3,14 @@ import SwiftLintTestHelpers
import XCTest
class IndentationWidthRuleTests: SwiftLintTestCase {
func testInvalidIndentation() {
func testInvalidIndentation() throws {
var testee = IndentationWidthConfiguration()
let defaultValue = testee.indentationWidth
for indentation in [0, -1, -5] {
checkError(Issue.invalidConfiguration(ruleID: IndentationWidthRule.description.identifier)) {
try testee.apply(configuration: ["indentation_width": indentation])
}
try testee.apply(configuration: ["indentation_width": indentation])
// Value remains the default.
XCTAssertEqual(testee.indentationWidth, defaultValue)
}
}