stack-utils
Advanced tools
+213
-208
| module.exports = StackUtils; | ||
| function StackUtils(opts) { | ||
| if (!(this instanceof StackUtils)) { | ||
| throw new Error('StackUtils constructor must be called with new'); | ||
| } | ||
| opts = opts || {}; | ||
| this._cwd = (opts.cwd || process.cwd()).replace(/\\/g, '/'); | ||
| this._internals = opts.internals || []; | ||
| if (!(this instanceof StackUtils)) { | ||
| throw new Error('StackUtils constructor must be called with new'); | ||
| } | ||
| opts = opts || {}; | ||
| this._cwd = (opts.cwd || process.cwd()).replace(/\\/g, '/'); | ||
| this._internals = opts.internals || []; | ||
| this._wrapCallSite = opts.wrapCallSite || false; | ||
| } | ||
@@ -15,265 +16,269 @@ | ||
| function nodeInternals() { | ||
| return [ | ||
| /\(native\)$/, | ||
| /\(domain.js:\d+:\d+\)$/, | ||
| /\(events.js:\d+:\d+\)$/, | ||
| /\(node.js:\d+:\d+\)$/, | ||
| /\(timers.js:\d+:\d+\)$/, | ||
| /\(module.js:\d+:\d+\)$/, | ||
| /\(internal\/[\w_-]+\.js:\d+:\d+\)$/, | ||
| /\s*at node\.js:\d+:\d+?$/, | ||
| /\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/ | ||
| ]; | ||
| if (!module.exports.natives) { | ||
| module.exports.natives = Object.keys(process.binding('natives')); | ||
| module.exports.natives.push('bootstrap_node', 'node'); | ||
| } | ||
| return module.exports.natives.map(function (n) { | ||
| return new RegExp('\\(' + n + '\\.js:\\d+:\\d+\\)$'); | ||
| }).concat([ | ||
| /\s*at (bootstrap_)?node\.js:\d+:\d+?$/, | ||
| /\/\.node-spawn-wrap-\w+-\w+\/node:\d+:\d+\)?$/ | ||
| ]); | ||
| } | ||
| StackUtils.prototype.clean = function (stack) { | ||
| if (!Array.isArray(stack)) { | ||
| stack = stack.split('\n'); | ||
| } | ||
| if (!Array.isArray(stack)) { | ||
| stack = stack.split('\n'); | ||
| } | ||
| if (!(/^\s*at /.test(stack[0])) && | ||
| (/^\s*at /.test(stack[1]))) { | ||
| stack = stack.slice(1); | ||
| } | ||
| if (!(/^\s*at /.test(stack[0])) && | ||
| (/^\s*at /.test(stack[1]))) { | ||
| stack = stack.slice(1); | ||
| } | ||
| var outdent = false; | ||
| var lastNonAtLine = null; | ||
| var result = []; | ||
| var outdent = false; | ||
| var lastNonAtLine = null; | ||
| var result = []; | ||
| stack.forEach(function (st) { | ||
| st = st.replace(/\\/g, '/'); | ||
| var isInternal = this._internals.some(function (internal) { | ||
| return internal.test(st); | ||
| }); | ||
| stack.forEach(function (st) { | ||
| st = st.replace(/\\/g, '/'); | ||
| var isInternal = this._internals.some(function (internal) { | ||
| return internal.test(st); | ||
| }); | ||
| if (isInternal) { | ||
| return null; | ||
| } | ||
| if (isInternal) { | ||
| return null; | ||
| } | ||
| var isAtLine = /^\s*at /.test(st); | ||
| var isAtLine = /^\s*at /.test(st); | ||
| if (outdent) { | ||
| st = st.replace(/\s+$/, '').replace(/^(\s+)at /, '$1'); | ||
| } else { | ||
| st = st.trim(); | ||
| if (isAtLine) { | ||
| st = st.substring(3); | ||
| } | ||
| } | ||
| if (outdent) { | ||
| st = st.replace(/\s+$/, '').replace(/^(\s+)at /, '$1'); | ||
| } else { | ||
| st = st.trim(); | ||
| if (isAtLine) { | ||
| st = st.substring(3); | ||
| } | ||
| } | ||
| st = st.replace(this._cwd + '/', ''); | ||
| st = st.replace(this._cwd + '/', ''); | ||
| if (st) { | ||
| if (isAtLine) { | ||
| if (lastNonAtLine) { | ||
| result.push(lastNonAtLine); | ||
| lastNonAtLine = null; | ||
| } | ||
| result.push(st); | ||
| } else { | ||
| outdent = true; | ||
| lastNonAtLine = st; | ||
| } | ||
| } | ||
| }, this); | ||
| if (st) { | ||
| if (isAtLine) { | ||
| if (lastNonAtLine) { | ||
| result.push(lastNonAtLine); | ||
| lastNonAtLine = null; | ||
| } | ||
| result.push(st); | ||
| } else { | ||
| outdent = true; | ||
| lastNonAtLine = st; | ||
| } | ||
| } | ||
| }, this); | ||
| stack = result.join('\n').trim(); | ||
| stack = result.join('\n').trim(); | ||
| if (stack) { | ||
| return stack + '\n'; | ||
| } | ||
| return ''; | ||
| if (stack) { | ||
| return stack + '\n'; | ||
| } | ||
| return ''; | ||
| }; | ||
| StackUtils.prototype.captureString = function (limit, fn) { | ||
| if (typeof limit === 'function') { | ||
| fn = limit; | ||
| limit = Infinity; | ||
| } | ||
| if (!fn) { | ||
| fn = this.captureString; | ||
| } | ||
| if (typeof limit === 'function') { | ||
| fn = limit; | ||
| limit = Infinity; | ||
| } | ||
| if (!fn) { | ||
| fn = this.captureString; | ||
| } | ||
| var limitBefore = Error.stackTraceLimit; | ||
| if (limit) { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| var limitBefore = Error.stackTraceLimit; | ||
| if (limit) { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| var obj = {}; | ||
| var obj = {}; | ||
| Error.captureStackTrace(obj, fn); | ||
| var stack = obj.stack; | ||
| Error.stackTraceLimit = limitBefore; | ||
| Error.captureStackTrace(obj, fn); | ||
| var stack = obj.stack; | ||
| Error.stackTraceLimit = limitBefore; | ||
| return this.clean(stack); | ||
| return this.clean(stack); | ||
| }; | ||
| StackUtils.prototype.capture = function (limit, fn) { | ||
| if (typeof limit === 'function') { | ||
| fn = limit; | ||
| limit = Infinity; | ||
| } | ||
| if (!fn) { | ||
| fn = this.capture; | ||
| } | ||
| var prepBefore = Error.prepareStackTrace; | ||
| var limitBefore = Error.stackTraceLimit; | ||
| if (typeof limit === 'function') { | ||
| fn = limit; | ||
| limit = Infinity; | ||
| } | ||
| if (!fn) { | ||
| fn = this.capture; | ||
| } | ||
| var prepBefore = Error.prepareStackTrace; | ||
| var limitBefore = Error.stackTraceLimit; | ||
| var wrapCallSite = this._wrapCallSite; | ||
| Error.prepareStackTrace = function (obj, site) { | ||
| return site; | ||
| }; | ||
| Error.prepareStackTrace = function (obj, site) { | ||
| if (wrapCallSite) { | ||
| return site.map(wrapCallSite); | ||
| } | ||
| return site; | ||
| }; | ||
| if (limit) { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| if (limit) { | ||
| Error.stackTraceLimit = limit; | ||
| } | ||
| var obj = {}; | ||
| Error.captureStackTrace(obj, fn); | ||
| var stack = obj.stack; | ||
| Error.prepareStackTrace = prepBefore; | ||
| Error.stackTraceLimit = limitBefore; | ||
| var obj = {}; | ||
| Error.captureStackTrace(obj, fn); | ||
| var stack = obj.stack; | ||
| Error.prepareStackTrace = prepBefore; | ||
| Error.stackTraceLimit = limitBefore; | ||
| return stack; | ||
| return stack; | ||
| }; | ||
| StackUtils.prototype.at = function at(fn) { | ||
| if (!fn) { | ||
| fn = at; | ||
| } | ||
| if (!fn) { | ||
| fn = at; | ||
| } | ||
| var site = this.capture(1, fn)[0]; | ||
| var site = this.capture(1, fn)[0]; | ||
| if (!site) { | ||
| return {}; | ||
| } | ||
| if (!site) { | ||
| return {}; | ||
| } | ||
| var res = { | ||
| line: site.getLineNumber(), | ||
| column: site.getColumnNumber() | ||
| }; | ||
| var res = { | ||
| line: site.getLineNumber(), | ||
| column: site.getColumnNumber() | ||
| }; | ||
| this._setFile(res, site.getFileName()); | ||
| this._setFile(res, site.getFileName()); | ||
| if (site.isConstructor()) { | ||
| res.constructor = true; | ||
| } | ||
| if (site.isConstructor()) { | ||
| res.constructor = true; | ||
| } | ||
| if (site.isEval()) { | ||
| res.evalOrigin = site.getEvalOrigin(); | ||
| } | ||
| if (site.isEval()) { | ||
| res.evalOrigin = site.getEvalOrigin(); | ||
| } | ||
| if (site.isNative()) { | ||
| res.native = true; | ||
| } | ||
| if (site.isNative()) { | ||
| res.native = true; | ||
| } | ||
| var typename = null; | ||
| try { | ||
| typename = site.getTypeName(); | ||
| } catch (er) {} | ||
| var typename = null; | ||
| try { | ||
| typename = site.getTypeName(); | ||
| } catch (er) {} | ||
| if (typename && | ||
| typename !== 'Object' && | ||
| typename !== '[object Object]') { | ||
| res.type = typename; | ||
| } | ||
| if (typename && | ||
| typename !== 'Object' && | ||
| typename !== '[object Object]') { | ||
| res.type = typename; | ||
| } | ||
| var fname = site.getFunctionName(); | ||
| if (fname) { | ||
| res.function = fname; | ||
| } | ||
| var fname = site.getFunctionName(); | ||
| if (fname) { | ||
| res.function = fname; | ||
| } | ||
| var meth = site.getMethodName(); | ||
| if (meth && fname !== meth) { | ||
| res.method = meth; | ||
| } | ||
| var meth = site.getMethodName(); | ||
| if (meth && fname !== meth) { | ||
| res.method = meth; | ||
| } | ||
| return res; | ||
| return res; | ||
| }; | ||
| StackUtils.prototype._setFile = function (result, filename) { | ||
| if (filename) { | ||
| filename = filename.replace(/\\/g, '/'); | ||
| if ((filename.indexOf(this._cwd + '/') === 0)) { | ||
| filename = filename.substr(this._cwd.length + 1); | ||
| } | ||
| result.file = filename; | ||
| } | ||
| if (filename) { | ||
| filename = filename.replace(/\\/g, '/'); | ||
| if ((filename.indexOf(this._cwd + '/') === 0)) { | ||
| filename = filename.substr(this._cwd.length + 1); | ||
| } | ||
| result.file = filename; | ||
| } | ||
| }; | ||
| var re = new RegExp( | ||
| '^' + | ||
| // Sometimes we strip out the ' at' because it's noisy | ||
| '(?:\\s*at )?' + | ||
| // $1 = ctor if 'new' | ||
| '(?:(new) )?' + | ||
| // Object.method [as foo] (, maybe | ||
| // $2 = function name | ||
| // $3 = method name | ||
| '(?:([^\\(\\[]*)(?: \\[as ([^\\]]+)\\])? \\()?' + | ||
| // (eval at <anonymous> (file.js:1:1), | ||
| // $4 = eval origin | ||
| // $5:$6:$7 are eval file/line/col, but not normally reported | ||
| '(?:eval at ([^ ]+) \\(([^\\)]+):(\\d+):(\\d+)\\), )?' + | ||
| // file:line:col | ||
| // $8:$9:$10 | ||
| // $11 = 'native' if native | ||
| '(?:([^\\)]+):(\\d+):(\\d+)|(native))' + | ||
| // maybe close the paren, then end | ||
| '\\)?$' | ||
| '^' + | ||
| // Sometimes we strip out the ' at' because it's noisy | ||
| '(?:\\s*at )?' + | ||
| // $1 = ctor if 'new' | ||
| '(?:(new) )?' + | ||
| // Object.method [as foo] (, maybe | ||
| // $2 = function name | ||
| // $3 = method name | ||
| '(?:([^\\(\\[]*)(?: \\[as ([^\\]]+)\\])? \\()?' + | ||
| // (eval at <anonymous> (file.js:1:1), | ||
| // $4 = eval origin | ||
| // $5:$6:$7 are eval file/line/col, but not normally reported | ||
| '(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?' + | ||
| // file:line:col | ||
| // $8:$9:$10 | ||
| // $11 = 'native' if native | ||
| '(?:(.+?):(\\d+):(\\d+)|(native))' + | ||
| // maybe close the paren, then end | ||
| '\\)?$' | ||
| ); | ||
| StackUtils.prototype.parseLine = function parseLine(line) { | ||
| var match = line && line.match(re); | ||
| if (!match) { | ||
| return null; | ||
| } | ||
| var match = line && line.match(re); | ||
| if (!match) { | ||
| return null; | ||
| } | ||
| var ctor = match[1] === 'new'; | ||
| var fname = match[2]; | ||
| var meth = match[3]; | ||
| var evalOrigin = match[4]; | ||
| var evalFile = match[5]; | ||
| var evalLine = Number(match[6]); | ||
| var evalCol = Number(match[7]); | ||
| var file = match[8]; | ||
| var lnum = match[9]; | ||
| var col = match[10]; | ||
| var native = match[11] === 'native'; | ||
| var ctor = match[1] === 'new'; | ||
| var fname = match[2]; | ||
| var meth = match[3]; | ||
| var evalOrigin = match[4]; | ||
| var evalFile = match[5]; | ||
| var evalLine = Number(match[6]); | ||
| var evalCol = Number(match[7]); | ||
| var file = match[8]; | ||
| var lnum = match[9]; | ||
| var col = match[10]; | ||
| var native = match[11] === 'native'; | ||
| var res = {}; | ||
| var res = {}; | ||
| if (lnum) { | ||
| res.line = Number(lnum); | ||
| } | ||
| if (lnum) { | ||
| res.line = Number(lnum); | ||
| } | ||
| if (col) { | ||
| res.column = Number(col); | ||
| } | ||
| if (col) { | ||
| res.column = Number(col); | ||
| } | ||
| this._setFile(res, file); | ||
| this._setFile(res, file); | ||
| if (ctor) { | ||
| res.constructor = true; | ||
| } | ||
| if (ctor) { | ||
| res.constructor = true; | ||
| } | ||
| if (evalOrigin) { | ||
| res.evalOrigin = evalOrigin; | ||
| res.evalLine = evalLine; | ||
| res.evalColumn = evalCol; | ||
| res.evalFile = evalFile && evalFile.replace(/\\/g, '/'); | ||
| } | ||
| if (evalOrigin) { | ||
| res.evalOrigin = evalOrigin; | ||
| res.evalLine = evalLine; | ||
| res.evalColumn = evalCol; | ||
| res.evalFile = evalFile && evalFile.replace(/\\/g, '/'); | ||
| } | ||
| if (native) { | ||
| res.native = true; | ||
| } | ||
| if (native) { | ||
| res.native = true; | ||
| } | ||
| if (fname) { | ||
| res.function = fname; | ||
| } | ||
| if (fname) { | ||
| res.function = fname; | ||
| } | ||
| if (meth && fname !== meth) { | ||
| res.method = meth; | ||
| } | ||
| if (meth && fname !== meth) { | ||
| res.method = meth; | ||
| } | ||
| return res; | ||
| return res; | ||
| }; | ||
@@ -284,3 +289,3 @@ | ||
| Object.keys(StackUtils.prototype).forEach(function (key) { | ||
| StackUtils[key] = bound[key].bind(bound); | ||
| StackUtils[key] = bound[key].bind(bound); | ||
| }); |
+4
-7
| { | ||
| "name": "stack-utils", | ||
| "version": "0.4.0", | ||
| "version": "1.0.0", | ||
| "description": "Captures and cleans stack traces", | ||
@@ -16,4 +16,3 @@ "license": "MIT", | ||
| "scripts": { | ||
| "test": "xo && nyc --reporter lcov --reporter text --cache ava --verbose", | ||
| "test-win": "ava --verbose" | ||
| "test": "tap test/*.js --cov" | ||
| }, | ||
@@ -28,12 +27,10 @@ "files": [ | ||
| "devDependencies": { | ||
| "ava": "^0.8.0", | ||
| "bluebird": "^3.1.1", | ||
| "coveralls": "^2.11.6", | ||
| "flatten": "0.0.1", | ||
| "nested-error-stacks": "^1.0.2", | ||
| "nyc": "^5.2.0", | ||
| "nested-error-stacks": "^2.0.0", | ||
| "pify": "^2.3.0", | ||
| "q": "^1.4.1", | ||
| "xo": "^0.12.1" | ||
| "tap": "^10.0.0" | ||
| } | ||
| } |
+7
-1
@@ -24,3 +24,3 @@ # stack-utils | ||
| console.log(stack.clean(new Error().stack)); | ||
| // outputs a beutified stack trace | ||
| // outputs a beautified stack trace | ||
| ``` | ||
@@ -51,3 +51,9 @@ | ||
| ##### wrapCallSite | ||
| Type: `function(CallSite)` | ||
| A mapping function for manipulating CallSites before processing. The first argument is a CallSite instance, and the function should return a modified CallSite. This is useful for providing source map support. | ||
| ### StackUtils.nodeInternals() | ||
@@ -54,0 +60,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
12078
6.2%7
-22.22%235
1.73%1
-50%133
4.72%1
Infinity%