mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
Merge pull request #2310 from Dschee/file-name
Add options `prefix_pattern` and `suffix_pattern` to `file_name` rule
This commit is contained in:
@@ -22,6 +22,10 @@
|
||||
`class` for class-only protocols.
|
||||
[Ornithologist Coder](https://github.com/ornithocoder)
|
||||
[#2283](https://github.com/realm/SwiftLint/issues/2283)
|
||||
|
||||
* Add options `prefix_pattern` and `suffix_pattern` to rule `file_name`.
|
||||
[Cihat Gündüz](https://github.com/Dschee)
|
||||
[#2309](https://github.com/realm/SwiftLint/issues/2309)
|
||||
|
||||
* Add new bool config option `if_only` to rule `conditional_returns_on_newline`
|
||||
to specify that the rule should only be applied to `if` statements.
|
||||
|
||||
@@ -71,6 +71,10 @@ extension String {
|
||||
return fromIndex..<toIndex
|
||||
}
|
||||
|
||||
internal var fullNSRange: NSRange {
|
||||
return NSRange(location: 0, length: utf16.count)
|
||||
}
|
||||
|
||||
public func absolutePathStandardized() -> String {
|
||||
return bridge().absolutePathRepresentation().bridge().standardizingPath
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ private extension Dictionary where Key: ExpressibleByStringLiteral {
|
||||
}
|
||||
|
||||
public struct FileNameRule: ConfigurationProviderRule, OptInRule {
|
||||
public var configuration = FileNameConfiguration(severity: .warning, excluded: ["main.swift", "LinuxMain.swift"])
|
||||
public var configuration = FileNameConfiguration(
|
||||
severity: .warning,
|
||||
excluded: ["main.swift", "LinuxMain.swift"],
|
||||
prefixPattern: "",
|
||||
suffixPattern: "\\+.*"
|
||||
)
|
||||
|
||||
public init() {}
|
||||
|
||||
@@ -33,7 +38,20 @@ public struct FileNameRule: ConfigurationProviderRule, OptInRule {
|
||||
return []
|
||||
}
|
||||
|
||||
let typeInFileName = fileName.components(separatedBy: CharacterSet(charactersIn: "+.")).first ?? fileName
|
||||
let prefixRegex = regex("\\A\(configuration.prefixPattern)")
|
||||
let suffixRegex = regex("\(configuration.suffixPattern)\\z")
|
||||
|
||||
var typeInFileName = fileName.components(separatedBy: ".").first ?? fileName
|
||||
|
||||
if let match = prefixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
|
||||
let range = typeInFileName.nsrangeToIndexRange(match.range) {
|
||||
typeInFileName.removeSubrange(range)
|
||||
}
|
||||
|
||||
if let match = suffixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
|
||||
let range = typeInFileName.nsrangeToIndexRange(match.range) {
|
||||
typeInFileName.removeSubrange(range)
|
||||
}
|
||||
|
||||
let allDeclaredTypeNames = file.structure.dictionary.recursiveDeclaredTypeNames()
|
||||
guard !allDeclaredTypeNames.isEmpty, !allDeclaredTypeNames.contains(typeInFileName) else {
|
||||
|
||||
@@ -6,10 +6,15 @@ public struct FileNameConfiguration: RuleConfiguration, Equatable {
|
||||
|
||||
private(set) public var severity: SeverityConfiguration
|
||||
private(set) public var excluded: Set<String>
|
||||
private(set) public var prefixPattern: String
|
||||
private(set) public var suffixPattern: String
|
||||
|
||||
public init(severity: ViolationSeverity, excluded: [String] = []) {
|
||||
public init(severity: ViolationSeverity, excluded: [String] = [],
|
||||
prefixPattern: String = "", suffixPattern: String = "\\+.*") {
|
||||
self.severity = SeverityConfiguration(severity)
|
||||
self.excluded = Set(excluded)
|
||||
self.prefixPattern = prefixPattern
|
||||
self.suffixPattern = suffixPattern
|
||||
}
|
||||
|
||||
public mutating func apply(configuration: Any) throws {
|
||||
@@ -23,10 +28,18 @@ public struct FileNameConfiguration: RuleConfiguration, Equatable {
|
||||
if let excluded = [String].array(of: configurationDict["excluded"]) {
|
||||
self.excluded = Set(excluded)
|
||||
}
|
||||
if let prefixPattern = configurationDict["prefix_pattern"] as? String {
|
||||
self.prefixPattern = prefixPattern
|
||||
}
|
||||
if let suffixPattern = configurationDict["suffix_pattern"] as? String {
|
||||
self.suffixPattern = suffixPattern
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: FileNameConfiguration, rhs: FileNameConfiguration) -> Bool {
|
||||
return lhs.severity == rhs.severity &&
|
||||
lhs.excluded == rhs.excluded
|
||||
lhs.excluded == rhs.excluded &&
|
||||
lhs.prefixPattern == rhs.prefixPattern &&
|
||||
lhs.suffixPattern == rhs.suffixPattern
|
||||
}
|
||||
|
||||
@@ -7,11 +7,18 @@ private let fixturesDirectory = #file.bridge()
|
||||
.appendingPathComponent("Resources/FileNameRuleFixtures")
|
||||
|
||||
class FileNameRuleTests: XCTestCase {
|
||||
private func validate(fileName: String, excludedOverride: [String]? = nil) throws -> [StyleViolation] {
|
||||
private func validate(fileName: String, excludedOverride: [String]? = nil,
|
||||
prefixPattern: String? = nil, suffixPattern: String? = nil) throws -> [StyleViolation] {
|
||||
let file = File(path: fixturesDirectory.stringByAppendingPathComponent(fileName))!
|
||||
let rule: FileNameRule
|
||||
if let excluded = excludedOverride {
|
||||
rule = try FileNameRule(configuration: ["excluded": excluded])
|
||||
} else if let prefixPattern = prefixPattern, let suffixPattern = suffixPattern {
|
||||
rule = try FileNameRule(configuration: ["prefix_pattern": prefixPattern, "suffix_pattern": suffixPattern])
|
||||
} else if let prefixPattern = prefixPattern {
|
||||
rule = try FileNameRule(configuration: ["prefix_pattern": prefixPattern])
|
||||
} else if let suffixPattern = suffixPattern {
|
||||
rule = try FileNameRule(configuration: ["suffix_pattern": suffixPattern])
|
||||
} else {
|
||||
rule = FileNameRule()
|
||||
}
|
||||
@@ -49,4 +56,32 @@ class FileNameRuleTests: XCTestCase {
|
||||
func testMainDoesTriggerWithoutOverride() {
|
||||
XCTAssertEqual(try validate(fileName: "main.swift", excludedOverride: []).count, 1)
|
||||
}
|
||||
|
||||
func testCustomSuffixPattern() {
|
||||
XCTAssert(try validate(fileName: "BoolExtension.swift", suffixPattern: "Extensions?").isEmpty)
|
||||
XCTAssert(try validate(fileName: "BoolExtensions.swift", suffixPattern: "Extensions?").isEmpty)
|
||||
}
|
||||
|
||||
func testCustomPrefixPattern() {
|
||||
XCTAssert(try validate(fileName: "ExtensionBool.swift", prefixPattern: "Extensions?").isEmpty)
|
||||
XCTAssert(try validate(fileName: "ExtensionsBool.swift", prefixPattern: "Extensions?").isEmpty)
|
||||
}
|
||||
|
||||
func testCustomPrefixAndSuffixPatterns() {
|
||||
XCTAssert(
|
||||
try validate(
|
||||
fileName: "SLBoolExtension.swift",
|
||||
prefixPattern: "SL",
|
||||
suffixPattern: "Extensions?|\\+.*"
|
||||
).isEmpty
|
||||
)
|
||||
|
||||
XCTAssert(
|
||||
try validate(
|
||||
fileName: "ExtensionBool+SwiftLint.swift",
|
||||
prefixPattern: "Extensions?",
|
||||
suffixPattern: "Extensions?|\\+.*"
|
||||
).isEmpty
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
struct MyStruct {}
|
||||
class MyClass {}
|
||||
|
||||
extension Bool {
|
||||
func toggle() {}
|
||||
}
|
||||
Reference in New Issue
Block a user