diff --git a/fs/unstable_read_dir.ts b/fs/unstable_read_dir.ts index f41b05f44d93..99fd7bb0ac48 100644 --- a/fs/unstable_read_dir.ts +++ b/fs/unstable_read_dir.ts @@ -5,9 +5,14 @@ import { mapError } from "./_map_error.ts"; import { toDirEntry } from "./_to_dir_entry.ts"; import type { DirEntry } from "./unstable_types.ts"; -/** Reads the directory given by `path` and returns an async iterable of +/** + * Reads the directory given by `path` and returns an async iterable of * {@linkcode DirEntry}. The order of entries is not guaranteed. * + * Throws Error if `path` is not a directory. + * + * Requires `allow-read` permission. + * * @example Usage * ```ts * import { readDir } from "@std/fs/unstable-read-dir"; @@ -17,12 +22,10 @@ import type { DirEntry } from "./unstable_types.ts"; * } * ``` * - * Throws error if `path` is not a directory. - * - * Requires `allow-read` permission. - * * @tags allow-read - * @category File System + * + * @param path The path to the directory. + * @returns An async iterable of `DirEntry` elements. */ export async function* readDir(path: string | URL): AsyncIterable { if (isDeno) { @@ -38,3 +41,40 @@ export async function* readDir(path: string | URL): AsyncIterable { } } } + +/** + * Synchronously reads the directory given by `path` and returns an iterable + * of {@linkcode Deno.DirEntry}. The order of entries is not guaranteed. + * + * Throws Error if `path` is not a directory. + * + * Requires `allow-read` permission. + * + * @example Usage + * ```ts + * import { readDirSync } from "@std/fs/unstable-read-dir"; + * + * for (const dirEntry of readDirSync("/")) { + * console.log(dirEntry.name); + * } + * ``` + * + * @tags allow-read + * + * @param path The path to the directory. + * @returns An iterator object of `DirEntry` elements. + */ +export function* readDirSync(path: string | URL): IteratorObject { + if (isDeno) { + return yield* Deno.readDirSync(path); + } else { + try { + const dir = getNodeFs().readdirSync(path, { withFileTypes: true }); + for (const entry of dir) { + yield toDirEntry(entry); + } + } catch (error) { + throw mapError(error); + } + } +} diff --git a/fs/unstable_read_dir_test.ts b/fs/unstable_read_dir_test.ts index c955798989e5..0154081cf00b 100644 --- a/fs/unstable_read_dir_test.ts +++ b/fs/unstable_read_dir_test.ts @@ -1,8 +1,8 @@ // Copyright 2018-2025 the Deno authors. MIT license. -import { assert, assertEquals, assertRejects } from "@std/assert"; +import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert"; import { fromFileUrl, join, resolve } from "@std/path"; -import { readDir } from "./unstable_read_dir.ts"; +import { readDir, readDirSync } from "./unstable_read_dir.ts"; import { NotFound } from "./unstable_errors.js"; const testdataDir = resolve(fromFileUrl(import.meta.url), "../testdata"); @@ -32,10 +32,37 @@ Deno.test("readDir() rejects when the path is not a directory", async () => { }); Deno.test("readDir() rejects when the directory does not exist", async () => { - await assertRejects( - async () => { - await readDir("non_existent_dir")[Symbol.asyncIterator]().next(); - }, - NotFound, - ); + await assertRejects(async () => { + await readDir("non_existent_dir")[Symbol.asyncIterator]().next(); + }, NotFound); +}); + +Deno.test("readDirSync() reads from the directory and its subdirectories", () => { + const files = []; + for (const e of readDirSync(testdataDir)) { + files.push(e); + } + + let counter = 0; + for (const f of files) { + if (f.name === "walk") { + assert(f.isDirectory); + counter++; + } + } + + assertEquals(counter, 1); +}); + +Deno.test("readDirSync() throws with Error when the path is not a directory", () => { + assertThrows(() => { + const testFile = join(testdataDir, "0.ts"); + readDirSync(testFile)[Symbol.iterator]().next(); + }, Error); +}); + +Deno.test("readDirSync() throws with NotFound when a directory does not exist", () => { + assertThrows(() => { + readDirSync("non_existent_dir")[Symbol.iterator]().next(); + }, NotFound); });