Home Identifier Source Repository

src/util/Util.js

/**
 * @module util.js
 * @author Joe Groseclose <@benderTheCrime>
 * @date 8/16/2015
 */

// System Modules
import fs from      'fs';
import util from    'util';

/**
 * @desc Util is a slient utility class which is not available via any provider
 * on the app object. The only way to access the methods on this class is to
 * import the module.
 * @extends util
 * @access private
 * @since 0.2.3
 */
class $Util {

    /**
     * @desc $Util empty function call helper
     * @since 0.2.3
     * @returns {undefined} undefined
     * @example $Util.noop(); // = undefined
     */
    static noop() {}
}
$Util = util._extend($Util, util);

/**
 * @desc Util is a silent utility class which is not available via any provider
 * on the app object. The only way to access the methods on this class is to
 * import the module. It holds methods quintessential to string manipulation.
 * @since 0.3.1
 */
class $StringUtil {

    /**
     * @desc Util helper to replace leading slashes
     * @since 0.2.3
     * @param {string} str [param=''] String to process
     * @returns {string} The str param with stripped leading slashes
     * @example 'test' === $StringUtil.removeTrailingLeadingSlashes('/test'); // true
     */
    static removeLeadingSlashes(str = '') {
        return str.replace(/(^(\/))/g, '');
    }

    /**
     * @desc Util helper to replace trailing slashes
     * @since 0.2.3
     * @param {string} str [param=''] String to process
     * @returns {string} The str param with stripped trailing slashes
     * @example 'test' === $StringUtil.removeTrailingLeadingSlashes('test/'); // true
     */
    static removeTrailingSlashes(str = '') {
        return str.replace(/((\/)$)/g, '');
    }

    /**
     * @desc Util helper to replace leading and trailing slashes
     * @since 0.2.3
     * @param {string} str [param=''] String to process
     * @returns {string} The str param with stripped trailing and leading slashes
     * @example 'test' === $StringUtil.removeTrailingLeadingSlashes('/test/'); // true
     */
    static removeTrailingLeadingSlashes(str = '') {
        return str.replace(/(^(\/)|(\/)$)/g, '');
    }

    /**
     * @desc Util helper to replace dash/slash separation with camelCase
     * @since 0.2.4
     * @param {string} str String to process
     * @returns {string} The str param converted to camelCase
     * @example $StringUtil.toCamel('test-test'); // = 'testTest'
     */
    static toCamel(str) {
        return str.toLowerCase().replace(
            /[-_][A-Za-z]/g, m => m.toUpperCase().replace(/[-_]/g, '')
        );
    }

    /**
     * @desc Util helper to replace camelCase with underscore_separation
     * @since 0.2.4
     * @param {string} str String to process
     * @returns {string} The str param converted to underscore_separation
     * @example $StringUtil.toCamel('testTest'); // = 'test_test'
     */
    static toUnderscore(str) {
        return this.toFormat(str, '_');
    }

    /**
     * @desc Util helper to replace camelCase with dash-separation
     * @since 0.2.4
     * @param {string} str String to process
     * @returns {string} The str param converted to dash-separation
     * @example $StringUtil.toDash('testTest'); // = 'test-test'
     */
    static toDash(str) {
        return this.toFormat(str, '-');
    }

    /**
     * @desc Util helper to perform `toDash` or `toUnderscore` style string
     * serilaization
     * @since 0.2.4
     * @param {string} str String to process
     * @param {string} del Character with which to replace camelCase capitals
     * @returns {string} The str param converted to `del` separation
     * @example $StringUtil.toFormat('testTest', '-'); // = 'test-test'
     * @example $StringUtil.toFormat('testTest', '_'); // = 'test_test'
     */
    static toFormat(str, del) {
        return str.replace(/([A-Z]+)/g, `${del}$1`).toLowerCase();
    }
}

/**
 * @desc $FileUtil is a silent utility class which is not available via any provider
 * on the app object. The only way to access the methods on this class is to
 * import the module. It holds methods quintessential to file management.
 * @since 0.3.1
 */
class $FileUtil {

    /**
     * @desc Util helper to help find files in the specified root
     * @since 0.2.4
     * @param {string} root The root directory in which to find files
     * @param {string} target The desired file name
     * @returns {string} The content of the file
     * @example $FileUtil.find(process.cwd(), 'test');
     */
    static find(root, target) {

        // Handle slashes
        target = $StringUtil.removeTrailingLeadingSlashes(target);

        // Pull this out because it is used several times
        const fileDirectoryExists = function fileDirectoryExists(n, t) {
            try {
                return fs.lstatSync(n)[ `is${t}` ]();
            } catch(e) {
                return false;
            }
        };

        let template;
        if (target.indexOf('/') > -1) {

            // We can just search the root for the file
            template = `${root}/${target}`;
        } else {

            // If file has no slash, search in all directories
            const fn = function deepFindFile(root, target) {
                let files = fs.readdirSync(root);
                for (let i = 0; i < files.length; ++i) {
                    let file = files[i],
                        isDir = fileDirectoryExists(file, 'Directory');
                    if (isDir) {

                        // We have a directory and we need to recurse through it
                        fn(`${root}/${file}`, target);
                    } else if (file.indexOf(target) > -1) {
                        template = `${root}/${target}`;
                    }
                    if (template) {
                        break;
                    }
                }
            };

            // Recursively call for all roots
            fn(root, target);
        }

        // Check to see that the 'template' we found is an actual file
        if (
            (template || template === '') &&
            fileDirectoryExists(template, 'File')
        ) {
            return template;
        }
        return undefined;
    }
}

export default $Util;
export {
    $StringUtil,
    $FileUtil
};