"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 _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _glob() {
  const data = _interopRequireDefault(require("glob"));

  _glob = 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 _semver() {
  const data = _interopRequireDefault(require("semver"));

  _semver = function () {
    return data;
  };

  return data;
}

function _consumer() {
  const data = require("../../../consumer");

  _consumer = function () {
    return data;
  };

  return data;
}

function _loader() {
  const data = _interopRequireDefault(require("../../../cli/loader"));

  _loader = function () {
    return data;
  };

  return data;
}

function _loaderMessages() {
  const data = require("../../../cli/loader/loader-messages");

  _loaderMessages = function () {
    return data;
  };

  return data;
}

function _flattenDependencies() {
  const data = require("../../../scope/flatten-dependencies");

  _flattenDependencies = function () {
    return data;
  };

  return data;
}

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

  _bitId = function () {
    return data;
  };

  return data;
}

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

  _analytics = function () {
    return data;
  };

  return data;
}

function _generalError() {
  const data = _interopRequireDefault(require("../../../error/general-error"));

  _generalError = function () {
    return data;
  };

  return data;
}

function _importComponents() {
  const data = _interopRequireDefault(require("../../../consumer/component-ops/import-components"));

  _importComponents = function () {
    return data;
  };

  return data;
}

const key = _ramda().default.compose(_ramda().default.head, _ramda().default.keys);

var _default =
/*#__PURE__*/
function () {
  var _importAction = (0, _bluebird().coroutine)(function* (environmentOptions, importOptions, packageManagerArgs) {
    function importEnvironment(_x4) {
      return _importEnvironment.apply(this, arguments);
    }

    function _importEnvironment() {
      _importEnvironment = (0, _bluebird().coroutine)(function* (consumer) {
        _loader().default.start(_loaderMessages().BEFORE_IMPORT_ENVIRONMENT);

        if (!importOptions.ids.length) throw new (_generalError().default)('you must specify component id for importing an environment');
        const idToImport = importOptions.ids[0];

        const bitIdToImport = _bitId().BitId.parse(idToImport, true); // import without id is not supported


        const envComponents = yield consumer.importEnvironment(bitIdToImport, importOptions.verbose, true);
        if (!envComponents.length) throw new (_generalError().default)(`the environment component ${idToImport} is installed already`);
        const id = envComponents[0].component.id.toString();

        function writeConfigIfNeeded() {
          if (environmentOptions.compiler) {
            consumer.config.compiler = id;

            _analytics().Analytics.setExtraData('build_env', id);

            return consumer.config.write({
              workspaceDir: consumer.getPath()
            });
          }

          if (environmentOptions.tester) {
            consumer.config.tester = id;

            _analytics().Analytics.setExtraData('test_env', id);

            return consumer.config.write({
              workspaceDir: consumer.getPath()
            });
          }

          if (environmentOptions.extension) {
            const idWithoutVersion = _bitId().BitId.getStringWithoutVersion(id); // don't create the same extension twice - check if older version exists and override it


            const oldVersion = Object.keys(consumer.config.extensions).find(ext => {
              return _bitId().BitId.getStringWithoutVersion(ext) === idWithoutVersion;
            });

            if (oldVersion) {
              consumer.config.extensions[id] = consumer.config.extensions[oldVersion];
              delete consumer.config.extensions[oldVersion];
              return consumer.config.write({
                workspaceDir: consumer.getPath()
              });
            }

            consumer.config.extensions[id] = {
              options: {},
              config: {}
            };
            return consumer.config.write({
              workspaceDir: consumer.getPath()
            });
          }

          return Promise.resolve(true);
        }

        yield writeConfigIfNeeded();
        return {
          envComponents
        };
      });
      return _importEnvironment.apply(this, arguments);
    }

    const consumer = yield (0, _consumer().loadConsumer)();
    consumer.packageManagerArgs = packageManagerArgs;

    if (environmentOptions.tester || environmentOptions.compiler || environmentOptions.extension) {
      return importEnvironment(consumer);
    }

    const importComponents = new (_importComponents().default)(consumer, importOptions);
    const {
      dependencies,
      envComponents,
      importDetails
    } = yield importComponents.importComponents();
    const bitIds = dependencies.map(_ramda().default.path(['component', 'id']));
    const warnings = yield warnForPackageDependencies({
      dependencies: (0, _flattenDependencies().flattenDependencies)(dependencies),
      envComponents,
      consumer,
      installNpmPackages: importOptions.installNpmPackages
    });

    _analytics().Analytics.setExtraData('num_components', bitIds.length);

    yield consumer.onDestroy();
    return {
      dependencies,
      envComponents,
      importDetails,
      warnings
    };
  });

  function importAction(_x, _x2, _x3) {
    return _importAction.apply(this, arguments);
  }

  return importAction;
}(); // TODO: refactor to better use of semver
// TODO: move to bit-javascript


