Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

trycatch

Package Overview
Dependencies
Maintainers
1
Versions
75
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

trycatch - npm Package Compare versions

Comparing version 0.2.1 to 0.2.2

11

lib/formatStackTrace.js

@@ -27,3 +27,3 @@ // Copyright 2006-2008 the V8 project authors. All rights reserved.

// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
module.exports = function(format, filter) {
module.exports = function(filter) {
filter = Array.isArray(filter) ? filter : []

@@ -57,10 +57,3 @@

line = " at " + line;
if ('function' === typeof format) {
line = format(line)
}
if (line) {
lines.push(line);
}
lines.push(line);
}

@@ -67,0 +60,0 @@ }

530

lib/trycatch.js

@@ -0,283 +1,365 @@

// Don't rely on domains to catch errors
// Use domains to pass caught errors to active
// Keep (add?) fix for event emitter handler
// emit uncaughtException if (isCore(err) && err instanceof EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError))
// when we run, set domain to active
// do usual long-stack-traces/trycatch run
//
// in guard, if it's eventemitter, reset active domain to closure domain
var util = require('util')
, domain = require('domain')
, FormatStackTrace = require('./formatStackTrace')
, hook = require('./hook')
, hooked = false
, fileNameFilter = [__filename, require.resolve('./hook'), 'domain.js']
, d = require('path').join('/')
, node_modules = d + 'node_modules' + d
, options = {
'long-stack-traces': null
, 'colors': {
'node': 'white',
'node_modules': 'cyan',
'default': 'red'
}
, 'format': defaultFormat
, 'filter': fileNameFilter
}
, domain = require('domain')
, path = require('path')
, FormatStackTrace = require('./formatStackTrace')
, hookit = require('hookit')
, fileNameFilter = [__filename, require.resolve('hookit'), 'domain.js']
, formatter = FormatStackTrace(fileNameFilter)
, node_modules = path.sep + 'node_modules' + path.sep
, hasGuardedWithoutLST
, options
options = {
'long-stack-traces': null
, 'colors': {
'node': false, //'white',
'node_modules': false, //'cyan',
'default': 'red'
}
, 'format': defaultFormat
, 'filter': fileNameFilter
}
module.exports = trycatch
Error.stackTraceLimit = 30
// use colors module, if available
if (process.stdout.isTTY) {
try { trycatch.colors = require('colors') } catch(err) {}
try { trycatch.colors = require('colors') } catch(err) {}
}
module.exports = trycatch
function trycatch(tryFn, catchFn) {
if ('function' !== typeof tryFn || 'function' !== typeof catchFn) {
throw new Error('tryFn and catchFn must be functions')
}
trycatch.begin(tryFn, catchFn)
if ('function' !== typeof tryFn || 'function' !== typeof catchFn) {
throw new Error('tryFn and catchFn must be functions')
}
return trycatch.run(tryFn, catchFn)
}
trycatch.begin = domainTrycatch
// Won't be used until long-stack-traces turned off=>on=>off
trycatch.guard = nopGuard
trycatch.run = run
trycatch.wrap = wrap
trycatch.configure = configure
trycatch.format = FormatStackTrace(defaultFormat, fileNameFilter)
trycatch.format = defaultFormat
function configure(opts) {
var resetFormat = false
hookit(function generateShim(callback, fnName) {
return trycatch.wrap(callback, fnName)
})
if ('undefined' !== typeof opts['long-stack-traces']) {
options['long-stack-traces'] = Boolean(opts['long-stack-traces'])
if (true === options['long-stack-traces']) {
if (!hooked) {
hooked = true
// Replace built-in async functions, shim callbacks with generator
hookit()
}
function run(fn, cb) {
var parentDomain = domain.active
, d = domain.create()
// findToken fails when _TOKEN_ deeper than Error.stackTraceLimit
Error.stackTraceLimit = Infinity
trycatch.begin = longStackTraceBegin
trycatch.guard = longStackTraceGuard
} else if (false === options['long-stack-traces'] && hooked) {
console.warn('Turning long-stack-traces off can result in indeterminate behavior.')
Error.stackTraceLimit = 10
trycatch.begin = domainTrycatch
trycatch.guard = nopGuard
}
}
d.on('error', function(e) {
handleException(e, parentDomain, cb)
})
if (null != opts.colors && 'object' === typeof opts.colors) {
if ('undefined' !== typeof opts.colors.node) {
options.colors.node = opts.colors.node
}
if ('undefined' !== typeof opts.colors.node_modules) {
options.colors.node_modules = opts.colors.node_modules
}
if ('undefined' !== typeof opts.colors.default) {
options.colors.default = opts.colors.default
}
}
if (options['long-stack-traces']) {
fn = lstRunWrap(fn)
}
if ('undefined' !== typeof opts.format) {
if ('function' === typeof opts.format) {
options.format = opts.format
resetFormat = true
} else if (!Boolean(opts.format)) {
options.format = defaultFormat
resetFormat = true
}
}
runInDomain(d, fn)
return d
}
if (Array.isArray(opts.filter)) {
options.filter = opts.filter
resetFormat = true
}
function handleException(err, parentDomain, cb) {
var caught
if (resetFormat) {
trycatch.format = FormatStackTrace(options.format, options.filter)
}
}
err = buildError(err, options['long-stack-traces'])
function hookit() {
hook(function generateShim(callback, fnName) {
return trycatch.guard(callback, fnName)
})
formatError(err)
if (!err.catchable) {
// Unexpected error, core in undefined state, requires restart
caught = process.emit('uncaughtException', err)
// Otherwise crash the process
if (!caught) {
throw err
}
return
}
if (!parentDomain) {
if ('function' === typeof cb) {
cb(err)
return
}
caught = process.emit('uncaughtApplicationException', err)
if (!caught) {
caught = process.emit('uncaughtException', err)
}
if (!caught) {
throw err
}
return
}
runInDomain(parentDomain, function() {
cb(err)
})
}
// In case long-stack-traces are switched on -> off
function nopGuard(cb) {
return cb
function runInDomain(d, fn) {
if (!d || d._disposed) {
try {
fn()
} catch(e1) {
handleException(e1)
}
return
}
try {
d.run(fn)
} catch(e2) {
d.emit('error', e2)
}
}
function domainTrycatch (fn, cb, isLongStackTrace) {
var parentDomain = domain.active
, d = domain.create()
function isCatchableError(err) {
if (!isCoreError(err)) return true
d.on('error', function onError(err) {
err = buildError(err, Boolean(options['long-stack-traces'] && isLongStackTrace))
// Unexpected runtime errors aren't catchable
if (err instanceof EvalError ||
err instanceof RangeError ||
err instanceof ReferenceError ||
err instanceof SyntaxError ||
err instanceof URIError) return false
runInDomain(parentDomain, function() {
cb(err)
})
})
runInDomain(d, fn)
// Can't catch invalid input errors more than 1 layer deep
return !isCoreSlice(err.stack.split('\n')[2])
}
function runInDomain(d, fn) {
if (d && !d._disposed) {
try {
d.run(fn)
} catch(e) {
d.emit('error', e)
}
} else {
fn()
}
function isCoreSlice(slice) {
return slice && slice.indexOf(path.sep) === -1
}
function buildError(err, isLongStackTrace) {
var parent
, token
, skip = false
, isError = err instanceof Error
function isCoreError(err) {
return true !== err.coerced && isCoreSlice(err.stack.split('\n')[1])
}
// Coerce to error
if (!isError) {
err = new Error(err)
}
function lstRunWrap(tryFn) {
// Create origin _TOKEN_ for stack termination
function _TOKEN_() {
tryFn()
}
_TOKEN_.error = new Error
_TOKEN_.parent = 'trycatch'
if (!isLongStackTrace) {
return generateStack(err)
} else if (!isError) {
console.warn('Unable to generate long-stack-trace for thrown non-Error')
return generateStack(err)
}
return _TOKEN_
}
if (err.token) {
skip = true
token = err.token
} else {
parent = generateStack(err, stackSearch).stack
err.stack = parent.stack
if (!parent.token) {
// options['long-stack-traces'] was probably toggled after async was invoked
return err
}
token = parent.token
parent = null
}
// Generate a new callback wrapped in _TOKEN_ (optionally with Error for LSTs)
function wrap(callback, name) {
var parentDomain = domain.active
while(token.error) {
if (!skip && token.catchFn) break
if ('function' !== typeof callback) return callback
skip = false
function _TOKEN_(that, args) {
callback.apply(that, args)
}
// HACK: Use Error.prepareStackTrace = stackSearch to find parent
parent = generateStack(token.error, stackSearch).stack
if (!parent) {
throw err
}
if (options['long-stack-traces']) {
_TOKEN_.parent = name
_TOKEN_.error = new Error
}
if (!token.catchFn && parent.stack) {
err.stack += '\n ----------------------------------------\n' +
' at '+token.parent+'\n' +
parent.stack.substring(parent.stack.indexOf("\n") + 1)
}
token = parent.token
}
// Running in parentDomain should only be necessary for EventEmitter handlers
// Core should handle the rest
// Wrapping is still necessary to fix core error handling
return function() {
var that = this
, args = arguments
if ('function' === typeof token.catchFn) {
err.token = token
return err
}
runInDomain(parentDomain, function() {
_TOKEN_(that, args)
})
}
}
function longStackTraceBegin(tryFn, catchFn) {
// Create origin _TOKEN_ for stack termination
function _TOKEN_() {
tryFn()
}
_TOKEN_.catchFn = catchFn
_TOKEN_.error = new Error
_TOKEN_.parent = 'trycatch'
function buildError(err, isLST) {
var parent
, token
, skip = false
, isError = err instanceof Error
domainTrycatch(_TOKEN_, catchFn, true)
}
// Coerce to error
if (!isError) {
err = new Error(err)
err.coerced = true
}
function generateStack(err, fn) {
if ('function' !== typeof fn) {
fn = trycatch.format
}
if (!err) err = new Error
var old = Error.prepareStackTrace
Error.prepareStackTrace = fn
// Generate stack trace by accessing stack property
err.stack = err.stack
Error.prepareStackTrace = old
return err
}
if (!isLST) {
return setProperties(generateStack(err))
} else if (!isError) {
console.warn('Unable to generate long-stack-trace for thrown non-Error')
return setProperties(generateStack(err))
}
// Generate a new callback wrapped in _TOKEN_ with Error to trace back
function longStackTraceGuard(callback, name) {
var parentDomain
// If previously caught
if (err.token) {
skip = true
token = err.token
} else {
parent = generateStack(err, stackSearch).stack
err.stack = parent.stack
err = setProperties(err)
if (!parent.token) {
// options['long-stack-traces'] was probably toggled after async was invoked
return err
}
token = parent.token
parent = null
}
if ('function' !== typeof callback) return callback
while(token.error) {
if (!skip && 'trycatch' === token.parent) break
parentDomain = domain.active
skip = false
// _TOKEN_ is the new callback and calls the real callback, callback()
function _TOKEN_() {
callback.apply(this, arguments)
}
// HACK: Use Error.prepareStackTrace = stackSearch to find parent
parent = generateStack(token.error, stackSearch).stack
if (!parent) {
throw err
}
_TOKEN_.parent = name
_TOKEN_.error = new Error
return function() {
var args = arguments
runInDomain(parentDomain, function() {
_TOKEN_.apply(this, args)
})
}
if ('trycatch' !== token.parent && parent.stack) {
err.stack += '\n ----------------------------------------\n' +
' at '+token.parent+'\n' +
parent.stack.substring(parent.stack.indexOf("\n") + 1)
}
token = parent.token
}
if ('trycatch' === token.parent) {
err.token = token
return err
}
}
function setProperties(err) {
err.coreThrown = isCoreError(err)
err.catchable = isCatchableError(err)
return err
}
function generateStack(err, fn) {
var old = Error.prepareStackTrace
if ('function' !== typeof fn) {
fn = formatter
}
if (!err) err = new Error
Error.prepareStackTrace = fn
// Generate stack trace by accessing stack property
err.stack = err.stack
Error.prepareStackTrace = old
return err
}
function stackSearch(error, structuredStackTrace) {
var stack, fn, i, l
var stack, fn, i, l
if (!structuredStackTrace) return
stack = trycatch.format(error, structuredStackTrace)
if (!structuredStackTrace) return
for (i=0, l=structuredStackTrace.length; i<l; i++) {
fn = structuredStackTrace[i].fun
if ('_TOKEN_' === fn.name) {
return {
token: fn,
stack: stack
}
}
}
return {stack: stack}
stack = formatter(error, structuredStackTrace)
for (i=0, l=structuredStackTrace.length; i<l; i++) {
fn = structuredStackTrace[i].fun
if ('_TOKEN_' === fn.name) {
return {
token: fn,
stack: stack
}
}
}
return {stack: stack}
}
function formatError(err) {
var stack = err.stack.split('\n')
, i = stack.length
while (i--) {
stack[i] = trycatch.format(stack[i])
}
return stack.join('')
}
function defaultFormat(line) {
var type, color
var type, color
if (trycatch.colors) {
if (line.indexOf(node_modules) >= 0) {
type = "node_modules";
} else if (line.indexOf(d) >= 0) {
type = "default";
} else {
type = "node"
}
if (trycatch.colors) {
if (line.indexOf(node_modules) >= 0) {
type = "node_modules";
} else if (line.indexOf(path.sep) >= 0) {
type = "default";
} else {
type = "node"
}
color = options.colors[type]
if ('none' === color || !Boolean(color)) {
return
}
color = options.colors[type]
if ('none' === color || !Boolean(color)) {
return
}
if (trycatch.colors[color]) {
return trycatch.colors[color](line);
}
}
if (trycatch.colors[color]) {
return trycatch.colors[color](line);
}
}
return line
}
function configure(opts) {
if (null != opts['long-stack-traces']) {
opts['long-stack-traces'] = Boolean(opts['long-stack-traces'])
if (opts['long-stack-traces']) {
if (hasGuardedWithoutLST) {
console.warn('Turning long-stack-traces off can result in indeterminate behavior.')
}
// findToken fails when _TOKEN_ deeper than Error.stackTraceLimit
Error.stackTraceLimit = Infinity
} else {
Error.stackTraceLimit = 30
}
options['long-stack-traces'] = opts['long-stack-traces']
}
if (null != opts.colors && 'object' === typeof opts.colors) {
if ('undefined' !== typeof opts.colors.node) {
options.colors.node = opts.colors.node
}
if ('undefined' !== typeof opts.colors.node_modules) {
options.colors.node_modules = opts.colors.node_modules
}
if ('undefined' !== typeof opts.colors.default) {
options.colors.default = opts.colors.default
}
}
if ('undefined' !== typeof opts.format) {
if ('function' === typeof opts.format) {
trycatch.format = options.format = opts.format
} else if (!Boolean(opts.format)) {
trycatch.format = options.format = defaultFormat
}
}
if (Array.isArray(opts.filter)) {
options.filter = opts.filter
}
}
{
"name": "trycatch",
"version": "0.2.1",
"version": "0.2.2",
"description": "An asynchronous domain-based exception handler with long stack traces for node.js",

@@ -19,3 +19,3 @@ "homepage": "http://github.com/CrabDude/trycatch",

"engines": {
"node": ">=0.9.5"
"node": ">=0.8.14"
},

@@ -33,3 +33,4 @@ "engineStrict": true,

"dependencies": {
"colors": ">=0.5.0 <0.6"
"colors": ">=0.5.0 <0.6",
"hookit": "0.0.2"
},

@@ -36,0 +37,0 @@ "keywords": [

var trycatch = require('../lib/trycatch')
, assert = require('assert')
/*

@@ -11,3 +11,3 @@ This tests the basic functionality of catching errors synchronously and asynchronously

var str = longStackTraces ? ' (long-stack-traces)' : ''
describe('Basic Error catching' + str, function() {

@@ -14,0 +14,0 @@ before(function() {

@@ -12,3 +12,3 @@ var assert = require('assert'),

var str = longStackTraces ? ' (long-stack-traces)' : ''
describe('Nested trycatchs' + str, function() {

@@ -74,3 +74,3 @@ before(function() {

assert.equal(count, 3)
if (longStackTraces) {

@@ -97,3 +97,3 @@ assert.equal(err.stack.split(delimitter).length, 3)

++count
if (longStackTraces) {

@@ -112,3 +112,3 @@ assert.equal(err.stack.split(delimitter).length, 2)

assert.equal(count, 3)
if (longStackTraces) {

@@ -115,0 +115,0 @@ assert.equal(err.stack.split(delimitter).length, 3)

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc