libflitter/errors/error_context.fn.js

/**
 * Adds additional contextual variables to an error and
 * modifies its stacktrace and toString output to include
 * that context.
 *
 * @param {Error} in_error
 * @param {object} context
 * @returns {Error}
 */
const error_context = (in_error, context = {}) => {
    // If the incoming error already has context, merge the two
    if ( typeof in_error.context === 'object' ) {
        in_error.context = {...in_error.context, ...context}
    } else { // Otherwise, assign the context
        in_error.context = context
    }

    // Preserve the original stacktrace
    if ( !in_error.original_stack ) {
        in_error.original_stack = in_error.stack
    }

    in_error.toString = () => {
        // Get the JS stacktrace
        let stack = in_error.original_stack

        // Build the context display
        const context_lines = []
        if ( typeof in_error.context === 'object' ) {
            for ( const name in in_error.context ) {
                const val = in_error.context[name]
                try {
                    const string = JSON.stringify(val)
                    context_lines.push(` - ${name}: ${string}`)
                } catch (e) {
                    if ( typeof val.toString === 'function' ) {
                        context_lines.push(` - ${name}: ${val}`)
                    }
                }
            }
        }

        if ( context_lines.length > 0 ) {
            stack += `\n\nWith the following context:\n${context_lines.join('\n')}\n`
        }

        return stack
    }

    in_error.stack = in_error.toString()
    return in_error
}

module.exports = exports = error_context