exports.default = _default;

const getSemverType = str => {
  if (_semver().default.valid(str)) return 'V'; // VALID_VERSION

  if (_semver().default.validRange(str)) return 'R'; // RANGE_VERSIONS

  return null;
}; // TODO: refactor to better use of semver
// TODO: move to bit-javascript


function compatibleWith(a, b) {
  const depName = key(a);
  if (!b[depName]) return false; // dependency does not exist - return false

  const bVersion = b[depName];
  const aVersion = a[depName];
  const aType = getSemverType(aVersion);
  const bType = getSemverType(bVersion);
  if (!aType || !bType) return false; // in case one of the versions is invalid - return false

  if (aType === 'V' && bType === 'V') {
    return _semver().default.eq(aVersion, bVersion);
  }

  if (aType === 'V' && bType === 'R') {
    return _semver().default.satisfies(aVersion, bVersion);
  }

  if (aType === 'R' && bType === 'V') {
    return _semver().default.satisfies(bVersion, aVersion);
  }

  if (aType === 'R' && bType === 'R') {
    if (aVersion.startsWith('^') && bVersion.startsWith('^')) {
      const aMajorVersion = parseInt(aVersion[1], 10);
      const bMajorVersion = parseInt(bVersion[1], 10);
      if (aMajorVersion === bMajorVersion) return true;
    }
  }

  return false;
} // TODO: refactor to better use of semver
// TODO: move to bit-javascript


const warnForPackageDependencies = ({
  dependencies,
  consumer,
  installNpmPackages
}) => {
  const warnings = {
    notInPackageJson: [],
    notInNodeModules: [],
    notInBoth: []
  };
  if (installNpmPackages) return Promise.resolve(warnings);
  const projectDir = consumer.getPath();

  const getPackageJson = dir => {
    try {
      return _fsExtra().default.readJSONSync(_path().default.join(dir, 'package.json'));
    } catch (e) {
      return {};
    } // do we want to inform the use that he has no package.json

  };

  const packageJson = getPackageJson(projectDir);

  const packageJsonDependencies = _ramda().default.merge(packageJson.dependencies || {}, packageJson.devDependencies || {});

  const getNameAndVersion = pj => ({
    [pj.name]: pj.version
  });

  const nodeModules = _ramda().default.mergeAll(_glob().default.sync(_path().default.join(projectDir, 'node_modules', '*')).map(_ramda().default.compose(getNameAndVersion, getPackageJson))); // eslint-disable-next-line


  dependencies.forEach(dep => {
    if (!dep.packageDependencies || _ramda().default.isEmpty(dep.packageDependencies)) return null;

    _ramda().default.forEachObjIndexed((packageDepVersion, packageDepName) => {
      const packageDep = {
        [packageDepName]: packageDepVersion
      };
      const compatibleWithPackgeJson = compatibleWith(packageDep, packageJsonDependencies);
      const compatibleWithNodeModules = compatibleWith(packageDep, nodeModules);

      if (!compatibleWithPackgeJson && !compatibleWithNodeModules && !_ramda().default.contains(packageDep, warnings.notInBoth)) {
        warnings.notInBoth.push(packageDep);
      }

      if (!compatibleWithPackgeJson && compatibleWithNodeModules && !_ramda().default.contains(packageDep, warnings.notInPackageJson)) {
        warnings.notInPackageJson.push(packageDep);
      }

      if (compatibleWithPackgeJson && !compatibleWithNodeModules && !_ramda().default.contains(packageDep, warnings.notInNodeModules)) {
        warnings.notInNodeModules.push(packageDep);
      }
    }, dep.packageDependencies);
  }); // Remove duplicates warnings for missing packages

  warnings.notInBoth = _ramda().default.uniq(warnings.notInBoth);
  return Promise.resolve(warnings);
};