mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
134 lines
5.4 KiB
Swift
134 lines
5.4 KiB
Swift
import Foundation
|
|
import SwiftLintCore
|
|
|
|
struct FileHeaderConfiguration: SeverityBasedRuleConfiguration {
|
|
typealias Parent = FileHeaderRule
|
|
|
|
private static let fileNamePlaceholder = "SWIFTLINT_CURRENT_FILENAME"
|
|
private static let stringRegexOptions: NSRegularExpression.Options = [.ignoreMetacharacters]
|
|
private static let patternRegexOptions: NSRegularExpression.Options =
|
|
[.anchorsMatchLines, .dotMatchesLineSeparators]
|
|
|
|
@ConfigurationElement(key: "severity")
|
|
private(set) var severityConfiguration = SeverityConfiguration<Parent>(.warning)
|
|
@ConfigurationElement(key: "required_string")
|
|
private var requiredString: String?
|
|
@ConfigurationElement(key: "required_pattern")
|
|
private var requiredPattern: String?
|
|
@ConfigurationElement(key: "forbidden_string")
|
|
private var forbiddenString: String?
|
|
@ConfigurationElement(key: "forbidden_pattern")
|
|
private var forbiddenPattern: String?
|
|
|
|
private var _forbiddenRegex: RegularExpression?
|
|
private var _requiredRegex: RegularExpression?
|
|
|
|
private static let defaultRegex = regex("\\bCopyright\\b", options: [.caseInsensitive])
|
|
|
|
mutating func apply(configuration: Any) throws(Issue) {
|
|
guard let configuration = configuration as? [String: String] else {
|
|
throw .invalidConfiguration(ruleID: Parent.identifier)
|
|
}
|
|
|
|
// Cache the created regexes if possible.
|
|
// If the pattern contains the SWIFTLINT_CURRENT_FILENAME placeholder,
|
|
// the regex will be recompiled for each validated file.
|
|
if let requiredString = configuration[$requiredString.key] {
|
|
self.requiredString = requiredString
|
|
if !requiredString.contains(Self.fileNamePlaceholder) {
|
|
_requiredRegex = try .from(
|
|
pattern: requiredString,
|
|
options: Self.stringRegexOptions,
|
|
for: Parent.identifier
|
|
)
|
|
}
|
|
} else if let requiredPattern = configuration[$requiredPattern.key] {
|
|
self.requiredPattern = requiredPattern
|
|
if !requiredPattern.contains(Self.fileNamePlaceholder) {
|
|
_requiredRegex = try .from(pattern: requiredPattern, for: Parent.identifier)
|
|
}
|
|
}
|
|
|
|
if let forbiddenString = configuration[$forbiddenString.key] {
|
|
self.forbiddenString = forbiddenString
|
|
if !forbiddenString.contains(Self.fileNamePlaceholder) {
|
|
_forbiddenRegex = try .from(
|
|
pattern: forbiddenString,
|
|
options: Self.stringRegexOptions,
|
|
for: Parent.identifier
|
|
)
|
|
}
|
|
} else if let forbiddenPattern = configuration[$forbiddenPattern.key] {
|
|
self.forbiddenPattern = forbiddenPattern
|
|
if !forbiddenPattern.contains(Self.fileNamePlaceholder) {
|
|
_forbiddenRegex = try .from(pattern: forbiddenPattern, for: Parent.identifier)
|
|
}
|
|
}
|
|
|
|
if let severityString = configuration[$severityConfiguration.key] {
|
|
try severityConfiguration.apply(configuration: severityString)
|
|
}
|
|
}
|
|
|
|
private func makeRegex(for file: SwiftLintFile,
|
|
using pattern: String,
|
|
options: NSRegularExpression.Options,
|
|
escapeFileName: Bool) -> NSRegularExpression? {
|
|
// Recompile the regex for this file...
|
|
let replacedPattern = file.path.map { path in
|
|
let fileName = path.bridge().lastPathComponent
|
|
|
|
// Replace SWIFTLINT_CURRENT_FILENAME with the filename.
|
|
let escapedName = escapeFileName ? NSRegularExpression.escapedPattern(for: fileName) : fileName
|
|
return pattern.replacingOccurrences(of: Self.fileNamePlaceholder,
|
|
with: escapedName)
|
|
} ?? pattern
|
|
|
|
do {
|
|
return try NSRegularExpression(pattern: replacedPattern, options: options)
|
|
} catch {
|
|
queuedFatalError("Failed to compile pattern '\(replacedPattern)'")
|
|
}
|
|
}
|
|
|
|
private func regexFromString(for file: SwiftLintFile, using pattern: String) -> NSRegularExpression? {
|
|
makeRegex(for: file, using: pattern, options: Self.stringRegexOptions, escapeFileName: false)
|
|
}
|
|
|
|
private func regexFromPattern(for file: SwiftLintFile, using pattern: String) -> NSRegularExpression? {
|
|
makeRegex(for: file, using: pattern, options: Self.patternRegexOptions, escapeFileName: true)
|
|
}
|
|
|
|
func forbiddenRegex(for file: SwiftLintFile) -> NSRegularExpression? {
|
|
if _forbiddenRegex != nil {
|
|
return _forbiddenRegex?.regex
|
|
}
|
|
|
|
if let regex = forbiddenString.flatMap({ regexFromString(for: file, using: $0) }) {
|
|
return regex
|
|
}
|
|
|
|
if let regex = forbiddenPattern.flatMap({ regexFromPattern(for: file, using: $0) }) {
|
|
return regex
|
|
}
|
|
|
|
if requiredPattern == nil, requiredString == nil {
|
|
return Self.defaultRegex
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func requiredRegex(for file: SwiftLintFile) -> NSRegularExpression? {
|
|
if _requiredRegex != nil {
|
|
return _requiredRegex?.regex
|
|
}
|
|
|
|
if let regex = requiredString.flatMap({ regexFromString(for: file, using: $0) }) {
|
|
return regex
|
|
}
|
|
|
|
return requiredPattern.flatMap { regexFromPattern(for: file, using: $0) }
|
|
}
|
|
}
|