Last active
November 21, 2015 04:25
-
-
Save jeancroy/5e0372dc4dbf03000e28 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// For use whithin node.js | |
referenceStack = null; | |
wrapperCache = null; | |
privilegiedCallback = null; | |
lastPrepareStackTrace = null; | |
// | |
// Each wrapper contain a link to their own callback | |
// And each of those will try to call the privileged callback before | |
// | |
// The test stack !== referenceStack is done so the privileged callback is | |
// called at most once per error. | |
// | |
// The privileged callback has to access the stack object before anyone else | |
// because other callback can modify the shared object. | |
// | |
// If holding on the stack object is detrimental, maybe it can be stored in a weakMap | |
// | |
function wrapperFactory(callback) { | |
lastPrepareStackTrace = callback; | |
return function (error, stack) { | |
if (!error) return stack; | |
if (stack !== referenceStack) { | |
referenceStack = stack; | |
if (typeof privilegiedCallback === 'function') { | |
privilegiedCallback.call(this, error, stack); | |
} | |
} | |
if (typeof callback === 'function') { | |
return callback.call(this, error, stack); | |
} | |
return stack | |
} | |
} | |
function hijackPrepareStackTrace() { | |
wrapperCache = wrapperFactory(Error.prepareStackTrace); | |
delete Error.prepareStackTrace; | |
Object.defineProperty(Error, "prepareStackTrace", { | |
get: function () { | |
return wrapperCache; | |
}, | |
set: function (value) { | |
wrapperCache = wrapperFactory(value); | |
}, | |
configurable: true, | |
enumerable: false | |
}); | |
} | |
function restorePrepareStackTrace(){ | |
delete Error.prepareStackTrace; | |
Error.prepareStackTrace = lastPrepareStackTrace; | |
privilegiedCallback = null; | |
referenceStack = null; | |
wrapperCache = null; | |
} | |
function setPrivilegiedCallback(value) { | |
privilegiedCallback = value | |
} | |
//--------------------------------------------------------------------- | |
// | |
// Demo | |
// | |
// (A) Test that we support multiple consecutive. First Hijack 1 register itself, then hijack 2 register and call previous. | |
// (B) Test that we report the original object, even if modified by a callback. | |
// ------ | |
// (C) Test that we support the restore pattern. (Hijack 2 remove itself from the chain without knowing there's a wrapper hook) | |
// ------ | |
// (D) Test that we can remove the wrapper hook. | |
//Setup Hook | |
hijackPrepareStackTrace(); | |
setPrivilegiedCallback(function(err,stack){ | |
console.log("privilegied", stack); | |
return stack | |
}); | |
// Hijack 1 | |
Error.prepareStackTrace = function(err,stack){ | |
console.log("hijack 1", stack); | |
return stack | |
}; | |
// Hijack 2 | |
beforeH2 = Error.prepareStackTrace; | |
Error.prepareStackTrace = function(err,stack){ | |
stack[0] = {hello:"world"}; | |
console.log("hijack 2", stack); | |
return beforeH2(err,stack); | |
}; | |
// throw error to get stack. | |
dummy = {}; | |
Error.captureStackTrace(dummy); | |
dummy.stack; | |
//--------------------------------------------- | |
console.log("\n"); | |
// Undo hicjack 2 | |
Error.prepareStackTrace = beforeH2; | |
// throw error to get stack. | |
dummy = {}; | |
Error.captureStackTrace(dummy); | |
dummy.stack; | |
//--------------------------------------------- | |
console.log("\n"); | |
// Release Wrapper Hook | |
restorePrepareStackTrace(); | |
// throw error to get stack. | |
dummy = {}; | |
Error.captureStackTrace(dummy); | |
dummy.stack; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment