[Pkg-javascript-commits] [node-stack-utils] 25/67: Support long stack traces
Bastien Roucariès
rouca at moszumanska.debian.org
Thu Sep 7 09:53:03 UTC 2017
This is an automated email from the git hooks/post-receive script.
rouca pushed a commit to branch master
in repository node-stack-utils.
commit ac75d4703abb94b1fbce6ed76c78d6d848397645
Author: James Talmage <james at talmage.io>
Date: Tue Jan 5 15:26:46 2016 -0500
Support long stack traces
---
index.js | 40 +++++--
package.json | 11 +-
test/_utils.js | 10 ++
{fixtures => test/fixtures}/capture-fixture.js | 0
test/fixtures/internal-error.js | 18 ++++
test/fixtures/internal-then.js | 17 +++
test/fixtures/long-stack-traces.js | 16 +++
test/fixtures/nested-errors.js | 49 +++++++++
test/fixtures/produce-long-stack-traces.js | 50 +++++++++
test/long-stack-traces.js | 138 +++++++++++++++++++++++++
test.js => test/test.js | 10 +-
11 files changed, 338 insertions(+), 21 deletions(-)
diff --git a/index.js b/index.js
index 2caf0d5..f97cd87 100644
--- a/index.js
+++ b/index.js
@@ -34,7 +34,12 @@ StackUtils.prototype.clean = function (stack) {
stack = stack.slice(1);
}
- stack = stack.map(function (st) {
+ var outdent = false;
+ var lastNonAtLine = null;
+ var result = [];
+
+ stack.forEach(function (st1) {
+ var st = st1;
var isInternal = this._internals.some(function (internal) {
return internal.test(st);
});
@@ -43,13 +48,36 @@ StackUtils.prototype.clean = function (stack) {
return null;
}
- return st.trim()
- .replace(/^\s*at /, '')
+ 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(/\\/g, '/')
.replace(this._cwd + '/', '');
- }, this).filter(function (st) {
- return st;
- }).join('\n').trim();
+
+ 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';
diff --git a/package.json b/package.json
index 6be2ac0..801163f 100644
--- a/package.json
+++ b/package.json
@@ -22,19 +22,16 @@
"keywords": [
""
],
- "config": {
- "nyc": {
- "exclude": [
- "fixtures/*"
- ]
- }
- },
"dependencies": {},
"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",
+ "pify": "^2.3.0",
+ "q": "^1.4.1",
"xo": "^0.12.1"
}
}
diff --git a/test/_utils.js b/test/_utils.js
new file mode 100644
index 0000000..e9e3ff7
--- /dev/null
+++ b/test/_utils.js
@@ -0,0 +1,10 @@
+var 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';
+}
diff --git a/fixtures/capture-fixture.js b/test/fixtures/capture-fixture.js
similarity index 100%
rename from fixtures/capture-fixture.js
rename to test/fixtures/capture-fixture.js
diff --git a/test/fixtures/internal-error.js b/test/fixtures/internal-error.js
new file mode 100644
index 0000000..d524c2f
--- /dev/null
+++ b/test/fixtures/internal-error.js
@@ -0,0 +1,18 @@
+'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));
+}
diff --git a/test/fixtures/internal-then.js b/test/fixtures/internal-then.js
new file mode 100644
index 0000000..6b20a49
--- /dev/null
+++ b/test/fixtures/internal-then.js
@@ -0,0 +1,17 @@
+
+//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;
+ });
+ });
+};
+
diff --git a/test/fixtures/long-stack-traces.js b/test/fixtures/long-stack-traces.js
new file mode 100644
index 0000000..a79cbbc
--- /dev/null
+++ b/test/fixtures/long-stack-traces.js
@@ -0,0 +1,16 @@
+'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');
diff --git a/test/fixtures/nested-errors.js b/test/fixtures/nested-errors.js
new file mode 100644
index 0000000..b43a37e
--- /dev/null
+++ b/test/fixtures/nested-errors.js
@@ -0,0 +1,49 @@
+'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);
+ });
+};
diff --git a/test/fixtures/produce-long-stack-traces.js b/test/fixtures/produce-long-stack-traces.js
new file mode 100644
index 0000000..32ae07e
--- /dev/null
+++ b/test/fixtures/produce-long-stack-traces.js
@@ -0,0 +1,50 @@
+'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);
+});
diff --git a/test/long-stack-traces.js b/test/long-stack-traces.js
new file mode 100644
index 0000000..5b62d11
--- /dev/null
+++ b/test/long-stack-traces.js
@@ -0,0 +1,138 @@
+import test from 'ava';
+import StackUtils from '../';
+import longStackTraces from './fixtures/long-stack-traces';
+import pify from 'pify';
+const nestedErrors = pify(require('./fixtures/nested-errors'), Promise);
+
+import {join, fixtureDir} from './_utils';
+
+function internals() {
+ return StackUtils.nodeInternals().concat([
+ /[\\\/]long-stack-traces\.js:[0-9]+:[0-9]+\)?$/,
+ /[\\\/]internal-error\.js:[0-9]+:[0-9]+\)?$/,
+ /[\\\/]internal-then\.js:[0-9]+:[0-9]+\)?$/,
+ /[\\\/]node_modules[\\\/]/,
+ // TODO: Should any of these be default internals?
+ /[\\\/]\.node-spawn-wrap-\w+-\w+[\\\/]node:[0-9]+:[0-9]+\)?$/,
+ /internal[\\\/]module\.js:[0-9]+:[0-9]+\)?$/,
+ /node\.js:[0-9]+:[0-9]+\)?$/
+ ]);
+}
+
+const stackUtils = new StackUtils({internals: internals(), cwd: fixtureDir});
+
+test('indents lines after first "From previous event:"', async t => {
+ const cleanedStack = stackUtils.clean(await longStackTraces.bluebird);
+ const expected = 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.<anonymous> (produce-long-stack-traces.js:6:36)'
+ ]);
+
+ t.is(cleanedStack, expected);
+});
+
+test('removes empty "From previous event:" sections from the bottom', async t => {
+ const stack = await longStackTraces.bluebird.bottom;
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = 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);
+});
+
+test('removes empty "From previous event:" sections from the top', async t => {
+ const stack = await longStackTraces.bluebird.top;
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = 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.<anonymous> (produce-long-stack-traces.js:30:40)'
+ ]);
+
+ t.is(cleanedStack, expected);
+});
+
+test('removes empty "From previous event:" sections from the middle', async t => {
+ const stack = await longStackTraces.bluebird.middle;
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = 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.<anonymous> (produce-long-stack-traces.js:18:43)'
+ ]);
+
+ t.is(cleanedStack, expected);
+});
+
+test.cb('removes empty "Caused by:" sections from the top', t => {
+ nestedErrors.top(stack => {
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = join([
+ 'Caused By: Error: baz',
+ ' Object.module.exports.top (nested-errors.js:36:5)'
+ ]);
+
+ t.is(cleanedStack, expected);
+ t.end();
+ });
+});
+
+test.cb('removes empty "Caused by:" sections from the bottom', t => {
+ nestedErrors.bottom(stack => {
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = 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();
+ });
+});
+
+test.cb('removes empty "Caused by:" sections from the middle', t => {
+ nestedErrors.middle(stack => {
+ const cleanedStack = stackUtils.clean(stack);
+
+ const expected = join([
+ 'nested-errors.js:41:6',
+ 'Caused By: Error: bar',
+ ' Object.module.exports.middle (nested-errors.js:42:5)'
+ ]);
+
+ t.is(cleanedStack, expected);
+ t.end();
+ });
+});
diff --git a/test.js b/test/test.js
similarity index 97%
rename from test.js
rename to test/test.js
index 555b095..9a764e4 100644
--- a/test.js
+++ b/test/test.js
@@ -1,12 +1,11 @@
import path from 'path';
import test from 'ava';
-import flatten from 'flatten';
-import StackUtils from './';
+import StackUtils from '../';
import CaptureFixture from './fixtures/capture-fixture';
+import {join, fixtureDir} from './_utils';
const LinuxStack1 = join(linuxStack1(), internalStack());
const WindowsStack1 = join(windowsStack1(), internalStack());
-const fixtureDir = path.join(__dirname, 'fixtures');
const version = process.version.slice(1).split('.').map(function (val) {
return parseInt(val, 10);
@@ -294,11 +293,6 @@ test('parseLine: handles native errors', t => {
});
});
-function join() {
- var args = Array.prototype.slice.call(arguments);
- return flatten(args).join('\n') + '\n';
-}
-
function linuxStack1() {
return [
'Error: foo',
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-stack-utils.git
More information about the Pkg-javascript-commits
mailing list