@@ -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 ;
@@ -17,6 +18,10 @@ var sourceMapCache = {};
17
18
// Regex for detecting source maps
18
19
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 , / ;
19
20
21
+ // Priority list of retrieve handlers
22
+ var retrieveFileHandlers = [ ] ;
23
+ var retrieveMapHandlers = [ ] ;
24
+
20
25
function isInBrowser ( ) {
21
26
return ( ( typeof window !== 'undefined' ) && ( typeof XMLHttpRequest === 'function' ) ) ;
22
27
}
@@ -25,7 +30,21 @@ function hasGlobalProcessEventEmitter() {
25
30
return ( ( typeof process === 'object' ) && ( process !== null ) && ( typeof process . on === 'function' ) ) ;
26
31
}
27
32
28
- function retrieveFile ( path ) {
33
+ function handlerExec ( list ) {
34
+ return function ( arg ) {
35
+ for ( var i = 0 ; i < list . length ; i ++ ) {
36
+ var ret = list [ i ] ( arg ) ;
37
+ if ( ret ) {
38
+ return ret ;
39
+ }
40
+ }
41
+ return null ;
42
+ } ;
43
+ }
44
+
45
+ var retrieveFile = handlerExec ( retrieveFileHandlers ) ;
46
+
47
+ retrieveFileHandlers . push ( function ( path ) {
29
48
// Trim the path to make sure there is no extra whitespace.
30
49
path = path . trim ( ) ;
31
50
if ( path in fileContentsCache ) {
@@ -53,7 +72,7 @@ function retrieveFile(path) {
53
72
}
54
73
55
74
return fileContentsCache [ path ] = contents ;
56
- }
75
+ } ) ;
57
76
58
77
// Support URLs relative to a directory, but be careful about a protocol prefix
59
78
// in case we are in the browser (i.e. directories may start with "http://")
@@ -99,7 +118,8 @@ function retrieveSourceMapURL(source) {
99
118
// there is no source map. The map field may be either a string or the parsed
100
119
// JSON object (ie, it must be a valid argument to the SourceMapConsumer
101
120
// constructor).
102
- function retrieveSourceMap ( source ) {
121
+ var retrieveSourceMap = handlerExec ( retrieveMapHandlers ) ;
122
+ retrieveMapHandlers . push ( function ( source ) {
103
123
var sourceMappingURL = retrieveSourceMapURL ( source ) ;
104
124
if ( ! sourceMappingURL ) return null ;
105
125
@@ -124,7 +144,7 @@ function retrieveSourceMap(source) {
124
144
url : sourceMappingURL ,
125
145
map : sourceMapData
126
146
} ;
127
- }
147
+ } ) ;
128
148
129
149
function mapSourcePosition ( position ) {
130
150
var sourceMap = sourceMapCache [ position . source ] ;
@@ -386,7 +406,7 @@ function shimEmitUncaughtException () {
386
406
}
387
407
388
408
return origEmit . apply ( this , arguments ) ;
389
- }
409
+ } ;
390
410
}
391
411
392
412
exports . wrapCallSite = wrapCallSite ;
@@ -395,26 +415,43 @@ exports.mapSourcePosition = mapSourcePosition;
395
415
exports . retrieveSourceMap = retrieveSourceMap ;
396
416
397
417
exports . install = function ( options ) {
398
- if ( ! alreadyInstalled ) {
399
- alreadyInstalled = true ;
400
- Error . prepareStackTrace = prepareStackTrace ;
418
+ options = options || { } ;
401
419
402
- // Configure options
403
- options = options || { } ;
404
- var installHandler = 'handleUncaughtExceptions' in options ?
405
- options . handleUncaughtExceptions : true ;
420
+ // Allow sources to be found by methods other than reading the files
421
+ // directly from disk.
422
+ if ( options . retrieveFile ) {
423
+ if ( options . overrideRetrieveFile ) {
424
+ retrieveFileHandlers . length = 0 ;
425
+ }
426
+
427
+ retrieveFileHandlers . unshift ( options . retrieveFile ) ;
428
+ }
429
+
430
+ // Allow source maps to be found by methods other than reading the files
431
+ // directly from disk.
432
+ if ( options . retrieveSourceMap ) {
433
+ if ( options . overrideRetrieveSourceMap ) {
434
+ retrieveMapHandlers . length = 0 ;
435
+ }
436
+
437
+ retrieveMapHandlers . unshift ( options . retrieveSourceMap ) ;
438
+ }
439
+
440
+ // Configure options
441
+ if ( ! emptyCacheBetweenOperations ) {
406
442
emptyCacheBetweenOperations = 'emptyCacheBetweenOperations' in options ?
407
443
options . emptyCacheBetweenOperations : false ;
444
+ }
408
445
409
- // Allow sources to be found by methods other than reading the files
410
- // directly from disk.
411
- if ( options . retrieveFile )
412
- retrieveFile = options . retrieveFile ;
446
+ // Install the error reformatter
447
+ if ( ! errorFormatterInstalled ) {
448
+ errorFormatterInstalled = true ;
449
+ Error . prepareStackTrace = prepareStackTrace ;
450
+ }
413
451
414
- // Allow source maps to be found by methods other than reading the files
415
- // directly from disk.
416
- if ( options . retrieveSourceMap )
417
- retrieveSourceMap = options . retrieveSourceMap ;
452
+ if ( ! uncaughtShimInstalled ) {
453
+ var installHandler = 'handleUncaughtExceptions' in options ?
454
+ options . handleUncaughtExceptions : true ;
418
455
419
456
// Provide the option to not install the uncaught exception handler. This is
420
457
// to support other uncaught exception handlers (in test frameworks, for
@@ -424,6 +461,7 @@ exports.install = function(options) {
424
461
// generated JavaScript code will be shown above the stack trace instead of
425
462
// the original source code.
426
463
if ( installHandler && hasGlobalProcessEventEmitter ( ) ) {
464
+ uncaughtShimInstalled = true ;
427
465
shimEmitUncaughtException ( ) ;
428
466
}
429
467
}
0 commit comments