pax_global_header00006660000000000000000000000064130772075240014521gustar00rootroot0000000000000052 comment=f080bcb2ee9be20520cfb312837d6056011e9094 stack-utils-1.0.1/000077500000000000000000000000001307720752400137635ustar00rootroot00000000000000stack-utils-1.0.1/.editorconfig000066400000000000000000000003511307720752400164370ustar00rootroot00000000000000root = true [*] indent_style = space end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [{package.json,*.yml}] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false stack-utils-1.0.1/.gitattributes000066400000000000000000000000141307720752400166510ustar00rootroot00000000000000* text=auto stack-utils-1.0.1/.gitignore000066400000000000000000000000421307720752400157470ustar00rootroot00000000000000node_modules coverage .nyc_output stack-utils-1.0.1/.travis.yml000066400000000000000000000002261307720752400160740ustar00rootroot00000000000000language: node_js node_js: - '7' - '6' - '4' - '0.12' - '0.10' after_script: - 'cat ./coverage/lcov.info | ./node_modules/.bin/coveralls' stack-utils-1.0.1/appveyor.yml000066400000000000000000000010411307720752400163470ustar00rootroot00000000000000environment: matrix: - nodejs_version: '7' - nodejs_version: '6' - nodejs_version: '4' - nodejs_version: '0.12' - nodejs_version: '0.10' install: - ps: Install-Product node $env:nodejs_version - set CI=true - npm -g install npm@latest || (timeout 30 && npm -g install npm@latest) - set PATH=%APPDATA%\npm;%PATH% - npm install || (timeout 30 && npm install) matrix: fast_finish: true build: off version: '{build}' shallow_clone: true clone_depth: 1 test_script: - node --version - npm --version - npm test stack-utils-1.0.1/index.js000066400000000000000000000161541307720752400154370ustar00rootroot00000000000000module.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 || []; this._wrapCallSite = opts.wrapCallSite || false; } module.exports.nodeInternals = nodeInternals; function nodeInternals() { 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 (!(/^\s*at /.test(stack[0])) && (/^\s*at /.test(stack[1]))) { stack = stack.slice(1); } 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); }); if (isInternal) { return null; } 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); } } 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); stack = result.join('\n').trim(); 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; } var limitBefore = Error.stackTraceLimit; if (limit) { Error.stackTraceLimit = limit; } var obj = {}; Error.captureStackTrace(obj, fn); var stack = obj.stack; Error.stackTraceLimit = limitBefore; 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; var wrapCallSite = this._wrapCallSite; Error.prepareStackTrace = function (obj, site) { if (wrapCallSite) { return site.map(wrapCallSite); } return site; }; if (limit) { Error.stackTraceLimit = limit; } var obj = {}; Error.captureStackTrace(obj, fn); var stack = obj.stack; Error.prepareStackTrace = prepBefore; Error.stackTraceLimit = limitBefore; return stack; }; StackUtils.prototype.at = function at(fn) { if (!fn) { fn = at; } var site = this.capture(1, fn)[0]; if (!site) { return {}; } var res = { line: site.getLineNumber(), column: site.getColumnNumber() }; this._setFile(res, site.getFileName()); if (site.isConstructor()) { res.constructor = true; } if (site.isEval()) { res.evalOrigin = site.getEvalOrigin(); } if (site.isNative()) { res.native = true; } var typename = null; try { typename = site.getTypeName(); } catch (er) {} if (typename && typename !== 'Object' && typename !== '[object Object]') { res.type = typename; } var fname = site.getFunctionName(); if (fname) { res.function = fname; } var meth = site.getMethodName(); if (meth && fname !== meth) { res.method = meth; } 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; } }; var re = new RegExp( '^' + // Sometimes we strip out the ' at' because it's noisy '(?:\\s*at )?' + // $1 = ctor if 'new' '(?:(new) )?' + // $2 = function name (can be literally anything) // May contain method at the end as [as xyz] '(?:(.*?) \\()?' + // (eval at (file.js:1:1), // $3 = eval origin // $4:$5:$6 are eval file/line/col, but not normally reported '(?:eval at ([^ ]+) \\((.+?):(\\d+):(\\d+)\\), )?' + // file:line:col // $7:$8:$9 // $10 = 'native' if native '(?:(.+?):(\\d+):(\\d+)|(native))' + // maybe close the paren, then end // if $11 is ), then we only allow balanced parens in the filename // any imbalance is placed on the fname. This is a heuristic, and // bound to be incorrect in some edge cases. The bet is that // having weird characters in method names is more common than // having weird characters in filenames, which seems reasonable. '(\\)?)$' ); var methodRe = /^(.*?) \[as (.*?)\]$/; StackUtils.prototype.parseLine = function parseLine(line) { var match = line && line.match(re); if (!match) { return null; } var ctor = match[1] === 'new'; var fname = match[2]; var evalOrigin = match[3]; var evalFile = match[4]; var evalLine = Number(match[5]); var evalCol = Number(match[6]); var file = match[7]; var lnum = match[8]; var col = match[9]; var native = match[10] === 'native'; var closeParen = match[11] === ')'; var res = {}; if (lnum) { res.line = Number(lnum); } if (col) { res.column = Number(col); } if (closeParen && file) { // make sure parens are balanced // if we have a file like "asdf) [as foo] (xyz.js", then odds are // that the fname should be += " (asdf) [as foo]" and the file // should be just "xyz.js" // walk backwards from the end to find the last unbalanced ( var closes = 0; for (var i = file.length - 1; i > 0; i--) { if (file.charAt(i) === ')') { closes ++; } else if (file.charAt(i) === '(' && file.charAt(i - 1) === ' ') { closes --; if (closes === -1 && file.charAt(i - 1) === ' ') { var before = file.substr(0, i - 1); var after = file.substr(i + 1); file = after; fname += ' (' + before; break; } } } } if (fname) { var methodMatch = fname.match(methodRe); if (methodMatch) { fname = methodMatch[1]; var meth = methodMatch[2]; } } this._setFile(res, file); if (ctor) { res.constructor = true; } if (evalOrigin) { res.evalOrigin = evalOrigin; res.evalLine = evalLine; res.evalColumn = evalCol; res.evalFile = evalFile && evalFile.replace(/\\/g, '/'); } if (native) { res.native = true; } if (fname) { res.function = fname; } if (meth && fname !== meth) { res.method = meth; } return res; }; var bound = new StackUtils(); Object.keys(StackUtils.prototype).forEach(function (key) { StackUtils[key] = bound[key].bind(bound); }); stack-utils-1.0.1/license000066400000000000000000000023131307720752400153270ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) Isaac Z. Schlueter , James Talmage (github.com/jamestalmage), and Contributors Extracted from code in node-tap http://www.node-tap.org/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. stack-utils-1.0.1/package.json000066400000000000000000000014361307720752400162550ustar00rootroot00000000000000{ "name": "stack-utils", "version": "1.0.1", "description": "Captures and cleans stack traces", "license": "MIT", "repository": "tapjs/stack-utils", "author": { "name": "James Talmage", "email": "james@talmage.io", "url": "github.com/jamestalmage" }, "engines": { "node": ">=0.10.0" }, "scripts": { "test": "tap test/*.js --100 -J", "preversion": "npm test", "postversion": "npm publish", "postpublish": "git push origin --all; git push origin --tags" }, "files": [ "index.js" ], "keywords": [ "" ], "dependencies": {}, "devDependencies": { "bluebird": "^3.1.1", "coveralls": "^2.11.6", "flatten": "0.0.1", "nested-error-stacks": "^2.0.0", "pify": "^2.3.0", "q": "^1.4.1", "tap": "^10.3.2" } } stack-utils-1.0.1/readme.md000066400000000000000000000101671307720752400155470ustar00rootroot00000000000000# stack-utils > Captures and cleans stack traces. [![Linux Build](https://travis-ci.org/tapjs/stack-utils.svg?branch=master)](https://travis-ci.org/tapjs/stack-utils) [![Build status](https://ci.appveyor.com/api/projects/status/fb9i157knoixe3iq/branch/master?svg=true)](https://ci.appveyor.com/project/jamestalmage/stack-utils-oiw96/branch/master) [![Coverage](https://coveralls.io/repos/tapjs/stack-utils/badge.svg?branch=master&service=github)](https://coveralls.io/github/tapjs/stack-utils?branch=master) Extracted from `lib/stack.js` in the [`node-tap` project](https://github.com/tapjs/node-tap) ## Install ``` $ npm install --save stack-utils ``` ## Usage ```js const StackUtils = require('stack-utils'); const stack = new StackUtils({cwd: process.cwd(), internals: StackUtils.nodeInternals()}); console.log(stack.clean(new Error().stack)); // outputs a beautified stack trace ``` ## API ### new StackUtils([options]) Creates a new `stackUtils` instance. #### options ##### internals Type: `array` of `RegularExpression`s A set of regular expressions that match internal stack stack trace lines which should be culled from the stack trace. `StackUtils.nodeInternals()` returns a relatively set of sensible defaults for use on the node platform. ##### cwd Type: `string` The path to the current working directory. File names in the stack trace will be shown relative to this directory. ##### 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() Returns an array of regular expressions that be used to cull lines from the stack trace that reference common Node.js internal files. ### stackUtils.clean(stack) Cleans up a stack trace by deleting any lines that match the `internals` passed to the constructor, and shortening file names relative to `cwd`. Returns a `string` with the cleaned up stack (always terminated with a `\n` newline character). #### stack *Required* Type: `string` or an `array` of `string`s ### stackUtils.capture([limit], [startStackFunction]) Captures the current stack trace, returning an array of `CallSite`s. There are good overviews of the available CallSite methods [here](https://github.com/v8/v8/wiki/Stack%20Trace%20API#customizing-stack-traces), and [here](https://github.com/sindresorhus/callsites#api). #### limit Type: `number` Default: `Infinity` Limits the number of lines returned by dropping all lines in excess of the limit. This removes lines from the stack trace. #### startStackFunction Type: `function` The function where the stack trace should start. The first line of the stack trace will be the function that called `startStackFunction`. This removes lines from the end of the stack trace. ### stackUtils.captureString([limit], [startStackFunction]) Captures the current stack trace, cleans it using `stackUtils.clean(stack)`, and returns a string with the cleaned stack trace. It takes the same arguments as `stackUtils.capture`. ### stackUtils.at([startStackFunction]) Captures the first line of the stack trace (or the first line after `startStackFunction` if supplied), and returns a `CallSite` like object that is serialization friendly (properties are actual values instead of getter functions). The available properties are: - `line`: `number` - `column`: `number` - `file`: `string` - `constructor`: `boolean` - `evalOrigin`: `string` - `native`: `boolean` - `typename`: `string` - `function`: `string` - `method`: `string` ### stackUtils.parseLine(line) Parses a `string` (which should be a single line from a stack trace), and generates an object with the following properties: - `line`: `number` - `column`: `number` - `file`: `string` - `constructor`: `boolean` - `evalOrigin`: `string` - `evalLine`: `number` - `evalColumn`: `number` - `evalFile`: `string` - `native`: `boolean` - `function`: `string` - `method`: `string` ## License MIT © [Isaac Z. Schlueter](http://github.com/isaacs), [James Talmage](http://github.com/jamestalmage) stack-utils-1.0.1/test/000077500000000000000000000000001307720752400147425ustar00rootroot00000000000000stack-utils-1.0.1/test/_utils.js000066400000000000000000000005201307720752400165740ustar00rootroot00000000000000var flatten = require('flatten'); var path = require('path'); module.exports.join = join; module.exports.fixtureDir = path.join(__dirname, 'fixtures'); function join() { var args = Array.prototype.slice.call(arguments); return flatten(args).join('\n') + '\n'; } if (module === require.main) require('tap').pass('this is fine') stack-utils-1.0.1/test/at.js000066400000000000000000000011061307720752400157020ustar00rootroot00000000000000// some capture edge cases not already covered by other tests var StackUtils = require('../') var t = require('tap') var stack = new StackUtils() // a capture with no function, not much to it, actually var base = __filename.substr(process.cwd().length + 1) t.match(stack.at(), { line: Number, column: Number, file: base }) // a capture from a native site var arr = [ 0 ] var captures = arr.map(function xyz (n) { return stack.at(xyz) }) t.match(captures, [ { line: Number, column: Number, file: 'native array.js', native: true, type: 'Array', function: 'map' } ]) stack-utils-1.0.1/test/fixtures/000077500000000000000000000000001307720752400166135ustar00rootroot00000000000000stack-utils-1.0.1/test/fixtures/capture-fixture.js000066400000000000000000000026761307720752400223130ustar00rootroot00000000000000'use strict'; module.exports = CaptureFixture; function CaptureFixture(stack) { this.stack = stack; } CaptureFixture.prototype.redirect1 = function () { var args = Array.prototype.slice.call(arguments); var method = args.shift(); return this[method].apply(this, args); }; CaptureFixture.prototype.redirect2 = function () { var args = Array.prototype.slice.call(arguments); var method = args.shift(); return this[method].apply(this, args); }; CaptureFixture.prototype.call = function () { var args = Array.prototype.slice.call(arguments); var method = args.shift(); return this.stack[method].apply(this.stack, args); }; CaptureFixture.prototype.const = function () { var args = Array.prototype.slice.call(arguments); var method = args.shift(); var self = this; function Constructor() { this.val = self[method].apply(self, args); } return new Constructor().val; }; CaptureFixture.prototype.obj = function () { var args = Array.prototype.slice.call(arguments); var methodName = args.shift(); var method = args.shift(); var self = this; var obj = {}; obj[methodName] = function () { return self[method].apply(self, args); }; return obj[methodName](); }; CaptureFixture.prototype.eval = function () { var args = Array.prototype.slice.call(arguments); var method = args.shift(); var self = this; return eval('self[method].apply(self, args)'); }; CaptureFixture.prototype.error = function (message) { return new Error(message); }; stack-utils-1.0.1/test/fixtures/generate-parse-fixture.js000066400000000000000000000075711307720752400235510ustar00rootroot00000000000000'use strict' // Run this file to re-generate the parse fixture json after changes. let lines = new Set() const basename = require('path').basename(__filename) const lineRE = new RegExp('\\b' + basename + ':([0-9]+):([0-9]+)\\b', 'g') const capture = e => e.stack.split('\n').forEach(line => { if (line === 'Error: ok') return lines.add( line .split(__dirname).join('__dirname') .replace(lineRE, basename + ':420:69') ) }) const done = _ => { const StackUtils = require('../..') var stack = new StackUtils() const obj = Object.create(null) lines.forEach(line => obj[line] = stack.parseLine(line)) const fs = require('fs') const json = JSON.stringify(obj, null, 2) + '\n' fs.writeFileSync(__dirname + '/parse-fixture.json', json) } { const s = Symbol('foo') const o = { [s] () { throw new Error('ok') } } try { o[s]() } catch (e) { capture(e) } } { const o = { ['asdf ][)( \u0000\u0001\u0002\u0003\u001b[44;37m foo'] () { throw new Error('ok') } } try { o['asdf ][)( \u0000\u0001\u0002\u0003\u001b[44;37m foo']() } catch (e) { capture(e) } } { const s = 'asdf (' + __filename + ':1:9999)' const o = { [s] () { throw new Error('ok') } } try { o[s]() } catch (e) { capture(e) } } { const s = 'eval' const o = { [s] () { throw new Error('ok') } } try { eval('o[s]()') } catch (e) { capture(e) } } { const vm = require('vm') const code = 'function fooeval () { eval("o[s]()") }; fooeval()' const s = 'a (s) d [f]' const o = { [s] () { throw new Error('ok') } } try { vm.runInNewContext(code, {o, s}, { filename: 'a file with eval .js' }) } catch (e) { capture(e) } } { const vm = require('vm') const code = 'eval("o[s]()")' const s = 'a (s) d [f]' const o = { [s] () { throw new Error('ok') } } try { vm.runInNewContext(code, {o, s}, { filename: 'a file with eval .js' }) } catch (e) { capture(e) } } { const s = 'function ctor (file.js:1:2) ' const o = { [s] () { throw new Error('ok') } } try { new Function('o', 's', 'o[s]()')(o, s) } catch (e) { capture(e) } } { const s = Symbol.iterator const o = { [s] () { throw new Error('ok') } } try { new Function('o', 's', 'o[s]()')(o, s) } catch (e) { capture(e) } } { const s = Symbol.iterator const o = new class Classy { [s] () { throw new Error('ok') } } try { new Function('o', 's', 'o[s]()')(o, s) } catch (e) { capture(e) } } { const s = Symbol('some (weird) []') const o = new class Classy { [s] () { throw new Error('ok') } } try { const x = o[s] x() } catch (e) { capture(e) } } { const s = Symbol('some (weird) []') const o = new class Classy { [s] () { throw new Error('ok') } } try { const x = { foo: o[s] } x.foo() } catch (e) { capture(e) } } { const s = Symbol('some (weird) []') const o = new class Classy { [s] () { throw new Error('ok') } } try { const x = new class OtherClass { constructor() { this.foo = o[s] } } x.foo() } catch (e) { capture(e) } } { const vm = require('vm') const o = { ['a (w) []'] () { throw new Error('ok') } } try { vm.runInNewContext('o["a (w) []"]()', { o: o }) } catch (e) { capture(e) } } { const vm = require('vm') const o = { ['a (w) []'] () { throw new Error('ok') } } try { vm.runInNewContext( 'function x () { o["a (w) []"]() }\n' + 'x()', { o: o }, { filename: ' f[i](l:.js:1:2) ' }) } catch (e) { capture(e) } } { class Foo { constructor () { throw new Error('ok') } } try { new Foo() } catch (e) { capture(e) } } { class Foo { constructor (n) { this.n = n throw new Error('ok') } } const arr = [1,2,3] try { arr.map(n => new Foo(n)) } catch (e) { capture(e) } } done() stack-utils-1.0.1/test/fixtures/internal-error.js000066400000000000000000000007141307720752400221160ustar00rootroot00000000000000'use strict'; var NestedError = require('nested-error-stacks'); var util = require('util'); function InternalError(message, nested) { NestedError.call(this, message, nested); } util.inherits(InternalError, NestedError); InternalError.prototype.name = 'InternalError'; module.exports = function (cb, err) { setTimeout(bound.bind(null, cb, err), 0); }; function bound(cb, err) { cb(new InternalError('internal' + (err ? ': ' + err.message : ''), err)); } stack-utils-1.0.1/test/fixtures/internal-then.js000066400000000000000000000010251307720752400217170ustar00rootroot00000000000000 //var p = global.InternalPromise.resolve().then(function () {}); module.exports = function internalLibraryOuterFn(then) { return global.InternalPromise.resolve().then(function internalLibraryInnerFn() { return global.InternalPromise.resolve().then(then); }); }; module.exports.reject = function internalLibraryOuterReject() { return global.InternalPromise.resolve().then(function internalLibraryInnerReject() { return global.InternalPromise.reject(new Error('inner')).catch(function (e) { return e.stack; }); }); }; stack-utils-1.0.1/test/fixtures/long-stack-traces.js000066400000000000000000000010321307720752400224660ustar00rootroot00000000000000'use strict'; var Q = require('q'); Q.longStackSupport = true; global.InternalPromise = Q; module.exports.q = require('./produce-long-stack-traces'); var longStackTracePath = require.resolve('./produce-long-stack-traces'); var internalThen = require.resolve('./internal-then'); delete require.cache[longStackTracePath]; delete require.cache[internalThen]; var bluebird = require('bluebird'); bluebird.config({longStackTraces: true}); global.InternalPromise = bluebird; module.exports.bluebird = require('./produce-long-stack-traces'); stack-utils-1.0.1/test/fixtures/nested-errors.js000066400000000000000000000017421307720752400217510ustar00rootroot00000000000000'use strict'; var NestedError = require('nested-error-stacks'); var util = require('util'); var internal = require('./internal-error'); function foo(cb) { bar(function nested(err) { cb(new FooError('foo' + err.message, err)); }); } function bar(cb) { internal(function moreNested(err) { cb(new BarError('bar: ' + err.message, err)); }); } function FooError(message, nested) { NestedError.call(this, message, nested); } util.inherits(FooError, NestedError); FooError.prototype.name = 'FooError'; function BarError(message, nested) { NestedError.call(this, message, nested); } util.inherits(BarError, NestedError); BarError.prototype.name = 'BarError'; module.exports.top = function(cb) { internal(function (err) { cb(err.stack); }, new Error('baz')); }; module.exports.middle = function (cb) { internal(function (err) { cb(new FooError('foo', err).stack); }, new Error('bar')); }; module.exports.bottom = function (cb) { foo(function (err){ cb(err.stack); }); }; stack-utils-1.0.1/test/fixtures/parse-fixture.json000066400000000000000000000161101307720752400223030ustar00rootroot00000000000000{ " at Object.[foo] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.[foo]" }, " at Object. (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object." }, " at Module._compile (module.js:571:32)": { "line": 571, "column": 32, "file": "module.js", "function": "Module._compile" }, " at Object.Module._extensions..js (module.js:580:10)": { "line": 580, "column": 10, "file": "module.js", "function": "Object.Module._extensions..js" }, " at Module.load (module.js:488:32)": { "line": 488, "column": 32, "file": "module.js", "function": "Module.load" }, " at tryModuleLoad (module.js:447:12)": { "line": 447, "column": 12, "file": "module.js", "function": "tryModuleLoad" }, " at Function.Module._load (module.js:439:3)": { "line": 439, "column": 3, "file": "module.js", "function": "Function.Module._load" }, " at Module.runMain (module.js:605:10)": { "line": 605, "column": 10, "file": "module.js", "function": "Module.runMain" }, " at run (bootstrap_node.js:418:7)": { "line": 418, "column": 7, "file": "bootstrap_node.js", "function": "run" }, " at startup (bootstrap_node.js:139:9)": { "line": 139, "column": 9, "file": "bootstrap_node.js", "function": "startup" }, " at Object.asdf ][)( \u0000\u0001\u0002\u0003\u001b[44;37m foo (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.asdf ][)( \u0000\u0001\u0002\u0003\u001b[44;37m foo" }, " at Object.asdf (__dirname/generate-parse-fixture.js:420:69) (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.asdf (__dirname/generate-parse-fixture.js:420:69)" }, " at Object.eval (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.eval" }, " at eval (eval at (__dirname/generate-parse-fixture.js:420:69), :1:5)": { "line": 1, "column": 5, "file": "", "evalOrigin": "", "evalLine": 420, "evalColumn": 69, "evalFile": "__dirname/generate-parse-fixture.js", "function": "eval" }, " at Object.a (s) d [f] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.a (s) d [f]" }, " at eval (eval at fooeval (a file with eval .js:1:23), :1:5)": { "line": 1, "column": 5, "file": "", "evalOrigin": "fooeval", "evalLine": 1, "evalColumn": 23, "evalFile": "a file with eval .js", "function": "eval" }, " at fooeval (a file with eval .js:1:23)": { "line": 1, "column": 23, "file": "a file with eval .js", "function": "fooeval" }, " at a file with eval .js:1:41": { "line": 1, "column": 41, "file": "a file with eval .js" }, " at ContextifyScript.Script.runInContext (vm.js:32:29)": { "line": 32, "column": 29, "file": "vm.js", "function": "ContextifyScript.Script.runInContext" }, " at ContextifyScript.Script.runInNewContext (vm.js:38:15)": { "line": 38, "column": 15, "file": "vm.js", "function": "ContextifyScript.Script.runInNewContext" }, " at Object.exports.runInNewContext (vm.js:69:17)": { "line": 69, "column": 17, "file": "vm.js", "function": "Object.exports.runInNewContext" }, " at eval (eval at (a file with eval .js:1:1), :1:5)": { "line": 1, "column": 5, "file": "", "evalOrigin": "", "evalLine": 1, "evalColumn": 1, "evalFile": "a file with eval .js", "function": "eval" }, " at a file with eval .js:1:1": { "line": 1, "column": 1, "file": "a file with eval .js" }, " at Object.function ctor (file.js:1:2) (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.function ctor (file.js:1:2) " }, " at eval (eval at (__dirname/generate-parse-fixture.js:420:69), :3:5)": { "line": 3, "column": 5, "file": "", "evalOrigin": "", "evalLine": 420, "evalColumn": 69, "evalFile": "__dirname/generate-parse-fixture.js", "function": "eval" }, " at Object.[Symbol.iterator] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.[Symbol.iterator]" }, " at Classy.[Symbol.iterator] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Classy.[Symbol.iterator]" }, " at [some (weird) []] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "[some (weird) []]" }, " at Object.[some (weird) []] [as foo] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.[some (weird) []]", "method": "foo" }, " at OtherClass.[some (weird) []] [as foo] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "OtherClass.[some (weird) []]", "method": "foo" }, " at Object.a (w) [] (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "Object.a (w) []" }, " at evalmachine.:1:17": { "line": 1, "column": 17, "file": "evalmachine." }, " at x ( f[i](l:.js:1:2) :1:33)": { "line": 1, "column": 33, "file": " f[i](l:.js:1:2) ", "function": "x" }, " at f[i](l:.js:1:2) :2:1": { "line": 2, "column": 1, "file": " f[i](l:.js:1:2) " }, " at new Foo (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "constructor": true, "function": "Foo" }, " at arr.map.n (__dirname/generate-parse-fixture.js:420:69)": { "line": 420, "column": 69, "file": "__dirname/generate-parse-fixture.js", "function": "arr.map.n" }, " at Array.map (native)": { "native": true, "function": "Array.map" } } stack-utils-1.0.1/test/fixtures/produce-long-stack-traces.js000066400000000000000000000025151307720752400241340ustar00rootroot00000000000000'use strict'; var Promise = global.InternalPromise; var internalThen = require('./internal-then'); module.exports = Promise.resolve().then(function outer() { return Promise.resolve().then(function inner() { return Promise.resolve().then(function evenMoreInner() { return Promise.resolve().then(function mostInner() { a.b.c.d() }).catch(function catcher(e) { return e.stack; }); }); }); }); module.exports.middle = Promise.resolve().then(function outer() { return Promise.resolve().then(function inner() { return internalThen(function evenMoreInner() { return Promise.resolve().then(function mostInner() { a.b.c.d() }).catch(function catcher(e) { return e.stack; }); }); }); }); module.exports.top = Promise.resolve().then(function outer() { return Promise.resolve().then(function inner() { return Promise.resolve().then(function evenMoreInner() { return Promise.resolve().then(internalThen.reject); }); }); }); module.exports.bottom = new Promise(function (resolve) { setTimeout(internalThen.bind(null, function outer() { return Promise.resolve().then(function inner() { return Promise.resolve().then(function evenMoreInner() { return Promise.resolve().then(function mostInner() { a.b.c.d() }).catch(function catcher(e) { resolve(e.stack); }); }); }); }),0); }); stack-utils-1.0.1/test/long-stack-traces.js000066400000000000000000000107071307720752400206260ustar00rootroot00000000000000var t = require('tap'); var StackUtils = require('../'); var longStackTraces = require('./fixtures/long-stack-traces'); var pify = require('pify'); var Promise = require('bluebird'); var nestedErrors = pify(require('./fixtures/nested-errors'), Promise); var utils = require('./_utils'); function internals() { return StackUtils.nodeInternals().concat([ /\/long-stack-traces\.js:\d+:\d+\)?$/, /\/internal-error\.js:\d+:\d+\)?$/, /\/internal-then\.js:\d+:\d+\)?$/, /\/node_modules\// ]); } var stackUtils = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); t.test('indents lines after first "From previous event:"', function (t) { return longStackTraces.bluebird .then(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'mostInner (produce-long-stack-traces.js:10:5)', 'From previous event:', ' evenMoreInner (produce-long-stack-traces.js:9:29)', 'From previous event:', ' inner (produce-long-stack-traces.js:8:28)', 'From previous event:', ' outer (produce-long-stack-traces.js:7:27)', 'From previous event:', ' Object. (produce-long-stack-traces.js:6:36)' ]); t.is(cleanedStack, expected); }); }); t.test('removes empty "From previous event:" sections from the bottom', function (t) { return longStackTraces.bluebird.bottom .then(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'mostInner (produce-long-stack-traces.js:43:6)', 'From previous event:', ' evenMoreInner (produce-long-stack-traces.js:42:30)', 'From previous event:', ' inner (produce-long-stack-traces.js:41:29)', 'From previous event:', ' outer (produce-long-stack-traces.js:40:28)' ]); t.is(cleanedStack, expected); }); }); t.test('removes empty "From previous event:" sections from the top', function (t) { return longStackTraces.bluebird.top then(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'From previous event:', ' evenMoreInner (produce-long-stack-traces.js:33:29)', 'From previous event:', ' inner (produce-long-stack-traces.js:32:28)', 'From previous event:', ' outer (produce-long-stack-traces.js:31:27)', 'From previous event:', ' Object. (produce-long-stack-traces.js:30:40)' ]); t.is(cleanedStack, expected); }); }); t.test('removes empty "From previous event:" sections from the middle', function (t) { return longStackTraces.bluebird.middle then(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'mostInner (produce-long-stack-traces.js:22:5)', 'From previous event:', ' evenMoreInner (produce-long-stack-traces.js:21:29)', 'From previous event:', ' inner (produce-long-stack-traces.js:20:10)', 'From previous event:', ' outer (produce-long-stack-traces.js:19:27)', 'From previous event:', ' Object. (produce-long-stack-traces.js:18:43)' ]); t.match(cleanedStack, expected); }); }); t.test('removes empty "Caused by:" sections from the top', function (t) { nestedErrors.top(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'Caused By: Error: baz', ' Object.module.exports.top (nested-errors.js:36:5)' ]); t.match(cleanedStack, expected); t.end(); }); }); t.test('removes empty "Caused by:" sections from the bottom', function (t) { nestedErrors.bottom(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'nested (nested-errors.js:9:6)', 'moreNested (nested-errors.js:15:3)', 'Caused By: BarError: bar: internal', ' moreNested (nested-errors.js:15:6)' ]); t.is(cleanedStack, expected); t.end(); }); }); t.test('removes empty "Caused by:" sections from the middle', function (t) { nestedErrors.middle(function (stack) { var cleanedStack = stackUtils.clean(stack); var expected = utils.join([ 'nested-errors.js:41:6', 'Caused By: Error: bar', ' Object.module.exports.middle (nested-errors.js:42:5)' ]); t.match(cleanedStack, expected); t.end(); }); }); stack-utils-1.0.1/test/parse-line-fixtures.js000066400000000000000000000006431307720752400212110ustar00rootroot00000000000000var t = require('tap') var cases = require('./fixtures/parse-fixture.json') var lines = Object.keys(cases) var StackUtils = require('../') var stack = new StackUtils() t.plan(lines.length * 2) lines.forEach(function (line) { var expect = cases[line] t.match(stack.parseLine(line), expect, JSON.stringify(line)) line = line.replace(/^ at /, '') t.match(stack.parseLine(line), expect, JSON.stringify(line)) }) stack-utils-1.0.1/test/test.js000066400000000000000000000347601307720752400162710ustar00rootroot00000000000000var path = require('path'); var t = require('tap'); var StackUtils = require('../'); var CaptureFixture = require('./fixtures/capture-fixture'); var utils = require('./_utils'); // Use a fixed known set of native modules, since this changes // depending on the version of Node we're testing with. StackUtils.natives = [ 'internal/bootstrap_node', '_debug_agent', '_debugger', 'assert', 'buffer', 'child_process', 'console', 'constants', 'crypto', 'cluster', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', '_http_agent', '_http_client', '_http_common', '_http_incoming', '_http_outgoing', '_http_server', 'https', '_linklist', 'module', 'net', 'os', 'path', 'process', 'punycode', 'querystring', 'readline', 'repl', 'stream', '_stream_readable', '_stream_writable', '_stream_duplex', '_stream_transform', '_stream_passthrough', '_stream_wrap', 'string_decoder', 'sys', 'timers', 'tls', '_tls_common', '_tls_legacy', '_tls_wrap', 'tty', 'url', 'util', 'v8', 'vm', 'zlib', 'internal/buffer', 'internal/child_process', 'internal/cluster', 'internal/freelist', 'internal/fs', 'internal/linkedlist', 'internal/net', 'internal/module', 'internal/process/next_tick', 'internal/process/promises', 'internal/process/stdio', 'internal/process/warning', 'internal/process', 'internal/readline', 'internal/repl', 'internal/socket_list', 'internal/url', 'internal/util', 'internal/v8_prof_polyfill', 'internal/v8_prof_processor', 'internal/streams/lazy_transform', 'internal/streams/BufferList', 'v8/tools/splaytree', 'v8/tools/codemap', 'v8/tools/consarray', 'v8/tools/csvparser', 'v8/tools/profile', 'v8/tools/profile_view', 'v8/tools/logreader', 'v8/tools/tickprocessor', 'v8/tools/SourceMap', 'v8/tools/tickprocessor-driver', 'bootstrap_node', 'node' ]; var LinuxStack1 = utils.join(linuxStack1(), internalStack()); var WindowsStack1 = utils.join(windowsStack1(), internalStack()); var version = process.version.slice(1).split('.').map(function (val) { return parseInt(val, 10); }); t.test('must be called with new', function (t) { t.is(typeof StackUtils, 'function'); var stackUtils = StackUtils; t.throws(function () { stackUtils() }); t.end() }); t.test('clean: truncates cwd', function (t) { var expected = utils.join([ 'foo (foo.js:3:8)', 'bar (foo.js:7:2)', 'bar (bar.js:4:2)', 'Object. (bar.js:7:1)', 'ontimeout (timers.js:365:14)', 'tryOnTimeout (timers.js:237:5)', 'Timer.listOnTimeout (timers.js:207:5)', '_combinedTickCallback (internal/process/next_tick.js:67:7)', 'process._tickCallback (internal/process/next_tick.js:98:9)', 'Module.runMain (module.js:645:11)', 'Module._compile (module.js:398:26)', 'Object.Module._extensions..js (module.js:405:10)', 'Module.load (module.js:344:32)', 'Function.Module._load (module.js:301:12)', 'Function.Module.runMain (module.js:430:10)', 'run (bootstrap_node.js:420:7)', 'startup (bootstrap_node.js:139:9)', 'bootstrap_node.js:535:3', 'startup (node.js:141:18)' ]); var stack = new StackUtils({cwd: '/user/dev/project'}); t.is(stack.clean(LinuxStack1), expected, 'accepts a linux string'); t.is(stack.clean(LinuxStack1.split('\n')), expected, 'accepts an array'); t.is(stack.clean(LinuxStack1.split('\n').slice(1)), expected, 'slices off the message line'); stack = new StackUtils({cwd: 'Z:\\user\\dev\\project'}); t.is(stack.clean(WindowsStack1), expected, 'accepts a windows string'); t.end() }); t.test('clean: eliminates internals', function (t) { var stack = new StackUtils({cwd: '/user/dev', internals: StackUtils.nodeInternals()}); var expected = utils.join([ 'foo (project/foo.js:3:8)', 'bar (project/foo.js:7:2)', 'bar (project/bar.js:4:2)', 'Object. (project/bar.js:7:1)' ]); t.is(stack.clean(LinuxStack1), expected); stack = new StackUtils({cwd: 'Z:\\user\\dev', internals: StackUtils.nodeInternals()}); t.is(stack.clean(WindowsStack1), expected); t.end() }); t.test('clean: returns null if it is all internals', function (t) { var stack = new StackUtils({internals: StackUtils.nodeInternals()}); t.is(stack.clean(utils.join(internalStack())), ''); t.end() }); t.test('captureString: two redirects', function (t) { var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stack); var capturedString = capture.redirect1('redirect2', 'call', 'captureString'); t.is(capturedString, utils.join([ 'CaptureFixture.call (capture-fixture.js:23:28)', 'CaptureFixture.redirect2 (capture-fixture.js:17:22)', 'CaptureFixture.redirect1 (capture-fixture.js:11:22)' ])); t.end() }); t.test('captureString: with startStack function', function (t) { var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stack); var capturedString = capture.redirect1('redirect2', 'call', 'captureString', capture.call); t.is(capturedString, utils.join([ 'CaptureFixture.redirect2 (capture-fixture.js:17:22)', 'CaptureFixture.redirect1 (capture-fixture.js:11:22)' ])); t.end() }); t.test('captureString: with limit', function (t) { var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stack); var capturedString = capture.redirect1('redirect2', 'call', 'captureString', 1); t.is(capturedString, utils.join([ 'CaptureFixture.call (capture-fixture.js:23:28)' ])); t.end() }); t.test('captureString: with limit and startStack', function (t) { var stack = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stack); var capturedString = capture.redirect1('redirect2', 'call', 'captureString', 1, capture.call); t.is(capturedString, utils.join([ 'CaptureFixture.redirect2 (capture-fixture.js:17:22)' ])); t.end() }); t.test('capture returns an array of call sites', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var stack = capture.redirect1('call', 'capture').slice(0, 2); t.is(stack[0].getFileName(), path.join(utils.fixtureDir, 'capture-fixture.js')); t.is(stack[0].getFunctionName(), 'CaptureFixture.call'); t.is(stack[1].getFunctionName(), 'CaptureFixture.redirect1'); t.end() }); t.test('capture: with limit', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var stack = capture.redirect1('redirect2', 'call', 'capture', 1); t.is(stack.length, 1); t.is(stack[0].getFunctionName(), 'CaptureFixture.call'); t.end() }); t.test('capture: with stackStart function', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var stack = capture.redirect1('redirect2', 'call', 'capture', capture.call); t.true(stack.length > 1); t.is(stack[0].getFunctionName(), 'CaptureFixture.redirect2'); t.end() }); t.test('capture: with limit and stackStart function', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var stack = capture.redirect1('redirect2', 'call', 'capture', 1, capture.call); t.is(stack.length, 1); t.is(stack[0].getFunctionName(), 'CaptureFixture.redirect2'); t.end() }); t.test('capture: with wrapCallSite function', function (t) { var wrapper = function (callsite) { return { getMethodName: function () { return callsite.getMethodName(); }, getFunctionName: function () { return 'testOverrideFunctionName'; } }; }; var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir, wrapCallSite: wrapper}); var capture = new CaptureFixture(stackUtil); var stack = capture.redirect1('redirect2', 'call', 'capture', 1, capture.call); t.is(stack.length, 1); t.is(stack[0].getFunctionName(), 'testOverrideFunctionName'); t.is(stack[0].getMethodName(), 'redirect2'); t.end() }); t.test('at', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var at = capture.redirect1('call', 'at'); t.same(at, { file: 'capture-fixture.js', line: 23, column: 28, type: 'CaptureFixture', function: 'CaptureFixture.call', method: 'call' }); t.end() }); t.test('at: with stackStart', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: __dirname}); var capture = new CaptureFixture(stackUtil); var at = capture.redirect1('call', 'at', capture.call); t.same(at, { file: 'fixtures/capture-fixture.js', line: 11, column: 22, type: 'CaptureFixture', function: 'CaptureFixture.redirect1', method: 'redirect1' }); t.end() }); t.test('at: inside a constructor call', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var at = capture.const('call', 'at', capture.call); // TODO: File an issue - if this assert fails, the power assert diagram renderer blows up. t.same(at, { file: 'capture-fixture.js', line: 32, column: 27, constructor: true, type: 'Constructor', function: 'Constructor' }); t.end() }); t.test('at: method on an [Object] instance', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var at = capture.const('obj', 'foo', 'call', 'at', capture.call); t.same(at, { file: 'capture-fixture.js', line: 46, column: 23, function: 'obj.(anonymous function)', method: 'foo' }); t.end() }); t.test('at: returns empty object if #capture() returns an empty stack', function (t) { var stackUtil = new StackUtils(); stackUtil.capture = function () { return []; }; t.same(stackUtil.at(), {}); t.end() }); t.test('at: eval', function (t) { var stackUtil = new StackUtils({internals: internals(), cwd: utils.fixtureDir}); var capture = new CaptureFixture(stackUtil); var at = capture.eval('call', 'at', capture.call); var expected = { line: 1, column: 14, evalOrigin: /eval at (|CaptureFixture.eval) \(.*capture-fixture.js:57:9\)/, function: 'eval' }; // TODO: There are some inconsistencies between this and how `parseLine` works. if (version[0] < 4) { expected.type = 'CaptureFixture'; expected.function = 'eval'; } t.match(at, expected); t.end() }); t.test('parseLine', function (t) { var stack = new StackUtils({internals: internals(), cwd: '/user/dev/project'}); var capture = new CaptureFixture(stack); t.same(stack.parseLine('foo'), null, 'should not match'); t.same(stack.parseLine(' at bar (/user/dev/project/foo.js:3:8)'), { file: 'foo.js', line: 3, column: 8, function: 'bar' }); t.same(stack.parseLine(' at SomeClass.someFunc (/user/dev/project/foo.js:3:8)'), { file: 'foo.js', line: 3, column: 8, function: 'SomeClass.someFunc' }); // { "foo bar" () { throw new Error() } } t.same(stack.parseLine(' at Object.foo bar (/user/dev/project/foo.js:3:8)'), { file: 'foo.js', line: 3, column: 8, function: 'Object.foo bar' }) // Array.from({ *[Symbol.iterator] () { throw new Error() } }) t.same(stack.parseLine(' at Object.[Symbol.iterator] (/user/dev/project/foo.js:3:8)'), { file: 'foo.js', line: 3, column: 8, function: 'Object.[Symbol.iterator]' }) t.same(stack.parseLine(' at foo (/some/other/dir/file.js:3:8)'), { file: '/some/other/dir/file.js', line: 3, column: 8, function: 'foo' }); // TODO: report issue - this also causes power-assert diagram renderer to fail t.same(stack.parseLine(' at new Foo (/user/dev/project/foo.js:3:8)'), { file: 'foo.js', line: 3, column: 8, constructor: true, function: 'Foo' }); // EVAL var evalStack = capture.eval('error', 'foo').stack.split('\n'); var expected = { file: '', line: 1, column: 14, evalOrigin: /CaptureFixture.eval|/, evalLine: 57, evalColumn: 9, evalFile: path.join(utils.fixtureDir, 'capture-fixture.js').replace(/\\/g, '/'), function: 'eval' }; if (version[0] < 4) { expected.function = 'CaptureFixture.eval'; } var actual = stack.parseLine(evalStack[2]); t.match(actual, expected); t.end() }); t.test('parseLine: handles native errors', function (t) { t.same(StackUtils.parseLine(' at Error (native)'), { native: true, function: 'Error' }); t.end() }); t.test('parseLine: handles parens', function (t) { var line = ' at X. (/USER/Db (Person)/x/y.js:14:11)'; t.same(StackUtils.parseLine(line), { line: 14, column: 11, file: '/USER/Db (Person)/x/y.js', function: 'X.' }); t.end() }); function linuxStack1() { return [ 'Error: foo', ' at foo (/user/dev/project/foo.js:3:8)', ' at bar (/user/dev/project/foo.js:7:2)', ' at bar (/user/dev/project/bar.js:4:2)', ' at Object. (/user/dev/project/bar.js:7:1)' ]; } function windowsStack1() { return [ 'Error: foo', ' at foo (Z:\\user\\dev\\project\\foo.js:3:8)', ' at bar (Z:\\user\\dev\\project\\foo.js:7:2)', ' at bar (Z:\\user\\dev\\project\\bar.js:4:2)', ' at Object. (Z:\\user\\dev\\project\\bar.js:7:1)' ]; } function internalStack() { return [ ' at ontimeout (timers.js:365:14)', ' at tryOnTimeout (timers.js:237:5)', ' at Timer.listOnTimeout (timers.js:207:5)', ' at _combinedTickCallback (internal/process/next_tick.js:67:7)', ' at process._tickCallback (internal/process/next_tick.js:98:9)', ' at Module.runMain (module.js:645:11)', ' at Module._compile (module.js:398:26)', ' at Object.Module._extensions..js (module.js:405:10)', ' at Module.load (module.js:344:32)', ' at Function.Module._load (module.js:301:12)', ' at Function.Module.runMain (module.js:430:10)', ' at run (bootstrap_node.js:420:7)', ' at startup (bootstrap_node.js:139:9)', ' at bootstrap_node.js:535:3', ' at startup (node.js:141:18)' ]; } function internals() { return StackUtils.nodeInternals().concat([ /test\.js:\d+:\d+\)?$/, /\/node_modules\// ]); }