diff options
Diffstat (limited to 'std/fs')
-rw-r--r-- | std/fs/walk.ts | 127 | ||||
-rw-r--r-- | std/fs/walk_test.ts | 20 |
2 files changed, 67 insertions, 80 deletions
diff --git a/std/fs/walk.ts b/std/fs/walk.ts index 60eb9b483..1655b63ab 100644 --- a/std/fs/walk.ts +++ b/std/fs/walk.ts @@ -14,31 +14,21 @@ export interface WalkOptions { exts?: string[]; match?: RegExp[]; skip?: RegExp[]; - onError?: (err: Error) => void; } -function patternTest(patterns: RegExp[], path: string): boolean { - // Forced to reset last index on regex while iterating for have - // consistent results. - // See: https://stackoverflow.com/a/1520853 - return patterns.some((pattern): boolean => { - const r = pattern.test(path); - pattern.lastIndex = 0; - return r; - }); -} - -function include(filename: string, options: WalkOptions): boolean { - if ( - options.exts && - !options.exts.some((ext): boolean => filename.endsWith(ext)) - ) { +function include( + filename: string, + exts?: string[], + match?: RegExp[], + skip?: RegExp[] +): boolean { + if (exts && !exts.some((ext): boolean => filename.endsWith(ext))) { return false; } - if (options.match && !patternTest(options.match, filename)) { + if (match && !match.some((pattern): boolean => !!filename.match(pattern))) { return false; } - if (options.skip && patternTest(options.skip, filename)) { + if (skip && skip.some((pattern): boolean => !!filename.match(pattern))) { return false; } return true; @@ -62,7 +52,6 @@ export interface WalkInfo { * - exts?: string[]; * - match?: RegExp[]; * - skip?: RegExp[]; - * - onError?: (err: Error) => void; * * for await (const { filename, info } of walk(".")) { * console.log(filename); @@ -71,38 +60,29 @@ export interface WalkInfo { */ export async function* walk( root: string, - options: WalkOptions = {} + { + maxDepth = Infinity, + includeFiles = true, + includeDirs = true, + followSymlinks = false, + exts = null, + match = null, + skip = null + }: WalkOptions = {} ): AsyncIterableIterator<WalkInfo> { - const maxDepth = options.maxDepth != undefined ? options.maxDepth! : Infinity; if (maxDepth < 0) { return; } - if (options.includeDirs != false && include(root, options)) { - let rootInfo: FileInfo; - try { - rootInfo = await stat(root); - } catch (err) { - if (options.onError) { - options.onError(err); - return; - } - } - yield { filename: root, info: rootInfo! }; + if (includeDirs && include(root, exts, match, skip)) { + yield { filename: root, info: await stat(root) }; } - if (maxDepth < 1 || patternTest(options.skip || [], root)) { + if (maxDepth < 1 || !include(root, null, null, skip)) { return; } - let ls: FileInfo[] = []; - try { - ls = await readDir(root); - } catch (err) { - if (options.onError) { - options.onError(err); - } - } + const ls: FileInfo[] = await readDir(root); for (const info of ls) { if (info.isSymlink()) { - if (options.followSymlinks) { + if (followSymlinks) { // TODO(ry) Re-enable followSymlinks. unimplemented(); } else { @@ -113,11 +93,19 @@ export async function* walk( const filename = join(root, info.name!); if (info.isFile()) { - if (options.includeFiles != false && include(filename, options)) { + if (includeFiles && include(filename, exts, match, skip)) { yield { filename, info }; } } else { - yield* walk(filename, { ...options, maxDepth: maxDepth - 1 }); + yield* walk(filename, { + maxDepth: maxDepth - 1, + includeFiles, + includeDirs, + followSymlinks, + exts, + match, + skip + }); } } } @@ -125,38 +113,29 @@ export async function* walk( /** Same as walk() but uses synchronous ops */ export function* walkSync( root: string, - options: WalkOptions = {} + { + maxDepth = Infinity, + includeFiles = true, + includeDirs = true, + followSymlinks = false, + exts = null, + match = null, + skip = null + }: WalkOptions = {} ): IterableIterator<WalkInfo> { - const maxDepth = options.maxDepth != undefined ? options.maxDepth! : Infinity; if (maxDepth < 0) { return; } - if (options.includeDirs != false && include(root, options)) { - let rootInfo: FileInfo; - try { - rootInfo = statSync(root); - } catch (err) { - if (options.onError) { - options.onError(err); - return; - } - } - yield { filename: root, info: rootInfo! }; + if (includeDirs && include(root, exts, match, skip)) { + yield { filename: root, info: statSync(root) }; } - if (maxDepth < 1 || patternTest(options.skip || [], root)) { + if (maxDepth < 1 || !include(root, null, null, skip)) { return; } - let ls: FileInfo[] = []; - try { - ls = readDirSync(root); - } catch (err) { - if (options.onError) { - options.onError(err); - } - } + const ls: FileInfo[] = readDirSync(root); for (const info of ls) { if (info.isSymlink()) { - if (options.followSymlinks) { + if (followSymlinks) { unimplemented(); } else { continue; @@ -166,11 +145,19 @@ export function* walkSync( const filename = join(root, info.name!); if (info.isFile()) { - if (options.includeFiles != false && include(filename, options)) { + if (includeFiles && include(filename, exts, match, skip)) { yield { filename, info }; } } else { - yield* walkSync(filename, { ...options, maxDepth: maxDepth - 1 }); + yield* walkSync(filename, { + maxDepth: maxDepth - 1, + includeFiles, + includeDirs, + followSymlinks, + exts, + match, + skip + }); } } } diff --git a/std/fs/walk_test.ts b/std/fs/walk_test.ts index abd5adbcf..c0884175f 100644 --- a/std/fs/walk_test.ts +++ b/std/fs/walk_test.ts @@ -1,7 +1,10 @@ -const { cwd, chdir, makeTempDir, mkdir, open, remove } = Deno; +const { DenoError, ErrorKind, cwd, chdir, makeTempDir, mkdir, open } = Deno; +const { remove } = Deno; +type ErrorKind = Deno.ErrorKind; +type DenoError = Deno.DenoError<ErrorKind>; import { walk, walkSync, WalkOptions, WalkInfo } from "./walk.ts"; import { test, TestFunction, runIfMain } from "../testing/mod.ts"; -import { assertEquals } from "../testing/asserts.ts"; +import { assertEquals, assertThrowsAsync } from "../testing/asserts.ts"; export async function testWalk( setup: (arg0: string) => void | Promise<void>, @@ -232,14 +235,11 @@ testWalk( testWalk( async (_d: string): Promise<void> => {}, - async function onError(): Promise<void> { - assertReady(1); - const ignored = await walkArray("missing"); - assertEquals(ignored, ["missing"]); - let errors = 0; - await walkArray("missing", { onError: (_e): number => (errors += 1) }); - // It's 2 since walkArray iterates over both sync and async. - assertEquals(errors, 2); + async function nonexistentRoot(): Promise<void> { + const error = (await assertThrowsAsync(async () => { + await walkArray("nonexistent"); + }, DenoError)) as DenoError; + assertEquals(error.kind, ErrorKind.NotFound); } ); |