'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _regenerator;

function _load_regenerator() {
  return _regenerator = _interopRequireDefault(require('babel-runtime/regenerator'));
}

var _path;

function _load_path() {
  return _path = _interopRequireDefault(require('path'));
}

var _fsExtra;

function _load_fsExtra() {
  return _fsExtra = _interopRequireDefault(require('fs-extra'));
}

var _moveComponents;

function _load_moveComponents() {
  return _moveComponents = require('./move-components');
}

var _links;

function _load_links() {
  return _links = require('../../links');
}

var _installPackages;

function _load_installPackages() {
  return _installPackages = require('../../npm-client/install-packages');
}

var _packageJson;

function _load_packageJson() {
  return _packageJson = _interopRequireWildcard(require('../component/package-json'));
}

var _scope;

function _load_scope() {
  return _scope = require('../../scope');
}

var _consumerComponent;

function _load_consumerComponent() {
  return _consumerComponent = _interopRequireDefault(require('../component/consumer-component'));
}

var _remotes;

function _load_remotes() {
  return _remotes = require('../../remotes');
}

var _constants;

function _load_constants() {
  return _constants = require('../../constants');
}

var _logger;

function _load_logger() {
  return _logger = _interopRequireDefault(require('../../logger/logger'));
}

var _analytics;

function _load_analytics() {
  return _analytics = require('../../analytics/analytics');
}

var _;

function _load_() {
  return _ = require('..');
}

var _utils;

function _load_utils() {
  return _utils = require('../../utils');
}

var _generalError;

function _load_generalError() {
  return _generalError = _interopRequireDefault(require('../../error/general-error'));
}

var _componentMap;

function _load_componentMap() {
  return _componentMap = _interopRequireDefault(require('../bit-map/component-map'));
}

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 _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

function throwErrorWhenDirectoryNotEmpty(componentDir, override, componentMap, writeToPath) {
  // if not writeToPath specified, it goes to the default directory. When componentMap exists, the
  // component is not new, and it's ok to override the existing directory.
  if (!writeToPath && componentMap) return;
  // if writeToPath specified and that directory is already used for that component, it's ok to override
  if (writeToPath && componentMap && componentMap.rootDir && componentMap.rootDir === writeToPath) return;

  if ((_fsExtra || _load_fsExtra()).default.pathExistsSync(componentDir)) {
    if (!(0, (_utils || _load_utils()).isDir)(componentDir)) {
      throw new (_generalError || _load_generalError()).default(`unable to import to ${componentDir} because it's a file`);
    }
    if (!(0, (_utils || _load_utils()).isDirEmptySync)(componentDir) && !override) {
      throw new (_generalError || _load_generalError()).default(`unable to import to ${componentDir}, the directory is not empty. use --override flag to delete the directory and then import`);
    }
  }
}

/**
 * write the components into '/components' dir (or according to the bit.map) and its dependencies in the
 * '/components/.dependencies' dir. Both directories are configurable in bit.json
 * For example: global/a has a dependency my-scope/global/b@1. The directories will be:
 * project/root/components/global/a/impl.js
 * project/root/components/.dependencies/global/b/my-scope/1/impl.js
 *
 * In case there are some same dependencies shared between the components, it makes sure to
 * write them only once.
 */

