mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
With the binding of configurations to their associated rule types "unknown configuration" errors can be made more specific mentioning also the rule's identifier in the printed message.
98 lines
3.4 KiB
Swift
98 lines
3.4 KiB
Swift
import Foundation
|
|
|
|
// MARK: - CustomRulesConfiguration
|
|
|
|
struct CustomRulesConfiguration: RuleConfiguration, Equatable, CacheDescriptionProvider {
|
|
typealias Parent = CustomRules
|
|
|
|
var consoleDescription: String { return "user-defined" }
|
|
var cacheDescription: String {
|
|
return customRuleConfigurations
|
|
.sorted { $0.identifier < $1.identifier }
|
|
.map { $0.cacheDescription }
|
|
.joined(separator: "\n")
|
|
}
|
|
var customRuleConfigurations = [RegexConfiguration<Parent>]()
|
|
|
|
mutating func apply(configuration: Any) throws {
|
|
guard let configurationDict = configuration as? [String: Any] else {
|
|
throw Issue.unknownConfiguration(ruleID: Parent.identifier)
|
|
}
|
|
|
|
for (key, value) in configurationDict {
|
|
var ruleConfiguration = RegexConfiguration<Parent>(identifier: key)
|
|
|
|
do {
|
|
try ruleConfiguration.apply(configuration: value)
|
|
} catch {
|
|
Issue.invalidConfiguration(ruleID: key).print()
|
|
continue
|
|
}
|
|
|
|
customRuleConfigurations.append(ruleConfiguration)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - CustomRules
|
|
|
|
struct CustomRules: Rule, ConfigurationProviderRule, CacheDescriptionProvider {
|
|
var cacheDescription: String {
|
|
return configuration.cacheDescription
|
|
}
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "custom_rules",
|
|
name: "Custom Rules",
|
|
description: """
|
|
Create custom rules by providing a regex string. Optionally specify what syntax kinds to match against, \
|
|
the severity level, and what message to display.
|
|
""",
|
|
kind: .style)
|
|
|
|
var configuration = CustomRulesConfiguration()
|
|
|
|
func validate(file: SwiftLintFile) -> [StyleViolation] {
|
|
var configurations = configuration.customRuleConfigurations
|
|
|
|
guard configurations.isNotEmpty else {
|
|
return []
|
|
}
|
|
|
|
if let path = file.path {
|
|
configurations = configurations.filter { config in
|
|
config.shouldValidate(filePath: path)
|
|
}
|
|
}
|
|
|
|
return configurations.flatMap { configuration -> [StyleViolation] in
|
|
let start = Date()
|
|
defer {
|
|
CustomRuleTimer.shared.register(time: -start.timeIntervalSinceNow, forRuleID: configuration.identifier)
|
|
}
|
|
|
|
let pattern = configuration.regex.pattern
|
|
let captureGroup = configuration.captureGroup
|
|
let excludingKinds = configuration.excludedMatchKinds
|
|
return file.match(pattern: pattern, excludingSyntaxKinds: excludingKinds, captureGroup: captureGroup).map({
|
|
StyleViolation(ruleDescription: configuration.description,
|
|
severity: configuration.severity,
|
|
location: Location(file: file, characterOffset: $0.location),
|
|
reason: configuration.message)
|
|
}).filter { violation in
|
|
guard let region = file.regions().first(where: { $0.contains(violation.location) }) else {
|
|
return true
|
|
}
|
|
|
|
return !region.isRuleDisabled(customRuleIdentifier: configuration.identifier)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension Region {
|
|
func isRuleDisabled(customRuleIdentifier: String) -> Bool {
|
|
return disabledRuleIdentifiers.contains(RuleIdentifier(customRuleIdentifier))
|
|
}
|
|
}
|