@@ -265,33 +265,6 @@ Writable.prototype.pipe = function() {
265
265
errorOrDestroy ( this , new ERR_STREAM_CANNOT_PIPE ( ) ) ;
266
266
} ;
267
267
268
-
269
- function writeAfterEnd ( stream , cb ) {
270
- const er = new ERR_STREAM_WRITE_AFTER_END ( ) ;
271
- // TODO: defer error events consistently everywhere, not just the cb
272
- errorOrDestroy ( stream , er ) ;
273
- process . nextTick ( cb , er ) ;
274
- }
275
-
276
- // Checks that a user-supplied chunk is valid, especially for the particular
277
- // mode the stream is in. Currently this means that `null` is never accepted
278
- // and undefined/non-string values are only allowed in object mode.
279
- function validChunk ( stream , state , chunk , cb ) {
280
- var er ;
281
-
282
- if ( chunk === null ) {
283
- er = new ERR_STREAM_NULL_VALUES ( ) ;
284
- } else if ( typeof chunk !== 'string' && ! state . objectMode ) {
285
- er = new ERR_INVALID_ARG_TYPE ( 'chunk' , [ 'string' , 'Buffer' ] , chunk ) ;
286
- }
287
- if ( er ) {
288
- errorOrDestroy ( stream , er ) ;
289
- process . nextTick ( cb , er ) ;
290
- return false ;
291
- }
292
- return true ;
293
- }
294
-
295
268
Writable . prototype . write = function ( chunk , encoding , cb ) {
296
269
const state = this . _writableState ;
297
270
var ret = false ;
@@ -315,17 +288,25 @@ Writable.prototype.write = function(chunk, encoding, cb) {
315
288
if ( typeof cb !== 'function' )
316
289
cb = nop ;
317
290
291
+ let err ;
318
292
if ( state . ending ) {
319
- writeAfterEnd ( this , cb ) ;
293
+ err = new ERR_STREAM_WRITE_AFTER_END ( ) ;
320
294
} else if ( state . destroyed ) {
321
- const err = new ERR_STREAM_DESTROYED ( 'write' ) ;
322
- process . nextTick ( cb , err ) ;
323
- errorOrDestroy ( this , err ) ;
324
- } else if ( isBuf || validChunk ( this , state , chunk , cb ) ) {
295
+ err = new ERR_STREAM_DESTROYED ( 'write' ) ;
296
+ } else if ( chunk === null ) {
297
+ err = new ERR_STREAM_NULL_VALUES ( ) ;
298
+ } else if ( ! isBuf && typeof chunk !== 'string' && ! state . objectMode ) {
299
+ err = new ERR_INVALID_ARG_TYPE ( 'chunk' , [ 'string' , 'Buffer' ] , chunk ) ;
300
+ } else {
325
301
state . pendingcb ++ ;
326
302
ret = writeOrBuffer ( this , state , chunk , encoding , cb ) ;
327
303
}
328
304
305
+ if ( err ) {
306
+ process . nextTick ( cb , err ) ;
307
+ errorOrDestroy ( this , err , true ) ;
308
+ }
309
+
329
310
return ret ;
330
311
} ;
331
312
@@ -629,7 +610,7 @@ Writable.prototype._write = function(chunk, encoding, cb) {
629
610
if ( this . _writev ) {
630
611
this . _writev ( [ { chunk, encoding } ] , cb ) ;
631
612
} else {
632
- cb ( new ERR_METHOD_NOT_IMPLEMENTED ( '_write()' ) ) ;
613
+ process . nextTick ( cb , new ERR_METHOD_NOT_IMPLEMENTED ( '_write()' ) ) ;
633
614
}
634
615
} ;
635
616
@@ -656,15 +637,25 @@ Writable.prototype.end = function(chunk, encoding, cb) {
656
637
this . uncork ( ) ;
657
638
}
658
639
640
+ if ( typeof cb !== 'function' )
641
+ cb = nop ;
642
+
659
643
// Ignore unnecessary end() calls.
660
- if ( ! state . ending ) {
644
+ // TODO(ronag): Compat. Allow end() after destroy().
645
+ if ( ! state . errored && ! state . ending ) {
661
646
endWritable ( this , state , cb ) ;
662
- } else if ( typeof cb === 'function' ) {
663
- if ( ! state . finished ) {
664
- onFinished ( this , state , cb ) ;
665
- } else {
666
- cb ( new ERR_STREAM_ALREADY_FINISHED ( 'end' ) ) ;
667
- }
647
+ } else if ( state . finished ) {
648
+ const err = new ERR_STREAM_ALREADY_FINISHED ( 'end' ) ;
649
+ process . nextTick ( cb , err ) ;
650
+ // TODO(ronag): Compat. Don't error the stream.
651
+ // errorOrDestroy(this, err, true);
652
+ } else if ( state . destroyed ) {
653
+ const err = new ERR_STREAM_DESTROYED ( 'end' ) ;
654
+ process . nextTick ( cb , err ) ;
655
+ // TODO(ronag): Compat. Don't error the stream.
656
+ // errorOrDestroy(this, err, true);
657
+ } else if ( cb !== nop ) {
658
+ onFinished ( this , state , cb ) ;
668
659
}
669
660
670
661
return this ;
@@ -749,7 +740,7 @@ function finish(stream, state) {
749
740
function endWritable ( stream , state , cb ) {
750
741
state . ending = true ;
751
742
finishMaybe ( stream , state , true ) ;
752
- if ( cb ) {
743
+ if ( cb !== nop ) {
753
744
if ( state . finished )
754
745
process . nextTick ( cb ) ;
755
746
else
@@ -774,14 +765,6 @@ function onCorkedFinish(corkReq, state, err) {
774
765
}
775
766
776
767
function onFinished ( stream , state , cb ) {
777
- if ( state . destroyed && state . errorEmitted ) {
778
- // TODO(ronag): Backwards compat. Should be moved to end() without
779
- // errorEmitted check and with errorOrDestroy.
780
- const err = new ERR_STREAM_DESTROYED ( 'end' ) ;
781
- process . nextTick ( cb , err ) ;
782
- return ;
783
- }
784
-
785
768
function onerror ( err ) {
786
769
stream . removeListener ( 'finish' , onfinish ) ;
787
770
stream . removeListener ( 'error' , onerror ) ;
0 commit comments