exports.default = function () {
  var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(_ref) {
    var consumer = _ref.consumer,
        silentPackageManagerResult = _ref.silentPackageManagerResult,
        componentsWithDependencies = _ref.componentsWithDependencies,
        writeToPath = _ref.writeToPath,
        _ref$override = _ref.override,
        override = _ref$override === undefined ? true : _ref$override,
        _ref$writePackageJson = _ref.writePackageJson,
        writePackageJson = _ref$writePackageJson === undefined ? true : _ref$writePackageJson,
        _ref$writeConfig = _ref.writeConfig,
        writeConfig = _ref$writeConfig === undefined ? false : _ref$writeConfig,
        configDir = _ref.configDir,
        _ref$writeBitDependen = _ref.writeBitDependencies,
        writeBitDependencies = _ref$writeBitDependen === undefined ? false : _ref$writeBitDependen,
        _ref$createNpmLinkFil = _ref.createNpmLinkFiles,
        createNpmLinkFiles = _ref$createNpmLinkFil === undefined ? false : _ref$createNpmLinkFil,
        _ref$writeDists = _ref.writeDists,
        writeDists = _ref$writeDists === undefined ? true : _ref$writeDists,
        _ref$saveDependencies = _ref.saveDependenciesAsComponents,
        saveDependenciesAsComponents = _ref$saveDependencies === undefined ? false : _ref$saveDependencies,
        _ref$installNpmPackag = _ref.installNpmPackages,
        installNpmPackages = _ref$installNpmPackag === undefined ? true : _ref$installNpmPackag,
        _ref$installPeerDepen = _ref.installPeerDependencies,
        installPeerDependencies = _ref$installPeerDepen === undefined ? false : _ref$installPeerDepen,
        _ref$addToRootPackage = _ref.addToRootPackageJson,
        addToRootPackageJson = _ref$addToRootPackage === undefined ? true : _ref$addToRootPackage,
        _ref$verbose = _ref.verbose,
        verbose = _ref$verbose === undefined ? false : _ref$verbose,
        _ref$excludeRegistryP = _ref.excludeRegistryPrefix,
        excludeRegistryPrefix = _ref$excludeRegistryP === undefined ? false : _ref$excludeRegistryP;
    var dependenciesIdsCache, remotes, writeComponentsParams, writeComponentsP, writtenComponents, allDependenciesP, writtenDependenciesIncludesNull, writtenDependencies;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            dependenciesIdsCache = {};
            _context.next = 3;
            return consumer.scope.remotes();

          case 3:
            remotes = _context.sent;
            writeComponentsParams = componentsWithDependencies.map(function (componentWithDeps) {
              var bitDir = writeToPath ? (_path || _load_path()).default.resolve(writeToPath) : consumer.composeComponentPath(componentWithDeps.component.id);
              // if it doesn't go to the hub, it can't import dependencies as packages
              componentWithDeps.component.dependenciesSavedAsComponents = saveDependenciesAsComponents || !remotes.isHub(componentWithDeps.component.scope);
              // AUTHORED and IMPORTED components can't be saved with multiple versions, so we can ignore the version to
              // find the component in bit.map
              var componentMap = consumer.bitMap.getComponentIfExist(componentWithDeps.component.id, { ignoreVersion: true });
              var origin = componentMap && componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED ? (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED : (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED;
              if (origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED) {
                componentWithDeps.component.stripOriginallySharedDir(consumer.bitMap);
              }
              var configDirFromComponentMap = componentMap ? componentMap.configDir : undefined;
              throwErrorWhenDirectoryNotEmpty(bitDir, override, componentMap, writeToPath);
              // don't write dists files for authored components as the author has its own mechanism to generate them
              // also, don't write dists file for imported component, unless the user used '--dist' flag
              componentWithDeps.component.dists.writeDistsFiles = writeDists && origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED;
              return {
                component: componentWithDeps.component,
                writeParams: {
                  bitDir,
                  override: true,
                  writeConfig,
                  configDir: configDir || configDirFromComponentMap,
                  writePackageJson,
                  origin,
                  consumer,
                  writeBitDependencies: writeBitDependencies || !componentWithDeps.component.dependenciesSavedAsComponents, // when dependencies are written as npm packages, they must be written in package.json
                  componentMap,
                  excludeRegistryPrefix
                }
              };
            });
            writeComponentsP = writeComponentsParams.map(function (_ref3) {
              var component = _ref3.component,
                  writeParams = _ref3.writeParams;
              return component.write(writeParams);
            });
            _context.next = 8;
            return Promise.all(writeComponentsP);

          case 8:
            writtenComponents = _context.sent;
            allDependenciesP = componentsWithDependencies.map(function (componentWithDeps) {
              var writeDependenciesP = componentWithDeps.allDependencies.map(function (dep) {
                var dependencyId = dep.id.toString();
                var depFromBitMap = consumer.bitMap.getComponentIfExist(dep.id);
                if (!componentWithDeps.component.dependenciesSavedAsComponents && !depFromBitMap) {
                  // when depFromBitMap is true, it means that this component was imported as a component already before
                  // don't change it now from a component to a package. (a user can do it at any time by using export --eject).
                  (_logger || _load_logger()).default.debug(`writeToComponentsDir, ignore dependency ${dependencyId}. It'll be installed later using npm-client`);
                  (_analytics || _load_analytics()).Analytics.addBreadCrumb('writeToComponentsDir', `writeToComponentsDir, ignore dependency ${(_analytics || _load_analytics()).Analytics.hashData(dependencyId)}. It'll be installed later using npm-client`);
                  return Promise.resolve(null);
                }
                if (depFromBitMap && depFromBitMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED) {
                  dep.writtenPath = consumer.getPath();
                  (_logger || _load_logger()).default.debug(`writeToComponentsDir, ignore dependency ${dependencyId} as it already exists in bit map`);
                  (_analytics || _load_analytics()).Analytics.addBreadCrumb('writeToComponentsDir', `writeToComponentsDir, ignore dependency ${(_analytics || _load_analytics()).Analytics.hashData(dependencyId)} as it already exists in bit map`);
                  consumer.bitMap.addDependencyToParent(componentWithDeps.component.id, dependencyId);
                  return Promise.resolve(dep);
                }
                if (depFromBitMap && (_fsExtra || _load_fsExtra()).default.existsSync(depFromBitMap.rootDir)) {
                  dep.writtenPath = depFromBitMap.rootDir;
                  (_logger || _load_logger()).default.debug(`writeToComponentsDir, ignore dependency ${dependencyId} as it already exists in bit map and file system`);
                  (_analytics || _load_analytics()).Analytics.addBreadCrumb('writeToComponentsDir', `writeToComponentsDir, ignore dependency ${(_analytics || _load_analytics()).Analytics.hashData(dependencyId)} as it already exists in bit map and file system`);
                  consumer.bitMap.addDependencyToParent(componentWithDeps.component.id, dependencyId);
                  return Promise.resolve(dep);
                }
                if (dependenciesIdsCache[dependencyId]) {
                  (_logger || _load_logger()).default.debug(`writeToComponentsDir, ignore dependency ${dependencyId} as it already exists in cache`);
                  (_analytics || _load_analytics()).Analytics.addBreadCrumb('writeToComponentsDir', `writeToComponentsDir, ignore dependency ${(_analytics || _load_analytics()).Analytics.hashData(dependencyId)} as it already exists in cache`);
                  dep.writtenPath = dependenciesIdsCache[dependencyId];
                  consumer.bitMap.addDependencyToParent(componentWithDeps.component.id, dependencyId);
                  return Promise.resolve(dep);
                }
                var depBitPath = consumer.composeDependencyPath(dep.id);
                dep.writtenPath = depBitPath;
                dependenciesIdsCache[dependencyId] = depBitPath;
                // When a component is NESTED we do interested in the exact version, because multiple components with the same scope
                // and namespace can co-exist with different versions.
                var componentMap = consumer.bitMap.getComponentIfExist(dep.id);
                return dep.write({
                  bitDir: depBitPath,
                  override: true,
                  writePackageJson,
                  origin: (_constants || _load_constants()).COMPONENT_ORIGINS.NESTED,
                  parent: componentWithDeps.component.id,
                  consumer,
                  componentMap,
                  excludeRegistryPrefix
                });
              });

              return Promise.all(writeDependenciesP).then(function (deps) {
                return deps.filter(function (dep) {
                  return dep;
                });
              });
            });
            _context.next = 12;
            return Promise.all(allDependenciesP);

          case 12:
            writtenDependenciesIncludesNull = _context.sent;
            writtenDependencies = writtenDependenciesIncludesNull.filter(function (dep) {
              return dep;
            });

            if (writeToPath) {
              componentsWithDependencies.forEach(function (componentWithDeps) {
                var relativeWrittenPath = consumer.getPathRelativeToConsumer(componentWithDeps.component.writtenPath);
                var absoluteWrittenPath = consumer.toAbsolutePath(relativeWrittenPath);
                var absoluteWriteToPath = (_path || _load_path()).default.resolve(writeToPath); // don't use consumer.toAbsolutePath, it might be an inner dir
                if (relativeWrittenPath && absoluteWrittenPath !== absoluteWriteToPath) {
                  var component = componentWithDeps.component;
                  (0, (_moveComponents || _load_moveComponents()).moveExistingComponent)(consumer, component, absoluteWrittenPath, absoluteWriteToPath);
                }
              });
            }

            // add workspaces if flag is true
            _context.next = 17;
            return (_packageJson || _load_packageJson()).addWorkspacesToPackageJson(consumer, writeToPath);

          case 17:
            if (!installNpmPackages) {
              _context.next = 20;
              break;
            }

            _context.next = 20;
            return (0, (_installPackages || _load_installPackages()).installNpmPackagesForComponents)(consumer, componentsWithDependencies, verbose, silentPackageManagerResult, installPeerDependencies);

          case 20:
            if (!addToRootPackageJson) {
              _context.next = 23;
              break;
            }

            _context.next = 23;
            return (_packageJson || _load_packageJson()).addComponentsToRoot(consumer, writtenComponents.map(function (c) {
              return c.id;
            }));

          case 23:
            return _context.abrupt('return', (0, (_links || _load_links()).linkComponents)(componentsWithDependencies, writtenComponents, writtenDependencies, consumer, createNpmLinkFiles, writePackageJson));

          case 24:
          case 'end':
            return _context.stop();
        }
      }
    }, _callee, this);
  }));

  function writeToComponentsDir(_x) {
    return _ref2.apply(this, arguments);
  }

  return writeToComponentsDir;
}();