UNPKG

error-polyfill

Version:
133 lines (127 loc) 5.2 kB
var Class = require("o3").Class, abstractMethod = require("o3").abstractMethod, eachCombination = require("u3").eachCombination, cache = require("u3").cache, capability = require("capability"); var AbstractFrameStringSource = Class(Object, { prototype: { captureFrameStrings: function (frameShifts) { var error = this.createError(); frameShifts.unshift(this.captureFrameStrings); frameShifts.unshift(this.createError); var capturedFrameStrings = this.getFrameStrings(error); var frameStrings = capturedFrameStrings.slice(frameShifts.length), functionValues = []; if (capability("arguments.callee.caller")) { var capturedFunctionValues = [ this.createError, this.captureFrameStrings ]; try { var aCaller = arguments.callee; while (aCaller = aCaller.caller) capturedFunctionValues.push(aCaller); } catch (useStrictError) { } functionValues = capturedFunctionValues.slice(frameShifts.length); } return { frameStrings: frameStrings, functionValues: functionValues }; }, getFrameStrings: function (error) { var message = error.message || ""; var name = error.name || ""; var stackString = this.getStackString(error); if (stackString === undefined) return; var stackStringChunks = stackString.split("\n"); var fromPosition = 0; var toPosition = stackStringChunks.length; if (this.hasHeader) fromPosition += name.split("\n").length + message.split("\n").length - 1; if (this.hasFooter) toPosition -= 1; return stackStringChunks.slice(fromPosition, toPosition); }, createError: abstractMethod, getStackString: abstractMethod, hasHeader: undefined, hasFooter: undefined } }); var FrameStringSourceCalibrator = Class(Object, { prototype: { calibrateClass: function (FrameStringSource) { return this.calibrateMethods(FrameStringSource) && this.calibrateEnvelope(FrameStringSource); }, calibrateMethods: function (FrameStringSource) { try { eachCombination([[ function (message) { return new Error(message); }, function (message) { try { throw new Error(message); } catch (error) { return error; } } ], [ function (error) { return error.stack; }, function (error) { return error.stacktrace; } ]], function (createError, getStackString) { if (getStackString(createError())) throw { getStackString: getStackString, createError: createError }; }); } catch (workingImplementation) { Class.merge.call(FrameStringSource, { prototype: workingImplementation }); return true; } return false; }, calibrateEnvelope: function (FrameStringSource) { var getStackString = FrameStringSource.prototype.getStackString; var createError = FrameStringSource.prototype.createError; var calibratorStackString = getStackString(createError("marker")); var calibratorFrameStrings = calibratorStackString.split("\n"); Class.merge.call(FrameStringSource, { prototype: { hasHeader: /marker/.test(calibratorFrameStrings[0]), hasFooter: calibratorFrameStrings[calibratorFrameStrings.length - 1] === "" } }); return true; } } }); module.exports = { getClass: cache(function () { var FrameStringSource; if (FrameStringSource) return FrameStringSource; FrameStringSource = Class(AbstractFrameStringSource, {}); var calibrator = new FrameStringSourceCalibrator(); if (!calibrator.calibrateClass(FrameStringSource)) throw new Error("Cannot read Error.prototype.stack in this environment."); return FrameStringSource; }), getInstance: cache(function () { var FrameStringSource = this.getClass(); var instance = new FrameStringSource(); return instance; }) };