From a9eda9b9e17ab4de74d3b68c83b192950218c08a Mon Sep 17 00:00:00 2001 From: MrKleeblatt <66536608+MrKleeblatt@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:07:44 +0200 Subject: [PATCH] feat(fs/walk): include symlink option (#3464) Co-authored-by: Yoshiya Hinosawa --- fs/expand_glob_test.ts | 3 +++ fs/walk.ts | 20 ++++++++++++++++++-- fs/walk_test.ts | 6 ++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/fs/expand_glob_test.ts b/fs/expand_glob_test.ts index 61d1993fd..4a2970ffc 100644 --- a/fs/expand_glob_test.ts +++ b/fs/expand_glob_test.ts @@ -51,6 +51,7 @@ Deno.test("expandGlobWildcard", async function () { "abc", "abcdef", "abcdefghi", + "link", "subdir", ]); }); @@ -70,6 +71,7 @@ Deno.test("expandGlobParent", async function () { "abc", "abcdef", "abcdefghi", + "link", "subdir", ]); }); @@ -118,6 +120,7 @@ Deno.test("expandGlobGlobstarFalseWithGlob", async function () { "abc", "abcdef", "abcdefghi", + "link", "subdir", ]); }); diff --git a/fs/walk.ts b/fs/walk.ts index 05323f63b..9153c29ea 100644 --- a/fs/walk.ts +++ b/fs/walk.ts @@ -55,6 +55,8 @@ export interface WalkOptions { includeFiles?: boolean; /** @default {true} */ includeDirs?: boolean; + /** @default {true} */ + includeSymlinks?: boolean; /** @default {false} */ followSymlinks?: boolean; exts?: string[]; @@ -84,6 +86,7 @@ export async function* walk( maxDepth = Infinity, includeFiles = true, includeDirs = true, + includeSymlinks = true, followSymlinks = false, exts = undefined, match = undefined, @@ -108,7 +111,12 @@ export async function* walk( let { isSymlink, isDirectory } = entry; if (isSymlink) { - if (!followSymlinks) continue; + if (!followSymlinks) { + if (includeSymlinks && include(path, exts, match, skip)) { + yield { path, ...entry }; + } + continue; + } path = await Deno.realPath(path); // Caveat emptor: don't assume |path| is not a symlink. realpath() // resolves symlinks but another process can replace the file system @@ -121,6 +129,7 @@ export async function* walk( maxDepth: maxDepth - 1, includeFiles, includeDirs, + includeSymlinks, followSymlinks, exts, match, @@ -142,6 +151,7 @@ export function* walkSync( maxDepth = Infinity, includeFiles = true, includeDirs = true, + includeSymlinks = true, followSymlinks = false, exts = undefined, match = undefined, @@ -171,7 +181,12 @@ export function* walkSync( let { isSymlink, isDirectory } = entry; if (isSymlink) { - if (!followSymlinks) continue; + if (!followSymlinks) { + if (includeSymlinks && include(path, exts, match, skip)) { + yield { path, ...entry }; + } + continue; + } path = Deno.realPathSync(path); // Caveat emptor: don't assume |path| is not a symlink. realpath() // resolves symlinks but another process can replace the file system @@ -184,6 +199,7 @@ export function* walkSync( maxDepth: maxDepth - 1, includeFiles, includeDirs, + includeSymlinks, followSymlinks, exts, match, diff --git a/fs/walk_test.ts b/fs/walk_test.ts index a37b5e190..a82768cad 100644 --- a/fs/walk_test.ts +++ b/fs/walk_test.ts @@ -78,6 +78,12 @@ Deno.test("[fs/walk] symlink", async () => followSymlinks: true, })); +Deno.test("[fs/walk] symlink without followSymlink", async () => { + await assertWalkPaths("symlink", [".", "x", "y"], { + followSymlinks: false, + }); +}); + Deno.test("[fs/walk] non-existent root", async () => { const root = resolve(testdataDir, "non_existent"); await assertRejects(