'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 _ramda;

function _load_ramda() {
  return _ramda = _interopRequireDefault(require('ramda'));
}

var _constants;

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

var _componentMap;

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

var _bitId;

function _load_bitId() {
  return _bitId = require('../../../../bit-id');
}

var _component;

function _load_component() {
  return _component = _interopRequireDefault(require('../../../component'));
}

var _driver;

function _load_driver() {
  return _driver = require('../../../../driver');
}

var _utils;

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

var _logger;

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

var _consumer;

function _load_consumer() {
  return _consumer = require('../../../../consumer');
}

var _dependencies;

function _load_dependencies() {
  return _dependencies = _interopRequireDefault(require('../dependencies'));
}

var _generalError;

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

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"); }); }; }

/**
 * Given the tree of file dependencies from the driver, find the components of these files.
 * Each dependency file has a path, use bit.map to search for the component name by that path.
 * If the component is found, add it to "componentsDeps". Otherwise, add it to "untrackedDeps".
 *
 * For the found components, add their sourceRelativePath and destinationRelativePath, they are being used for
 * generating links upon import:
 * sourceRelativePath - location of the link file.
 * destinationRelativePath - destination written inside the link file.
 *
 * @param {Object} tree - contains direct deps for each file
 * @param {string[]} files - component files to search
 * @param {string[]} testsFiles - component test files
 * @param {string} entryComponentId - component id for the entry of traversing - used to know which of the files are part of that component
 * @param {consumer} consumer
 * @param componentFromModel
 */
