UNPKG

@bevry/fs-list

Version:

List the entire contents of a directory.

189 lines (188 loc) 7.03 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.readdirFileTypes = exports.readdirRecursive = void 0; // builtin const fs_1 = require("fs"); const path_1 = require("path"); // versions const process_1 = require("process"); const version_compare_1 = __importDefault(require("version-compare")); const nodeVersion = String(process_1.versions.node || '0'); // external const fs_accessible_1 = __importStar(require("@bevry/fs-accessible")); const errlop_1 = __importDefault(require("errlop")); /** * List the entire contents of a directory, for Node.js versions 18.7.0 and up. 110-120ms. * @returns the subpaths of the directory, sorted alphabetically. * @experimental used internally, however external use is for your curiosity */ async function readdirRecursive(directory) { return new Promise(function (resolve, reject) { (0, fs_1.readdir)(directory, { encoding: null, recursive: true }, function (err, files) { if (err) reject(err); else resolve(files.sort()); }); }); } exports.readdirRecursive = readdirRecursive; /** Helper for {@link readdirStat} to fetch {@link Stats} */ async function statHelper(path) { return new Promise(function (resolve, reject) { (0, fs_1.stat)(path, function (err, stats) { if (err) reject(err); else resolve(stats); }); }); } /** Helper for {@link readdirStat} to fetch {@link Paths} */ async function readdirHelper(directory) { return new Promise(function (resolve, reject) { (0, fs_1.readdir)(directory, function (err, files) { if (err) reject(err); else resolve(files); }); }); } /** * List the entire contents of a directory, for all Node.js versions. 70-80ms. * @returns the subpaths of the directory, sorted alphabetically. * @experimental used internally, however external use is for your curiosity */ async function readdirStat(directory) { // prepare const pending = [directory]; const results = []; const trim = directory === '.' ? 0 : directory.length + 1; // add subsequent while (pending.length) { await Promise.all(pending.splice(0, pending.length).map(async function (subdirectory) { const files = await readdirHelper(subdirectory); for (const file of files) { const path = (0, path_1.join)(subdirectory, file); const stat = await statHelper(path); results.push(trim ? path.substring(trim) : path); if (stat.isDirectory()) pending.push(path); } })); } // return sorted results return results.sort(); } /** Helper for {@link readdirFileTypes} to fetch {@link Dirent} */ async function readdirFileTypesHelper(directory) { return new Promise(function (resolve, reject) { (0, fs_1.readdir)(directory, { withFileTypes: true }, function (err, files) { if (err) reject(err); else resolve(files); }); }); } /** * List the entire contents of a directory, for Node.js versions 10 and up. 70-80ms. * @returns the subpaths of the directory, sorted alphabetically. * @experimental used internally, however external use is for your curiosity */ async function readdirFileTypes(directory) { // prepare const pending = [directory]; const results = []; const trim = directory === '.' ? 0 : directory.length + 1; // add subsequent while (pending.length) { await Promise.all(pending.splice(0, pending.length).map(async function (subdirectory) { const files = await readdirFileTypesHelper(subdirectory); for (const file of files) { const path = (0, path_1.join)(subdirectory, file.name); results.push(trim ? path.substring(trim) : path); if (file.isDirectory()) pending.push(path); } })); } // return sorted results return results.sort(); } exports.readdirFileTypes = readdirFileTypes; /** * List the entire contents of a directory, selecting the appropriate technique for the Node.js version. * @returns the subpaths of the directory, sorted alphabetically. */ async function list(directory) { // check accessible try { await (0, fs_accessible_1.default)(directory); } catch (err) { throw new errlop_1.default(`unable to list contents of the non-accessible directory: ${directory}`, err); } // check readable try { await (0, fs_accessible_1.default)(directory, fs_accessible_1.R_OK); } catch (err) { throw new errlop_1.default(`unable to list contents of the non-readable directory: ${directory}`, err); } // fatest method try { return (0, version_compare_1.default)(nodeVersion, '18.7.0') >= 0 ? await readdirRecursive(directory) : (0, version_compare_1.default)(nodeVersion, '10') >= 0 ? await readdirFileTypes(directory) : await readdirStat(directory); } catch (err) { throw new errlop_1.default(`unable to list contents of the directory: ${directory}`, err); } } exports.default = list; // 100-110ms, macOS only // import { exec } from 'child_process' // async function readdirFind(directory: string): Promise<Paths> { // return new Promise(function (resolve, reject) { // exec('find .', { cwd: directory }, function (err, stdout: string) { // if (err) return reject(err) // return resolve( // stdout // .split('\n') // .map((p) => p.replace(/^[./\\]+/, '')) // trim . and ./ // .filter(Boolean) // .sort() // ) // }) // }) // }