@@ -94,6 +94,47 @@ EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
94
94
return $getMaxListeners ( this ) ;
95
95
} ;
96
96
97
+ // Returns the longest sequence of `a` that fully appears in `b`,
98
+ // of length at least 3.
99
+ // This is a lazy approach but should work well enough, given that stack
100
+ // frames are usually unequal or otherwise appear in groups, and that
101
+ // we only run this code in case of an unhandled exception.
102
+ function longestSeqContainedIn ( a , b ) {
103
+ for ( var len = a . length ; len >= 3 ; -- len ) {
104
+ for ( var i = 0 ; i < a . length - len ; ++ i ) {
105
+ // Attempt to find a[i:i+len] in b
106
+ for ( var j = 0 ; j < b . length - len ; ++ j ) {
107
+ let matches = true ;
108
+ for ( var k = 0 ; k < len ; ++ k ) {
109
+ if ( a [ i + k ] !== b [ j + k ] ) {
110
+ matches = false ;
111
+ break ;
112
+ }
113
+ }
114
+ if ( matches )
115
+ return [ len , i , j ] ;
116
+ }
117
+ }
118
+ }
119
+
120
+ return [ 0 , 0 , 0 ] ;
121
+ }
122
+
123
+ function enhanceStackTrace ( err , own ) {
124
+ const sep = '\nEmitted \'error\' event at:\n' ;
125
+
126
+ const errStack = err . stack . split ( '\n' ) . slice ( 1 ) ;
127
+ const ownStack = own . stack . split ( '\n' ) . slice ( 1 ) ;
128
+
129
+ const [ len , off ] = longestSeqContainedIn ( ownStack , errStack ) ;
130
+ if ( len > 0 ) {
131
+ ownStack . splice ( off + 1 , len - 1 ,
132
+ ' [... lines matching original stack trace ...]' ) ;
133
+ }
134
+ // Do this last, because it is the only operation with side effects.
135
+ err . stack = err . stack + sep + ownStack . join ( '\n' ) ;
136
+ }
137
+
97
138
EventEmitter . prototype . emit = function emit ( type , ...args ) {
98
139
let doError = ( type === 'error' ) ;
99
140
@@ -109,13 +150,25 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
109
150
if ( args . length > 0 )
110
151
er = args [ 0 ] ;
111
152
if ( er instanceof Error ) {
153
+ try {
154
+ const { kExpandStackSymbol } = require ( 'internal/util' ) ;
155
+ const capture = { } ;
156
+ Error . captureStackTrace ( capture , EventEmitter . prototype . emit ) ;
157
+ Object . defineProperty ( er , kExpandStackSymbol , {
158
+ value : enhanceStackTrace . bind ( null , er , capture ) ,
159
+ configurable : true
160
+ } ) ;
161
+ } catch ( e ) { }
162
+
163
+ // Note: The comments on the `throw` lines are intentional, they show
164
+ // up in Node's output if this results in an unhandled exception.
112
165
throw er ; // Unhandled 'error' event
113
166
}
114
167
// At least give some kind of context to the user
115
168
const errors = lazyErrors ( ) ;
116
169
const err = new errors . Error ( 'ERR_UNHANDLED_ERROR' , er ) ;
117
170
err . context = er ;
118
- throw err ;
171
+ throw err ; // Unhandled 'error' event
119
172
}
120
173
121
174
const handler = events [ type ] ;
0 commit comments