src/util.js
function _inspect(inspecting, inspection = '', seen = [], times = 0, indent = 2) {
    let type = getType(inspecting);
    switch(type) {
        case types.undefined:
            return 'undefined';
        case types.null:
            return 'null';
        case types.function:
            let name = inspecting.name ? ': ' + inspecting.name : '';
            return `[Function${name}]`;
        case types.string:
            return `'${inspecting}'`;
        case types.array:
            if (seen.indexOf(inspecting) > -1)
                return '[Circular]';
            times++;
            inspection = '[ ';
            seen.push(inspecting);
            var inspected = [];
            for (let val of inspecting)
                inspected.push(_inspect(val, inspection, seen, times));
            if (inspected.length === 0)
                return '[]';
            let length = inspected.reduce((prev, cur) => {
                return prev + cur.length;
            }, 0);
            if (length > 60)
                inspection = '[ ' + inspected.join(',\n' + ' '.repeat(times * indent)) + ' ]';
            else
                inspection = '[ ' + inspected.join(', ') + ' ]';
            return inspection;
        case types.object:
            if (seen.indexOf(inspecting) > -1)
                return '[Circular]';
            times++;
            inspection = '{ ';
            seen.push(inspecting);
            let objInspected = [];
            if (inspecting instanceof Error) // to match nodejs inspect methods
                objInspected.push('[' + inspecting.toString() + ']');
            for (let [key, val] of each(inspecting))
                objInspected.push(key + ': ' + _inspect(val, inspection, seen, times));
            if (objInspected.length === 0)
                return '{}';
            let objLength = objInspected.reduce((prev, cur) => {
                return prev + cur.length;
            }, 0);
            if (objLength > 60)
                inspection = '{\n' + ' '.repeat(times * indent) + objInspected.join(',\n' + ' '.repeat(times * indent)) + ' }';
            else
                inspection = '{ ' + objInspected.join(', ') + ' }';
            return inspection;
        case types.map:
        case types.set:
            return _inspect([...inspecting]);
        case types.number:
        case types.boolean:
        default:
            if (inspecting instanceof Error)
                return '[' + inspecting.toString() + ']';
            return inspecting.toString();
    }
}
function _inspect(inspecting, inspection = '', seen = [], times = 0, indent = 2) {
    let type = getType(inspecting);
    switch(type) {
        case types.undefined:
            return 'undefined';
        case types.null:
            return 'null';
        case types.function:
            let name = inspecting.name ? ': ' + inspecting.name : '';
            return `[Function${name}]`;
        case types.string:
            return `'${inspecting}'`;
        case types.array:
            if (seen.indexOf(inspecting) > -1)
                return '[Circular]';
            times++;
            inspection = '[ ';
            seen.push(inspecting);
            var inspected = [];
            for (let val of inspecting)
                inspected.push(_inspect(val, inspection, seen, times));
            if (inspected.length === 0)
                return '[]';
            let length = inspected.reduce((prev, cur) => {
                return prev + cur.length;
            }, 0);
            if (length > 60)
                inspection = '[ ' + inspected.join(',\n' + ' '.repeat(times * indent)) + ' ]';
            else
                inspection = '[ ' + inspected.join(', ') + ' ]';
            return inspection;
        case types.object:
            if (seen.indexOf(inspecting) > -1)
                return '[Circular]';
            times++;
            inspection = '{ ';
            seen.push(inspecting);
            let objInspected = [];
            if (inspecting instanceof Error) // to match nodejs inspect methods
                objInspected.push('[' + inspecting.toString() + ']');
            for (let [key, val] of each(inspecting))
                objInspected.push(key + ': ' + _inspect(val, inspection, seen, times));
            if (objInspected.length === 0)
                return '{}';
            let objLength = objInspected.reduce((prev, cur) => {
                return prev + cur.length;
            }, 0);
            if (objLength > 60)
                inspection = '{\n' + ' '.repeat(times * indent) + objInspected.join(',\n' + ' '.repeat(times * indent)) + ' }';
            else
                inspection = '{ ' + objInspected.join(', ') + ' }';
            return inspection;
        case types.map:
        case types.set:
            return _inspect([...inspecting]);
        case types.number:
        case types.boolean:
        default:
            if (inspecting instanceof Error)
                return '[' + inspecting.toString() + ']';
            return inspecting.toString();
    }
}
/*
Internal method for inspecting a value
and providing a string representation of that value.

(params TBD)