FS

Copyright(c) 2016 Stefano Balietti MIT Licensed

Collection of static functions related to file system operations

(function(JSUS) {

    "use strict";

    if (!JSUS.isNodeJS()){
        JSUS.log('Cannot load JSUS.FS outside of Node.JS.');
        return false;
    }

    var resolve = require('resolve'),
    path = require('path'),
    fs = require('fs')


    function FS() {}

FS.existsSync

Backward-compatible version of fs.existsSync

    FS.existsSync = ('undefined' === typeof fs.existsSync) ?
        path.existsSync : fs.existsSync;

FS.resolveModuleDir

Resolves the root directory of a module

Npm does not install a dependency if the same module is available in a parent folder. This method returns the full path of the root directory of the specified module as installed by npm.

Trailing slash is added.

Params
module string The name of the module
basedir string Optional. The basedir from which to start searching
Returns
string The path of the root directory of the module
See
    FS.resolveModuleDir = function(module, basedir) {
        var str, stop;
        if ('string' !== typeof module) {
            throw new TypeError('FS.resolveModuleDir: module must be string.');
        }
        if (basedir && 'string' !== typeof basedir) {
            throw new TypeError('FS.resolveModuleDir: basedir must be ' +
                                'string or undefined.');
        }

Added this line because it might fail.

        if (module === 'JSUS') return path.resolve(__dirname, '..') + '/';
        str = resolve.sync(module, {basedir: basedir || __dirname});
        stop = str.indexOf(module) + module.length;
        return str.substr(0, stop) + '/';
    };

FS.deleteIfExists

Deletes a file or directory

Returns false if the file does not exist.

Params
file string The path to the file or directory
cb function Optional. A callback to execute after successful file deletion
Returns
boolean TRUE, if file is found. An error can still occurs during async removal
See
FS.cleanDir
    FS.deleteIfExists = function(file, cb) {
        var stats;
        if (!FS.existsSync(file)) {
            return false;
        }
        stats = fs.lstatSync(file);
        if (stats.isDirectory()) {
            fs.rmdir(file, function(err) {
                if (err) throw err;
                if (cb) cb();
            });
        }
        else {
            fs.unlink(file, function(err) {
                if (err) throw err;
                if (cb) cb();
            });
        }
        return true;
    };

FS.cleanDir

Removes all files from a target directory

It is possible to specify an extension as second parameter. In such case, only file with that extension will be removed. The '.' (dot) must be included as part of the extension.

Params
dir string The directory to clean
ext string Optional. If set, only files with this extension will be removed
cb function Optional. A callback function to call if no error is raised
Returns
boolean TRUE, if the operation is successful
See
FS.deleteIfExists
    FS.cleanDir = function(dir, ext, cb) {
        var filterFunc;
        if (!dir) {
            JSUS.log('You must specify a directory to clean.');
            return false;
        }
        if (ext) {
            filterFunc = function(file) {
                return path.extname(file) ===  ext;
            };
        }
        else {
            filterFunc = function() {
                return true;
            };
        }

        if (dir[dir.length] !== '/') dir = dir + '/';

        fs.readdir(dir, function(err, files) {
            var asq, mycb;
            if (err) {
                JSUS.log(err);
                return;
            }

Create async queue if a callback was specified.

            if (cb) asq = JSUS.getQueue();

Create a nested callback for the async queue, if necessary.

            files.filter(filterFunc).forEach(function(file) {
                if (cb) {
                    asq.add(file);
                    mycb = asq.getRemoveCb(file);
                }
                JSUS.deleteIfExists(dir + file, mycb);
            });

            if (cb) {
                asq.onReady(cb);
            }
        });

        return true;
    };

FS.copyFromDir

Copies all files from a source directory to a destination directory.

It is possible to specify an extension as second parameter (e.g. '.js'). In such case, only file with that extension will be copied.

Warning! If an extension filter is not specified, and if subdirectories are found, an error will occur.

Params
dirIn string The source directory
dirOut string The destination directory
ext string Optional. If set, only files with this extension will be copied
cb function Optional. A callback function to call if no error is raised
Returns
boolean TRUE, if the operation is successful
See
FS.copyFile
    FS.copyFromDir = function(dirIn, dirOut, ext, cb) {
        var i, dir, dirs, stats;
        if (!dirIn) {
            JSUS.log('You must specify a source directory.');
            return false;
        }
        if (!dirOut) {
            JSUS.log('You must specify a destination directory.');
            return false;
        }

        dirOut = path.resolve(dirOut) + '/';
        dirs = [dirIn, dirOut];

        for (i = 0; i < 2; i++) {
            dir = dirs[i];
            if (!FS.existsSync(dir)) {
                console.log(dir + ' does not exist.');
                return false;
            }

            stats = fs.lstatSync(dir);
            if (!stats.isDirectory()) {
                console.log(dir + ' is not a directory.');
                return false;
            }
        }

        fs.readdir(dirIn, function(err, files) {
            var asq, i, mycb;
            if (err) {
                JSUS.log(err);
                throw new Error();
            }

Create async queue if a callback was specified.

            if (cb) asq = JSUS.getQueue();
            for (i in files) {
                if (ext && path.extname(files[i]) !== ext) {
                    continue;
                }

Create a nested callback for the asq, if necessary.

                if (cb) {
                    asq.add(i);
                    mycb = asq.getRemoveCb(i);
                }
                FS.copyFile(dirIn + files[i], dirOut + files[i], mycb);
            }

            if (cb) {
                asq.onReady(cb);
            }
        });

        return true;
    };

FS.copyFile

Copies a file into another path

Params
srcFile string The source file
destFile string The destination file
cb function Optional. If set, the callback will be executed upon success
Returns
boolean TRUE, if the operation is successful
    FS.copyFile = function(srcFile, destFile, cb) {
        var fdr, fdw;
        fdr = fs.createReadStream(srcFile);
        fdw = fs.createWriteStream(destFile);
        fdr.on('end', function() {
            if (cb) return cb(null);
        });
        return fdr.pipe(fdw);
    };

    JSUS.extend(FS);

})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);