Stop descending into excluded directories
Docs / docs (push) Canceled after 0s
Docs / deploy (push) Canceled after 0s

The resolver skipped an excluded directory in its result but still
walked its subtree, so watches were installed below names such as
`.git` or `node_modules`. Exclusion now prunes the walk.
This commit is contained in:
T. R. Bernstein
2026-09-13 23:15:21 +02:00
parent 134034f3ea
commit c79691cb6f
2 changed files with 16 additions and 9 deletions
+6 -9
View File
@@ -13,11 +13,7 @@ public struct DirectoryResolver {
for path in paths { for path in paths {
let path = FilePath(path) let path = FilePath(path)
resolved.append(path) resolved.append(path)
try await withSubdirectories(at: path, recursive: true) { subdirectoryPath in try await withSubdirectories(at: path, excluding: itemNames) { resolved.append($0) }
guard let basename = subdirectoryPath.lastComponent?.description else { return }
guard !itemNames.contains(basename) else { return }
resolved.append(subdirectoryPath)
}
} }
return resolved return resolved
@@ -36,14 +32,15 @@ public struct DirectoryResolver {
return entries return entries
} }
private static func withSubdirectories(at path: FilePath, recursive: Bool = false, body: (FilePath) async throws -> Void) async throws { /// Calls `body` for every subdirectory below `path`, depth first. Excluded
/// names are neither reported nor descended into.
private static func withSubdirectories(at path: FilePath, excluding itemNames: Set<String>, body: (FilePath) async throws -> Void) async throws {
let directoryHandle = try await fileManager.openDirectory(atPath: path) let directoryHandle = try await fileManager.openDirectory(atPath: path)
for try await childContent in directoryHandle.listContents() { for try await childContent in directoryHandle.listContents() {
guard childContent.type == .directory else { continue } guard childContent.type == .directory else { continue }
guard let name = childContent.path.lastComponent?.string, !itemNames.contains(name) else { continue }
try await body(childContent.path) try await body(childContent.path)
if recursive { try await withSubdirectories(at: childContent.path, excluding: itemNames, body: body)
try await withSubdirectories(at: childContent.path, recursive: recursive, body: body)
}
} }
try await directoryHandle.close() try await directoryHandle.close()
} }
@@ -14,4 +14,14 @@ struct DirectoryResolverTests {
#expect(directories.map { $0.description } == [dir, "\(dir)/Subfolder", subDirectory]) #expect(directories.map { $0.description } == [dir, "\(dir)/Subfolder", subDirectory])
} }
} }
@Test func doesNotDescendIntoExcludedDirectories() async throws {
try await withTempDir { dir in
let excludedSubdirectory = "\(dir)/Excluded/Inside"
try FileManager.default.createDirectory(atPath: excludedSubdirectory, withIntermediateDirectories: true)
let directories = try await DirectoryResolver.resolve(dir, excluding: ["Excluded"])
#expect(directories.map { $0.description } == [dir])
}
}
} }