diff --git a/fs/walk.ts b/fs/walk.ts index 600e301cfa3f..51dc70ceef49 100644 --- a/fs/walk.ts +++ b/fs/walk.ts @@ -469,7 +469,10 @@ export async function* walk( if (exts) { exts = exts.map((ext) => ext.startsWith(".") ? ext : `.${ext}`); } - if (includeDirs && include(root, exts, match, skip)) { + // Directories don't have file extensions, so the `exts` filter must not be + // applied when deciding whether to yield a directory entry. The `match` + // and `skip` regex filters still apply. See #6736. + if (includeDirs && include(root, undefined, match, skip)) { yield await createWalkEntry(root); } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { @@ -898,7 +901,10 @@ export function* walkSync( if (maxDepth < 0) { return; } - if (includeDirs && include(root, exts, match, skip)) { + // Directories don't have file extensions, so the `exts` filter must not + // be applied when deciding whether to yield a directory entry. The + // `match` and `skip` regex filters still apply. See #6736. + if (includeDirs && include(root, undefined, match, skip)) { yield createWalkEntrySync(root); } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { diff --git a/fs/walk_test.ts b/fs/walk_test.ts index ae507dd3ad25..68f9ef453eea 100644 --- a/fs/walk_test.ts +++ b/fs/walk_test.ts @@ -113,23 +113,42 @@ Deno.test("walkSync() accepts includeFiles option set to false", () => includeFiles: false, })); +// `includeDirs` defaults to true, so the root directory entry is also +// expected. `exts` no longer filters directories (see #6736). Deno.test("walk() accepts ext option as strings", async () => - await assertWalkPaths(testdataDir, "ext", ["y.rs", "x.ts"], { + await assertWalkPaths(testdataDir, "ext", [".", "y.rs", "x.ts"], { exts: [".rs", ".ts"], })); Deno.test("walk() accepts ext option as strings (excluding period prefix)", async () => - await assertWalkPaths(testdataDir, "ext", ["y.rs", "x.ts"], { + await assertWalkPaths(testdataDir, "ext", [".", "y.rs", "x.ts"], { exts: ["rs", "ts"], })); Deno.test("walkSync() accepts ext option as strings", () => - assertWalkSyncPaths(testdataDir, "ext", ["y.rs", "x.ts"], { + assertWalkSyncPaths(testdataDir, "ext", [".", "y.rs", "x.ts"], { exts: [".rs", ".ts"], })); Deno.test("walkSync() accepts ext option as strings (excluding period prefix)", () => + assertWalkSyncPaths(testdataDir, "ext", [".", "y.rs", "x.ts"], { + exts: [".rs", ".ts"], + })); + +// https://github.com/denoland/std/issues/6736 — explicit includeDirs:false +// still drops the directory when an `exts` filter is set. Before the fix, +// includeDirs:true also dropped it (because the dir name had no extension); +// after the fix, the dir is yielded as expected (verified by the strings +// tests above). +Deno.test("walk() with exts and includeDirs:false yields only files", async () => + await assertWalkPaths(testdataDir, "ext", ["y.rs", "x.ts"], { + includeDirs: false, + exts: [".rs", ".ts"], + })); + +Deno.test("walkSync() with exts and includeDirs:false yields only files", () => assertWalkSyncPaths(testdataDir, "ext", ["y.rs", "x.ts"], { + includeDirs: false, exts: [".rs", ".ts"], }));