Last active
October 6, 2018 16:10
-
-
Save Stradivario/c7c2183e55e89fa757c31225f94390fd to your computer and use it in GitHub Desktop.
Asynchronous reading folder structure in NodeJS with @rxdi/core and rxjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Service } from "@rxdi/core"; | |
import { switchMap } from "rxjs/operators"; | |
import { stat, Stats, readdir } from "fs"; | |
import { resolve } from "path"; | |
import { from } from "rxjs"; | |
@Service() | |
export class FileService { | |
units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; | |
results: string[] = []; | |
async wholeReadDirRecursive(path: string = '.') { | |
const directory = await this.readDir(path); | |
const pathinternal = path; | |
const self = this; | |
return (await Promise.all(directory.map(async file => { | |
const path = resolve(pathinternal, file); | |
const stat = await this.statAsync(path); | |
if (stat && stat.isDirectory()) { | |
if (!file.includes('node_modules')) { | |
await self.wholeReadDirRecursive.bind(self)(path); | |
} else { | |
return null; | |
} | |
} else { | |
this.results = [...this.results, path]; | |
} | |
}))).filter(a => !!a); | |
} | |
async readCurrentDirFlat(path: string = '.') { | |
return (await this.readDir(path)).map(file => resolve(path, file)).filter(a => !!a); | |
} | |
async listFolder(folder: string) { | |
return await new Promise((resolve, reject) => { | |
from(this.readCurrentDirFlat(folder)) | |
.pipe( | |
switchMap((res) => this.map(res)) | |
) | |
.subscribe(res => resolve(res), e => reject(e)); | |
}); | |
} | |
async readDir(folder: string, limit: number = 200) { | |
return await new Promise<string[]>((resolve, reject) => { | |
readdir(folder, (err, list: string[]) => { | |
if (err) { | |
reject(err); | |
} else { | |
let count = 0; | |
resolve(list.map(f => { | |
count++; | |
if (limit > count) { | |
return f; | |
} else { | |
return null; | |
} | |
}).filter(res => !!res)); | |
} | |
}); | |
}); | |
} | |
async map(res) { | |
let foldersCount = 100; | |
let counter = 0; | |
return (await Promise.all(res.map(async (r) => { | |
counter++; | |
const mapping = { | |
path: r, | |
directory: null, | |
file: null, | |
name: null, | |
status: null | |
}; | |
const status: Stats = await this.statAsync(r); | |
if (!status.isDirectory || status && status['prototype'] === String) { | |
return null; | |
} | |
if (status.isDirectory()) { | |
mapping.directory = true; | |
} else { | |
mapping.file = true; | |
} | |
mapping.name = r.split("/").pop(); | |
mapping.path = r.replace(process.cwd(), '.'); | |
if (process.argv.toString().includes('--enable-full-folder-access')) { | |
mapping.path = r; | |
} | |
mapping.status = status; | |
mapping.status.size = this.niceBytes(status.size); | |
if (counter === foldersCount) { | |
return null; | |
} | |
return mapping; | |
}))).filter(res => !!res); | |
} | |
private niceBytes(x) { | |
let l = 0, n = parseInt(x, 10) || 0; | |
while (n >= 1024 && ++l) | |
n = n / 1024; | |
return (n.toFixed(n >= 10 || l < 1 ? 0 : 1) + ' ' + this.units[l]); | |
} | |
async statAsync(path: string): Promise<any> { | |
return await new Promise((resolve, reject) => { | |
stat(path, (e, stats) => { | |
if (e) { | |
reject(e); | |
} | |
resolve(stats); | |
}) | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment