import { unimplemented, assert } from "../testing/asserts.ts";import { join } from "../path/mod.ts";const { readdir, readdirSync, stat, statSync } = Deno;
export interface WalkOptions { maxDepth?: number; includeFiles?: boolean; includeDirs?: boolean; followSymlinks?: boolean; exts?: string[]; match?: RegExp[]; skip?: RegExp[];}
function include( filename: string, exts?: string[], match?: RegExp[], skip?: RegExp[]): boolean { if (exts && !exts.some((ext): boolean => filename.endsWith(ext))) { return false; } if (match && !match.some((pattern): boolean => !!filename.match(pattern))) { return false; } if (skip && skip.some((pattern): boolean => !!filename.match(pattern))) { return false; } return true;}
export interface WalkEntry { filename: string; info: Deno.FileInfo;}
export async function* walk( root: string, { maxDepth = Infinity, includeFiles = true, includeDirs = true, followSymlinks = false, exts = undefined, match = undefined, skip = undefined, }: WalkOptions = {}): AsyncIterableIterator<WalkEntry> { if (maxDepth < 0) { return; } if (includeDirs && include(root, exts, match, skip)) { yield { filename: root, info: await stat(root) }; } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { return; } for await (const dirEntry of readdir(root)) { if (dirEntry.isSymlink) { if (followSymlinks) { unimplemented(); } else { continue; } }
const filename = join(root, dirEntry.name);
if (dirEntry.isFile) { if (includeFiles && include(filename, exts, match, skip)) { yield { filename, info: dirEntry }; } } else { yield* walk(filename, { maxDepth: maxDepth - 1, includeFiles, includeDirs, followSymlinks, exts, match, skip, }); } }}
export function* walkSync( root: string, { maxDepth = Infinity, includeFiles = true, includeDirs = true, followSymlinks = false, exts = undefined, match = undefined, skip = undefined, }: WalkOptions = {}): IterableIterator<WalkEntry> { if (maxDepth < 0) { return; } if (includeDirs && include(root, exts, match, skip)) { yield { filename: root, info: statSync(root) }; } if (maxDepth < 1 || !include(root, undefined, undefined, skip)) { return; } for (const dirEntry of readdirSync(root)) { if (dirEntry.isSymlink) { if (followSymlinks) { unimplemented(); } else { continue; } }
assert(dirEntry.name != null); const filename = join(root, dirEntry.name);
if (dirEntry.isFile) { if (includeFiles && include(filename, exts, match, skip)) { yield { filename, info: dirEntry }; } } else { yield* walkSync(filename, { maxDepth: maxDepth - 1, includeFiles, includeDirs, followSymlinks, exts, match, skip, }); } }}