text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.description = exports.name = undefined;
  
  var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  
  exports.setup = setup;
  exports.run = run;
  
  var _node = require('../lib/node.js');
  
  var _fileUtils = require('../lib/fileUtils.js');
  
  var _github = require('../lib/github.js');
  
  var _libDefs = require('../lib/libDefs.js');
  
  var _isInFlowTypedRepo = require('../lib/isInFlowTypedRepo');
  
  var _isInFlowTypedRepo2 = _interopRequireDefault(_isInFlowTypedRepo);
  
  var _flowVersion = require('../lib/flowVersion');
  
  var _git = require('../lib/git');
  
  var _got = require('got');
  
  var _got2 = _interopRequireDefault(_got);
  
  var _semver = require('semver');
  
  var semver = _interopRequireWildcard(_semver);
  
  var _unzip = require('unzip');
  
  var unzip = _interopRequireWildcard(_unzip);
  
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  
  // Used to decide which binary to fetch for each version of Flow
  var BIN_PLATFORM = function (_) {
    switch (_node.os.type()) {
      case 'Linux':
        return 'linux64';
      case 'Darwin':
        return 'osx';
      case 'Windows_NT':
        return 'win64';
  
      default:
        throw new Error('Unsupported os.type()! ' + _node.os.type());
    }
  }();
  var PKG_ROOT_DIR = _node.path.join(__dirname, '..', '..');
  var TEST_DIR = _node.path.join(PKG_ROOT_DIR, '.test-dir');
  var BIN_DIR = _node.path.join(PKG_ROOT_DIR, '.flow-bins-cache');
  var P = Promise;
  
  /**
   * Scan the definitions/ directory to extract a flat list of TestGroup
   * structs. Each TestGroup represents a Package/PackageVersion/FlowVersion
   * directory.
   */
  var basePathRegex = new RegExp('definitions/npm/(@[^/]*/)?[^/]*/?');
  function getTestGroups(repoDirPath) {
    var onlyChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
    var libDefs, diff, changedDefs, baseDiff;
    return regeneratorRuntime.async(function getTestGroups$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return regeneratorRuntime.awrap((0, _libDefs.getLibDefs)(repoDirPath));
  
          case 2:
            libDefs = _context.sent;
  
            if (!onlyChanged) {
              _context.next = 11;
              break;
            }
  
            _context.next = 6;
            return regeneratorRuntime.awrap((0, _git.getDiff)());
  
          case 6:
            diff = _context.sent;
            changedDefs = void 0;
            // $FlowFixMe
  
            baseDiff = diff.map(function (d) {
              var match = d.match(basePathRegex);
              if (match) {
                return match[0];
              }
            }).filter(function (d) {
              return d != null;
            });
  
            changedDefs = baseDiff.map(function (d) {
              return (0, _libDefs.parseRepoDirItem)(d).pkgName;
            });
            libDefs = libDefs.filter(function (def) {
              return changedDefs.includes(def.pkgName);
            });
  
          case 11:
            return _context.abrupt('return', libDefs.map(function (libDef) {
              var groupID = libDef.pkgName + '_' + libDef.pkgVersionStr + '/' + libDef.flowVersionStr;
              return {
                id: groupID,
                testFilePaths: libDef.testFilePaths,
                libDefPath: libDef.path,
                flowVersion: libDef.flowVersion
              };
            }));
  
          case 12:
          case 'end':
            return _context.stop();
        }
      }
    }, null, this);
  }
  
  /**
   * Memoized function that queries the GitHub releases for Flow, downloads the
   * zip for each version, extracts the zip, and moves the binary to
   * TEST_BIN/flow-vXXX for use later when running tests.
   */
  var _flowBinVersionPromise = null;
  function getOrderedFlowBinVersions() {
    var numberOfReleases = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 15;
    return regeneratorRuntime.async(function getOrderedFlowBinVersions$(_context4) {
      while (1) {
        switch (_context4.prev = _context4.next) {
          case 0:
            if (_flowBinVersionPromise === null) {
              _flowBinVersionPromise = function _callee2() {
                var _this = this;
  
                var IS_WINDOWS, FLOW_BIN_VERSION_ORDER, GH_CLIENT, QUERY_PAGE_SIZE, OS_ARCH_FILTER_RE, binURLs, apiPayload, page;
                return regeneratorRuntime.async(function _callee2$(_context3) {
                  while (1) {
                    switch (_context3.prev = _context3.next) {
                      case 0:
                        console.log('Fetching all Flow binaries...');
                        IS_WINDOWS = _node.os.type() === 'Windows_NT';
                        FLOW_BIN_VERSION_ORDER = [];
                        GH_CLIENT = (0, _github.gitHubClient)();
                        // We only test against the latest numberOfReleases Versions
  
                        QUERY_PAGE_SIZE = numberOfReleases;
                        OS_ARCH_FILTER_RE = new RegExp('flow-' + BIN_PLATFORM);
                        binURLs = new Map();
                        apiPayload = null;
                        page = 0;
  
                      case 9:
                        if (!(apiPayload === null /* || apiPayload.length === QUERY_PAGE_SIZE*/
                        )) {
                          _context3.next = 16;
                          break;
                        }
  
                        _context3.next = 12;
                        return regeneratorRuntime.awrap(new Promise(function (res, rej) {
                          GH_CLIENT.releases.listReleases({
                            owner: 'facebook',
                            repo: 'flow',
                            page: page++,
                            per_page: QUERY_PAGE_SIZE
                          }, function (err, result) {
                            if (err) {
                              rej(err);
                            } else {
                              res(result);
                            }
                          });
                        }));
  
                      case 12:
                        apiPayload = _context3.sent;
  
  
                        apiPayload.forEach(function (rel) {
                          // We only test against versions since 0.15.0 because it has proper
                          // [ignore] fixes (which are necessary to run tests)
                          // Because Windows was only supported starting with version 0.30.0, we also skip version prior to that when running on windows.
                          if (semver.lt(rel.tag_name, IS_WINDOWS ? '0.30.0' : '0.15.0')) {
                            return;
                          }
                          // Because flow 0.57 was broken before 0.57.3 on the Windows platform, we also skip those versions when running on windows.
                          if (IS_WINDOWS && (semver.eq(rel.tag_name, '0.57.0') || semver.eq(rel.tag_name, '0.57.1') || semver.eq(rel.tag_name, '0.57.2'))) {
                            return;
                          }
  
                          // Find the binary zip in the list of assets
                          var binZip = rel.assets.filter(function (_ref) {
                            var name = _ref.name;
  
                            return OS_ARCH_FILTER_RE.test(name) && !/-latest.zip$/.test(name);
                          }).map(function (asset) {
                            return asset.browser_download_url;
                          });
  
                          if (binZip.length !== 1) {
                            throw new Error('Unexpected number of ' + BIN_PLATFORM + ' assets for flow-' + rel.tag_name + '! ' + JSON.stringify(binZip));
                          } else {
                            var version = rel.tag_name[0] === 'v' ? rel.tag_name : 'v' + rel.tag_name;
  
                            FLOW_BIN_VERSION_ORDER.push(version);
                            binURLs.set(version, binZip[0]);
                          }
                        });
                        _context3.next = 9;
                        break;
  
                      case 16:
  
                        FLOW_BIN_VERSION_ORDER.sort(function (a, b) {
                          return semver.lt(a, b) ? -1 : 1;
                        });
  
                        _context3.next = 19;
                        return regeneratorRuntime.awrap(P.all(Array.from(binURLs).map(function _callee(_ref2) {
                          var _ref3 = _slicedToArray(_ref2, 2),
                              version = _ref3[0],
                              binURL = _ref3[1];
  
                          var zipPath, binPath, flowBinDirPath;
                          return regeneratorRuntime.async(function _callee$(_context2) {
                            while (1) {
                              switch (_context2.prev = _context2.next) {
                                case 0:
                                  zipPath = _node.path.join(BIN_DIR, 'flow-' + version + '.zip');
                                  binPath = _node.path.join(BIN_DIR, 'flow-' + version + (IS_WINDOWS ? '.exe' : ''));
                                  _context2.next = 4;
                                  return regeneratorRuntime.awrap(_node.fs.exists(binPath));
  
                                case 4:
                                  if (!_context2.sent) {
                                    _context2.next = 6;
                                    break;
                                  }
  
                                  return _context2.abrupt('return');
  
                                case 6:
                                  _context2.next = 8;
                                  return regeneratorRuntime.awrap(new Promise(function (res, rej) {
                                    console.log('  Fetching flow-%s...', version);
                                    _got2.default.stream(binURL, {
                                      headers: {
                                        'User-Agent': 'flow-typed Test Runner ' + '(github.com/flowtype/flow-typed)'
                                      }
                                    }).on('error', function (err) {
                                      return rej(err);
                                    }).pipe(_node.fs.createWriteStream(zipPath).on('close', function () {
                                      console.log('    flow-%s finished downloading.', version);
                                      res();
                                    }));
                                  }));
  
                                case 8:
  
                                  // Extract the flow binary
                                  flowBinDirPath = _node.path.join(BIN_DIR, 'TMP-flow-' + version);
                                  _context2.next = 11;
                                  return regeneratorRuntime.awrap(_node.fs.mkdir(flowBinDirPath));
  
                                case 11:
                                  console.log('  Extracting flow-%s...', version);
                                  _context2.next = 14;
                                  return regeneratorRuntime.awrap(new Promise(function (res, rej) {
                                    var unzipExtractor = unzip.Extract({ path: flowBinDirPath });
                                    unzipExtractor.on('error', function (err) {
                                      rej(err);
                                    });
                                    unzipExtractor.on('close', function () {
                                      res();
                                    });
                                    _node.fs.createReadStream(zipPath).pipe(unzipExtractor);
                                  }));
  
                                case 14:
                                  if (!IS_WINDOWS) {
                                    _context2.next = 19;
                                    break;
                                  }
  
                                  _context2.next = 17;
                                  return regeneratorRuntime.awrap(_node.fs.rename(_node.path.join(flowBinDirPath, 'flow', 'flow.exe'), _node.path.join(BIN_DIR, 'flow-' + version + '.exe')));
  
                                case 17:
                                  _context2.next = 23;
                                  break;
  
                                case 19:
                                  _context2.next = 21;
                                  return regeneratorRuntime.awrap(_node.fs.rename(_node.path.join(flowBinDirPath, 'flow', 'flow'), _node.path.join(BIN_DIR, 'flow-' + version)));
  
                                case 21:
                                  _context2.next = 23;
                                  return regeneratorRuntime.awrap(_node.child_process.execP(['chmod', '755', _node.path.join(BIN_DIR, 'flow-' + version)].join(' ')));
  
                                case 23:
  
                                  console.log('  Removing flow-%s artifacts...', version);
                                  _context2.next = 26;
                                  return regeneratorRuntime.awrap(P.all([(0, _fileUtils.recursiveRmdir)(flowBinDirPath), _node.fs.unlink(zipPath)]));
  
                                case 26:
                                  console.log('    flow-%s complete!', version);
  
                                case 27:
                                case 'end':
                                  return _context2.stop();
                              }
                            }
                          }, null, _this);
                        })));
  
                      case 19:
  
                        console.log('Finished fetching Flow binaries.\n');
  
                        return _context3.abrupt('return', FLOW_BIN_VERSION_ORDER);
  
                      case 21:
                      case 'end':
                        return _context3.stop();
                    }
                  }
                }, null, this);
              }();
            }
            return _context4.abrupt('return', _flowBinVersionPromise);
  
          case 2:
          case 'end':
            return _context4.stop();
        }
      }
    }, null, this);
  }
  
  var flowNameRegex = /^flow-v[0-9]+.[0-9]+.[0-9]+$/;
  /**
   * flow filename should be `flow-vx.x.x`
   * @param {string} name
   */
  function checkFlowFilename(name) {
    return flowNameRegex.test(name);
  }
  
  /**
   * Return the sorted list of cached flow binaries that have previously been retrieved from github
   * and cached in the `.flow-bins-cache` directory.  This function is usually called when a failure
   * has occurred when attempting to refresh the flow releases from github, i.e. offline or over
   * API limit.
   */
  function getCachedFlowBinVersions() {
    var numberOfReleases = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 15;
    var versions;
    return regeneratorRuntime.async(function getCachedFlowBinVersions$(_context5) {
      while (1) {
        switch (_context5.prev = _context5.next) {
          case 0:
            _context5.next = 2;
            return regeneratorRuntime.awrap(_node.fs.readdir(_node.path.join(BIN_DIR)));
  
          case 2:
            _context5.t0 = checkFlowFilename;
  
            _context5.t1 = function (dir) {
              return dir.slice(6);
            };
  
            versions = _context5.sent.filter(_context5.t0).map(_context5.t1);
  
  
            // sort the versions that we have inplace
            versions.sort(function (a, b) {
              return semver.lt(a, b) ? -1 : 1;
            });
  
            versions.splice(0, versions.length - numberOfReleases);
  
            // return the versions with a leading 'v' to satisfy the expected return value
            return _context5.abrupt('return', versions.map(function (version) {
              return 'v' + version;
            }));
  
          case 8:
          case 'end':
            return _context5.stop();
        }
      }
    }, null, this);
  }
  
  function writeFlowConfig(testDirPath, libDefPath, includeWarnings) {
    var destFlowConfigPath, flowConfigData;
    return regeneratorRuntime.async(function writeFlowConfig$(_context6) {
      while (1) {
        switch (_context6.prev = _context6.next) {
          case 0:
            destFlowConfigPath = _node.path.join(testDirPath, '.flowconfig');
            flowConfigData = ['[libs]', _node.path.basename(libDefPath), '', '[options]', 'suppress_comment=\\\\(.\\\\|\\n\\\\)*\\\\$ExpectError', includeWarnings ? 'include_warnings=true' : '', '',
  
            // Be sure to ignore stuff in the node_modules directory of the flow-typed
            // CLI repository!
            '[ignore]', _node.path.join(testDirPath, '..', '..', 'node_modules')].join('\n');
            _context6.next = 4;
            return regeneratorRuntime.awrap(_node.fs.writeFile(destFlowConfigPath, flowConfigData));
  
          case 4:
          case 'end':
            return _context6.stop();
        }
      }
    }, null, this);
  }
  
  function testTypeDefinition(flowVer, testDirPath) {
    return new Promise(function (res) {
      var child = _node.child_process.exec([_node.path.join(BIN_DIR, 'flow-' + flowVer), 'check', '--strip-root', '--all', testDirPath].join(' '));
  
      var stdErrOut = '';
      child.stdout.on('data', function (data) {
        return stdErrOut += data;
      });
      child.stderr.on('data', function (data) {
        return stdErrOut += data;
      });
  
      child.on('error', function (execError) {
        res({ stdErrOut: stdErrOut, errCode: null, execError: execError });
      });
  
      child.on('close', function (errCode) {
        res({ stdErrOut: stdErrOut, errCode: errCode, execError: null });
      });
    });
  }
  
  function runFlowTypeDefTests(flowVersionsToRun, groupId, testDirPath) {
    var _this2 = this;
  
    var errors, testBatch;
    return regeneratorRuntime.async(function runFlowTypeDefTests$(_context8) {
      while (1) {
        switch (_context8.prev = _context8.next) {
          case 0:
            errors = [];
  
          case 1:
            if (!(flowVersionsToRun.length > 0)) {
              _context8.next = 7;
              break;
            }
  
            // Run tests in batches to avoid saturation
            testBatch = flowVersionsToRun.slice(0, Math.min(flowVersionsToRun.length, 5)).map(function (group) {
              return flowVersionsToRun.shift(), group;
            });
            _context8.next = 5;
            return regeneratorRuntime.awrap(P.all(testBatch.map(function _callee3(flowVer) {
              var testRunId, _ref4, stdErrOut, errCode, execError;
  
              return regeneratorRuntime.async(function _callee3$(_context7) {
                while (1) {
                  switch (_context7.prev = _context7.next) {
                    case 0:
                      testRunId = groupId + ' (flow-' + flowVer + ')';
  
  
                      console.log('Testing %s...', testRunId);
  
                      _context7.next = 4;
                      return regeneratorRuntime.awrap(testTypeDefinition(flowVer, testDirPath));
  
                    case 4:
                      _ref4 = _context7.sent;
                      stdErrOut = _ref4.stdErrOut;
                      errCode = _ref4.errCode;
                      execError = _ref4.execError;
  
  
                      if (execError !== null) {
                        errors.push(testRunId + ': Error executing Flow process: ' + execError.stack);
                      } else if (!stdErrOut.endsWith('Found 0 errors\n')) {
                        errors.push(testRunId + ': Unexpected Flow errors(' + String(errCode) + '):\n' + stdErrOut + '\n' + String(execError));
                      }
  
                    case 9:
                    case 'end':
                      return _context7.stop();
                  }
                }
              }, null, _this2);
            })));
  
          case 5:
            _context8.next = 1;
            break;
  
          case 7:
            return _context8.abrupt('return', errors);
  
          case 8:
          case 'end':
            return _context8.stop();
        }
      }
    }, null, this);
  }
  
  function testLowestCapableFlowVersion(lowerVersions, testDirPath, lowestFlowVersionRan) {
    var _this3 = this;
  
    var lowerFlowVersionsToRun, lowestCapableFlowVersion, lowerTestBatch;
    return regeneratorRuntime.async(function testLowestCapableFlowVersion$(_context10) {
      while (1) {
        switch (_context10.prev = _context10.next) {
          case 0:
            lowerFlowVersionsToRun = lowerVersions;
            lowestCapableFlowVersion = lowestFlowVersionRan;
  
          case 2:
            if (!(lowerFlowVersionsToRun.length > 0)) {
              _context10.next = 8;
              break;
            }
  
            lowerTestBatch = lowerFlowVersionsToRun.slice(0, Math.min(lowerFlowVersionsToRun.length, 5)).map(function (group) {
              return lowerFlowVersionsToRun.shift(), group;
            });
            _context10.next = 6;
            return regeneratorRuntime.awrap(P.all(lowerTestBatch.map(function _callee4(flowVer) {
              var _ref5, stdErrOut, execError;
  
              return regeneratorRuntime.async(function _callee4$(_context9) {
                while (1) {
                  switch (_context9.prev = _context9.next) {
                    case 0:
                      _context9.next = 2;
                      return regeneratorRuntime.awrap(testTypeDefinition(flowVer, testDirPath));
  
                    case 2:
                      _ref5 = _context9.sent;
                      stdErrOut = _ref5.stdErrOut;
                      execError = _ref5.execError;
  
  
                      if (execError !== null || !stdErrOut.endsWith('Found 0 errors\n')) {
                        lowerFlowVersionsToRun = [];
                      } else {
                        lowestCapableFlowVersion = semver.lt(lowestCapableFlowVersion, flowVer) ? lowestCapableFlowVersion : flowVer;
                      }
  
                    case 6:
                    case 'end':
                      return _context9.stop();
                  }
                }
              }, null, _this3);
            })));
  
          case 6:
            _context10.next = 2;
            break;
  
          case 8:
            return _context10.abrupt('return', lowestCapableFlowVersion);
  
          case 9:
          case 'end':
            return _context10.stop();
        }
      }
    }, null, this);
  }
  
  function findLowestCapableFlowVersion(orderedFlowVersions, lowestFlowVersionRan, testDirPath, libDefPath) {
    var lowerFlowVersionsToRun, lowerLowVersions, higherLowVersions, lowestOfHigherVersions;
    return regeneratorRuntime.async(function findLowestCapableFlowVersion$(_context11) {
      while (1) {
        switch (_context11.prev = _context11.next) {
          case 0:
            lowerFlowVersionsToRun = orderedFlowVersions.filter(function (flowVer) {
              return semver.lt(flowVer, lowestFlowVersionRan);
            });
  
            lowerFlowVersionsToRun.reverse();
            lowerLowVersions = lowerFlowVersionsToRun.filter(function (flowVer) {
              return semver.lt(flowVer, '0.53.0');
            });
            higherLowVersions = lowerFlowVersionsToRun.filter(function (flowVer) {
              return semver.gte(flowVer, '0.53.0');
            });
            _context11.next = 6;
            return regeneratorRuntime.awrap(writeFlowConfig(testDirPath, libDefPath, true));
  
          case 6:
            _context11.next = 8;
            return regeneratorRuntime.awrap(testLowestCapableFlowVersion(higherLowVersions, testDirPath, lowestFlowVersionRan));
  
          case 8:
            lowestOfHigherVersions = _context11.sent;
            _context11.next = 11;
            return regeneratorRuntime.awrap(writeFlowConfig(testDirPath, libDefPath, false));
  
          case 11:
            _context11.next = 13;
            return regeneratorRuntime.awrap(testLowestCapableFlowVersion(lowerLowVersions, testDirPath, lowestOfHigherVersions));
  
          case 13:
            return _context11.abrupt('return', _context11.sent);
  
          case 14:
          case 'end':
            return _context11.stop();
        }
      }
    }, null, this);
  }
  
  /**
   * Remove all files except flow instances
   */
  function removeTrashFromBinDir() {
    var _this4 = this;
  
    return regeneratorRuntime.async(function removeTrashFromBinDir$(_context13) {
      while (1) {
        switch (_context13.prev = _context13.next) {
          case 0:
            _context13.next = 2;
            return regeneratorRuntime.awrap(_node.fs.readdir(_node.path.join(BIN_DIR)));
  
          case 2:
            _context13.t0 = function (name) {
              return !checkFlowFilename(name);
            };
  
            _context13.t1 = function _callee5(el) {
              return regeneratorRuntime.async(function _callee5$(_context12) {
                while (1) {
                  switch (_context12.prev = _context12.next) {
                    case 0:
                      _context12.next = 2;
                      return regeneratorRuntime.awrap(_node.fs.unlink(_node.path.resolve(BIN_DIR, el)));
  
                    case 2:
                    case 'end':
                      return _context12.stop();
                  }
                }
              }, null, _this4);
            };
  
            _context13.sent.filter(_context13.t0).forEach(_context13.t1);
  
          case 5:
          case 'end':
            return _context13.stop();
        }
      }
    }, null, this);
  }
  
  /**
   * Given a TestGroup structure determine all versions of Flow that match the
   * FlowVersion specification and, for each, run `flow check` on the test
   * directory.
   */
  function runTestGroup(testGroup) {
    var _this5 = this;
  
    var numberOfFlowVersions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 15;
    var errors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
    var testDirName, testDirPath, orderedFlowVersions, destLibDefPath, testGrpFlowSemVerRange, flowVersionsToRun, lowestFlowVersionRan, lowerVersions, higherVersions, lowerVersionErrors, higherVersionErrors, lowestCapableFlowVersion;
    return regeneratorRuntime.async(function runTestGroup$(_context15) {
      while (1) {
        switch (_context15.prev = _context15.next) {
          case 0:
            // Some older versions of Flow choke on ">"/"<"/"="
            testDirName = testGroup.id.replace(/\//g, '--').replace(/>/g, 'gt').replace(/</g, 'lt').replace(/=/g, 'eq');
            testDirPath = _node.path.join(TEST_DIR, testDirName);
            _context15.next = 4;
            return regeneratorRuntime.awrap(_node.fs.exists(testDirPath));
  
          case 4:
            if (!_context15.sent) {
              _context15.next = 6;
              break;
            }
  
            throw new Error('Trying to run ' + testGroup.id + ', but test dir already exists! I\'m' + 'confused... Bailing out!');
  
          case 6:
            _context15.next = 8;
            return regeneratorRuntime.awrap(_node.fs.exists(BIN_DIR));
  
          case 8:
            if (_context15.sent) {
              _context15.next = 11;
              break;
            }
  
            _context15.next = 11;
            return regeneratorRuntime.awrap(_node.fs.mkdir(BIN_DIR));
  
          case 11:
            _context15.next = 13;
            return regeneratorRuntime.awrap(removeTrashFromBinDir());
  
          case 13:
            orderedFlowVersions = void 0;
            _context15.prev = 14;
            _context15.next = 17;
            return regeneratorRuntime.awrap(getOrderedFlowBinVersions(numberOfFlowVersions));
  
          case 17:
            orderedFlowVersions = _context15.sent;
            _context15.next = 25;
            break;
  
          case 20:
            _context15.prev = 20;
            _context15.t0 = _context15['catch'](14);
            _context15.next = 24;
            return regeneratorRuntime.awrap(getCachedFlowBinVersions(numberOfFlowVersions));
  
          case 24:
            orderedFlowVersions = _context15.sent;
  
          case 25:
            _context15.prev = 25;
            _context15.next = 28;
            return regeneratorRuntime.awrap(_node.fs.mkdir(testDirPath));
  
          case 28:
  
            // Copy files into the test dir
            destLibDefPath = _node.path.join(testDirPath, _node.path.basename(testGroup.libDefPath));
            _context15.next = 31;
            return regeneratorRuntime.awrap(P.all([P.all(testGroup.testFilePaths.map(function _callee6(filePath, idx) {
              var destBasename;
              return regeneratorRuntime.async(function _callee6$(_context14) {
                while (1) {
                  switch (_context14.prev = _context14.next) {
                    case 0:
                      // Because there could be multiple test files with the same basename,
                      // we disambiguate each one with a locally-unique index.
                      //
                      // i.e. underscore/v1.x.x/test-underscore.js
                      //      underscore/v1.x.x/flow-v0.22.x/test-underscore.js
                      destBasename = idx + '-' + _node.path.basename(filePath);
                      _context14.next = 3;
                      return regeneratorRuntime.awrap((0, _fileUtils.copyFile)(filePath, _node.path.join(testDirPath, destBasename)));
  
                    case 3:
                    case 'end':
                      return _context14.stop();
                  }
                }
              }, null, _this5);
            })), (0, _fileUtils.copyFile)(testGroup.libDefPath, destLibDefPath)]));
  
          case 31:
  
            // For each compatible version of Flow, run `flow check` and verify there
            // are no errors.
            testGrpFlowSemVerRange = (0, _flowVersion.toSemverString)(testGroup.flowVersion);
            flowVersionsToRun = orderedFlowVersions.filter(function (flowVer) {
              return semver.satisfies(flowVer, testGrpFlowSemVerRange);
            });
  
            // Windows hasn't flow < 30.0 but we have tests for flow < 30.0. We need skip it. Example: redux_v3
  
            if (flowVersionsToRun.length) {
              _context15.next = 35;
              break;
            }
  
            return _context15.abrupt('return', []);
  
          case 35:
            lowestFlowVersionRan = flowVersionsToRun[0];
            lowerVersions = flowVersionsToRun.filter(function (flowVer) {
              return semver.lt(flowVer, '0.53.0');
            });
            higherVersions = flowVersionsToRun.filter(function (flowVer) {
              return semver.gte(flowVer, '0.53.0');
            });
            _context15.next = 40;
            return regeneratorRuntime.awrap(writeFlowConfig(testDirPath, testGroup.libDefPath, false));
  
          case 40:
            _context15.next = 42;
            return regeneratorRuntime.awrap(runFlowTypeDefTests(lowerVersions, testGroup.id, testDirPath));
  
          case 42:
            lowerVersionErrors = _context15.sent;
            _context15.next = 45;
            return regeneratorRuntime.awrap(writeFlowConfig(testDirPath, testGroup.libDefPath, true));
  
          case 45:
            _context15.next = 47;
            return regeneratorRuntime.awrap(runFlowTypeDefTests(higherVersions, testGroup.id, testDirPath));
  
          case 47:
            higherVersionErrors = _context15.sent;
  
  
            errors.push.apply(errors, _toConsumableArray(higherVersionErrors).concat(_toConsumableArray(lowerVersionErrors)));
            _context15.next = 51;
            return regeneratorRuntime.awrap(findLowestCapableFlowVersion(orderedFlowVersions, lowestFlowVersionRan, testDirPath, testGroup.libDefPath));
  
          case 51:
            lowestCapableFlowVersion = _context15.sent;
  
  
            if (lowestCapableFlowVersion !== lowestFlowVersionRan) {
              console.log('Tests for ' + testGroup.id + ' ran successfully on flow ' + lowestCapableFlowVersion + '.\n        Consider setting ' + lowestCapableFlowVersion + ' as the lower bound!');
            }
  
            return _context15.abrupt('return', errors);
  
          case 54:
            _context15.prev = 54;
            _context15.next = 57;
            return regeneratorRuntime.awrap(_node.fs.exists(testDirPath));
  
          case 57:
            if (!_context15.sent) {
              _context15.next = 60;
              break;
            }
  
            _context15.next = 60;
            return regeneratorRuntime.awrap((0, _fileUtils.recursiveRmdir)(testDirPath));
  
          case 60:
            return _context15.finish(54);
  
          case 61:
          case 'end':
            return _context15.stop();
        }
      }
    }, null, this, [[14, 20], [25,, 54, 61]]);
  }
  
  function runTests(repoDirPath, testPatterns, onlyChanged, numberOfFlowVersions) {
    var testPatternRes, testGroups, results, testGroup, testGroupErrors;
    return regeneratorRuntime.async(function runTests$(_context16) {
      while (1) {
        switch (_context16.prev = _context16.next) {
          case 0:
            testPatternRes = testPatterns.map(function (patt) {
              return new RegExp(patt, 'g');
            });
            _context16.next = 3;
            return regeneratorRuntime.awrap(getTestGroups(repoDirPath, onlyChanged));
  
          case 3:
            _context16.t0 = function (testGroup) {
              if (testPatternRes.length === 0) {
                return true;
              }
  
              for (var i = 0; i < testPatternRes.length; i++) {
                var pattern = testPatternRes[i];
                if (testGroup.id.match(pattern) != null) {
                  return true;
                }
              }
  
              return false;
            };
  
            testGroups = _context16.sent.filter(_context16.t0);
            _context16.prev = 5;
            _context16.next = 8;
            return regeneratorRuntime.awrap(_node.fs.exists(TEST_DIR));
  
          case 8:
            if (!_context16.sent) {
              _context16.next = 11;
              break;
            }
  
            _context16.next = 11;
            return regeneratorRuntime.awrap((0, _fileUtils.recursiveRmdir)(TEST_DIR));
  
          case 11:
            _context16.next = 13;
            return regeneratorRuntime.awrap(_node.fs.mkdir(TEST_DIR));
  
          case 13:
            results = new Map();
  
          case 14:
            if (!(testGroups.length > 0)) {
              _context16.next = 22;
              break;
            }
  
            testGroup = testGroups.shift();
            _context16.next = 18;
            return regeneratorRuntime.awrap(runTestGroup(testGroup, numberOfFlowVersions));
  
          case 18:
            testGroupErrors = _context16.sent;
  
            if (testGroupErrors.length > 0) {
              (function () {
                var errors = results.get(testGroup.id) || [];
                testGroupErrors.forEach(function (err) {
                  return errors.push(err);
                });
                results.set(testGroup.id, errors);
              })();
            }
            _context16.next = 14;
            break;
  
          case 22:
            return _context16.abrupt('return', results);
  
          case 23:
            _context16.prev = 23;
            _context16.next = 26;
            return regeneratorRuntime.awrap(_node.fs.exists(TEST_DIR));
  
          case 26:
            if (!_context16.sent) {
              _context16.next = 29;
              break;
            }
  
            _context16.next = 29;
            return regeneratorRuntime.awrap((0, _fileUtils.recursiveRmdir)(TEST_DIR));
  
          case 29:
            return _context16.finish(23);
  
          case 30:
          case 'end':
            return _context16.stop();
        }
      }
    }, null, this, [[5,, 23, 30]]);
  }
  
  var name = exports.name = 'run-tests';
  var description = exports.description = 'Run definition tests for library definitions in the flow-typed project';
  
  function setup(yargs) {
    return yargs.usage('$0 ' + name + ' - ' + description).options({
      path: {
        describe: 'Override default path for libdef root (Mainly for testing purposes)',
        type: 'string',
        demand: false
      },
      onlyChanged: {
        type: 'boolean',
        description: 'Run only changed definition tests',
        demand: false
      },
      numberOfFlowVersions: {
        type: 'number',
        description: 'Only run against the latest X versions of flow',
        demand: false
      }
    });
  }
  
  function run(argv) {
    var testPatterns, onlyChanged, numberOfFlowVersions, cwd, basePath, cwdDefsNPMPath, repoDirPath, results;
    return regeneratorRuntime.async(function run$(_context17) {
      while (1) {
        switch (_context17.prev = _context17.next) {
          case 0:
            if ((0, _isInFlowTypedRepo2.default)()) {
              _context17.next = 3;
              break;
            }
  
            console.log('This command only works in a clone of flowtype/flow-typed. ' + 'It is a tool used to run tests of the library definitions in the flow-typed project.');
            return _context17.abrupt('return', 1);
  
          case 3:
            testPatterns = argv._.slice(1);
            onlyChanged = Boolean(argv.onlyChanged);
            numberOfFlowVersions = Number(argv.numberOfFlowVersions) || 15;
            cwd = process.cwd();
            basePath = argv.path ? String(argv.path) : cwd;
            cwdDefsNPMPath = _node.path.join(basePath, 'definitions', 'npm');
            _context17.next = 11;
            return regeneratorRuntime.awrap(_node.fs.exists(cwdDefsNPMPath));
  
          case 11:
            if (!_context17.sent) {
              _context17.next = 15;
              break;
            }
  
            _context17.t0 = cwdDefsNPMPath;
            _context17.next = 16;
            break;
  
          case 15:
            _context17.t0 = _node.path.join(__dirname, '..', '..', '..', 'definitions', 'npm');
  
          case 16:
            repoDirPath = _context17.t0;
  
  
            if (onlyChanged) {
              console.log('Running changed definition tests against latest %s flow versions in %s...\n', numberOfFlowVersions, repoDirPath);
            } else {
              console.log('Running definition tests against latest %s flow versions in %s...\n', numberOfFlowVersions, repoDirPath);
            }
  
            _context17.next = 20;
            return regeneratorRuntime.awrap(runTests(repoDirPath, testPatterns, onlyChanged, numberOfFlowVersions));
  
          case 20:
            results = _context17.sent;
  
            console.log(' ');
            Array.from(results).forEach(function (_ref6) {
              var _ref7 = _slicedToArray(_ref6, 2),
                  testGroupName = _ref7[0],
                  errors = _ref7[1];
  
              console.log('ERROR: %s', testGroupName);
              errors.forEach(function (err) {
                return console.log(' * %s\n', err.split('\n').map(function (line, idx) {
                  return idx === 0 ? line : '   ' + line;
                }).join('\n'));
              });
            });
  
            if (!(results.size === 0)) {
              _context17.next = 26;
              break;
            }
  
            console.log('All tests passed!');
            return _context17.abrupt('return', 0);
  
          case 26:
            return _context17.abrupt('return', 1);
  
          case 27:
          case 'end':
            return _context17.stop();
        }
      }
    }, null, this);
  }