import FilenameMatcher import Foundation extension Configuration { // MARK: Lintable Paths /// Returns the files that can be linted by SwiftLint in the specified parent path. /// /// - parameter path: The parent path in which to search for lintable files. Can be a directory or a /// file. /// - parameter forceExclude: Whether or not excludes defined in this configuration should be applied even if /// `path` is an exact match. /// - parameter excludeByPrefix: Whether or not it uses the exclude-by-prefix algorithm. /// /// - returns: Files to lint. public func lintableFiles(inPath path: String, forceExclude: Bool, excludeByPrefix: Bool) -> [SwiftLintFile] { lintablePaths(inPath: path, forceExclude: forceExclude, excludeByPrefix: excludeByPrefix) .parallelCompactMap { SwiftLintFile(pathDeferringReading: $0) } } /// Returns the paths for files that can be linted by SwiftLint in the specified parent path. /// /// - parameter path: The parent path in which to search for lintable files. Can be a directory or a /// file. /// - parameter forceExclude: Whether or not excludes defined in this configuration should be applied even if /// `path` is an exact match. /// - parameter excludeByPrefix: Whether or not it uses the exclude-by-prefix algorithm. /// - parameter fileManager: The lintable file manager to use to search for lintable files. /// /// - returns: Paths for files to lint. func lintablePaths( inPath path: String, forceExclude: Bool, excludeByPrefix: Bool, fileManager: some LintableFileManager = FileManager.default ) -> [String] { let excluder = createExcluder(excludeByPrefix: excludeByPrefix) // Handle single file path. if path.isFile { return fileManager.filesToLint( inPath: path, rootDirectory: rootDirectory, excluder: forceExclude ? excluder : .noExclusion ) } // With no included paths, we lint everything in the given path. if includedPaths.isEmpty { return fileManager.filesToLint( inPath: path, rootDirectory: rootDirectory, excluder: excluder ) } // With included paths, only lint them (after resolving globs). let pathsToLint = includedPaths.flatMap(Glob.resolveGlob).parallelFlatMap { fileManager.filesToLint( inPath: $0, rootDirectory: rootDirectory, excluder: excluder ) } // Duplicates may arise, so make them unique. return makeUnique(paths: pathsToLint) } private func makeUnique(paths: [String]) -> [String] { #if os(Linux) let result = NSMutableOrderedSet(capacity: paths.count) result.addObjects(from: paths) #else let result = NSOrderedSet(array: paths) #endif return result.array as! [String] // swiftlint:disable:this force_cast } func filteredPaths(in paths: [String], excludeByPrefix: Bool) -> [String] { let excluder = createExcluder(excludeByPrefix: excludeByPrefix) return paths.filter { !excluder.excludes(path: $0) } } private func createExcluder(excludeByPrefix: Bool) -> Excluder { if excludedPaths.isEmpty { return .noExclusion } if excludeByPrefix { return .byPrefix( prefixes: excludedPaths .flatMap { Glob.resolveGlob($0) } .map { $0.absolutePathStandardized() } ) } return .matching( matchers: excludedPaths.flatMap { Glob.createFilenameMatchers(root: rootDirectory, pattern: $0) } ) } }