UNPKG

fs-utilities

Version:

utility module for interacting with the file system e.g. asynchronously retreiving list of folders

210 lines (173 loc) 6.88 kB
/* jslint node: true */ var fs = require('fs'); var path = require('path'); var async = require('async'); /** * @callback errorDataCallback * @param {Object|null} err - contains an object representing an occured error or null * @param {*} data - returned data */ /** * @callback dataCallback * @param {*} data - returned data */ /** * @callback errorCallback * @param {Object|null} err - contains an object representing an occured error or null */ /** * Creates a new NotAFolderError object. * * @constructor * @augments Error * @param {string} fileName - name of the file that is not a directory */ function NotAFolderError( fileName ) { this.name = "NotAFolderError"; this.message = fileName + ' is not a directory'; } NotAFolderError.prototype = Error.prototype; /** * Asynchronously tests if the specified file is a directory. * * @param {string} directoryPath - fullpath to file which should be tested * @param {errorDataCallback} callback - will be executed after test finished. If `directoryPath` is not * a folder, second callback argument will be undefined. */ function checkIfIsDirectory( directoryPath, callback ){ fs.stat( directoryPath, function( err, stats ){ if( err ){ callback( err ); } else if( stats.isDirectory() ){ callback( null, directoryPath ); } else { callback( new NotAFolderError( directoryPath ) ); } }); } /** * Synchron function to test if the specified file is a directory. * * @param {string} directoryPath - fullpath to file which should be tested * @returns {Boolean} true if tested file is indeed a folder */ function checkIfIsDirectorySync( directoryPath ){ var stats = fs.statSync( directoryPath ); return stats.isDirectory(); } /** * Asynchron function which will pass an array containing all subfolders of the given directory * to the also passed callback function. * * @param {string} directoryPath - path to look for subfolders * @param {errorDataCallback} callback - will be executed after all subfolders have been detected. * If case of an error, the search will be aborted and the second * argument of the callback function will be undefined. */ function getSubfolders( directoryPath, callback ){ var folders = []; var iteratorFunction = function( item, finishedCallback ){ var fullFilePath = path.join( directoryPath, item ); checkIfIsDirectory( fullFilePath, function( err, folder ){ if( !err ){ folders.push( folder ); } else if( !(err instanceof NotAFolderError) ){ finishedCallback( err ); } finishedCallback(); }); }; // get all files contained in the folder $directoryPath fs.readdir( directoryPath, function( err, files ){ if( err ){ callback( err ); } // iterate through those files and add all found folders to $folders async.each( files, iteratorFunction, function( err ){ callback( err, folders ); }); }); } /** * Synchronously generates and returns an array containing all subfolders of the given directory. * * @param {string} directoryPath - path to look for subfolders * @returns {string[]} array containing the full path of all subfolders located in directoryPath */ function getSubfoldersSync( directoryPath ){ var files = fs.readdirSync( directoryPath ); var fullFileName; var folders = []; var i; for( i in files ){ fullFileName = path.join( directoryPath, files[i] ); if( checkIfIsDirectorySync( fullFileName ) ){ folders.push( fullFileName ); } } return folders; } /** * Asynchron function which will recursively traverse all subfolers. * * @param {string} directoryPath - path from where to start traversing * @param {dataCallback} callback - will be called for each traversed folder * @param {string[]} [opt_excludedDirectories] - list of folders that will be skiped * @param {errorCallback} [opt_finishedCallback] - function that is called after all subfolders * have been traversed */ function traverseAllSubFolders( directoryPath, callback, opt_excludedDirectories, opt_finishedCallback ){ opt_excludedDirectories = opt_excludedDirectories || []; opt_finishedCallback = opt_finishedCallback || function(){}; var iteratorFunction = function( item, iteratorCallback ){ var folderName = path.basename( item ); if( opt_excludedDirectories.indexOf( folderName ) === -1 ){ callback( item ); traverseAllSubFolders( item, callback, opt_excludedDirectories, iteratorCallback ); } else { iteratorCallback(); } }; getSubfolders( directoryPath, function( err, folders ){ if( ! err ){ async.each( folders, iteratorFunction, opt_finishedCallback); } else { opt_finishedCallback( err ); } }); } /** * Synchronous function which will recursively traverse all subfolers. * * @param {string} directoryPath - path from where to start traversing * @param {dataCallback} callback - will be called for each traversed folder * @param {string[]} [opt_excludedDirectories] - list of folders that will be skiped */ function traverseAllSubFoldersSync( directoryPath, callback, opt_excludedDirectories ){ opt_excludedDirectories = opt_excludedDirectories || []; var folders = getSubfoldersSync( directoryPath ); var folderName; var i; for( i in folders ){ folderName = path.basename( folders[i] ); if( opt_excludedDirectories.indexOf( folderName ) === -1 ){ callback( folders[i] ); traverseAllSubFoldersSync( folders[i], callback, opt_excludedDirectories ); } } } module.exports.NotAFolderError = NotAFolderError; module.exports.checkIfIsDirectory = checkIfIsDirectory; module.exports.checkIfIsDirectorySync = checkIfIsDirectorySync; module.exports.getSubfolders = getSubfolders; module.exports.getSubfoldersSync = getSubfoldersSync; module.exports.traverseAllSubFolders = traverseAllSubFolders; module.exports.traverseAllSubFoldersSync = traverseAllSubFoldersSync; // legacy module.exports.getSubfoders = getSubfolders; module.exports.getSubfodersSync = getSubfoldersSync;