Compare commits
5 Commits
main
...
jp-file-na
Author | SHA1 | Date |
---|---|---|
![]() |
8881a8d3da | |
![]() |
0402ae7fab | |
![]() |
fa3d48a97e | |
![]() |
d37ff39613 | |
![]() |
17256e4fcf |
|
@ -101,6 +101,11 @@
|
|||
* Make `closure_spacing` a `CorrectableRule`.
|
||||
[J. Cheyo Jimenez](https://github.com/masters3d)
|
||||
|
||||
* Add `file_name` opt-in rule validating that file names contain the name of a
|
||||
type or extension declared in the file (if any).
|
||||
[JP Simard](https://github.com/jpsim)
|
||||
[#1420](https://github.com/realm/SwiftLint/issues/1420)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* `emoji` and `checkstyle` reporter output report sorted by file name.
|
||||
|
|
|
@ -99,6 +99,7 @@ public let masterRuleList = RuleList(rules:
|
|||
FatalErrorMessageRule.self,
|
||||
FileHeaderRule.self,
|
||||
FileLengthRule.self,
|
||||
FileNameRule.self,
|
||||
FirstWhereRule.self,
|
||||
ForceCastRule.self,
|
||||
ForceTryRule.self,
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// FileNameRule.swift
|
||||
// SwiftLint
|
||||
//
|
||||
// Created by JP Simard on 5/24/17.
|
||||
// Copyright © 2017 Realm. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SourceKittenFramework
|
||||
|
||||
private let typeAndExtensionKinds = SwiftDeclarationKind.typeKinds() + [.extension, .protocol]
|
||||
|
||||
extension Dictionary where Key: ExpressibleByStringLiteral {
|
||||
fileprivate func recursiveDeclaredTypeNames() -> [String] {
|
||||
let subNames = substructure.flatMap { $0.recursiveDeclaredTypeNames() }
|
||||
if let kind = kind.flatMap(SwiftDeclarationKind.init),
|
||||
typeAndExtensionKinds.contains(kind), let name = name {
|
||||
return [name] + subNames
|
||||
}
|
||||
return subNames
|
||||
}
|
||||
}
|
||||
|
||||
public struct FileNameRule: ConfigurationProviderRule, OptInRule {
|
||||
public var configuration = FileNameConfiguration(severity: .warning, excluded: ["main.swift"])
|
||||
|
||||
public init() {}
|
||||
|
||||
public static let description = RuleDescription(
|
||||
identifier: "file_name",
|
||||
name: "File Name",
|
||||
description: "File name should match a type declared in the file (if any)."
|
||||
)
|
||||
|
||||
public func validate(file: File) -> [StyleViolation] {
|
||||
guard let filePath = file.path,
|
||||
case let fileName = filePath.bridge().lastPathComponent,
|
||||
!configuration.excluded.contains(fileName) else {
|
||||
return []
|
||||
}
|
||||
|
||||
let typeInFileName = fileName.components(separatedBy: CharacterSet(charactersIn: "+.")).first ?? fileName
|
||||
|
||||
let allDeclaredTypeNames = file.structure.dictionary.recursiveDeclaredTypeNames()
|
||||
guard !allDeclaredTypeNames.isEmpty, !allDeclaredTypeNames.contains(typeInFileName) else {
|
||||
return []
|
||||
}
|
||||
|
||||
return [StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severity.severity,
|
||||
location: Location(file: filePath, line: 1))]
|
||||
}
|
||||
}
|
||||
|
||||
public struct FileNameConfiguration: RuleConfiguration, Equatable {
|
||||
public var consoleDescription: String {
|
||||
return "(severity) \(severity.consoleDescription), " +
|
||||
"excluded: \(excluded.sorted())"
|
||||
}
|
||||
|
||||
private(set) public var severity: SeverityConfiguration
|
||||
private(set) public var excluded: Set<String>
|
||||
|
||||
public init(severity: ViolationSeverity, excluded: [String] = []) {
|
||||
self.severity = SeverityConfiguration(severity)
|
||||
self.excluded = Set(excluded)
|
||||
}
|
||||
|
||||
public mutating func apply(configuration: Any) throws {
|
||||
guard let configurationDict = configuration as? [String: Any] else {
|
||||
throw ConfigurationError.unknownConfiguration
|
||||
}
|
||||
|
||||
if let severityConfiguration = configurationDict["severity"] {
|
||||
try severity.apply(configuration: severityConfiguration)
|
||||
}
|
||||
if let excluded = [String].array(of: configurationDict["excluded"]) {
|
||||
self.excluded = Set(excluded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: FileNameConfiguration, rhs: FileNameConfiguration) -> Bool {
|
||||
return lhs.severity == rhs.severity &&
|
||||
lhs.excluded == rhs.excluded
|
||||
}
|
|
@ -187,6 +187,7 @@
|
|||
E82367E01ED3BD1E0040A88E /* Configuration+Cache.swift in Sources */ = {isa = PBXBuildFile; fileRef = E82367DF1ED3BD1E0040A88E /* Configuration+Cache.swift */; };
|
||||
E832F10B1B17E2F5003F265F /* NSFileManager+SwiftLint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */; };
|
||||
E832F10D1B17E725003F265F /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E832F10C1B17E725003F265F /* IntegrationTests.swift */; };
|
||||
E83530C61ED6328A00FBAF79 /* FileNameRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83530C51ED6328A00FBAF79 /* FileNameRule.swift */; };
|
||||
E83A0B351A5D382B0041A60A /* VersionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83A0B341A5D382B0041A60A /* VersionCommand.swift */; };
|
||||
E847F0A91BFBBABD00EA9363 /* EmptyCountRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E847F0A81BFBBABD00EA9363 /* EmptyCountRule.swift */; };
|
||||
E84E07471C13F95300F11122 /* AutoCorrectCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E84E07461C13F95300F11122 /* AutoCorrectCommand.swift */; };
|
||||
|
@ -482,6 +483,7 @@
|
|||
E82367DF1ED3BD1E0040A88E /* Configuration+Cache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Configuration+Cache.swift"; sourceTree = "<group>"; };
|
||||
E832F10A1B17E2F5003F265F /* NSFileManager+SwiftLint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFileManager+SwiftLint.swift"; sourceTree = "<group>"; };
|
||||
E832F10C1B17E725003F265F /* IntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = "<group>"; };
|
||||
E83530C51ED6328A00FBAF79 /* FileNameRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileNameRule.swift; sourceTree = "<group>"; };
|
||||
E83A0B341A5D382B0041A60A /* VersionCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionCommand.swift; sourceTree = "<group>"; };
|
||||
E847F0A81BFBBABD00EA9363 /* EmptyCountRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyCountRule.swift; sourceTree = "<group>"; };
|
||||
E84E07461C13F95300F11122 /* AutoCorrectCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoCorrectCommand.swift; sourceTree = "<group>"; };
|
||||
|
@ -875,6 +877,7 @@
|
|||
C3DE5DAA1E7DF99B00761483 /* FatalErrorMessageRule.swift */,
|
||||
D4C4A34D1DEA877200E0E04C /* FileHeaderRule.swift */,
|
||||
E88DEA891B0992B300A66CB0 /* FileLengthRule.swift */,
|
||||
E83530C51ED6328A00FBAF79 /* FileNameRule.swift */,
|
||||
D42D2B371E09CC0D00CD7A2E /* FirstWhereRule.swift */,
|
||||
E88DEA7F1B09903300A66CB0 /* ForceCastRule.swift */,
|
||||
E816194D1BFBFEAB00946723 /* ForceTryRule.swift */,
|
||||
|
@ -1351,6 +1354,7 @@
|
|||
E80746F61ECB722F00548D31 /* CacheDescriptionProvider.swift in Sources */,
|
||||
094385041D5D4F7C009168CF /* PrivateOutletRule.swift in Sources */,
|
||||
E88DEA6B1B0983FE00A66CB0 /* StyleViolation.swift in Sources */,
|
||||
E83530C61ED6328A00FBAF79 /* FileNameRule.swift in Sources */,
|
||||
3BB47D831C514E8100AE6A10 /* RegexConfiguration.swift in Sources */,
|
||||
D4C889711E385B7B00BAE88D /* RedundantDiscardableLetRule.swift in Sources */,
|
||||
D4D1B9BB1EAC2C910028BE6A /* AccessControlLevel.swift in Sources */,
|
||||
|
|
Loading…
Reference in New Issue