"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _bluebird() {
  const data = require("bluebird");

  _bluebird = function () {
    return data;
  };

  return data;
}

function _ramda() {
  const data = _interopRequireDefault(require("ramda"));

  _ramda = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _execa() {
  const data = _interopRequireDefault(require("execa"));

  _execa = function () {
    return data;
  };

  return data;
}

function _pEvent() {
  const data = _interopRequireDefault(require("p-event"));

  _pEvent = function () {
    return data;
  };

  return data;
}

function _deserializeError() {
  const data = _interopRequireDefault(require("deserialize-error"));

  _deserializeError = function () {
    return data;
  };

  return data;
}

function _specsResults() {
  const data = require("../consumer/specs-results");

  _specsResults = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _analytics() {
  const data = require("../analytics/analytics");

  _analytics = function () {
    return data;
  };

  return data;
}

function _logger() {
  const data = _interopRequireDefault(require("../logger/logger"));

  _logger = function () {
    return data;
  };

  return data;
}

function _externalErrors() {
  const data = _interopRequireDefault(require("../error/external-errors"));

  _externalErrors = function () {
    return data;
  };

  return data;
}

function _externalBuildErrors() {
  const data = _interopRequireDefault(require("../consumer/component/exceptions/external-build-errors"));

  _externalBuildErrors = function () {
    return data;
  };

  return data;
}

function _externalTestErrors() {
  const data = _interopRequireDefault(require("../consumer/component/exceptions/external-test-errors"));

  _externalTestErrors = function () {
    return data;
  };

  return data;
}

function _bitId() {
  const data = require("../bit-id");

  _bitId = function () {
    return data;
  };

  return data;
}

var _default =
/*#__PURE__*/
function () {
  var _run = (0, _bluebird().coroutine)(function* ({
    ids,
    forkLevel,
    includeUnmodified = false,
    verbose
  }) {
    if (!ids || _ramda().default.isEmpty(ids)) {
      _analytics().Analytics.addBreadCrumb('specs-runner.run', 'running tests on one child process without ids');

      _logger().default.debug('specs-runner.run', 'running tests on one child process without ids');

      return runOnChildProcess({
        includeUnmodified,
        verbose
      });
    }

    if (forkLevel === _constants().TESTS_FORK_LEVEL.ONE) {
      _analytics().Analytics.addBreadCrumb('specs-runner.run', 'running tests on one child process with ids');

      _logger().default.debug('specs-runner.run', 'running tests on one child process with ids');

      return runOnChildProcess({
        ids,
        includeUnmodified: false,
        // no meaning to pass this when there is specific ids
        verbose
      });
    }

    _analytics().Analytics.addBreadCrumb('specs-runner.run', 'running tests on child process for each component');

    _logger().default.debug('specs-runner.run', 'running tests on child process for each component');

    const allRunnersP = ids.map(id => runOnChildProcess({
      ids: [id],
      includeUnmodified: false,
      // no meaning to pass this when there is specific ids
      verbose
    }));
    const allRunnersResults = yield Promise.all(allRunnersP);
    if (!allRunnersResults || !allRunnersResults.length) return undefined;
    const finalResults = allRunnersResults.reduce((acc, curr) => {
      // if (!curr || !curr[0]) return acc;
      if (curr.childOutput) {
        acc.childOutput = `${acc.childOutput}\n${curr.childOutput}`;
      }

      if (curr.results && curr.results[0]) {
        acc.results.push(curr.results[0]);
      }

      return acc;
    }, {
      type: 'results',
      childOutput: '',
      results: []
    });
    return finalResults;
  });

  function run(_x) {
    return _run.apply(this, arguments);
  }

  return run;
}();

exports.default = _default;

function runOnChildProcess(_x2) {
  return _runOnChildProcess.apply(this, arguments);
}

function _runOnChildProcess() {
  _runOnChildProcess = (0, _bluebird().coroutine)(function* ({
    ids,
    includeUnmodified,
    verbose
  }) {
    // Check if we run from npm or from binary (pkg)
    let args = [];

    if (ids) {
      args = args.concat(ids);
    }

    if (verbose) {
      args.push('--verbose');
    }

    if (includeUnmodified) {
      args.push('--all');
    }

    const baseEnv = {
      __verbose__: verbose,
      __includeUnmodified__: includeUnmodified
    }; // Don't use ternary condition since if we put it as undefined
    // It will pass to the fork as "undefined" (string) instad of not passing it at all
    // __ids__: ids ? ids.join() : undefined,

    if (ids) {
      baseEnv.__ids__ = ids.join();
    } // Merge process.env from the main process


    const env = Object.assign({}, process.env, baseEnv);

    try {
      const workerPath = _path().default.join(__dirname, 'worker.js'); // if (process.pkg) {
      //   const entryPoint = process.argv[1];
      //   workerPath = path.join(entryPoint, '../../dist/specs-runner/worker.js');
      // }


      const child = _execa().default.node(workerPath, args, {
        env
      });

      const result = yield (0, _pEvent().default)(child, 'message');
      const childResult = yield child;

      if (!result) {
        return null;
      }

      const deserializedResults = deserializeResults(result);
      if (!deserializedResults) return null;

      if (childResult.all) {
        deserializedResults.childOutput = childResult.all;
      }

      if (deserializedResults.type === 'error') {
        if (deserializedResults.error instanceof Error) {
          throw deserializedResults.error;
        }

        throw new Error(deserializedResults.error);
      }

      return deserializedResults;
    } catch (e) {
      throw e;
    }
  });
  return _runOnChildProcess.apply(this, arguments);
}

function deserializeResults(results) {
  if (!results) return undefined;

  if (results.type === 'error') {
    let deserializedError = (0, _deserializeError().default)(results.error); // Special desrialization for external errors

    if (deserializedError.originalErrors) {
      const deserializedOriginalErrors = deserializedError.originalErrors.map(_deserializeError().default);

      if (results.error.name === _externalBuildErrors().default.name) {
        deserializedError = new (_externalBuildErrors().default)(deserializedError.id, deserializedOriginalErrors);
      } else if (results.error.name === _externalTestErrors().default.name) {
        deserializedError = new (_externalTestErrors().default)(deserializedError.id, deserializedOriginalErrors);
      } else {
        deserializedError = new (_externalErrors().default)(deserializedOriginalErrors);
      }
    }

    if (deserializedError.originalError) {
      const deserializedOriginalError = (0, _deserializeError().default)(deserializedError.originalError);
      const compName = deserializedError.compName && typeof deserializedError.compName === 'string' ? deserializedError.compName : '';
      deserializedError = new (_externalTestErrors().default)(compName, [deserializedOriginalError]);
    }

    const finalResults = {
      type: 'error',
      error: deserializedError
    };
    return finalResults;
  }

  const deserializeFailure = failure => {
    if (!failure) return undefined;
    const deserializedFailure = failure;

    if (failure.err) {
      try {
        deserializedFailure.err = (0, _deserializeError().default)(failure.err);
      } catch (e) {
        _logger().default.debug(`fail parsing error ${deserializedFailure.err}`);
      }
    }

    return deserializedFailure;
  };

  const deserializeResult = result => {
    result.componentId = new (_bitId().BitId)(result.componentId); // when BitId is received from a fork it loses its class and appears as an object

    if (!result.failures) return result;
    result.failures = result.failures.map(deserializeFailure);
    return result;
  };

  const deserializedResults = results.results.map(deserializeResult);
  return {
    type: 'results',
    results: deserializedResults
  };
}