mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
a6c4fd98bc
Ideally, SwiftLintCore would some day only contain components that are needed to define rules. Consequently, it would be the only bundle required to import for (external) rule development.
134 lines
5.8 KiB
Swift
134 lines
5.8 KiB
Swift
public extension Configuration {
|
|
/// Returns the rule for the specified ID, if configured in this configuration.
|
|
///
|
|
/// - parameter ruleID: The identifier for the rule to look up.
|
|
///
|
|
/// - returns: The rule for the specified ID, if configured in this configuration.
|
|
func configuredRule(forID ruleID: String) -> (any Rule)? {
|
|
rules.first { rule in
|
|
if type(of: rule).identifier == ruleID {
|
|
if let customRules = rule as? CustomRules {
|
|
return customRules.configuration.customRuleConfigurations.isNotEmpty
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
/// Represents how a Configuration object can be configured with regards to rules.
|
|
enum RulesMode: Equatable {
|
|
/// The default rules mode, which will enable all rules that aren't defined as being opt-in
|
|
/// (conforming to the `OptInRule` protocol), minus the rules listed in `disabled`, plus the rules listed in
|
|
/// `optIn`.
|
|
case defaultConfiguration(disabled: Set<String>, optIn: Set<String>)
|
|
|
|
/// Only enable the rules explicitly listed in the configuration files.
|
|
case onlyConfiguration(Set<String>)
|
|
|
|
/// Only enable the rule(s) explicitly listed on the command line (and their aliases). `--only-rule` can be
|
|
/// specified multiple times to enable multiple rules.
|
|
case onlyCommandLine(Set<String>)
|
|
|
|
/// Enable all available rules.
|
|
case allCommandLine
|
|
|
|
internal init(
|
|
enableAllRules: Bool,
|
|
onlyRule: [String],
|
|
onlyRules: [String],
|
|
optInRules: [String],
|
|
disabledRules: [String],
|
|
analyzerRules: [String]
|
|
) throws {
|
|
func warnAboutDuplicates(in identifiers: [String]) {
|
|
if Set(identifiers).count != identifiers.count {
|
|
let duplicateRules = identifiers.reduce(into: [String: Int]()) { $0[$1, default: 0] += 1 }
|
|
.filter { $0.1 > 1 }
|
|
for duplicateRule in duplicateRules {
|
|
Issue.listedMultipleTime(ruleID: duplicateRule.0, times: duplicateRule.1).print()
|
|
}
|
|
}
|
|
}
|
|
|
|
if enableAllRules {
|
|
self = .allCommandLine
|
|
} else if onlyRule.isNotEmpty {
|
|
self = .onlyCommandLine(Set(onlyRule))
|
|
} else if onlyRules.isNotEmpty {
|
|
if disabledRules.isNotEmpty || optInRules.isNotEmpty {
|
|
throw Issue.genericWarning(
|
|
"'\(Configuration.Key.disabledRules.rawValue)' or " +
|
|
"'\(Configuration.Key.optInRules.rawValue)' cannot be used in combination " +
|
|
"with '\(Configuration.Key.onlyRules.rawValue)'"
|
|
)
|
|
}
|
|
|
|
warnAboutDuplicates(in: onlyRules + analyzerRules)
|
|
self = .onlyConfiguration(Set(onlyRules + analyzerRules))
|
|
} else {
|
|
warnAboutDuplicates(in: disabledRules)
|
|
|
|
let effectiveOptInRules: [String]
|
|
if optInRules.contains(RuleIdentifier.all.stringRepresentation) {
|
|
let allOptInRules = RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in
|
|
ruleType is any OptInRule.Type && !(ruleType is any AnalyzerRule.Type) ? ruleID : nil
|
|
}
|
|
effectiveOptInRules = Array(Set(allOptInRules + optInRules))
|
|
} else {
|
|
effectiveOptInRules = optInRules
|
|
}
|
|
|
|
let effectiveAnalyzerRules: [String]
|
|
if analyzerRules.contains(RuleIdentifier.all.stringRepresentation) {
|
|
let allAnalyzerRules = RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in
|
|
ruleType is any AnalyzerRule.Type ? ruleID : nil
|
|
}
|
|
effectiveAnalyzerRules = allAnalyzerRules
|
|
} else {
|
|
effectiveAnalyzerRules = analyzerRules
|
|
}
|
|
|
|
warnAboutDuplicates(in: effectiveOptInRules + effectiveAnalyzerRules)
|
|
self = .defaultConfiguration(
|
|
disabled: Set(disabledRules), optIn: Set(effectiveOptInRules + effectiveAnalyzerRules)
|
|
)
|
|
}
|
|
}
|
|
|
|
internal func applied(aliasResolver: (String) -> String) -> Self {
|
|
switch self {
|
|
case let .defaultConfiguration(disabled, optIn):
|
|
return .defaultConfiguration(
|
|
disabled: Set(disabled.map(aliasResolver)),
|
|
optIn: Set(optIn.map(aliasResolver))
|
|
)
|
|
|
|
case let .onlyConfiguration(onlyRules):
|
|
return .onlyConfiguration(Set(onlyRules.map(aliasResolver)))
|
|
|
|
case let .onlyCommandLine(onlyRules):
|
|
return .onlyCommandLine(Set(onlyRules.map(aliasResolver)))
|
|
|
|
case .allCommandLine:
|
|
return .allCommandLine
|
|
}
|
|
}
|
|
|
|
internal func activateCustomRuleIdentifiers(allRulesWrapped: [ConfigurationRuleWrapper]) -> Self {
|
|
// In the only mode, if the custom rules rule is enabled, all custom rules are also enabled implicitly
|
|
// This method makes the implicitly explicit
|
|
switch self {
|
|
case let .onlyConfiguration(onlyRules) where onlyRules.contains {
|
|
$0 == CustomRules.identifier
|
|
}:
|
|
let customRulesRule = (allRulesWrapped.first { $0.rule is CustomRules })?.rule as? CustomRules
|
|
return .onlyConfiguration(onlyRules.union(Set(customRulesRule?.customRuleIdentifiers ?? [])))
|
|
|
|
default:
|
|
return self
|
|
}
|
|
}
|
|
}
|
|
}
|