michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: module.metadata = { michael@0: "stability": "experimental" michael@0: }; michael@0: michael@0: const { Cc, Ci, components } = require("chrome"); michael@0: const { parseStack, sourceURI } = require("toolkit/loader"); michael@0: const { readURISync } = require("../net/url"); michael@0: michael@0: exports.sourceURI = sourceURI michael@0: michael@0: function safeGetFileLine(path, line) { michael@0: try { michael@0: var scheme = require("../url").URL(path).scheme; michael@0: // TODO: There should be an easier, more accurate way to figure out michael@0: // what's the case here. michael@0: if (!(scheme == "http" || scheme == "https")) michael@0: return readURISync(path).split("\n")[line - 1]; michael@0: } catch (e) {} michael@0: return null; michael@0: } michael@0: michael@0: function nsIStackFramesToJSON(frame) { michael@0: var stack = []; michael@0: michael@0: while (frame) { michael@0: if (frame.filename) { michael@0: stack.unshift({ michael@0: fileName: sourceURI(frame.filename), michael@0: lineNumber: frame.lineNumber, michael@0: name: frame.name michael@0: }); michael@0: } michael@0: frame = frame.caller; michael@0: } michael@0: michael@0: return stack; michael@0: }; michael@0: michael@0: var fromException = exports.fromException = function fromException(e) { michael@0: if (e instanceof Ci.nsIException) michael@0: return nsIStackFramesToJSON(e.location); michael@0: if (e.stack && e.stack.length) michael@0: return parseStack(e.stack); michael@0: if (e.fileName && typeof(e.lineNumber == "number")) michael@0: return [{fileName: sourceURI(e.fileName), michael@0: lineNumber: e.lineNumber, michael@0: name: null}]; michael@0: return []; michael@0: }; michael@0: michael@0: var get = exports.get = function get() { michael@0: return nsIStackFramesToJSON(components.stack.caller); michael@0: }; michael@0: michael@0: var format = exports.format = function format(tbOrException) { michael@0: if (tbOrException === undefined) { michael@0: tbOrException = get(); michael@0: tbOrException.pop(); michael@0: } michael@0: michael@0: var tb; michael@0: if (typeof(tbOrException) == "object" && michael@0: tbOrException.constructor.name == "Array") michael@0: tb = tbOrException; michael@0: else michael@0: tb = fromException(tbOrException); michael@0: michael@0: var lines = ["Traceback (most recent call last):"]; michael@0: michael@0: tb.forEach( michael@0: function(frame) { michael@0: if (!(frame.fileName || frame.lineNumber || frame.name)) michael@0: return; michael@0: michael@0: lines.push(' File "' + frame.fileName + '", line ' + michael@0: frame.lineNumber + ', in ' + frame.name); michael@0: var sourceLine = safeGetFileLine(frame.fileName, frame.lineNumber); michael@0: if (sourceLine) michael@0: lines.push(' ' + sourceLine.trim()); michael@0: }); michael@0: michael@0: return lines.join("\n"); michael@0: };