@@ -3,7 +3,8 @@ var path = require('path');
3
3
var fs = require ( 'fs' ) ;
4
4
5
5
// Only install once if called multiple times
6
- var alreadyInstalled = false ;
6
+ var errorFormatterInstalled = false ;
7
+ var uncaughtShimInstalled = false ;
7
8
8
9
// If true, the caches are reset before a stack trace formatting operation
9
10
var emptyCacheBetweenOperations = false ;
@@ -20,6 +21,10 @@ var sourceMapCache = {};
20
21
// Regex for detecting source maps
21
22
var reSourceMap = / ^ d a t a : a p p l i c a t i o n \/ j s o n [ ^ , ] + b a s e 6 4 , / ;
22
23
24
+ // Priority list of retrieve handlers
25
+ var retrieveFileHandlers = [ ] ;
26
+ var retrieveMapHandlers = [ ] ;
27
+
23
28
function isInBrowser ( ) {
24
29
if ( environment === "browser" )
25
30
return true ;
@@ -32,7 +37,21 @@ function hasGlobalProcessEventEmitter() {
32
37
return ( ( typeof process === 'object' ) && ( process !== null ) && ( typeof process . on === 'function' ) ) ;
33
38
}
34
39
35
- function retrieveFile ( path ) {
40
+ function handlerExec ( list ) {
41
+ return function ( arg ) {
42
+ for ( var i = 0 ; i < list . length ; i ++ ) {
43
+ var ret = list [ i ] ( arg ) ;
44
+ if ( ret ) {
45
+ return ret ;
46
+ }
47
+ }
48
+ return null ;
49
+ } ;
50
+ }
51
+
52
+ var retrieveFile = handlerExec ( retrieveFileHandlers ) ;
53
+
54
+ retrieveFileHandlers . push ( function ( path ) {
36
55
// Trim the path to make sure there is no extra whitespace.
37
56
path = path . trim ( ) ;
38
57
if ( path in fileContentsCache ) {
@@ -60,7 +79,7 @@ function retrieveFile(path) {
60
79
}
61
80
62
81
return fileContentsCache [ path ] = contents ;
63
- }
82
+ } ) ;
64
83
65
84
// Support URLs relative to a directory, but be careful about a protocol prefix
66
85
// in case we are in the browser (i.e. directories may start with "http://")
@@ -106,7 +125,8 @@ function retrieveSourceMapURL(source) {
106
125
// there is no source map. The map field may be either a string or the parsed
107
126
// JSON object (ie, it must be a valid argument to the SourceMapConsumer
108
127
// constructor).
109
- function retrieveSourceMap ( source ) {
128
+ var retrieveSourceMap = handlerExec ( retrieveMapHandlers ) ;
129
+ retrieveMapHandlers . push ( function ( source ) {
110
130
var sourceMappingURL = retrieveSourceMapURL ( source ) ;
111
131
if ( ! sourceMappingURL ) return null ;
112
132
@@ -131,7 +151,7 @@ function retrieveSourceMap(source) {
131
151
url : sourceMappingURL ,
132
152
map : sourceMapData
133
153
} ;
134
- }
154
+ } ) ;
135
155
136
156
function mapSourcePosition ( position ) {
137
157
var sourceMap = sourceMapCache [ position . source ] ;
@@ -393,7 +413,7 @@ function shimEmitUncaughtException () {
393
413
}
394
414
395
415
return origEmit . apply ( this , arguments ) ;
396
- }
416
+ } ;
397
417
}
398
418
399
419
exports . wrapCallSite = wrapCallSite ;
@@ -402,33 +422,50 @@ exports.mapSourcePosition = mapSourcePosition;
402
422
exports . retrieveSourceMap = retrieveSourceMap ;
403
423
404
424
exports . install = function ( options ) {
405
- if ( ! alreadyInstalled ) {
406
- alreadyInstalled = true ;
407
- Error . prepareStackTrace = prepareStackTrace ;
425
+ options = options || { } ;
408
426
409
- // Configure options
410
- options = options || { } ;
411
- var installHandler = 'handleUncaughtExceptions' in options ?
412
- options . handleUncaughtExceptions : true ;
413
-
427
+ if ( options . environment ) {
428
+ environment = options . environment ;
429
+ if ( [ "node" , "browser" , "auto" ] . indexOf ( environment ) === - 1 ) {
430
+ throw new Error ( "environment " + environment + " was unknown. Available options are {auto, browser, node}" )
431
+ }
432
+ }
433
+
434
+ // Allow sources to be found by methods other than reading the files
435
+ // directly from disk.
436
+ if ( options . retrieveFile ) {
437
+ if ( options . overrideRetrieveFile ) {
438
+ retrieveFileHandlers . length = 0 ;
439
+ }
440
+
441
+ retrieveFileHandlers . unshift ( options . retrieveFile ) ;
442
+ }
443
+
444
+ // Allow source maps to be found by methods other than reading the files
445
+ // directly from disk.
446
+ if ( options . retrieveSourceMap ) {
447
+ if ( options . overrideRetrieveSourceMap ) {
448
+ retrieveMapHandlers . length = 0 ;
449
+ }
450
+
451
+ retrieveMapHandlers . unshift ( options . retrieveSourceMap ) ;
452
+ }
453
+
454
+ // Configure options
455
+ if ( ! emptyCacheBetweenOperations ) {
414
456
emptyCacheBetweenOperations = 'emptyCacheBetweenOperations' in options ?
415
457
options . emptyCacheBetweenOperations : false ;
458
+ }
416
459
417
- if ( options . environment ) {
418
- environment = options . environment ;
419
- if ( [ "node" , "browser" , "auto" ] . indexOf ( environment ) === - 1 )
420
- throw new Error ( "environment " + environment + " was unknown. Available options are {auto, browser, node}" )
421
- }
422
-
423
- // Allow sources to be found by methods other than reading the files
424
- // directly from disk.
425
- if ( options . retrieveFile )
426
- retrieveFile = options . retrieveFile ;
460
+ // Install the error reformatter
461
+ if ( ! errorFormatterInstalled ) {
462
+ errorFormatterInstalled = true ;
463
+ Error . prepareStackTrace = prepareStackTrace ;
464
+ }
427
465
428
- // Allow source maps to be found by methods other than reading the files
429
- // directly from disk.
430
- if ( options . retrieveSourceMap )
431
- retrieveSourceMap = options . retrieveSourceMap ;
466
+ if ( ! uncaughtShimInstalled ) {
467
+ var installHandler = 'handleUncaughtExceptions' in options ?
468
+ options . handleUncaughtExceptions : true ;
432
469
433
470
// Provide the option to not install the uncaught exception handler. This is
434
471
// to support other uncaught exception handlers (in test frameworks, for
@@ -438,6 +475,7 @@ exports.install = function(options) {
438
475
// generated JavaScript code will be shown above the stack trace instead of
439
476
// the original source code.
440
477
if ( installHandler && hasGlobalProcessEventEmitter ( ) ) {
478
+ uncaughtShimInstalled = true ;
441
479
shimEmitUncaughtException ( ) ;
442
480
}
443
481
}
0 commit comments