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