All files / lib/internal/streams legacy.js

96.49% Statements 110/114
85% Branches 17/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 11521x 21x 21x 21x 21x 21x 21x 21x 21x 227401x 227401x 227401x 21x 21x 21x 21x 336x 336x 336x 477x 18x 18x 477x 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 21x 21x 4399x 4399x 4399x 4399x 4399x 3x 3x 3x 3x 3x 4399x 4399x         4399x 21x 21x  
'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 };