Source: tools.js

/**
  * This can be either a string or a Object holds a property alled errpr_message
  * or err_msg that is being passed throught the cli tool functions/application.
  * @typedef {(string|Object)} err
*/

/**
  * This function takes a array functions called arr_func and some data of any
  * type weather it be a object, array, string ot interger, and passes it into
  * the function in the array to be mutated/changed then returns back that changed
  * data.
  * @function
  * @param {array} arr_funcs array of functions
  * @param {any} data data of any data type
  * @return {last_result}
*/
module.exports.pipeline = (arr_funcs, data) => {
    if ( typeof arr_funs != 'array' ) {

        arr_funcs = [ arr_funcs ];
    }

    let last_result = data;
    for ( let f in arr_funcs ) {

        last_result = arr_funcs[f]( last_result )
    }
    return last_result;
};


/**
  * This function goes through two arrays simultaneously
  * and executes the callback that is returned appending
  * the result of the callback to a array. Then returning
  * the array of the return data from the callback.
  * @function
  * @param {array} arr1 array data type given
  * @param {array} arr2 array data type given
  * @param {function} callback the callback thet excutes whatever it is
  * @return {callbackResults}
*/
module.exports.zip = (arr1, arr2, callback) => {
  var callbackResults = [];

  for ( i = 0, j = 0; i < arr1.length, j < arr2.length; i++, j++  ) {
      newArray.push( callback( arr1[i], arr2[j] ) )
  }
  return callbackResults;
};


/**
  * This function returns the result of a flag dispath_action function,
  * excuting all flags that were passed to the cli application in the
  * the array 'flags arr'.
  * Assigning the data to output so when it passes it to method
  * on the first run it does not reference the same value after running
  * the fucntion again passing a new value. Therefore changing the data
  * that was given to this function.
  * @function
  * @param {function} method method of a dispath_action function
  * @param {array} flags_arr array of flags passed to the cli application
  * @param {any} data any data type cretaed by the cli application
*/
module.exports.exArgs = (method, flags_arr, data) => {
    var output = data;

    for ( var i = 0; i < flags_arr.length; i++ ) {

        // call the mwthod again nd pass in the data
        output = method(flags_arr[i], output);
    }
    return output;
};


/**
  * This fucntion creates a prompt of stdin taking in a placeholder
  * to display a prompt symbol or message which is a sting and returns
  * a callback of that returns the recived data.
  * @param {string} placeholder this is a strnng that is a message or symbol
  * @param {function} callback a callback thta retruns a err or a stdout data from recived stdin data
  * @return {callback}
*/
module.exports.prompt = (placeholder, callback) => {

    // gets the stout & stdin processes
    const rl = readline.createInterface({
        input_data: process.stdin,
        output: process.stdout
    })

    // creates a prompt
    rl.question(placeholder, (stdout) => {

        // if the stdout of the prompt is undefned or a empty string
        if ( stdout.length == 0 || stdout === undefined ) {

            rl.close();
            return callback({
                stdout: stdout,
                status: false,
                msg: 'error: No datawas passed in'
            }, undefined)
        }

        // return a callback with a status of true and the stdout data
        rl.close();
        return callback(null, {
            stdout: stdout,
            status: true
        })
    })
};


/**
  * This is a a fucntion that dispays error messages that is caught by a
  * failure in a cli applaiction of functions. this takes a string or
  * Object and returns back the error message of that string or Object
  * stoping the application once a eror is caught.
  * @function
  * @param {err} err - this is a err message that is a string or error object
  * @param {fucntion} callback this returns a error message of any kind
  * @return {callback}
*/
module.exports.catchError = (err, callback) => {

    // checking if the callback param is undefined
    if ( callback === undefined ) {

        /*
            // check if in debug or dev mode
            if ( mode === 'debug' ) {

                // log to the console and break the chain flow
                return console.error( err || err.msg || `*error: ${ err.message.split(' ').splice(1, err.message.split(' ').length).join(' ') }.`);
            }
        */

        // else if not in debug mode or is 'mode' is eqaul to undefined
        // log to the console and return
        return console.log( err.msg || err || `*error: ${ err.message.split(' ').splice(1, err.message.split(' ').length).join(' ') }.`);
    }

    // if the callback is not undefined then return callback
    return callback({
        // return back whatever error message is not null or undefined
            // for the 'err.message' remove the JavaScript error tags
        msg: err.msg || err || `*error: ${ err.message.split(' ').splice(1, err.message.split(' ').length).join(' ') }.`,
        status: false
    });
};



/**
  * This is a logger function that takes a file name to write log 'input_data'
  * to this is also takes the data whihc can be any data type and a callback to
  * return the data that was passed that is formated into log string.
  * This fucntion can optionaly take a callback fucntion to return the output
  * log string and a err if it has occured or return the log sting without the callback
  * @param {string} dest_file A string of the file path
  * @param {any} input_data the data passed to the logger which can be any type of data excet a function
  * @param {function} callback the call back that returns a err or log string
  * @return {callback}
*/
module.exports.logger = (dest_file, input_data, callback) => {

    /*
        requires the fs module and the tools module.

        Also 'new Date' and formates the date.

        lastly declaring but never using two varibles.
    */
    const fs = require('fs'),
    tool = require('./tools.js'),
    date = new Date,
    formatedDate = `${ date.getMonth() }/${ date.getDate() }/${ date.getFullYear() } ${ date.getHours() > 12 ? date.getHours() - 12 : date.getHours() }:${ date.getMinutes() } +0000`;
    var data, log_string;

    // if the 'input_data' os a obj or array then strinfgy or return input if a string
    log_string = `\n # ${ log_stringedDate } \n\t ${ JSON.stringify( input_data ) || input_data }\n`;


    // checks if the file exist
    var exst = fs.exists(dest_file);

    /*
        if the file does not exist catchError()
        passing the callback if not undefined
    */
    if (!exst) {

        return tool.catchError(`*error: File'${ dest_file }' does not exist.`, (err) => {

            console.log(err.msg);

            console.log(`\n creating logger document '${ dest_file }'.\n
            action => ${ input_data.action } : ${ log_string }`);
            fs.writeFileSync(dest_file, log_string, 'utf8');

            return log_string || callback(null, log_string);
        })
    }

    // if the file exist get the ata from the 'dest_file'
    // then format the data from the input_data argument
    data = fs.readFileSync(dest_file, 'utf8');

    // concatinate the data from the file 'looger' file or 'logger data' with the new fromated data
    data = data += log_string;

    // ru the script and catch any errors
    try {

        // write to the file in utf8 format and concatenat the data from the 'dest_file' and the 'fomat'
        fs.writeFileSync(dest_file, data, 'utf8');
        return callback !== undefined ? callback(null, {
            status: true,
            msg: `action => ${ input_data.action } : ${ log_string }`
        }) : console.log(`action => ${ input_data.action } : ${ log_string }`)
    }
    catch (e) {

        return tool.catchError(e);
    }
};