palin.js
function formatter(options, severity, date, elems) {

    /*
    OPTIONS
    */
    const indent = options.indent || defaultIndent;
    const objectDepth = options.objectDepth;
    const timestamp = (function () {
        if (check.function(options.timestamp)) {
            return options.timestamp; // user-provided timestamp generating function
        } else if (options.timestamp === false) {
            return false; // no timestamp
        } else {
            return getTimestampString; // default timestamp generating function
        }
    })();
    const rootFolderName = options.rootFolderName;

    /*
    LOGIC
    */

    // the last element is an aggregate object of all of the additional passed in elements
    var aggObj = elems[elems.length - 1];

    // initial log string
    var build = ' ';

    // add the date
    if (timestamp !== false) {
        // otherwise, use the default timestamp generator function
        build += ' ' + timestamp(date);
    }

    build += ' ' + getColorSeverity(severity) + ' ';

    // add the component if provided
    if (aggObj.scope) {
        build += getScopeString(aggObj.scope) + ' ';
        delete aggObj.scope;
    }

    // errors are a special case that we absolutely need to keep track of and log the entire stack
    var errors = [];

    for (let i = 0; i < elems.length - 1; i++) { // iterate through all elements in the array except the last (obj map of options)
        let element = elems[i];

        // Attempt to determine an appropriate title given the first element
        if (i === 0) {
            let elementConsumed = false;
            if (check.string(element)) {
                // string is obviously the title
                build += chalk.blue(element);
                elementConsumed = true;
            } else if (check.instance(element, Error)) {
                // title is the error text representation
                build += chalk.blue(element.message || '[no message]');
                // also store error stacktrace in the aggregate object
                errors.push(element);
                elementConsumed = true;
            }

            // add on the file and line number, which always go after the title, inline
            if (aggObj.file && aggObj.line) {
                aggObj.file = truncFilename(aggObj.file, rootFolderName);
                build += chalk.dim(` (${aggObj.file}:${aggObj.line})`);
                delete aggObj.file;
                delete aggObj.line;
            }

            // do not add element 0 to the 'extra' data section
            if (elementConsumed) {
                continue;
            }
        }

        // add the element to the errors array if it's an error
        if (check.instance(element, Error)) {
            errors.push(element);
            // the error will be concatinated later so continue to the next element
            continue;
        }

        let objString = '\n' + util.inspect(element, { colors: true, depth: objectDepth });
        build += objString.replace(/\n/g, indent);
    }

    if (Object.keys(aggObj).length > 0) {
        let objString = '\n' + util.inspect(aggObj, { colors: true, depth: objectDepth });
        build += objString.replace(/\n/g, indent);
    }

    // iterate through the top-level object keys looking for Errors as well
    for (let o of Object.keys(aggObj)) {
        if (check.instance(o, Error)) {
            errors.push(o);
        }
    }

    // iterate through all the Error objects and print the stacks
    for (let e of errors) {
        build += indent + e.stack.replace(/\n/g, indent);
    }

    return build;
}
function formatter(options, severity, date, elems) {

    /*
    OPTIONS
    */
    const indent = options.indent || defaultIndent;
    const objectDepth = options.objectDepth;
    const timestamp = (function () {
        if (check.function(options.timestamp)) {
            return options.timestamp; // user-provided timestamp generating function
        } else if (options.timestamp === false) {
            return false; // no timestamp
        } else {
            return getTimestampString; // default timestamp generating function
        }
    })();
    const rootFolderName = options.rootFolderName;

    /*
    LOGIC
    */

    // the last element is an aggregate object of all of the additional passed in elements
    var aggObj = elems[elems.length - 1];

    // initial log string
    var build = ' ';

    // add the date
    if (timestamp !== false) {
        // otherwise, use the default timestamp generator function
        build += ' ' + timestamp(date);
    }

    build += ' ' + getColorSeverity(severity) + ' ';

    // add the component if provided
    if (aggObj.scope) {
        build += getScopeString(aggObj.scope) + ' ';
        delete aggObj.scope;
    }

    // errors are a special case that we absolutely need to keep track of and log the entire stack
    var errors = [];

    for (let i = 0; i < elems.length - 1; i++) { // iterate through all elements in the array except the last (obj map of options)
        let element = elems[i];

        // Attempt to determine an appropriate title given the first element
        if (i === 0) {
            let elementConsumed = false;
            if (check.string(element)) {
                // string is obviously the title
                build += chalk.blue(element);
                elementConsumed = true;
            } else if (check.instance(element, Error)) {
                // title is the error text representation
                build += chalk.blue(element.message || '[no message]');
                // also store error stacktrace in the aggregate object
                errors.push(element);
                elementConsumed = true;
            }

            // add on the file and line number, which always go after the title, inline
            if (aggObj.file && aggObj.line) {
                aggObj.file = truncFilename(aggObj.file, rootFolderName);
                build += chalk.dim(` (${aggObj.file}:${aggObj.line})`);
                delete aggObj.file;
                delete aggObj.line;
            }

            // do not add element 0 to the 'extra' data section
            if (elementConsumed) {
                continue;
            }
        }

        // add the element to the errors array if it's an error
        if (check.instance(element, Error)) {
            errors.push(element);
            // the error will be concatinated later so continue to the next element
            continue;
        }

        let objString = '\n' + util.inspect(element, { colors: true, depth: objectDepth });
        build += objString.replace(/\n/g, indent);
    }

    if (Object.keys(aggObj).length > 0) {
        let objString = '\n' + util.inspect(aggObj, { colors: true, depth: objectDepth });
        build += objString.replace(/\n/g, indent);
    }

    // iterate through the top-level object keys looking for Errors as well
    for (let o of Object.keys(aggObj)) {
        if (check.instance(o, Error)) {
            errors.push(o);
        }
    }

    // iterate through all the Error objects and print the stacks
    for (let e of errors) {
        build += indent + e.stack.replace(/\n/g, indent);
    }

    return build;
}
function formatter ( options , severity , date , elems ) { /*
    OPTIONS
    */ const indent = options . indent || defaultIndent ; const objectDepth = options . objectDepth ; const timestamp = ( function ( ) { if ( check . function ( options . timestamp ) ) { return options . timestamp ; // user-provided timestamp generating function } else if ( options . timestamp === false ) { return false ; // no timestamp } else { return getTimestampString ; // default timestamp generating function } } ) ( ) ; const rootFolderName = options . rootFolderName ; /*
    LOGIC
    */ // the last element is an aggregate object of all of the additional passed in elements var aggObj = elems [ elems . length - 1 ] ; // initial log string var build = ' ' ; // add the date if ( timestamp !== false ) { // otherwise, use the default timestamp generator function build += ' ' + timestamp ( date ) ; } build += ' ' + getColorSeverity ( severity ) + ' ' ; // add the component if provided if ( aggObj . scope ) { build += getScopeString ( aggObj . scope ) + ' ' ; delete aggObj . scope ; } // errors are a special case that we absolutely need to keep track of and log the entire stack var errors = [ ] ; for ( let i = 0 ; i < elems . length - 1 ; i ++ ) { // iterate through all elements in the array except the last (obj map of options) let element = elems [ i ] ; // Attempt to determine an appropriate title given the first element if ( i === 0 ) { let elementConsumed = false ; if ( check . string ( element ) ) { // string is obviously the title build += chalk . blue ( element ) ; elementConsumed = true ; } else if ( check . instance ( element , Error ) ) { // title is the error text representation build += chalk . blue ( element . message || '[no message]' ) ; // also store error stacktrace in the aggregate object errors . push ( element ) ; elementConsumed = true ; } // add on the file and line number, which always go after the title, inline if ( aggObj . file && aggObj . line ) { aggObj . file = truncFilename ( aggObj . file , rootFolderName ) ; build += chalk . dim ( ` ${ aggObj . file } ${ aggObj . line } ` ) ; delete aggObj . file ; delete aggObj . line ; } // do not add element 0 to the 'extra' data section if ( elementConsumed ) { continue ; } } // add the element to the errors array if it's an error if ( check . instance ( element , Error ) ) { errors . push ( element ) ; // the error will be concatinated later so continue to the next element continue ; } let objString = '\n' + util . inspect ( element , { colors : true , depth : objectDepth } ) ; build += objString . replace ( / \n / g , indent ) ; } if ( Object . keys ( aggObj ) . length > 0 ) { let objString = '\n' + util . inspect ( aggObj , { colors : true , depth : objectDepth } ) ; build += objString . replace ( / \n / g , indent ) ; } // iterate through the top-level object keys looking for Errors as well for ( let o of Object . keys ( aggObj ) ) { if ( check . instance ( o , Error ) ) { errors . push ( o ) ; } } // iterate through all the Error objects and print the stacks for ( let e of errors ) { build += indent + e . stack . replace ( / \n / g , indent ) ; } return build ; }
the formatter to export
the formatter to export