-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Refactor Exclude by behavior into a Strategy pattern #6166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,6 @@ | ||
import Foundation | ||
|
||
extension Configuration { | ||
public enum ExcludeBy { | ||
case prefix | ||
case paths(excludedPaths: [String]) | ||
} | ||
|
||
// MARK: Lintable Paths | ||
/// Returns the files that can be linted by SwiftLint in the specified parent path. | ||
/// | ||
|
@@ -18,7 +13,7 @@ extension Configuration { | |
/// - returns: Files to lint. | ||
public func lintableFiles(inPath path: String, | ||
forceExclude: Bool, | ||
excludeBy: ExcludeBy) -> [SwiftLintFile] { | ||
excludeBy: any ExcludeByStrategy) -> [SwiftLintFile] { | ||
lintablePaths(inPath: path, forceExclude: forceExclude, excludeBy: excludeBy) | ||
.parallelCompactMap { | ||
SwiftLintFile(pathDeferringReading: $0) | ||
|
@@ -38,17 +33,12 @@ extension Configuration { | |
internal func lintablePaths( | ||
inPath path: String, | ||
forceExclude: Bool, | ||
excludeBy: ExcludeBy, | ||
excludeBy: any ExcludeByStrategy, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can also be |
||
fileManager: some LintableFileManager = FileManager.default | ||
) -> [String] { | ||
if fileManager.isFile(atPath: path) { | ||
if forceExclude { | ||
switch excludeBy { | ||
case .prefix: | ||
return filterExcludedPathsByPrefix(in: [path.absolutePathStandardized()]) | ||
case .paths(let excludedPaths): | ||
return filterExcludedPaths(excludedPaths, in: [path.absolutePathStandardized()]) | ||
} | ||
return excludeBy.filterExcludedPaths(in: [path.absolutePathStandardized()]) | ||
} | ||
// If path is a file and we're not forcing excludes, skip filtering with excluded/included paths | ||
return [path] | ||
|
@@ -59,62 +49,6 @@ extension Configuration { | |
.flatMap(Glob.resolveGlob) | ||
.parallelFlatMap { fileManager.filesToLint(inPath: $0, rootDirectory: rootDirectory) } | ||
|
||
switch excludeBy { | ||
case .prefix: | ||
return filterExcludedPathsByPrefix(in: pathsForPath, includedPaths) | ||
case .paths(let excludedPaths): | ||
return filterExcludedPaths(excludedPaths, in: pathsForPath, includedPaths) | ||
} | ||
} | ||
|
||
/// Returns an array of file paths after removing the excluded paths as defined by this configuration. | ||
/// | ||
/// - parameter fileManager: The lintable file manager to use to expand the excluded paths into all matching paths. | ||
/// - parameter paths: The input paths to filter. | ||
/// | ||
/// - returns: The input paths after removing the excluded paths. | ||
public func filterExcludedPaths( | ||
_ excludedPaths: [String], | ||
in paths: [String]... | ||
) -> [String] { | ||
let allPaths = paths.flatMap { $0 } | ||
#if os(Linux) | ||
let result = NSMutableOrderedSet(capacity: allPaths.count) | ||
result.addObjects(from: allPaths) | ||
#else | ||
let result = NSMutableOrderedSet(array: allPaths) | ||
#endif | ||
|
||
result.minusSet(Set(excludedPaths)) | ||
// swiftlint:disable:next force_cast | ||
return result.map { $0 as! String } | ||
} | ||
|
||
/// Returns the file paths that are excluded by this configuration using filtering by absolute path prefix. | ||
/// | ||
/// For cases when excluded directories contain many lintable files (e. g. Pods) it works faster than default | ||
/// algorithm `filterExcludedPaths`. | ||
/// | ||
/// - returns: The input paths after removing the excluded paths. | ||
public func filterExcludedPathsByPrefix(in paths: [String]...) -> [String] { | ||
let allPaths = paths.flatMap { $0 } | ||
let excludedPaths = self.excludedPaths | ||
.parallelFlatMap { @Sendable in Glob.resolveGlob($0) } | ||
.map { $0.absolutePathStandardized() } | ||
return allPaths.filter { path in | ||
!excludedPaths.contains { path.hasPrefix($0) } | ||
} | ||
} | ||
|
||
/// Returns the file paths that are excluded by this configuration after expanding them using the specified file | ||
/// manager. | ||
/// | ||
/// - parameter fileManager: The file manager to get child paths in a given parent location. | ||
/// | ||
/// - returns: The expanded excluded file paths. | ||
public func excludedPaths(fileManager: some LintableFileManager = FileManager.default) -> [String] { | ||
excludedPaths | ||
.flatMap(Glob.resolveGlob) | ||
.parallelFlatMap { fileManager.filesToLint(inPath: $0, rootDirectory: rootDirectory) } | ||
return excludeBy.filterExcludedPaths(in: pathsForPath, includedPaths) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// | ||
// ExcludeByPathsByExpandingSubPaths.swift | ||
// | ||
rlf-doordash marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
import Foundation | ||
|
||
public struct ExcludeByPathsByExpandingSubPaths: ExcludeByStrategy { | ||
rlf-doordash marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
let excludedPaths: [String] | ||
|
||
public init(configuration: Configuration, fileManager: some LintableFileManager = FileManager.default) { | ||
self.excludedPaths = configuration.excludedPaths | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can call the other |
||
.flatMap(Glob.resolveGlob) | ||
.parallelFlatMap { fileManager.filesToLint(inPath: $0, rootDirectory: configuration.rootDirectory) } | ||
} | ||
|
||
public init(_ excludedPaths: [String]) { | ||
self.excludedPaths = excludedPaths | ||
} | ||
|
||
public func filterExcludedPaths(in paths: [String]...) -> [String] { | ||
let allPaths = paths.flatMap { $0 } | ||
#if os(Linux) | ||
let result = NSMutableOrderedSet(capacity: allPaths.count) | ||
result.addObjects(from: allPaths) | ||
#else | ||
let result = NSMutableOrderedSet(array: allPaths) | ||
#endif | ||
|
||
result.minusSet(Set(excludedPaths)) | ||
// swiftlint:disable:next force_cast | ||
return result.map { $0 as! String } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// | ||
// ExcludeByPrefixStrategy.swift | ||
// | ||
|
||
struct ExcludeByPrefixStrategy: ExcludeByStrategy { | ||
let excludedPaths: [String] | ||
|
||
func filterExcludedPaths(in paths: [String]...) -> [String] { | ||
let allPaths = paths.flatMap { $0 } | ||
let excludedPaths = self.excludedPaths | ||
.parallelFlatMap { @Sendable in Glob.resolveGlob($0) } | ||
.map { $0.absolutePathStandardized() } | ||
return allPaths.filter { path in | ||
!excludedPaths.contains { path.hasPrefix($0) } | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// | ||
// ExcludeByStrategy.swift | ||
// | ||
|
||
public protocol ExcludeByStrategy { | ||
func filterExcludedPaths(in paths: [String]...) -> [String] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Foundation | ||
|
||
class ExcludeByStrategyFactory { | ||
static func createExcludeByStrategy(options: LintOrAnalyzeOptions, | ||
|
||
configuration: Configuration, | ||
fileManager: some LintableFileManager = FileManager.default) | ||
-> any ExcludeByStrategy { | ||
if options.useExcludingByPrefix { | ||
return ExcludeByPrefixStrategy(excludedPaths: configuration.excludedPaths) | ||
} | ||
|
||
return ExcludeByPathsByExpandingSubPaths(configuration: configuration, fileManager: fileManager) | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.