"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var util_1 = require("./util");
var lang_1 = require("@dojo/core/lang");
var Formatter = (function () {
    function Formatter(options) {
        if (options === void 0) { options = {}; }
        this.filterErrorStack = false;
        lang_1.mixin(this, options);
    }
    Formatter.prototype.format = function (error, options) {
        options = options || {};
        var message;
        if (typeof error !== 'string' && (error.message || error.stack)) {
            message = (error.name || 'Error') + ': ' + (error.message || 'Unknown error');
            var stack = error.stack;
            if (stack) {
                if (stack.indexOf(message) === 0) {
                    stack = stack.slice(message.length);
                }
                else if (stack.indexOf(error.message) === 0) {
                    stack = stack.slice(String(error.message).length);
                }
                stack = normalizeStackTrace(stack, this.filterErrorStack, this._getSource);
            }
            var anyError = error;
            if (anyError.showDiff && typeof anyError.actual === 'object' && typeof anyError.expected === 'object') {
                var diff = util_1.createDiff(anyError.actual, anyError.expected);
                if (diff) {
                    message += '\n\n' + diff + '\n';
                }
            }
            if (stack && /\S/.test(stack)) {
                message += stack;
            }
            else if (anyError.fileName) {
                message += '\n  at ' + anyError.fileName;
                if (anyError.lineNumber != null) {
                    message += ':' + anyError.lineNumber;
                    if (anyError.columnNumber != null) {
                        message += ':' + anyError.columnNumber;
                    }
                }
                message += '\nNo stack';
            }
            else {
                message += '\nNo stack or location';
            }
        }
        else {
            message = String(error);
        }
        var space = options.space;
        if (space != null) {
            message = message.split('\n').map(function (line) {
                return space + line;
            }).join('\n');
        }
        return message;
    };
    Formatter.prototype._getSource = function (tracepath) {
        return tracepath;
    };
    return Formatter;
}());
exports.default = Formatter;
function formatLine(data, getSource) {
    if (!data.func) {
        return '  at <' + getSource(data.source) + '>';
    }
    return '  at ' + data.func + '  <' + getSource(data.source) + '>';
}
function normalizeStackTrace(stack, filterStack, getSource) {
    var lines = stack.replace(/\s+$/, '').split('\n');
    var firstLine = '';
    if (/^(?:[A-Z]\w+)?Error: /.test(lines[0])) {
        firstLine = lines[0] + '\n';
        lines = lines.slice(1);
    }
    while (/^\s*$/.test(lines[0])) {
        lines = lines.slice(1);
    }
    var stackLines = /^\s*at /.test(lines[0]) ? processChromeTrace(lines, getSource) : processSafariTrace(lines, getSource);
    if (filterStack) {
        stackLines = stackLines.filter(function (line) {
            return !(/internal\/process\//.test(line) ||
                /node_modules\/(?!digdug|leadfoot)/.test(line) ||
                /Module\.runMain/.test(line) ||
                /bootstrap_node\.js/.test(line));
        });
    }
    return '\n' + firstLine + stackLines.join('\n');
}
function processChromeTrace(lines, getSource) {
    return lines.map(function (line) {
        var match;
        if ((match = /^\s*at (.+?) \(([^)]+)\)$/.exec(line))) {
            return formatLine({ func: match[1], source: match[2] }, getSource);
        }
        else if ((match = /^\s*at (.*)/.exec(line))) {
            return formatLine({ source: match[1] }, getSource);
        }
        else {
            return line;
        }
    });
}
function processSafariTrace(lines, getSource) {
    return lines.map(function (line) {
        var match;
        if ((match = /^([^@]+)@(.*)/.exec(line))) {
            return formatLine({ func: match[1], source: match[2] }, getSource);
        }
        else if ((match = /^(\w+:\/\/.*)/.exec(line))) {
            return formatLine({ source: match[1] }, getSource);
        }
        else {
            return line;
        }
    });
}
//# sourceMappingURL=Formatter.js.map