All files / lib/internal/streams legacy.js

96.49% Statements 110/114
80% Branches 16/20
100% Functions 9/9
96.49% Lines 110/114

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 11519x 19x 19x 19x 19x 19x 19x 19x 19x 211820x 211820x 211820x 19x 19x 19x 19x 336x 336x 336x 478x 18x 18x 478x 336x 336x 336x 336x 18x 18x 18x 18x 336x 336x 336x 336x 336x 336x 336x 336x 336x 336x 336x 336x 126x 126x 126x 126x 126x 336x 336x 336x 101x 101x 101x 101x 101x 336x 336x 336x 5x 5x 1x 1x 5x 336x 336x 336x 336x 336x 336x 333x 333x 333x 333x 333x 333x 333x 333x 333x 333x 333x 333x 333x 333x 336x 336x 336x 336x 336x 336x 336x 336x 336x 19x 19x 2764x 2764x 2764x 2764x 2764x 3x 3x 3x 3x 3x 2764x 2764x         2764x 19x 19x  
'use strict';
 
const {
  ArrayIsArray,
  ObjectSetPrototypeOf,
} = primordials;
 
const EE = require('events');
 
function Stream(opts) {
  EE.call(this, opts);
}
ObjectSetPrototypeOf(Stream.prototype, EE.prototype);
ObjectSetPrototypeOf(Stream, EE);
 
Stream.prototype.pipe = function(dest, options) {
  const source = this;
 
  function ondata(chunk) {
    if (dest.writable && dest.write(chunk) === false && source.pause) {
      source.pause();
    }
  }
 
  source.on('data', ondata);
 
  function ondrain() {
    if (source.readable && source.resume) {
      source.resume();
    }
  }
 
  dest.on('drain', ondrain);
 
  // If the 'end' option is not supplied, dest.end() will be called when
  // source gets the 'end' or 'close' events.  Only dest.end() once.
  if (!dest._isStdio && (!options || options.end !== false)) {
    source.on('end', onend);
    source.on('close', onclose);
  }
 
  let didOnEnd = false;
  function onend() {
    if (didOnEnd) return;
    didOnEnd = true;
 
    dest.end();
  }
 
 
  function onclose() {
    if (didOnEnd) return;
    didOnEnd = true;
 
    if (typeof dest.destroy === 'function') dest.destroy();
  }
 
  // Don't leave dangling pipes when there are errors.
  function onerror(er) {
    cleanup();
    if (EE.listenerCount(this, 'error') === 0) {
      this.emit('error', er);
    }
  }
 
  prependListener(source, 'error', onerror);
  prependListener(dest, 'error', onerror);
 
  // Remove all the event listeners that were added.
  function cleanup() {
    source.removeListener('data', ondata);
    dest.removeListener('drain', ondrain);
 
    source.removeListener('end', onend);
    source.removeListener('close', onclose);
 
    source.removeListener('error', onerror);
    dest.removeListener('error', onerror);
 
    source.removeListener('end', cleanup);
    source.removeListener('close', cleanup);
 
    dest.removeListener('close', cleanup);
  }
 
  source.on('end', cleanup);
  source.on('close', cleanup);
 
  dest.on('close', cleanup);
  dest.emit('pipe', source);
 
  // Allow for unix-like usage: A.pipe(B).pipe(C)
  return dest;
};
 
function prependListener(emitter, event, fn) {
  // Sadly this is not cacheable as some libraries bundle their own
  // event emitter implementation with them.
  if (typeof emitter.prependListener === 'function')
    return emitter.prependListener(event, fn);
 
  // This is a hack to make sure that our error handler is attached before any
  // userland ones.  NEVER DO THIS. This is here only because this code needs
  // to continue to work with older versions of Node.js that do not include
  // the prependListener() method. The goal is to eventually remove this hack.
  if (!emitter._events || !emitter._events[event])
    emitter.on(event, fn);
  else if (ArrayIsArray(emitter._events[event]))
    emitter._events[event].unshift(fn);
  else
    emitter._events[event] = [fn, emitter._events[event]];
}
 
module.exports = { Stream, prependListener };