<commit_before>var fs = require('fs');
var util = require('util');
var debug = require('debug')('mocha:multi');

module.exports = MochaMulti

// HAAAACK - attempt to trick node into waiting for the streams to finish
var exit = process.exit;
process.exit = function(code) {
  var quit = exit.bind(process, code);
  process.on('exit', quit);
}

function MochaMulti(runner) {
  initReporters(runner, parseSetup());
}

var msgs = {
  no_definitions: "reporter definitions should be set in \
the `multi` shell variable\n\
eg. `multi='dot=- xunit=file.xml' mocha`",
  invalid_definition: "'%s' is an invalid definition\n\
expected <reporter>=<destination>",
  invalid_reporter: "Unable to find '%s' reporter"
}
function bombOut(id) {
  var args = Array.prototype.slice.call(arguments, 0);
  args[0] = 'ERROR: ' + msgs[id];
  console.warn.apply(console, args);
  process.exit(1);
}

function parseSetup() {
  var reporterDefinition = process.env.multi || '';
  var reporterDefs = reporterDefinition.trim().split(/\s/).filter(identity);
  if (!reporterDefs.length) {
    bombOut('no_definitions');
  }
  debug("Got reporter defs: %j", reporterDefs);
  return reporterDefs.map(parseReporter);
}

function parseReporter(definition) {
  var pair = definition.split('=');
  if (pair.length != 2) {
    bombOut('invalid_definition', definition);
  }
  return pair;
}

function initReporters(runner, setup) {
  setup.forEach(function(definition) {

    debug("Initialising reporter '%s' to '%s'", definition[0], definition[1]);

    var stream = resolveStream(definition[1]);
    var shim = createRunnerShim(runner, stream);

    debug("Shimming runner into reporter '%s'", definition[0]);

    withReplacedStdout(stream, function() {
      var Reporter = resolveReporter(definition[0]);
      return new Reporter(shim);
    })

  })
}

function resolveReporter(name) {
  // Cribbed from Mocha.prototype.reporter()
  var reporter;
  reporter = safeRequire('mocha/lib/reporters/' + name);
  if (!reporter) {
    reporter = safeRequire(name);
  }
  if (!reporter) {
    bombOut('invalid_reporter', name);
  }
  debug("Resolved reporter '%s' into '%s'", name, util.inspect(reporter));
  return reporter;
}

function safeRequire(module) {
  try {
    return require(module);
  } catch (err) {
    return null;
  }
}

function resolveStream(destination) {
  if (destination == '-') {
    debug("Resolved stream '-' into stdout and stderr");
    return null;
  }
  debug("Resolved stream '%s' into writeable file stream", destination);
  // Ensure we can write here
  fs.writeFileSync(destination, '');
  return fs.createWriteStream(destination);
}

function createRunnerShim(runner, stream) {
  var shim = new (require('events').EventEmitter)();

  addDelegate('grepTotal');
  addDelegate('suite');
  addDelegate('total');

  function addDelegate(prop) {
    shim.__defineGetter__(prop, function() {
      return runner[prop];
    });
  }

  var delegatedEvents = {};

  shim.on('newListener', function(event) {

    if (event in delegatedEvents) return;

    delegatedEvents[event] = true;<commit_msg>Ensure `this` is correct when delegating runner properties<commit_after>var fs = require('fs');
var util = require('util');
var debug = require('debug')('mocha:multi');

module.exports = MochaMulti

// HAAAACK - attempt to trick node into waiting for the streams to finish
var exit = process.exit;
process.exit = function(code) {
  var quit = exit.bind(process, code);
  process.on('exit', quit);
}

function MochaMulti(runner) {
  initReporters(runner, parseSetup());
}

var msgs = {
  no_definitions: "reporter definitions should be set in \
the `multi` shell variable\n\
eg. `multi='dot=- xunit=file.xml' mocha`",
  invalid_definition: "'%s' is an invalid definition\n\
expected <reporter>=<destination>",
  invalid_reporter: "Unable to find '%s' reporter"
}
function bombOut(id) {
  var args = Array.prototype.slice.call(arguments, 0);
  args[0] = 'ERROR: ' + msgs[id];
  console.warn.apply(console, args);
  process.exit(1);
}

function parseSetup() {
  var reporterDefinition = process.env.multi || '';
  var reporterDefs = reporterDefinition.trim().split(/\s/).filter(identity);
  if (!reporterDefs.length) {
    bombOut('no_definitions');
  }
  debug("Got reporter defs: %j", reporterDefs);
  return reporterDefs.map(parseReporter);
}

function parseReporter(definition) {
  var pair = definition.split('=');
  if (pair.length != 2) {
    bombOut('invalid_definition', definition);
  }
  return pair;
}

function initReporters(runner, setup) {
  setup.forEach(function(definition) {

    debug("Initialising reporter '%s' to '%s'", definition[0], definition[1]);

    var stream = resolveStream(definition[1]);
    var shim = createRunnerShim(runner, stream);

    debug("Shimming runner into reporter '%s'", definition[0]);

    withReplacedStdout(stream, function() {
      var Reporter = resolveReporter(definition[0]);
      return new Reporter(shim);
    })

  })
}

function resolveReporter(name) {
  // Cribbed from Mocha.prototype.reporter()
  var reporter;
  reporter = safeRequire('mocha/lib/reporters/' + name);
  if (!reporter) {
    reporter = safeRequire(name);
  }
  if (!reporter) {
    bombOut('invalid_reporter', name);
  }
  debug("Resolved reporter '%s' into '%s'", name, util.inspect(reporter));
  return reporter;
}

function safeRequire(module) {
  try {
    return require(module);
  } catch (err) {
    return null;
  }
}

function resolveStream(destination) {
  if (destination == '-') {
    debug("Resolved stream '-' into stdout and stderr");
    return null;
  }
  debug("Resolved stream '%s' into writeable file stream", destination);
  // Ensure we can write here
  fs.writeFileSync(destination, '');
  return fs.createWriteStream(destination);
}

function createRunnerShim(runner, stream) {
  var shim = new (require('events').EventEmitter)();

  addDelegate('grepTotal');
  addDelegate('suite');
  addDelegate('total');

  function addDelegate(prop) {
    shim.__defineGetter__(prop, function() {
      var property = runner[prop];
      if (typeof property === 'function') {
        property = property.bind(runner);
      }
      return property;
    });
  }

  var delegatedEvents = {};

  shim.on('newListener', function(event) {

    if (event in delegatedEvents) return;

    delegatedEvents[event] = true;
{'fraction_non_alphanumeric': 0.14804292929292928, 'fraction_numerical': 0.002840909090909091, 'mean_word_length': 4.29406850459482, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2303833', 'n_tokens_mistral': 2009, 'n_tokens_neox': 1982, 'n_words': 483}