UNPKG

@bevry/fs-list

Version:

List the entire contents of a directory.

216 lines (215 loc) 8.73 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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; 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 */ function readdirRecursive(directory) { return __awaiter(this, void 0, void 0, function* () { 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} */ function statHelper(path) { return __awaiter(this, void 0, void 0, function* () { 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} */ function readdirHelper(directory) { return __awaiter(this, void 0, void 0, function* () { 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 */ function readdirStat(directory) { return __awaiter(this, void 0, void 0, function* () { // prepare const pending = [directory]; const results = []; const trim = directory === '.' ? 0 : directory.length + 1; // add subsequent while (pending.length) { yield Promise.all(pending.splice(0, pending.length).map(function (subdirectory) { return __awaiter(this, void 0, void 0, function* () { const files = yield readdirHelper(subdirectory); for (const file of files) { const path = (0, path_1.join)(subdirectory, file); const stat = yield 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} */ function readdirFileTypesHelper(directory) { return __awaiter(this, void 0, void 0, function* () { 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 */ function readdirFileTypes(directory) { return __awaiter(this, void 0, void 0, function* () { // prepare const pending = [directory]; const results = []; const trim = directory === '.' ? 0 : directory.length + 1; // add subsequent while (pending.length) { yield Promise.all(pending.splice(0, pending.length).map(function (subdirectory) { return __awaiter(this, void 0, void 0, function* () { const files = yield 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. */ function list(directory) { return __awaiter(this, void 0, void 0, function* () { // check accessible try { yield (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 { yield (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 ? yield readdirRecursive(directory) : (0, version_compare_1.default)(nodeVersion, '10') >= 0 ? yield readdirFileTypes(directory) : yield 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() // ) // }) // }) // }