22
33const util = require ( 'util' ) ;
44
5- function Console ( stdout , stderr ) {
5+ function Console ( stdout , stderr , ignoreErrors = true ) {
66 if ( ! ( this instanceof Console ) ) {
7- return new Console ( stdout , stderr ) ;
7+ return new Console ( stdout , stderr , ignoreErrors ) ;
88 }
99 if ( ! stdout || typeof stdout . write !== 'function' ) {
1010 throw new TypeError ( 'Console expects a writable stream instance' ) ;
@@ -24,8 +24,14 @@ function Console(stdout, stderr) {
2424 Object . defineProperty ( this , '_stdout' , prop ) ;
2525 prop . value = stderr ;
2626 Object . defineProperty ( this , '_stderr' , prop ) ;
27+ prop . value = ignoreErrors ;
28+ Object . defineProperty ( this , '_ignoreErrors' , prop ) ;
2729 prop . value = new Map ( ) ;
2830 Object . defineProperty ( this , '_times' , prop ) ;
31+ prop . value = createWriteErrorHandler ( stdout ) ;
32+ Object . defineProperty ( this , '_stdoutErrorHandler' , prop ) ;
33+ prop . value = createWriteErrorHandler ( stderr ) ;
34+ Object . defineProperty ( this , '_stderrErrorHandler' , prop ) ;
2935
3036 // bind the prototype functions to this Console instance
3137 var keys = Object . keys ( Console . prototype ) ;
@@ -35,20 +41,60 @@ function Console(stdout, stderr) {
3541 }
3642}
3743
44+ // Make a function that can serve as the callback passed to `stream.write()`.
45+ function createWriteErrorHandler ( stream ) {
46+ return ( err ) => {
47+ // This conditional evaluates to true if and only if there was an error
48+ // that was not already emitted (which happens when the _write callback
49+ // is invoked asynchronously).
50+ if ( err && ! stream . _writableState . errorEmitted ) {
51+ // If there was an error, it will be emitted on `stream` as
52+ // an `error` event. Adding a `once` listener will keep that error
53+ // from becoming an uncaught exception, but since the handler is
54+ // removed after the event, non-console.* writes won’t be affected.
55+ stream . once ( 'error' , noop ) ;
56+ }
57+ } ;
58+ }
59+
60+ function write ( ignoreErrors , stream , string , errorhandler ) {
61+ if ( ! ignoreErrors ) return stream . write ( string ) ;
62+
63+ // There may be an error occurring synchronously (e.g. for files or TTYs
64+ // on POSIX systems) or asynchronously (e.g. pipes on POSIX systems), so
65+ // handle both situations.
66+ try {
67+ // Add and later remove a noop error handler to catch synchronous errors.
68+ stream . once ( 'error' , noop ) ;
69+
70+ stream . write ( string , errorhandler ) ;
71+ } catch ( e ) {
72+ // Sorry, there’s no proper way to pass along the error here.
73+ } finally {
74+ stream . removeListener ( 'error' , noop ) ;
75+ }
76+ }
77+
3878
3979// As of v8 5.0.71.32, the combination of rest param, template string
4080// and .apply(null, args) benchmarks consistently faster than using
4181// the spread operator when calling util.format.
4282Console . prototype . log = function log ( ...args ) {
43- this . _stdout . write ( `${ util . format . apply ( null , args ) } \n` ) ;
83+ write ( this . _ignoreErrors ,
84+ this . _stdout ,
85+ `${ util . format . apply ( null , args ) } \n` ,
86+ this . _stdoutErrorHandler ) ;
4487} ;
4588
4689
4790Console . prototype . info = Console . prototype . log ;
4891
4992
5093Console . prototype . warn = function warn ( ...args ) {
51- this . _stderr . write ( `${ util . format . apply ( null , args ) } \n` ) ;
94+ write ( this . _ignoreErrors ,
95+ this . _stderr ,
96+ `${ util . format . apply ( null , args ) } \n` ,
97+ this . _stderrErrorHandler ) ;
5298} ;
5399
54100
@@ -57,7 +103,7 @@ Console.prototype.error = Console.prototype.warn;
57103
58104Console . prototype . dir = function dir ( object , options ) {
59105 options = Object . assign ( { customInspect : false } , options ) ;
60- this . _stdout . write ( `${ util . inspect ( object , options ) } \n` ) ;
106+ write ( this . _ignoreErrors , this . _stdout , `${ util . inspect ( object , options ) } \n` ) ;
61107} ;
62108
63109
@@ -99,3 +145,5 @@ Console.prototype.assert = function assert(expression, ...args) {
99145
100146module . exports = new Console ( process . stdout , process . stderr ) ;
101147module . exports . Console = Console ;
148+
149+ function noop ( ) { }
0 commit comments