@@ -217,33 +217,65 @@ Test.prototype._assert = function assert (ok, opts) {
217
217
var e = new Error ( 'exception' ) ;
218
218
var err = ( e . stack || '' ) . split ( '\n' ) ;
219
219
var dir = __dirname + path . sep ;
220
-
220
+
221
221
for ( var i = 0 ; i < err . length ; i ++ ) {
222
- var m = / ^ [ ^ \s ] * \s * \b a t \s + ( .+ ) / . exec ( err [ i ] ) ;
222
+ /*
223
+ Stack trace lines may resemble one of the following. We need
224
+ to should correctly extract a function name (if any) and
225
+ path / line no. for each line.
226
+
227
+ at myFunction (/path/to/file.js:123:45)
228
+ at myFunction (/path/to/file.other-ext:123:45)
229
+ at myFunction (/path to/file.js:123:45)
230
+ at myFunction (C:\path\to\file.js:123:45)
231
+ at myFunction (/path/to/file.js:123)
232
+ at Test.<anonymous> (/path/to/file.js:123:45)
233
+ at Test.bound [as run] (/path/to/file.js:123:45)
234
+ at /path/to/file.js:123:45
235
+
236
+ Regex has three parts. First is non-capturing group for 'at '
237
+ (plus anything preceding it).
238
+
239
+ /^(?:[^\s]*\s*\bat\s+)/
240
+
241
+ Second captures function call description (optional). This is
242
+ not necessarily a valid JS function name, but just what the
243
+ stack trace is using to represent a function call. It may look
244
+ like `<anonymous>` or 'Test.bound [as run]'.
245
+
246
+ For our purposes, we assume that, if there is a function
247
+ name, it's everything leading up to the first open
248
+ parentheses (trimmed) before our pathname.
249
+
250
+ /(?:(.*)\s+\()?/
251
+
252
+ Last part captures file path plus line no (and optional
253
+ column no).
254
+
255
+ /((?:\/|[A-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)/
256
+ */
257
+ var re = / ^ (?: [ ^ \s ] * \s * \b a t \s + ) (?: ( .* ) \s + \( ) ? ( (?: \/ | [ A - Z ] : \\ ) [ ^ : \) ] + : ( \d + ) (?: : ( \d + ) ) ? ) /
258
+ var m = re . exec ( err [ i ] ) ;
259
+
223
260
if ( ! m ) {
224
261
continue ;
225
262
}
263
+
264
+ var callDescription = m [ 1 ] || '<anonymous>' ;
265
+ var filePath = m [ 2 ] ;
226
266
227
- var s = m [ 1 ] . split ( / \s + / ) ;
228
- var filemRe = / ( (?: \/ | [ A - Z ] : \\ ) [ ^ : \s ] + : ( \d + ) (?: : ( \d + ) ) ? ) / ;
229
- var filem ;
230
- var sIndex ;
231
- for ( sIndex in s . slice ( 0 , 4 ) ) {
232
- filem = filemRe . exec ( s [ sIndex ] ) ;
233
- if ( filem ) break ;
234
- }
235
- if ( ! filem ) continue ;
236
-
237
- if ( filem [ 1 ] . slice ( 0 , dir . length ) === dir ) {
267
+ if ( filePath . slice ( 0 , dir . length ) === dir ) {
238
268
continue ;
239
269
}
240
270
241
- res . functionName = s . length > 1 ? s [ 0 ] : '<anonymous>' ;
242
- res . file = filem [ 1 ] ;
243
- res . line = Number ( filem [ 2 ] ) ;
244
- if ( filem [ 3 ] ) res . column = filem [ 3 ] ;
271
+ // Function call description may not (just) be a function name.
272
+ // Try to extract function name by looking at first "word" only.
273
+ res . functionName = callDescription . split ( / s + / ) [ 0 ]
274
+ res . file = filePath ;
275
+ res . line = Number ( m [ 3 ] ) ;
276
+ if ( m [ 4 ] ) res . column = Number ( m [ 4 ] ) ;
245
277
246
- res . at = s . length > 1 ? m [ 1 ] : '<anonymous> (' + m [ 1 ] + ')' ;
278
+ res . at = callDescription + ' (' + filePath + ')' ;
247
279
break ;
248
280
}
249
281
}
0 commit comments