diff options
author | Chris Knight <cknight1234@gmail.com> | 2020-03-12 14:12:27 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-12 10:12:27 -0400 |
commit | cabe63eb05f334bc9921dc8633b254b05519b434 (patch) | |
tree | 4e6ad72e742a2acca605c0cf253e1f97586ce9da /std/node/_fs/_fs_dir.ts | |
parent | 3ed6ccc905394ed9c5d9cbcb8fa2426151780788 (diff) |
fix: Node polyfill fsAppend rework (#4322)
* My original implementation of `fs.appendFile` used an async API, which, though
it would work fine as a polyfill, wasn't an exact match with the Node API. This PR
reworks that API to mimic the Node API fully as a synchronous void function with
an async internal implementation.
* Refactor move of other internal fs `dirent` and `dir` classes to the _fs internal
directory.
Diffstat (limited to 'std/node/_fs/_fs_dir.ts')
-rw-r--r-- | std/node/_fs/_fs_dir.ts | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/std/node/_fs/_fs_dir.ts b/std/node/_fs/_fs_dir.ts new file mode 100644 index 000000000..e3830bb31 --- /dev/null +++ b/std/node/_fs/_fs_dir.ts @@ -0,0 +1,114 @@ +import Dirent from "./_fs_dirent.ts"; + +export default class Dir { + private dirPath: string | Uint8Array; + private files: Dirent[] = []; + private filesReadComplete = false; + + constructor(path: string | Uint8Array) { + this.dirPath = path; + } + + get path(): string { + if (this.dirPath instanceof Uint8Array) { + return new TextDecoder().decode(this.dirPath); + } + return this.dirPath; + } + + /** + * NOTE: Deno doesn't provide an interface to the filesystem like readdir + * where each call to readdir returns the next file. This function simulates this + * behaviour by fetching all the entries on the first call, putting them on a stack + * and then popping them off the stack one at a time. + * + * TODO: Rework this implementation once https://github.com/denoland/deno/issues/4218 + * is resolved. + */ + read(callback?: Function): Promise<Dirent | null> { + return new Promise(async (resolve, reject) => { + try { + if (this.initializationOfDirectoryFilesIsRequired()) { + const denoFiles: Deno.FileInfo[] = await Deno.readdir(this.path); + this.files = denoFiles.map(file => new Dirent(file)); + } + const nextFile = this.files.pop(); + if (nextFile) { + resolve(nextFile); + this.filesReadComplete = this.files.length === 0; + } else { + this.filesReadComplete = true; + resolve(null); + } + if (callback) { + callback(null, !nextFile ? null : nextFile); + } + } catch (err) { + if (callback) { + callback(err, null); + } + reject(err); + } + }); + } + + readSync(): Dirent | null { + if (this.initializationOfDirectoryFilesIsRequired()) { + this.files.push( + ...Deno.readdirSync(this.path).map(file => new Dirent(file)) + ); + } + const dirent: Dirent | undefined = this.files.pop(); + this.filesReadComplete = this.files.length === 0; + + return !dirent ? null : dirent; + } + + private initializationOfDirectoryFilesIsRequired(): boolean { + return this.files.length === 0 && !this.filesReadComplete; + } + + /** + * Unlike Node, Deno does not require managing resource ids for reading + * directories, and therefore does not need to close directories when + * finished reading. + */ + close(callback?: Function): Promise<void> { + return new Promise((resolve, reject) => { + try { + if (callback) { + callback(null); + } + resolve(); + } catch (err) { + if (callback) { + callback(err); + } + reject(err); + } + }); + } + + /** + * Unlike Node, Deno does not require managing resource ids for reading + * directories, and therefore does not need to close directories when + * finished reading + */ + closeSync(): void { + //No op + } + + async *[Symbol.asyncIterator](): AsyncIterableIterator<Dirent> { + try { + while (true) { + const dirent: Dirent | null = await this.read(); + if (dirent === null) { + break; + } + yield dirent; + } + } finally { + await this.close(); + } + } +} |