function findComponentsOfDepsFiles(tree, files, testsFiles, entryComponentId, consumer, consumerComponent) {
  var driver = consumer.driver;
  var bindingPrefix = consumerComponent.bindingPrefix;
  var componentFromModel = consumerComponent.componentFromModel;
  var packagesDeps = {};
  var devPackagesDeps = {};
  var componentsDeps = {};
  var devComponentsDeps = {};
  var untrackedDeps = {};
  var relativeDeps = {}; // dependencies that are required with relative path (and should be required using 'bit/').
  var missingDeps = [];

  var consumerPath = consumer.getPath();
  var entryComponentMap = consumer.bitMap.getComponent(entryComponentId);
  var rootDir = entryComponentMap.rootDir;
  var processedFiles = [];

  var traverseTreeForComponentId = function traverseTreeForComponentId(depFile) {
    if (!tree[depFile] || !tree[depFile].files && !tree[depFile].bits) return;
    var rootDirFullPath = (_path || _load_path()).default.join(consumerPath, rootDir);
    if (tree[depFile].files && tree[depFile].files.length) {
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = tree[depFile].files[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var file = _step.value;

          var fullDepFile = (_path || _load_path()).default.resolve(rootDirFullPath, file.file);
          var depRelativeToConsumer = (0, (_utils || _load_utils()).pathNormalizeToLinux)((_path || _load_path()).default.relative(consumerPath, fullDepFile));
          var componentId = consumer.bitMap.getComponentIdByPath(depRelativeToConsumer);
          if (componentId) return componentId; // eslint-disable-line consistent-return
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
    if (tree[depFile].bits && tree[depFile].bits.length) {
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = tree[depFile].bits[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var bit = _step2.value;

          var _componentId = (_consumer || _load_consumer()).Consumer.getComponentIdFromNodeModulesPath(bit, bindingPrefix);
          if (_componentId) return _componentId; // eslint-disable-line consistent-return
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }

    var _iteratorNormalCompletion3 = true;
    var _didIteratorError3 = false;
    var _iteratorError3 = undefined;

    try {
      for (var _iterator3 = tree[depFile].files[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
        var _file = _step3.value;

        if (_file.file !== depFile) {
          var _componentId2 = traverseTreeForComponentId(_file.file);
          if (_componentId2) return _componentId2; // eslint-disable-line consistent-return
        } else {
          (_logger || _load_logger()).default.warn(`traverseTreeForComponentId found a cyclic dependency. ${_file.file} depends on itself`);
        }
      }
    } catch (err) {
      _didIteratorError3 = true;
      _iteratorError3 = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion3 && _iterator3.return) {
          _iterator3.return();
        }
      } finally {
        if (_didIteratorError3) {
          throw _iteratorError3;
        }
      }
    }
  };

  var getComponentIdByDepFile = function getComponentIdByDepFile(depFile) {
    var depFileRelative = depFile; // dependency file path relative to consumer root
    var componentId = void 0;
    var destination = void 0;

    if (rootDir) {
      // The depFileRelative is relative to rootDir, change it to be relative to current consumer.
      // We can't use path.resolve(rootDir, fileDep) because this might not work when running
      // bit commands not from root, because resolve take by default the process.cwd
      var rootDirFullPath = (_path || _load_path()).default.join(consumerPath, rootDir);
      var fullDepFile = (_path || _load_path()).default.resolve(rootDirFullPath, depFile);
      depFileRelative = (0, (_utils || _load_utils()).pathNormalizeToLinux)((_path || _load_path()).default.relative(consumerPath, fullDepFile));
    }

    componentId = consumer.bitMap.getComponentIdByPath(depFileRelative);
    // if not found here, the file is not a component file. It might be a bit-auto-generated file.
    // find the component file by the auto-generated file.
    // We make sure also that rootDir is there, otherwise, it's an AUTHORED component, which shouldn't have
    // auto-generated files.
    if (!componentId && rootDir) {
      componentId = traverseTreeForComponentId(depFile);
      if (componentId) {
        // it is verified now that this depFile is an auto-generated file, therefore the sourceRelativePath and the
        // destinationRelativePath should be a partial-path and not full-relative-to-consumer path.
        // since the dep-file is a generated file, it is safe to assume that the componentFromModel has in its
        // dependencies array this component with the relativePaths array. Find the relativePath of this dep-file
        // to get the correct destinationRelativePath. There is no other way to obtain this info.
        if (!componentFromModel) {
          throw new (_generalError || _load_generalError()).default(`Failed to resolve ${componentId} dependencies because the component is not in the model.
Try to run "bit import ${consumerComponent.id.toString()} --objects" to get the component saved in the model`);
        }
        var componentBitId = (_bitId || _load_bitId()).BitId.parse(componentId);
        var dependency = componentFromModel.getAllDependencies().find(function (dep) {
          return dep.id.toStringWithoutVersion() === componentBitId.toStringWithoutVersion();
        });
        if (!dependency) {
          throw new (_generalError || _load_generalError()).default(`the auto-generated file ${depFile} should be connected to ${componentId}, however, it's not part of the model dependencies of ${componentFromModel.id}`);
        }
        var originallySource = entryComponentMap.originallySharedDir ? (0, (_utils || _load_utils()).pathJoinLinux)(entryComponentMap.originallySharedDir, depFile) : depFile;
        var relativePath = dependency.relativePaths.find(function (r) {
          return r.sourceRelativePath === originallySource;
        });
        if (!relativePath) {
          throw new (_generalError || _load_generalError()).default(`unable to find ${originallySource} path in the dependencies relativePaths of ${componentFromModel.id}`);
        }

        componentId = dependency.id.toString();
        destination = relativePath.destinationRelativePath;

        depFileRelative = depFile; // change it back to partial-part, this will be later on the sourceRelativePath
      }
    }

    return { componentId, depFileRelative, destination };
  };

  var processDepFile = function processDepFile(originFile, depFile, importSpecifiers, linkFile) {
    var isTestFile = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
    var depFileObject = arguments[5];

    if (processedFiles.includes(depFile)) return;
    processedFiles.push(depFile);

    var _getComponentIdByDepF = getComponentIdByDepFile(depFile),
        componentId = _getComponentIdByDepF.componentId,
        depFileRelative = _getComponentIdByDepF.depFileRelative,
        destination = _getComponentIdByDepF.destination;
    // the file dependency doesn't have any counterpart component. Add it to untrackedDeps


    if (!componentId) {
      if (untrackedDeps[originFile]) untrackedDeps[originFile].push(depFileRelative);else untrackedDeps[originFile] = [depFileRelative];
      return;
    }

    // happens when in the same component one file requires another one. In this case, there is
    // noting to do regarding the dependencies
    if (componentId === entryComponentId) {
      if (depFileObject.isCustomResolveUsed) {
        consumerComponent.customResolvedPaths.push({
          destinationPath: depFileObject.file,
          importSource: depFileObject.importSource
        });
      }
      return;
    }

    var componentMap = consumer.bitMap.getComponent(componentId);
    // found a dependency component. Add it to componentsDeps
    var depRootDir = componentMap ? componentMap.rootDir : undefined;
    var destinationRelativePath = destination || (depRootDir && depFileRelative.startsWith(depRootDir) ? (0, (_utils || _load_utils()).pathRelativeLinux)(depRootDir, depFileRelative) : depFileRelative);

    var sourceRelativePath = void 0;
    if (linkFile) {
      sourceRelativePath = linkFile;
    } else {
      // when there is no rootDir for the current dependency (it happens when it's AUTHORED), keep the original path
      sourceRelativePath = depRootDir ? depFileRelative : depFile;
    }

    var depsPaths = {
      sourceRelativePath,
      destinationRelativePath
    };
    if (importSpecifiers) {
      depsPaths.importSpecifiers = importSpecifiers;
    }
    if (depFileObject.isCustomResolveUsed) {
      depsPaths.isCustomResolveUsed = depFileObject.isCustomResolveUsed;
      depsPaths.importSource = depFileObject.importSource;
    }
    var currentComponentsDeps = { [componentId]: [depsPaths] };

    if (componentMap && (componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED && entryComponentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED || componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED && entryComponentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED)) {
      // prevent author using relative paths for IMPORTED component
      // also prevent adding AUTHORED component to an IMPORTED component using relative syntax. The reason is that when
      // this component is imported somewhere else, a link-file between the IMPORTED and the AUTHORED must be written
      // outside the component directory, which might override user files.
      if (relativeDeps[originFile]) relativeDeps[originFile].push(componentId);else relativeDeps[originFile] = [componentId];
      return;
    }

    if (componentsDeps[componentId]) {
      // it is another file of an already existing component. Just add the new path
      componentsDeps[componentId].push(depsPaths);
    } else if (devComponentsDeps[componentId]) {
      devComponentsDeps[componentId].push(depsPaths);
    } else if (isTestFile) {
      Object.assign(devComponentsDeps, currentComponentsDeps);
    } else {
      Object.assign(componentsDeps, currentComponentsDeps);
    }
  };

  var processLinkFile = function processLinkFile(originFile, linkFile) {
    var isTestFile = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    if (!linkFile.linkDependencies || (_ramda || _load_ramda()).default.isEmpty(linkFile.linkDependencies)) return;
    var nonLinkImportSpecifiers = [];
    linkFile.linkDependencies.forEach(function (dependency) {
      var component = getComponentIdByDepFile(linkFile.file);
      if (component.componentId) {
        // the linkFile is already a component, no need to treat it differently than other depFile
        // aggregate all dependencies using the same linkFile and ultimately run processDepFile
        // with all importSpecifiers of that linkFile.
        // also, delete the linkFile attribute of importSpecifiers so then once the component is
        // imported and the link is generated, it won't be treated as a linkFile.
        dependency.importSpecifiers.map(function (a) {
          return delete a.linkFile;
        });
        nonLinkImportSpecifiers.push(dependency.importSpecifiers);
      } else {
        processDepFile(originFile, dependency.file, dependency.importSpecifiers, linkFile.file, isTestFile, linkFile);
      }
    });
    if (nonLinkImportSpecifiers.length) {
      processDepFile(originFile, linkFile.file, (_ramda || _load_ramda()).default.flatten(nonLinkImportSpecifiers), undefined, isTestFile, linkFile);
    }
  };

  var processDepFiles = function processDepFiles(originFile, allDepsFiles) {
    var isTestFile = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    if (!allDepsFiles || (_ramda || _load_ramda()).default.isEmpty(allDepsFiles)) return;
    allDepsFiles.forEach(function (depFile) {
      if (depFile.isLink) processLinkFile(originFile, depFile, isTestFile);else processDepFile(originFile, depFile.file, depFile.importSpecifiers, undefined, isTestFile, depFile);
    });
  };

  var processBits = function processBits(bits) {
    var isTestFile = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    if (bits && !(_ramda || _load_ramda()).default.isEmpty(bits)) {
      bits.forEach(function (bitDep) {
        var componentId = (_consumer || _load_consumer()).Consumer.getComponentIdFromNodeModulesPath(bitDep, bindingPrefix);
        var getExistingId = function getExistingId() {
          var existingId = consumer.bitMap.getExistingComponentId(componentId);
          if (existingId) return existingId;

          // maybe the dependencies were imported as npm packages
          if (bitDep.startsWith('node_modules')) {
            // Add the root dir in case it exists (to make sure we search for the dependency package json in the correct place)
            var basePath = rootDir ? (_path || _load_path()).default.join(consumerPath, rootDir) : consumerPath;
            var depPath = (_path || _load_path()).default.join(basePath, bitDep);
            var packageJson = driver.driver.PackageJson.findPackage(depPath);
            if (packageJson) {
              var depVersion = packageJson.version;
              existingId = (_bitId || _load_bitId()).BitId.parse(componentId, depVersion);
              return existingId.toString();
            }
          }
          if (componentFromModel) {
            var modelDep = componentFromModel.getAllDependencies().find(function (dep) {
              return dep.id.toStringWithoutVersion() === componentId;
            });
            if (modelDep) return modelDep.id.toString();
          }
          return null;
        };
        var existingId = getExistingId();
        if (existingId) {
          var currentComponentsDeps = { [existingId]: [] };
          if (!componentsDeps[existingId]) {
            if (isTestFile) {
              Object.assign(devComponentsDeps, currentComponentsDeps);
            } else {
              Object.assign(componentsDeps, currentComponentsDeps);
            }
          }
        } else {
          missingDeps.push(componentId);
        }
      });
    }
  };

  var processPackages = function processPackages(originFile, packages, isTestFile) {
    if (packages && !(_ramda || _load_ramda()).default.isEmpty(packages)) {
      if (isTestFile) {
        Object.assign(devPackagesDeps, packages);
      } else {
        Object.assign(packagesDeps, packages);
      }
    }
  };

  /**
   * currently the only unidentified packages being process are the ones coming from custom-modules-resolution.
   * assuming the author used custom-resolution, which enable using non-relative import syntax,
   * for example, requiring the file 'src/utils/is-string' from anywhere as require('utils/is-string');
   * now, when the component is imported, the driver recognizes 'utils/is-string' as a package,
   * because it's not relative.
   * the goal here is to use the 'package' the driver found and match it with one of the
   * dependencies from the model. In the example above, we might find in the model, a dependency
   * is-string with importSource of 'utils/is-string'.
   * Once a match is found, copy the relativePaths from the model. Before coping, we must strip the
   * originallySharedDir, because in this process, the component is loaded from the filesystem and
   * as such the sharedDir is expected to be stripped.
   */
  var processUnidentifiedPackages = function processUnidentifiedPackages(originFile, unidentifiedPackages, isTestFile) {
    if (!unidentifiedPackages) return;
    if (!componentFromModel) return; // not relevant, the component is not imported
    var dependencies = isTestFile ? componentFromModel.devDependencies : componentFromModel.dependencies;
    if (dependencies.isEmpty()) return;
    var importSourceMap = dependencies.getCustomResolvedData();
    if ((_ramda || _load_ramda()).default.isEmpty(importSourceMap)) return;
    // clone before stripping the sharedDir to not change the model by mistake
    var clonedDependencies = new (_dependencies || _load_dependencies()).default(dependencies.getClone());
    if (entryComponentMap.originallySharedDir) {
      // @todo: disabled for now. When the files are saved into the model, we don't add the sharedDir
      // in this case, so it should be fine. (see sources.consumerComponentToVersion())
      // it needs some more thinking whether there are cases when it is needed
      // clonedDependencies.stripOriginallySharedDir(consumer.bitMap, entryComponentMap.originallySharedDir);
    }
    unidentifiedPackages.forEach(function (unidentifiedPackage) {
      var packageLinuxFormat = (0, (_utils || _load_utils()).pathNormalizeToLinux)(unidentifiedPackage);
      var packageWithNoNodeModules = packageLinuxFormat.replace('node_modules/', '');
      var foundImportSource = Object.keys(importSourceMap).find(function (importSource) {
        return packageWithNoNodeModules.startsWith(importSource);
      });
      if (foundImportSource) {
        var dependencyId = importSourceMap[foundImportSource];
        var dependencyIdStr = dependencyId.toString();
        if (isTestFile && !devComponentsDeps[dependencyIdStr]) {
          devComponentsDeps[dependencyIdStr] = dependencies.getById(dependencyIdStr).relativePaths;
        } else if (!isTestFile && !componentsDeps[dependencyIdStr]) {
          componentsDeps[dependencyIdStr] = clonedDependencies.getById(dependencyIdStr).relativePaths;
        }
      }
    });
  };

  /**
   * Remove the dependencies which appear both in dev and regular deps from the dev
   * Because if a dependency is both dev dependency and regular dependecy it should be treated as regular one
   * Apply for both packages and components dependencies
   */
  var removeDevDepsIfTheyAlsoRegulars = function removeDevDepsIfTheyAlsoRegulars() {
    var devPackagesOnlyNames = (_ramda || _load_ramda()).default.difference((_ramda || _load_ramda()).default.keys(devPackagesDeps), (_ramda || _load_ramda()).default.keys(packagesDeps));
    devPackagesDeps = (_ramda || _load_ramda()).default.pick(devPackagesOnlyNames, devPackagesDeps);
    var devComponentsOnlyNames = (_ramda || _load_ramda()).default.difference((_ramda || _load_ramda()).default.keys(devComponentsDeps), (_ramda || _load_ramda()).default.keys(componentsDeps));
    devComponentsDeps = (_ramda || _load_ramda()).default.pick(devComponentsOnlyNames, devComponentsDeps);
  };

  files.forEach(function (file) {
    var isTestFile = (_ramda || _load_ramda()).default.contains(file, testsFiles);
    processPackages(file, tree[file].packages, isTestFile);
    processBits(tree[file].bits, isTestFile);
    processDepFiles(file, tree[file].files, isTestFile);
    processUnidentifiedPackages(file, tree[file].unidentifiedPackages, isTestFile);
  });
  removeDevDepsIfTheyAlsoRegulars();

  return { componentsDeps, devComponentsDeps, packagesDeps, devPackagesDeps, untrackedDeps, relativeDeps, missingDeps };
}

// @todo: move to bit-javascript
/**
 * For author, the peer-dependencies are set in the root package.json
 * For imported components, we don't want to change the peerDependencies of the author, unless
 * we're certain the user intent to do so. Therefore, we ignore the root package.json and look for
 * the package.json in the component's directory.
 */
function findPeerDependencies(consumerPath, component) {
  var componentMap = component.componentMap;
  var getPeerDependencies = function getPeerDependencies() {
    var componentRoot = componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED ? consumerPath : componentMap.rootDir;
    var packageJsonLocation = (_path || _load_path()).default.join(componentRoot, 'package.json');
    if ((_fsExtra || _load_fsExtra()).default.existsSync(packageJsonLocation)) {
      try {
        var packageJson = (_fsExtra || _load_fsExtra()).default.readJsonSync(packageJsonLocation);
        if (packageJson.peerDependencies) return packageJson.peerDependencies;
      } catch (err) {
        (_logger || _load_logger()).default.error(`Failed reading the project package.json at ${packageJsonLocation}. Error Message: ${err.message}`);
      }
    }
    if (component.componentFromModel && componentMap.origin !== (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED) {
      return component.componentFromModel.peerPackageDependencies;
    }
    return {};
  };
  var projectPeerDependencies = getPeerDependencies();
  var peerPackages = {};
  if ((_ramda || _load_ramda()).default.isEmpty(projectPeerDependencies)) return {};
  // check whether the peer-dependencies was actually require in the code. if so, remove it from
  // the packages/dev-packages and add it as a peer-package.
  Object.keys(projectPeerDependencies).forEach(function (pkg) {
    ['packageDependencies', 'devPackageDependencies'].forEach(function (field) {
      if (Object.keys(component[field]).includes(pkg)) {
        delete component[field][pkg];
        peerPackages[pkg] = projectPeerDependencies[pkg];
      }
    });
  });
  return peerPackages;
}

/**
 * Load components and packages dependencies for a component. The process is as follows:
 * 1) Use the language driver to parse the component files and find for each file its dependencies.
 * 2) The results we get from the driver per file tells us what are the files and packages that depend on our file.
 * and also whether there are missing packages and files.
 * 3) Using the information from the driver, we go over each one of the dependencies files and find its counterpart
 * component. The way how we find it, is by using the bit.map file which has a mapping between the component name and
 * the file paths.
 * 4) If we find a component to the file dependency, we add it to component.dependencies. Otherwise, it's added to
 * component.missingDependencies.untrackedDependencies
 * 5) Similarly, when we find the packages dependencies, they are added to component.packageDependencies. Otherwise,
 * they're added to component.missingDependencies.missingPackagesDependenciesOnFs
 * 6) In case the driver found a file dependency that is not on the file-system, we add that file to
 * component.missingDependencies.missingDependenciesOnFs
 */

exports.default = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(component, bitDir, consumer, idWithConcreteVersionString) {
    var _this = this;

    var driver, consumerPath, componentMap, componentFromModel, missingDependencies, _componentMap$getFile, allFiles, testsFiles, getDependenciesTree, dependenciesTree, missingDependenciesOnFs, missingPackagesDependenciesOnFs, missingComponents, missingLinks, missingCustomModuleResolutionLinks, componentFiles, findOriginallyCustomModuleResolvedDependencies, traversedDeps, traversedCompDeps, traversedCompDevDeps, dependencies, devDependencies, untrackedDependencies;

    return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            driver = consumer.driver;
            consumerPath = consumer.getPath();
            componentMap = component.componentMap;
            componentFromModel = component.componentFromModel;
            missingDependencies = {};
            _componentMap$getFile = componentMap.getFilesGroupedByBeingTests(), allFiles = _componentMap$getFile.allFiles, testsFiles = _componentMap$getFile.testsFiles;

            getDependenciesTree = function () {
              var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee() {
                return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
                  while (1) {
                    switch (_context.prev = _context.next) {
                      case 0:
                        return _context.abrupt('return', driver.getDependencyTree(bitDir, consumerPath, allFiles, component.bindingPrefix, consumer.bitJson.resolveModules));

                      case 1:
                      case 'end':
                        return _context.stop();
                    }
                  }
                }, _callee, _this);
              }));

              return function getDependenciesTree() {
                return _ref2.apply(this, arguments);
              };
            }();
            // find the dependencies (internal files and packages) through automatic dependency resolution


            _context2.next = 9;
            return getDependenciesTree();

          case 9:
            dependenciesTree = _context2.sent;
            missingDependenciesOnFs = {};
            missingPackagesDependenciesOnFs = {};
            missingComponents = {};
            missingLinks = {};
            missingCustomModuleResolutionLinks = {};
            componentFiles = component.files;
            /**
             * given missing packages name, find whether they were dependencies with custom-resolve before.
             */

            findOriginallyCustomModuleResolvedDependencies = function findOriginallyCustomModuleResolvedDependencies(packages) {
              if (!packages) return undefined;
              if (!componentFromModel) return undefined; // not relevant, the component is not imported
              var dependencies = new (_dependencies || _load_dependencies()).default(componentFromModel.getAllDependencies());
              if (dependencies.isEmpty()) return undefined;
              var importSourceMap = dependencies.getCustomResolvedData();
              if ((_ramda || _load_ramda()).default.isEmpty(importSourceMap)) return undefined;
              var foundPackages = packages.reduce(function (acc, value) {
                var packageLinuxFormat = (0, (_utils || _load_utils()).pathNormalizeToLinux)(value);
                var foundImportSource = Object.keys(importSourceMap).find(function (importSource) {
                  return importSource.startsWith(packageLinuxFormat);
                });
                if (foundImportSource) {
                  var dependencyId = importSourceMap[foundImportSource];
                  acc[value] = dependencyId;
                }
                return acc;
              }, {});

              return (_ramda || _load_ramda()).default.isEmpty(foundPackages) ? undefined : foundPackages;
            };

            dependenciesTree.missing.forEach(function (fileDep) {
              var doesFileExistInComponent = !(_ramda || _load_ramda()).default.isEmpty(componentFiles.filter(function (componentFile) {
                return componentFile.relative === fileDep.originFile;
              }));
              if (doesFileExistInComponent) {
                if (fileDep.files && !(_ramda || _load_ramda()).default.isEmpty(fileDep.files)) {
                  if (missingDependenciesOnFs[fileDep.originFile]) {
                    missingDependenciesOnFs[fileDep.originFile].concat(fileDep.files);
                  } else missingDependenciesOnFs[fileDep.originFile] = fileDep.files;
                }
                if (fileDep.packages && !(_ramda || _load_ramda()).default.isEmpty(fileDep.packages)) {
                  var customResolvedDependencies = findOriginallyCustomModuleResolvedDependencies(fileDep.packages);
                  if (customResolvedDependencies) {
                    Object.keys(customResolvedDependencies).forEach(function (missingPackage) {
                      var componentId = customResolvedDependencies[missingPackage].toString();
                      if (missingCustomModuleResolutionLinks[fileDep.originFile]) {
                        missingCustomModuleResolutionLinks[fileDep.originFile].push(componentId);
                      } else missingCustomModuleResolutionLinks[fileDep.originFile] = [componentId];
                    });
                  }
                  var missingPackages = customResolvedDependencies ? (_ramda || _load_ramda()).default.difference(fileDep.packages, Object.keys(customResolvedDependencies)) : fileDep.packages;

                  if (!(_ramda || _load_ramda()).default.isEmpty(missingPackages)) {
                    if (missingPackagesDependenciesOnFs[fileDep.originFile]) {
                      missingPackagesDependenciesOnFs[fileDep.originFile].concat(fileDep.packages);
                    } else missingPackagesDependenciesOnFs[fileDep.originFile] = fileDep.packages;
                  }
                }

                if (fileDep.bits && !(_ramda || _load_ramda()).default.isEmpty(fileDep.bits)) {
                  fileDep.bits.forEach(function (missingBit) {
                    var componentId = (_consumer || _load_consumer()).Consumer.getComponentIdFromNodeModulesPath(missingBit, component.bindingPrefix);
                    // todo: a component might be on bit.map but not on the FS, yet, it's not about missing links.
                    if (consumer.bitMap.getExistingComponentId(componentId)) {
                      if (missingLinks[fileDep.originFile]) missingLinks[fileDep.originFile].push(componentId);else missingLinks[fileDep.originFile] = [componentId];
                    } else if (missingComponents[fileDep.originFile]) missingComponents[fileDep.originFile].push(componentId);else missingComponents[fileDep.originFile] = [componentId];
                  });
                }
              }
            });
            if (!(_ramda || _load_ramda()).default.isEmpty(missingDependenciesOnFs)) missingDependencies.missingDependenciesOnFs = missingDependenciesOnFs;
            if (!(_ramda || _load_ramda()).default.isEmpty(missingPackagesDependenciesOnFs)) {
              missingDependencies.missingPackagesDependenciesOnFs = missingPackagesDependenciesOnFs;
            }

            // we have the files dependencies, these files should be components that are registered in bit.map. Otherwise,
            // they are referred as "untracked components" and the user should add them later on in order to commit
            traversedDeps = findComponentsOfDepsFiles(dependenciesTree.tree, allFiles, testsFiles, idWithConcreteVersionString, consumer, component);
            traversedCompDeps = traversedDeps.componentsDeps;
            traversedCompDevDeps = traversedDeps.devComponentsDeps;
            dependencies = Object.keys(traversedCompDeps).map(function (depId) {
              return { id: (_bitId || _load_bitId()).BitId.parse(depId), relativePaths: traversedCompDeps[depId] };
            });

            component.setDependencies(dependencies);
            devDependencies = Object.keys(traversedCompDevDeps).map(function (depId) {
              return { id: (_bitId || _load_bitId()).BitId.parse(depId), relativePaths: traversedCompDevDeps[depId] };
            });

            component.setDevDependencies(devDependencies);
            untrackedDependencies = traversedDeps.untrackedDeps;

            if (!(_ramda || _load_ramda()).default.isEmpty(untrackedDependencies)) missingDependencies.untrackedDependencies = untrackedDependencies;
            component.packageDependencies = traversedDeps.packagesDeps;
            component.devPackageDependencies = traversedDeps.devPackagesDeps;
            component.peerPackageDependencies = findPeerDependencies(consumerPath, component);
            if (!(_ramda || _load_ramda()).default.isEmpty(traversedDeps.relativeDeps)) {
              missingDependencies.relativeComponents = traversedDeps.relativeDeps;
            }
            if (!(_ramda || _load_ramda()).default.isEmpty(missingLinks)) missingDependencies.missingLinks = missingLinks;
            if (!(_ramda || _load_ramda()).default.isEmpty(missingCustomModuleResolutionLinks)) {
              missingDependencies.missingCustomModuleResolutionLinks = missingCustomModuleResolutionLinks;
            }
            if (!(_ramda || _load_ramda()).default.isEmpty(missingComponents)) missingDependencies.missingComponents = missingComponents;
            // assign missingDependencies to component only when it has data.
            // Otherwise, when it's empty, component.missingDependencies will be an empty object ({}), and for some weird reason,
            // Ramda.isEmpty returns false when the component is received after async/await of Array.map.
            if (!(_ramda || _load_ramda()).default.isEmpty(missingDependencies)) component.missingDependencies = missingDependencies;

            return _context2.abrupt('return', component);

          case 38:
          case 'end':
            return _context2.stop();
        }
      }
    }, _callee2, this);
  }));

  function loadDependenciesForComponent(_x5, _x6, _x7, _x8) {
    return _ref.apply(this, arguments);
  }

  return loadDependenciesForComponent;
}();