<commit_before>var fs = require('fs');
var util = require('util');
var debug = require('debug')('mocha:multi');
var path = require('path');
var isString = require('is-string');
var mkdirp = require('mkdirp');

// Let mocha decide about tty early
require('mocha/lib/reporters/base');

module.exports = MochaMulti

// Make sure we don't lose these!
var stdout = process.stdout;
var stderr = process.stderr;

function MochaMulti(runner, options) {
  var setup;
  var reporters = (options && options.reporterOptions);
  if (reporters && Object.keys(reporters).length > 0) {
    debug("options %j", options);
    setup = [];
    Object.keys(reporters).forEach(function(reporter) {
      debug("adding reporter %j %j", reporter, reporters[reporter]);

      var stdout;
      var options;
      if (isString(reporters[reporter])) {
        stdout = reporters[reporter];
        options = null;
      } else {
        stdout = reporters[reporter].stdout;
        options = reporters[reporter].options;
      }

      setup.push([ reporter, stdout, options ]);
    });
  } else {
    setup = parseSetup();
  }
  debug("setup %j", setup);
  var streams = initReportersAndStreams(runner, setup);
  // Remove nulls
  streams = streams.filter(identity);

  //we actually need to wait streams only if they are present
  if(streams.length > 0) {
    awaitStreamsOnExit(streams);
  }
}

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];
  stderr.write(util.format.apply(util, args) + "\n");
  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 initReportersAndStreams(runner, setup) {
  return setup.map(function(definition) {
    var reporter=definition[0], outstream=definition[1], options=definition[2]

    debug("Initialising reporter '%s' to '%s' with options %j", reporter, outstream, options);

    var stream = resolveStream(outstream);
    var shim = createRunnerShim(runner, stream);

    debug("Shimming runner into reporter '%s' %j", reporter, options);

    withReplacedStdout(stream, function() {
      var Reporter = resolveReporter(reporter);
      return new Reporter(shim, options || {});
    })

    return stream;
  })
}

function awaitStreamsOnExit(streams) {
  var exit = process.exit;
  var num = streams.length;
  process.exit = function(code) {
    var quit = exit.bind(process, code);
    streams.forEach(function(stream) {<commit_msg>[#23] Invoke done(fn) on reporters that have it on completion<commit_after>var fs = require('fs');
var util = require('util');
var debug = require('debug')('mocha:multi');
var path = require('path');
var isString = require('is-string');
var mkdirp = require('mkdirp');

// Let mocha decide about tty early
require('mocha/lib/reporters/base');

var Base = require('mocha').reporters.Base;

module.exports = MochaMulti

// Make sure we don't lose these!
var stdout = process.stdout;
var stderr = process.stderr;

function MochaMulti(runner, options) {
  var setup;
  // keep track of reporters that have a done method.
  this.reportersWithDone = [];
  var reporters = (options && options.reporterOptions);
  if (reporters && Object.keys(reporters).length > 0) {
    debug("options %j", options);
    setup = [];
    Object.keys(reporters).forEach(function(reporter) {
      debug("adding reporter %j %j", reporter, reporters[reporter]);

      var stdout;
      var options;
      if (isString(reporters[reporter])) {
        stdout = reporters[reporter];
        options = null;
      } else {
        stdout = reporters[reporter].stdout;
        options = reporters[reporter].options;
      }

      setup.push([ reporter, stdout, options ]);
    });
  } else {
    setup = parseSetup();
  }
  debug("setup %j", setup);
  var streams = initReportersAndStreams(runner, setup, this);
  // Remove nulls
  streams = streams.filter(identity);

  //we actually need to wait streams only if they are present
  if(streams.length > 0) {
    awaitStreamsOnExit(streams);
  }
}

util.inherits(MochaMulti, Base);

/**
 * Override done to allow done processing for any reporters that have a done method.
 */
MochaMulti.prototype.done = function (failures, fn) {
  var self = this;

  if(self.reportersWithDone.length !== 0) {
    var count = self.reportersWithDone.length;
    debug('Awaiting on %j reporters to invoke done callback.', count);
    var cb = function() {
      if(--count === 0) {
        debug('All reporters invoked done callback.');
        fn(failures);
      } else {
        debug('Awaiting on %j reporters to invoke done callback.', count);
      }
    };

    self.reportersWithDone.forEach(function(r) {
      r.done(failures, cb);
    });
  } else {
    debug('No reporters have done method, completing.');
    fn(failures);
  }
};

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];
  stderr.write(util.format.apply(util, args) + "\n");
  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 initReportersAndStreams(runner, setup, multi) {
  return setup.map(function(definition) {
    var reporter=definition[0], outstream=definition[1], options=definition[2]

    debug("Initialising reporter '%s' to '%s' with options %j", reporter, outstream, options);

    var stream = resolveStream(outstream);
    var shim = createRunnerShim(runner, stream);

    debug("Shimming runner into reporter '%s' %j", reporter, options);

    withReplacedStdout(stream, function() {
      var Reporter = resolveReporter(reporter);
      var r = new Reporter(shim, options || {});
      // If the reporter possess a done() method register it so we can
      // wait for it to complete when done.
      if(r && r.done) {
        multi.reportersWithDone.push(r);
      }
      return r;
    })

    return stream;
  })
}

function awaitStreamsOnExit(streams) {
  var exit = process.exit;
  var num = streams.length;
  process.exit = function(code) {
    var quit = exit.bind(process, code);
    streams.forEach(function(stream) {
{'fraction_non_alphanumeric': 0.1413493653974616, 'fraction_numerical': 0.0029392117568470275, 'mean_word_length': 3.7319848293299622, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, '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': '3165348', 'n_tokens_mistral': 2369, 'n_tokens_neox': 2303, 'n_words': 608}