"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

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

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

function _objectSpread2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));

  _objectSpread2 = function () {
    return data;
  };

  return data;
}

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

  _bluebird = function () {
    return data;
  };

  return data;
}

function _defineProperty2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

  _defineProperty2 = function () {
    return data;
  };

  return data;
}

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

  _path = function () {
    return data;
  };

  return data;
}

function _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

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

  _ramda = function () {
    return data;
  };

  return data;
}

function _chalk() {
  const data = _interopRequireDefault(require("chalk"));

  _chalk = function () {
    return data;
  };

  return data;
}

function _utils() {
  const data = require("../../utils");

  _utils = function () {
    return data;
  };

  return data;
}

function _createSymlinkOrCopy() {
  const data = _interopRequireDefault(require("../../utils/fs/create-symlink-or-copy"));

  _createSymlinkOrCopy = function () {
    return data;
  };

  return data;
}

function _config() {
  const data = _interopRequireDefault(require("../config"));

  _config = function () {
    return data;
  };

  return data;
}

function _sources() {
  const data = require("../component/sources");

  _sources = function () {
    return data;
  };

  return data;
}

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

  _bitId = function () {
    return data;
  };

  return data;
}

function _bitIds() {
  const data = _interopRequireDefault(require("../../bit-id/bit-ids"));

  _bitIds = function () {
    return data;
  };

  return data;
}

function _parser() {
  const data = _interopRequireDefault(require("../../jsdoc/parser"));

  _parser = function () {
    return data;
  };

  return data;
}

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

  _specsResults = function () {
    return data;
  };

  return data;
}

function _ejectConf() {
  const data = require("../component-ops/eject-conf");

  _ejectConf = function () {
    return data;
  };

  return data;
}

function _injectConf() {
  const data = _interopRequireDefault(require("../component-ops/inject-conf"));

  _injectConf = function () {
    return data;
  };

  return data;
}

function _componentSpecsFailed() {
  const data = _interopRequireDefault(require("../exceptions/component-specs-failed"));

  _componentSpecsFailed = function () {
    return data;
  };

  return data;
}

function _missingFilesFromComponent() {
  const data = _interopRequireDefault(require("./exceptions/missing-files-from-component"));

  _missingFilesFromComponent = function () {
    return data;
  };

  return data;
}

function _componentNotFoundInPath() {
  const data = _interopRequireDefault(require("./exceptions/component-not-found-in-path"));

  _componentNotFoundInPath = function () {
    return data;
  };

  return data;
}

function _environment() {
  const data = _interopRequireWildcard(require("../../environment"));

  _environment = function () {
    return data;
  };

  return data;
}

function _componentMap() {
  const data = _interopRequireDefault(require("../bit-map/component-map"));

  _componentMap = function () {
    return data;
  };

  return data;
}

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

  _logger = function () {
    return data;
  };

  return data;
}

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

  _loader = function () {
    return data;
  };

  return data;
}

function _compilerExtension() {
  const data = _interopRequireDefault(require("../../extensions/compiler-extension"));

  _compilerExtension = function () {
    return data;
  };

  return data;
}

function _testerExtension() {
  const data = _interopRequireDefault(require("../../extensions/tester-extension"));

  _testerExtension = function () {
    return data;
  };

  return data;
}

function _driver() {
  const data = require("../../driver");

  _driver = function () {
    return data;
  };

  return data;
}

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

  _loaderMessages = function () {
    return data;
  };

  return data;
}

function _fileSourceNotFound() {
  const data = _interopRequireDefault(require("./exceptions/file-source-not-found"));

  _fileSourceNotFound = function () {
    return data;
  };

  return data;
}

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

  _constants = function () {
    return data;
  };

  return data;
}

function _componentDependencies() {
  const data = _interopRequireDefault(require("../../scope/component-dependencies"));

  _componentDependencies = function () {
    return data;
  };

  return data;
}

function _dependencies() {
  const data = require("./dependencies");

  _dependencies = function () {
    return data;
  };

  return data;
}

function _dists() {
  const data = _interopRequireDefault(require("./sources/dists"));

  _dists = function () {
    return data;
  };

  return data;
}

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

  _externalTestErrors = function () {
    return data;
  };

  return data;
}

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

  _generalError = function () {
    return data;
  };

  return data;
}

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

  _analytics = function () {
    return data;
  };

  return data;
}

function _componentIssuesTemplate() {
  const data = require("../../cli/templates/component-issues-template");

  _componentIssuesTemplate = function () {
    return data;
  };

  return data;
}

function _mainFileRemoved() {
  const data = _interopRequireDefault(require("./exceptions/main-file-removed"));

  _mainFileRemoved = function () {
    return data;
  };

  return data;
}

function _envExtension() {
  const data = _interopRequireDefault(require("../../extensions/env-extension"));

  _envExtension = function () {
    return data;
  };

  return data;
}

function _ejectToWorkspace() {
  const data = _interopRequireDefault(require("./exceptions/eject-to-workspace"));

  _ejectToWorkspace = function () {
    return data;
  };

  return data;
}

function _ejectBoundToWorkspace() {
  const data = _interopRequireDefault(require("./exceptions/eject-bound-to-workspace"));

  _ejectBoundToWorkspace = function () {
    return data;
  };

  return data;
}

function _version() {
  const data = _interopRequireDefault(require("../../version"));

  _version = function () {
    return data;
  };

  return data;
}

function _injectNonEjected() {
  const data = _interopRequireDefault(require("./exceptions/inject-non-ejected"));

  _injectNonEjected = function () {
    return data;
  };

  return data;
}

function _configDir() {
  const data = _interopRequireDefault(require("../bit-map/config-dir"));

  _configDir = function () {
    return data;
  };

  return data;
}

function _buildComponent() {
  const data = _interopRequireDefault(require("../component-ops/build-component"));

  _buildComponent = function () {
    return data;
  };

  return data;
}

function _extensionFileNotFound() {
  const data = _interopRequireDefault(require("../../extensions/exceptions/extension-file-not-found"));

  _extensionFileNotFound = function () {
    return data;
  };

  return data;
}

function _dataToPersist() {
  const data = _interopRequireDefault(require("./sources/data-to-persist"));

  _dataToPersist = function () {
    return data;
  };

  return data;
}

function _componentOutOfSync() {
  const data = _interopRequireDefault(require("../exceptions/component-out-of-sync"));

  _componentOutOfSync = function () {
    return data;
  };

  return data;
}

function _componentOverrides() {
  const data = _interopRequireDefault(require("../config/component-overrides"));

  _componentOverrides = function () {
    return data;
  };

  return data;
}

function _envFactory() {
  const data = _interopRequireDefault(require("../../extensions/env-factory"));

  _envFactory = function () {
    return data;
  };

  return data;
}

function _packageJsonFile() {
  const data = _interopRequireDefault(require("./package-json-file"));

  _packageJsonFile = function () {
    return data;
  };

  return data;
}

function _isolator() {
  const data = _interopRequireDefault(require("../../environment/isolator"));

  _isolator = function () {
    return data;
  };

  return data;
}

function _capsule() {
  const data = _interopRequireDefault(require("../../../components/core/capsule"));

  _capsule = function () {
    return data;
  };

  return data;
}

function _manipulateDir() {
  const data = require("../component-ops/manipulate-dir");

  _manipulateDir = function () {
    return data;
  };

  return data;
}

class Component {
  // needed for generate links
  // needed when a user adds a package.json file to the component root
  get id() {
    return new (_bitId().default)({
      scope: this.scope,
      name: this.name,
      version: this.version
    });
  }

  get docs() {
    if (!this._docs) {
      this._docs = _ramda().default.flatten(this.files.map(file => file.test ? [] : (0, _parser().default)(file.contents.toString(), file.relative)));
    }

    return this._docs;
  }

  get driver() {
    if (!this._driver) {
      this._driver = _driver().Driver.load(this.lang);
    }

    return this._driver;
  }

  constructor({
    name,
    version,
    scope,
    files,
    lang,
    bindingPrefix,
    mainFile,
    compiler,
    tester,
    bitJson,
    dependencies,
    devDependencies,
    compilerDependencies,
    testerDependencies,
    flattenedDependencies,
    flattenedDevDependencies,
    flattenedCompilerDependencies,
    flattenedTesterDependencies,
    packageDependencies,
    devPackageDependencies,
    peerPackageDependencies,
    compilerPackageDependencies,
    testerPackageDependencies,
    overrides,
    packageJsonFile,
    packageJsonChangedProps,
    docs,
    dists,
    mainDistFile,
    specsResults,
    license,
    log,
    deprecated,
    origin,
    customResolvedPaths
  }) {
    (0, _defineProperty2().default)(this, "manuallyRemovedDependencies", {});
    (0, _defineProperty2().default)(this, "manuallyAddedDependencies", {});
    (0, _defineProperty2().default)(this, "dependenciesSavedAsComponents", true);
    (0, _defineProperty2().default)(this, "loadedFromFileSystem", false);
    this.name = name;
    this.version = version;
    this.scope = scope;
    this.files = files;
    this.lang = lang || _constants().DEFAULT_LANGUAGE;
    this.bindingPrefix = bindingPrefix || _constants().DEFAULT_BINDINGS_PREFIX;
    this.mainFile = _path().default.normalize(mainFile);
    this.compiler = compiler;
    this.tester = tester;
    this.bitJson = bitJson;
    this.setDependencies(dependencies);
    this.setDevDependencies(devDependencies);
    this.setCompilerDependencies(compilerDependencies);
    this.setTesterDependencies(testerDependencies);
    this.flattenedDependencies = flattenedDependencies || new (_bitIds().default)();
    this.flattenedDevDependencies = flattenedDevDependencies || new (_bitIds().default)();
    this.flattenedCompilerDependencies = flattenedCompilerDependencies || new (_bitIds().default)();
    this.flattenedTesterDependencies = flattenedTesterDependencies || new (_bitIds().default)();
    this.packageDependencies = packageDependencies || {};
    this.devPackageDependencies = devPackageDependencies || {};
    this.peerPackageDependencies = peerPackageDependencies || {};
    this.compilerPackageDependencies = compilerPackageDependencies || {};
    this.testerPackageDependencies = testerPackageDependencies || {};
    this.overrides = overrides;
    this.packageJsonFile = packageJsonFile;
    this.packageJsonChangedProps = packageJsonChangedProps;
    this._docs = docs;
    this.setDists(dists, mainDistFile ? _path().default.normalize(mainDistFile) : null);
    this.specsResults = specsResults;
    this.license = license;
    this.log = log;
    this.deprecated = deprecated || false;
    this.origin = origin;
    this.customResolvedPaths = customResolvedPaths || [];
    this.validateComponent();
  }

  validateComponent() {
    const nonEmptyFields = ['name', 'mainFile'];
    nonEmptyFields.forEach(field => {
      if (!this[field]) {
        throw new (_generalError().default)(`failed loading a component ${this.id}, the field "${field}" can't be empty`);
      }
    });
  }
  /**
   * Warning: this method does not return a deep copy for all objects in this class, only for the
   * ones you see in the implementation below.
   * Implement deep copy of other properties if needed
   */


  clone() {
    // $FlowFixMe
    const newInstance = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
    newInstance.setDependencies(this.dependencies.getClone());
    newInstance.setDevDependencies(this.devDependencies.getClone());
    newInstance.setCompilerDependencies(this.compilerDependencies.getClone());
    newInstance.setTesterDependencies(this.testerDependencies.getClone());
    newInstance.overrides = this.overrides.clone();
    newInstance.files = this.files.map(file => file.clone());
    newInstance.dists = this.dists.clone();
    return newInstance;
  }

  getTmpFolder(workspacePrefix = '') {
    let folder = _path().default.join(workspacePrefix, _constants().BIT_WORKSPACE_TMP_DIRNAME, this.id.name);

    if (this.componentMap) {
      const componentDir = this.componentMap.getComponentDir();

      if (componentDir) {
        folder = _path().default.join(workspacePrefix, componentDir, _constants().BIT_WORKSPACE_TMP_DIRNAME);
      }
    } // Isolated components (for ci-update for example)


    if (this.isolatedEnvironment && this.writtenPath) {
      // Do not join the workspacePrefix since the written path is already a full path
      folder = _path().default.join(this.writtenPath, _constants().BIT_WORKSPACE_TMP_DIRNAME);
    }

    return folder;
  }

  setDependencies(dependencies) {
    this.dependencies = new (_dependencies().Dependencies)(dependencies);
  }

  setDevDependencies(devDependencies) {
    this.devDependencies = new (_dependencies().Dependencies)(devDependencies);
  }

  setCompilerDependencies(compilerDependencies) {
    this.compilerDependencies = new (_dependencies().Dependencies)(compilerDependencies);
  }

  setTesterDependencies(testerDependencies) {
    this.testerDependencies = new (_dependencies().Dependencies)(testerDependencies);
  }

  setDists(dists, mainDistFile) {
    this.dists = new (_dists().default)(dists, mainDistFile);
  }

  getFileExtension() {
    switch (this.lang) {
      case _constants().DEFAULT_LANGUAGE:
      default:
        return 'js';
    }
  }

  getDetachedCompiler(consumer) {
    var _this = this;

    return (0, _bluebird().coroutine)(function* () {
      return _this._isEnvDetach(consumer, _constants().COMPILER_ENV_TYPE);
    })();
  }

  getDetachedTester(consumer) {
    var _this2 = this;

    return (0, _bluebird().coroutine)(function* () {
      return _this2._isEnvDetach(consumer, _constants().TESTER_ENV_TYPE);
    })();
  }

  _isEnvDetach(consumer, envType) {
    var _this3 = this;

    return (0, _bluebird().coroutine)(function* () {
      if (_this3.origin !== _constants().COMPONENT_ORIGINS.AUTHORED || !consumer) return true;
      const context = {
        workspaceDir: consumer.getPath()
      };
      const fromConsumer = yield consumer.getEnv(envType, context);
      const fromComponent = _this3[envType] ? _this3[envType].toModelObject() : null;
      return _envExtension().default.areEnvsDifferent(fromConsumer ? fromConsumer.toModelObject() : null, fromComponent);
    })();
  }

  _getHomepage() {
    // TODO: Validate somehow that this scope is really on bitsrc (maybe check if it contains . ?)
    const homepage = this.scope ? `https://${_constants().BASE_WEB_DOMAIN}/${this.scope.replace('.', '/')}/${this.name}` : undefined;
    return homepage;
  }

  writeConfig(consumer, configDir) {
    var _this4 = this;

    return (0, _bluebird().coroutine)(function* () {
      const ejectConfData = yield _this4.getConfigToWrite(consumer, consumer.bitMap, configDir);
      if (consumer) ejectConfData.dataToPersist.addBasePath(consumer.getPath());
      yield ejectConfData.dataToPersist.persistAllToFS();
      return ejectConfData;
    })();
  }

  getConfigToWrite(consumer, bitMap, configDir) {
    var _this5 = this;

    return (0, _bluebird().coroutine)(function* () {
      _this5.componentMap = _this5.componentMap || bitMap.getComponentIfExist(_this5.id);
      const componentMap = _this5.componentMap;

      if (!componentMap) {
        throw new (_generalError().default)('could not find component in the .bitmap file');
      }

      const configDirInstance = typeof configDir === 'string' ? new (_configDir().default)(configDir) : configDir.clone();

      if (configDirInstance.isWorkspaceRoot) {
        throw new (_ejectToWorkspace().default)();
      } // Nothing is detached.. no reason to eject


      if (componentMap.origin === _constants().COMPONENT_ORIGINS.AUTHORED) {
        const isCompilerDetached = yield _this5.getDetachedCompiler(consumer);
        const isTesterDetached = yield _this5.getDetachedTester(consumer);
        if (!isCompilerDetached && !isTesterDetached) throw new (_ejectBoundToWorkspace().default)();
      }

      const res = yield (0, _ejectConf().getEjectConfDataToPersist)(_this5, consumer, consumer.bitMap, configDirInstance);

      if (_this5.componentMap) {
        _this5.componentMap.setConfigDir(res.ejectedPath);
      }

      return res;
    })();
  }

  injectConfig(consumerPath, bitMap, force = false) {
    var _this6 = this;

    return (0, _bluebird().coroutine)(function* () {
      _this6.componentMap = _this6.componentMap || bitMap.getComponentIfExist(_this6.id);
      const componentMap = _this6.componentMap;

      if (!componentMap) {
        throw new (_generalError().default)('could not find component in the .bitmap file');
      }

      const configDir = componentMap.configDir;

      if (!configDir) {
        throw new (_injectNonEjected().default)();
      }

      const res = yield (0, _injectConf().default)(_this6, consumerPath, bitMap, configDir, force);

      if (_this6.componentMap) {
        _this6.componentMap.setConfigDir();
      }

      return res;
    })();
  }

  flattenedDependencies() {
    return _bitIds().default.fromObject(this.flattenedDependencies);
  }

  flattenedDevDependencies() {
    return _bitIds().default.fromObject(this.flattenedDevDependencies);
  }

  flattenedCompilerDependencies() {
    return _bitIds().default.fromObject(this.flattenedCompilerDependencies);
  }

  flattenedTesterDependencies() {
    return _bitIds().default.fromObject(this.flattenedTesterDependencies);
  }

  getAllDependencies() {
    return [...this.dependencies.dependencies, ...this.devDependencies.dependencies, ...this.compilerDependencies.dependencies, ...this.testerDependencies.dependencies];
  }

  getAllDependenciesCloned() {
    const dependencies = [...this.dependencies.getClone(), ...this.devDependencies.getClone(), ...this.compilerDependencies.getClone(), ...this.testerDependencies.getClone()];
    return new (_dependencies().Dependencies)(dependencies);
  }

  getAllNonEnvsDependencies() {
    return [...this.dependencies.dependencies, ...this.devDependencies.dependencies];
  }

  getAllDependenciesIds() {
    const allDependencies = this.getAllDependencies();
    return _bitIds().default.fromArray(allDependencies.map(dependency => dependency.id));
  }

  hasDependencies() {
    const allDependencies = this.getAllDependencies();
    return Boolean(allDependencies.length);
  }

  getAllFlattenedDependencies() {
    return [...this.flattenedDependencies, ...this.flattenedDevDependencies, ...this.flattenedCompilerDependencies, ...this.flattenedTesterDependencies];
  }

  getAllNonEnvsFlattenedDependencies() {
    return [...this.flattenedDependencies, ...this.flattenedDevDependencies];
  }
  /**
   * Before writing the files into the file-system, remove the path-prefix that is shared among the main component files
   * and its dependencies. It helps to avoid large file-system paths.
   *
   * This is relevant for IMPORTED and NESTED components only as the author may have long paths
   * that are not needed for whoever imports it. AUTHORED components are written as is.
   *
   * @see sources.consumerComponentToVersion() for the opposite action. meaning, adding back the sharedDir.
   */


  stripOriginallySharedDir(manipulateDirData) {
    if (this._wasOriginallySharedDirStripped) return;
    this.setOriginallySharedDir(manipulateDirData);
    const originallySharedDir = this.originallySharedDir;

    if (originallySharedDir) {
      _logger().default.debug(`stripping originallySharedDir "${originallySharedDir}" from ${this.id}`);
    }

    this.files.forEach(file => {
      const newRelative = (0, _manipulateDir().stripSharedDirFromPath)(file.relative, originallySharedDir);
      file.updatePaths({
        newBase: file.base,
        newRelative
      });
    });
    this.dists.stripOriginallySharedDir(originallySharedDir);
    this.mainFile = (0, _manipulateDir().stripSharedDirFromPath)(this.mainFile, originallySharedDir);
    this.dependencies.stripOriginallySharedDir(manipulateDirData, originallySharedDir);
    this.devDependencies.stripOriginallySharedDir(manipulateDirData, originallySharedDir);
    this.compilerDependencies.stripOriginallySharedDir(manipulateDirData, originallySharedDir);
    this.testerDependencies.stripOriginallySharedDir(manipulateDirData, originallySharedDir);
    this.customResolvedPaths.forEach(customPath => {
      customPath.destinationPath = (0, _utils().pathNormalizeToLinux)((0, _manipulateDir().stripSharedDirFromPath)(_path().default.normalize(customPath.destinationPath), originallySharedDir));
    });
    this.overrides.stripOriginallySharedDir(originallySharedDir);
    this._wasOriginallySharedDirStripped = true;
  }

  addWrapperDir(manipulateDirData) {
    const manipulateDirItem = manipulateDirData.find(m => m.id.isEqual(this.id));
    if (!manipulateDirItem || !manipulateDirItem.wrapDir) return;
    this.wrapDir = manipulateDirItem.wrapDir;

    const pathWithWrapDir = pathStr => {
      return _path().default.join(this.wrapDir, pathStr);
    };

    this.files.forEach(file => {
      const newRelative = pathWithWrapDir(file.relative);
      file.updatePaths({
        newBase: file.base,
        newRelative
      });
    }); // @todo: for dist also.

    this.mainFile = pathWithWrapDir(this.mainFile);
    const allDependencies = new (_dependencies().Dependencies)(this.getAllDependencies());
    allDependencies.addWrapDir(manipulateDirData, this.wrapDir);
    this.customResolvedPaths.forEach(customPath => {
      customPath.destinationPath = (0, _utils().pathNormalizeToLinux)(pathWithWrapDir(_path().default.normalize(customPath.destinationPath)));
    });
  }

  build({
    scope,
    save,
    consumer,
    noCache,
    verbose,
    dontPrintEnvMsg,
    directory,
    keep
  }) {
    var _this7 = this;

    return (0, _bluebird().coroutine)(function* () {
      return (0, _buildComponent().default)({
        component: _this7,
        scope,
        save,
        consumer,
        noCache,
        directory,
        verbose,
        dontPrintEnvMsg,
        keep
      });
    })();
  }

  runSpecs({
    scope,
    rejectOnFailure = false,
    // reject when some (or all) of the tests were failed. relevant when running tests during 'bit tag'
    consumer,
    save,
    verbose,
    dontPrintEnvMsg,
    isolated,
    directory,
    keep
  }) {
    var _this8 = this;

    return (0, _bluebird().coroutine)(function* () {
      const testFiles = _this8.files.filter(file => file.test);

      const consumerPath = consumer ? consumer.getPath() : '';
      if (!_this8.tester || !testFiles || _ramda().default.isEmpty(testFiles)) return null;

      _logger().default.debug('tester found, start running tests');

      _analytics().Analytics.addBreadCrumb('runSpecs', 'tester found, start running tests');

      const tester = _this8.tester;

      if (!tester.loaded) {
        const componentDir = _this8.componentMap ? _this8.componentMap.getComponentDir() : undefined;
        const context = {
          dependentId: _this8.id,
          workspaceDir: consumerPath,
          componentDir
        };

        _analytics().Analytics.addBreadCrumb('runSpecs', 'installing missing tester');

        yield tester.install(scope, {
          verbose,
          dontPrintEnvMsg
        }, context);

        _logger().default.debug('Environment components are installed');
      }

      const testerFilePath = tester.filePath;

      const run =
      /*#__PURE__*/
      function () {
        var _ref = (0, _bluebird().coroutine)(function* (component, cwd) {
          if (cwd) {
            _logger().default.debug(`changing process cwd to ${cwd}`);

            _analytics().Analytics.addBreadCrumb('runSpecs.run', 'changing process cwd');

            process.chdir(cwd);
          }

          _loader().default.start(_loaderMessages().BEFORE_RUNNING_SPECS);

          const testFilesList = !component.dists.isEmpty() ? component.dists.get().filter(dist => dist.test) : component.files.filter(file => file.test);
          let specsResults;
          let tmpFolderFullPath;
          let contextPaths = {};

          if (_this8.tester && _this8.tester.context) {
            contextPaths = _this8.tester.context;
          } else if (consumer && consumer.bitMap) {
            contextPaths = {
              workspaceDir: consumer.bitMap.projectRoot
            };
          }

          if (!contextPaths.componentDir && component.writtenPath) {
            contextPaths.componentDir = component.writtenPath;
          }

          try {
            if (tester && tester.action) {
              _logger().default.debug('running tests using new format');

              _analytics().Analytics.addBreadCrumb('runSpecs.run', 'running tests using new format');

              const isTesterDetached = yield component.getDetachedTester(consumer);
              const shouldWriteConfig = tester.writeConfigFilesOnAction && isTesterDetached;

              if (shouldWriteConfig) {
                tmpFolderFullPath = component.getTmpFolder(consumerPath);

                if (verbose) {
                  console.log(`\nwriting config files to ${tmpFolderFullPath}`); // eslint-disable-line no-console
                }

                yield (0, _ejectConf().writeEnvFiles)({
                  configDir: component.getTmpFolder(),
                  env: tester,
                  consumer,
                  component,
                  deleteOldFiles: false,
                  verbose: !!verbose
                });
              }

              const context = {
                componentObject: component.toObject()
              };
              contextPaths && Object.assign(context, contextPaths);
              const actionParams = {
                testFiles: testFilesList,
                rawConfig: tester.rawConfig,
                dynamicConfig: tester.dynamicConfig,
                configFiles: tester.files,
                api: tester.api,
                context
              };
              specsResults = yield tester.action(actionParams);

              if (tmpFolderFullPath) {
                if (verbose) {
                  console.log(`deleting tmp directory ${tmpFolderFullPath}`); // eslint-disable-line no-console
                }

                _logger().default.info(`consumer-component.runSpecs, deleting ${tmpFolderFullPath}`);

                yield _fsExtra().default.remove(tmpFolderFullPath);
              }
            } else {
              _logger().default.debug('running tests using old format');

              _analytics().Analytics.addBreadCrumb('runSpecs.run', 'running tests using old format');

              const oneFileSpecResult =
              /*#__PURE__*/
              function () {
                var _ref2 = (0, _bluebird().coroutine)(function* (testFile) {
                  const testFilePath = testFile.path;

                  try {
                    const isolateFunc =
                    /*#__PURE__*/
                    function () {
                      var _ref3 = (0, _bluebird().coroutine)(function* (destDir) {
                        const isolator = yield _isolator().default.getInstance('fs', scope, consumer, destDir);
                        const componentWithDependencies = yield isolator.isolate(component.id, {});
                        const testFileWithoutSharedDir = (0, _manipulateDir().stripSharedDirFromPath)(testFilePath, componentWithDependencies.component.originallySharedDir);
                        return {
                          capsule: isolator.capsule,
                          componentWithDependencies,
                          testFile: testFileWithoutSharedDir
                        };
                      });

                      return function isolateFunc(_x4) {
                        return _ref3.apply(this, arguments);
                      };
                    }();

                    const context = {
                      componentDir: cwd,
                      isolate: isolateFunc
                    };
                    const results = yield tester.oldAction(testFilePath, context);
                    results.specPath = testFile.relative;
                    return results;
                  } catch (err) {
                    const failures = [{
                      title: err.message,
                      err
                    }];
                    const results = {
                      specPath: testFile.relative,
                      pass: false,
                      tests: [],
                      failures
                    };
                    return results;
                  }
                });

                return function oneFileSpecResult(_x3) {
                  return _ref2.apply(this, arguments);
                };
              }();

              const specsResultsP = testFilesList.map(oneFileSpecResult);
              specsResults = yield Promise.all(specsResultsP);
            }
          } catch (e) {
            if (tmpFolderFullPath) {
              _logger().default.info(`consumer-component.runSpecs, deleting ${tmpFolderFullPath}`);

              _fsExtra().default.removeSync(tmpFolderFullPath);
            }

            const errors = e.errors || [e];
            const err = new (_externalTestErrors().default)(component.id.toString(), errors);
            throw err;
          }

          _this8.specsResults = specsResults.map(specRes => _specsResults().default.createFromRaw(specRes));

          if (rejectOnFailure && !_this8.specsResults.every(element => element.pass)) {
            // some or all the tests were failed.
            _loader().default.stop();

            if (verbose) {
              return Promise.reject(new (_componentSpecsFailed().default)(_this8.id.toString(), _this8.specsResults));
            }

            return Promise.reject(new (_componentSpecsFailed().default)());
          }

          if (save) {
            yield scope.sources.modifySpecsResults({
              source: _this8,
              specsResults: _this8.specsResults
            });
          }

          return _this8.specsResults;
        });

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

      if (!isolated && consumer) {
        // we got here from either bit-tag or bit-test. either way we executed already the build process
        return run(_this8, consumer.getPath());
      }

      const isolatedEnvironment = new (_environment().default)(scope, directory);

      try {
        yield isolatedEnvironment.create();
        const isolateOpts = {
          verbose,
          dist: true,
          installPackages: true,
          installPeerDependencies: true,
          noPackageJson: false
        };

        const localTesterPath = _path().default.join(isolatedEnvironment.getPath(), 'tester');

        const componentWithDependencies = yield isolatedEnvironment.isolateComponent(_this8.id, isolateOpts);
        (0, _createSymlinkOrCopy().default)(testerFilePath, localTesterPath);
        const component = componentWithDependencies.component;
        component.isolatedEnvironment = isolatedEnvironment;

        _logger().default.debug(`the component ${_this8.id.toString()} has been imported successfully into an isolated environment`);

        yield component.build({
          scope,
          verbose
        });

        if (!component.dists.isEmpty()) {
          const specDistWrite = component.dists.get().map(file => file.write());
          yield Promise.all(specDistWrite);
        }

        const results = yield run(component);
        if (!keep) yield isolatedEnvironment.destroy();
        return results;
      } catch (e) {
        if (!keep) yield isolatedEnvironment.destroy();
        return Promise.reject(e);
      }
    })();
  }

  isolate(scope, opts) {
    var _this9 = this;

    return (0, _bluebird().coroutine)(function* () {
      const isolatedEnvironment = new (_environment().default)(scope, opts.writeToPath);

      try {
        yield isolatedEnvironment.create();
        yield isolatedEnvironment.isolateComponent(_this9.id, opts);
        return isolatedEnvironment.path;
      } catch (err) {
        yield isolatedEnvironment.destroy();
        throw new (_generalError().default)(err);
      }
    })();
  }

  toObject() {
    return {
      name: this.name,
      version: this.version,
      mainFile: this.mainFile,
      scope: this.scope,
      lang: this.lang,
      bindingPrefix: this.bindingPrefix,
      compiler: this.compiler ? this.compiler.toObject() : null,
      tester: this.tester ? this.tester.toObject() : null,
      dependencies: this.dependencies.serialize(),
      devDependencies: this.devDependencies.serialize(),
      compilerDependencies: this.compilerDependencies.serialize(),
      testerDependencies: this.testerDependencies.serialize(),
      packageDependencies: this.packageDependencies,
      devPackageDependencies: this.devPackageDependencies,
      peerPackageDependencies: this.peerPackageDependencies,
      compilerPackageDependencies: this.compilerPackageDependencies,
      testerPackageDependencies: this.testerPackageDependencies,
      manuallyRemovedDependencies: this.manuallyRemovedDependencies,
      manuallyAddedDependencies: this.manuallyAddedDependencies,
      overrides: this.overrides.componentOverridesData,
      files: this.files,
      docs: this.docs,
      dists: this.dists,
      specsResults: this.specsResults ? this.specsResults.map(res => res.serialize()) : null,
      license: this.license ? this.license.serialize() : null,
      log: this.log,
      deprecated: this.deprecated
    };
  }

  toString() {
    return JSON.stringify(this.toObject());
  }

  copyFilesIntoDists() {
    const dists = this.files.map(file => new (_sources().Dist)({
      base: file.base,
      path: file.path,
      contents: file.contents
    }));
    this.setDists(dists);
  }

  setOriginallySharedDir(manipulateDirData) {
    const manipulateDirItem = manipulateDirData.find(m => m.id.isEqual(this.id));

    if (manipulateDirItem) {
      this.originallySharedDir = manipulateDirItem.originallySharedDir;
    }
  }

  static isComponentInvalidByErrorType(err) {
    const invalidComponentErrors = [_mainFileRemoved().default, _missingFilesFromComponent().default, _componentNotFoundInPath().default, _componentOutOfSync().default, _extensionFileNotFound().default];
    return invalidComponentErrors.some(errorType => err instanceof errorType);
  }

  toComponentWithDependencies(consumer) {
    var _this10 = this;

    return (0, _bluebird().coroutine)(function* () {
      const getFlatten = field => {
        // when loaded from filesystem, it doesn't have the flatten, fetch them from model.
        return _this10.loadedFromFileSystem ? _this10.componentFromModel[field] : _this10[field];
      };

      const getDependenciesComponents = ids => {
        return Promise.all(ids.map(dependencyId => {
          if (consumer.bitMap.isExistWithSameVersion(dependencyId)) {
            return consumer.loadComponent(dependencyId);
          } // when dependencies are imported as npm packages, they are not in bit.map


          _this10.dependenciesSavedAsComponents = false;
          return consumer.loadComponentFromModel(dependencyId);
        }));
      };

      const dependencies = yield getDependenciesComponents(getFlatten('flattenedDependencies'));
      const devDependencies = yield getDependenciesComponents(getFlatten('flattenedDevDependencies'));
      const compilerDependencies = yield getDependenciesComponents(getFlatten('flattenedCompilerDependencies'));
      const testerDependencies = yield getDependenciesComponents(getFlatten('flattenedTesterDependencies'));
      return new (_componentDependencies().default)({
        component: _this10,
        dependencies,
        devDependencies,
        compilerDependencies,
        testerDependencies
      });
    })();
  }

  copyDependenciesFromModel(ids) {
    const componentFromModel = this.componentFromModel;
    if (!componentFromModel) throw new Error('copyDependenciesFromModel: component is missing from the model');
    ids.forEach(id => {
      const addDependency = (modelDependencies, dependencies) => {
        const dependency = modelDependencies.getByIdStr(id);
        if (dependency) dependencies.add(dependency);
        return Boolean(dependency);
      };

      const addedDep = addDependency(componentFromModel.dependencies, this.dependencies);
      if (addedDep) return;
      const addedDevDep = addDependency(componentFromModel.devDependencies, this.devDependencies);
      if (addedDevDep) return;
      const addedCompilerDep = addDependency(componentFromModel.compilerDependencies, this.compilerDependencies);
      if (addedCompilerDep) return;
      const addedTesterDep = addDependency(componentFromModel.testerDependencies, this.testerDependencies);
      if (addedTesterDep) return;
      throw new Error(`copyDependenciesFromModel unable to find dependency ${id} in the model`);
    });
  }

  static fromObject(object) {
    return (0, _bluebird().coroutine)(function* () {
      const {
        name,
        box,
        version,
        scope,
        lang,
        bindingPrefix,
        compiler,
        tester,
        dependencies,
        devDependencies,
        compilerDependencies,
        testerDependencies,
        packageDependencies,
        devPackageDependencies,
        peerPackageDependencies,
        compilerPackageDependencies,
        testerPackageDependencies,
        docs,
        mainFile,
        dists,
        files,
        specsResults,
        license,
        overrides,
        deprecated
      } = object;
      const compilerProps = compiler ? yield _compilerExtension().default.loadFromSerializedModelObject(compiler) : null; // $FlowFixMe

      const compilerInstance = compilerProps ? yield (0, _envFactory().default)(_constants().COMPILER_ENV_TYPE, compilerProps) : null;
      const testerProps = tester ? yield _testerExtension().default.loadFromSerializedModelObject(tester) : null; // $FlowFixMe

      const testerInstance = testerProps ? yield (0, _envFactory().default)(_constants().TESTER_ENV_TYPE, testerProps) : null;
      return new Component({
        name: box ? `${box}/${name}` : name,
        version,
        scope,
        lang,
        bindingPrefix,
        compiler: compilerInstance,
        tester: testerInstance,
        dependencies,
        devDependencies,
        compilerDependencies,
        testerDependencies,
        packageDependencies,
        devPackageDependencies,
        peerPackageDependencies,
        compilerPackageDependencies,
        testerPackageDependencies,
        mainFile,
        files,
        docs,
        dists,
        specsResults: specsResults ? _specsResults().default.deserialize(specsResults) : null,
        license: license ? _sources().License.deserialize(license) : null,
        overrides: new (_componentOverrides().default)(overrides),
        deprecated: deprecated || false
      });
    })();
  }

  static fromString(str) {
    var _this11 = this;

    return (0, _bluebird().coroutine)(function* () {
      const object = JSON.parse(str);
      object.files = _sources().SourceFile.loadFromParsedStringArray(object.files); // added if statement to support new and old version of remote ls
      // old version of bit returns from server array of dists  and new version return object

      if (object.dists && Array.isArray(object.dists)) {
        object.dists = _sources().Dist.loadFromParsedStringArray(object.dists);
      } else if (object.dists && object.dists.dists) {
        object.dists = _sources().Dist.loadFromParsedStringArray(object.dists.dists);
      }

      return _this11.fromObject(object);
    })();
  }

  static loadFromFileSystem({
    bitDir,
    componentMap,
    id,
    consumer,
    componentFromModel
  }) {
    return (0, _bluebird().coroutine)(function* () {
      const consumerPath = consumer.getPath();
      const workspaceConfig = consumer.config;
      const bitMap = consumer.bitMap;
      const deprecated = componentFromModel ? componentFromModel.deprecated : false;
      const componentDir = componentMap.getComponentDir();
      let dists = componentFromModel ? componentFromModel.dists.get() : undefined;
      const mainDistFile = componentFromModel ? componentFromModel.dists.getMainDistFile() : undefined;

      const getLoadedFiles =
      /*#__PURE__*/
      function () {
        var _ref4 = (0, _bluebird().coroutine)(function* () {
          const sourceFiles = [];
          yield componentMap.trackDirectoryChanges(consumer, id);
          const filesToDelete = [];
          componentMap.files.forEach(file => {
            const filePath = _path().default.join(bitDir, file.relativePath);

            try {
              const sourceFile = _sources().SourceFile.load(filePath, workspaceConfig.distTarget, bitDir, consumerPath, {
                test: file.test
              });

              sourceFiles.push(sourceFile);
            } catch (err) {
              if (!(err instanceof _fileSourceNotFound().default)) throw err;

              _logger().default.warn(`a file ${filePath} will be deleted from bit.map as it does not exist on the file system`);

              filesToDelete.push(file);
            }
          });

          if (filesToDelete.length) {
            if (!sourceFiles.length) throw new (_missingFilesFromComponent().default)(id.toString());
            filesToDelete.forEach(fileToDelete => {
              if (fileToDelete.relativePath === componentMap.mainFile) {
                throw new (_mainFileRemoved().default)(componentMap.mainFile, id.toString());
              }
            });
            componentMap.removeFiles(filesToDelete);
            bitMap.hasChanged = true;
          }

          return sourceFiles;
        });

        return function getLoadedFiles() {
          return _ref4.apply(this, arguments);
        };
      }();

      if (!_fsExtra().default.existsSync(bitDir)) throw new (_componentNotFoundInPath().default)(bitDir);
      let configDir = componentDir ? _path().default.join(consumerPath, componentDir) : consumerPath;

      if (componentMap.configDir) {
        yield componentMap.deleteConfigDirIfNotExists();
        const resolvedBaseConfigDir = componentMap.getBaseConfigDir();

        if (resolvedBaseConfigDir) {
          configDir = _path().default.join(consumerPath, resolvedBaseConfigDir);
        }
      } // Load the base entry from the root dir in map file in case it was imported using -path
      // Or created using bit create so we don't want all the path but only the relative one
      // Check that bitDir isn't the same as consumer path to make sure we are not loading global stuff into component
      // (like dependencies)


      let componentConfig;

      if (configDir !== consumerPath) {
        // $FlowFixMe unclear error
        componentConfig = yield _config().default.load({
          componentDir: componentMap.rootDir,
          workspaceDir: consumerPath,
          configDir,
          workspaceConfig
        }); // by default, imported components are not written with bit.json file.
        // use the component from the model to get their bit.json values

        if (componentFromModel) {
          componentConfig.mergeWithComponentData(componentFromModel);
        }
      } // for authored componentConfig is normally undefined


      const bitJson = componentConfig || workspaceConfig; // Remove dists if compiler has been deleted

      if (dists && !bitJson.hasCompiler()) {
        dists = undefined;
      }

      const envsContext = {
        componentDir: bitDir,
        workspaceDir: consumerPath
      };

      const isNotNested = componentMap.origin !== _constants().COMPONENT_ORIGINS.NESTED; // overrides from consumer-config is not relevant and should not affect imported


      const overridesFromConsumer = isNotNested ? workspaceConfig.overrides.getOverrideComponentData(id) : null;
      const propsToLoadEnvs = {
        consumerPath,
        envType: _constants().COMPILER_ENV_TYPE,
        scopePath: consumer.scope.getPath(),
        componentOrigin: componentMap.origin,
        componentFromModel,
        overridesFromConsumer,
        workspaceConfig,
        componentConfig,
        context: envsContext
      };

      const compilerP = _envExtension().default.loadFromCorrectSource(propsToLoadEnvs);

      propsToLoadEnvs.envType = _constants().TESTER_ENV_TYPE;

      const testerP = _envExtension().default.loadFromCorrectSource(propsToLoadEnvs);

      const [compiler, tester] = yield Promise.all([compilerP, testerP]); // Load the compilerPackageDependencies/testerPackageDependencies from the actual compiler / tester or from the model
      // if they are not loaded (aka not installed)
      // We load it from model to prevent case when component is modified becasue changes in envsPackageDependencies
      // That occur as a result that we import component but didn't import its envs so we can't
      // calculate the envsPackageDependencies (without install the env, which we don't want)

      const compilerDynamicPackageDependencies = compiler && compiler.loaded ? compiler.dynamicPackageDependencies : {};
      const testerDynamicPackageDependencies = tester && tester.loaded ? tester.dynamicPackageDependencies : {};
      const modelCompilerPackageDependencies = componentFromModel ? componentFromModel.compilerPackageDependencies || {} : {};
      const modelTesterPackageDependencies = componentFromModel ? componentFromModel.testerPackageDependencies || {} : {};
      const compilerPackageDependencies = (0, _objectSpread2().default)({}, modelCompilerPackageDependencies, compilerDynamicPackageDependencies);
      const testerPackageDependencies = (0, _objectSpread2().default)({}, modelTesterPackageDependencies, testerDynamicPackageDependencies);
      const overridesFromModel = componentFromModel ? componentFromModel.overrides.componentOverridesData : null;

      const isAuthor = componentMap.origin === _constants().COMPONENT_ORIGINS.AUTHORED;

      const overrides = _componentOverrides().default.loadFromConsumer(overridesFromConsumer, overridesFromModel, componentConfig, isAuthor);

      const packageJsonFile = componentConfig && componentConfig.packageJsonFile || null;
      const packageJsonChangedProps = componentFromModel ? componentFromModel.packageJsonChangedProps : null;
      return new Component({
        name: id.name,
        scope: id.scope,
        version: id.version,
        lang: bitJson.lang,
        bindingPrefix: bitJson.bindingPrefix || _constants().DEFAULT_BINDINGS_PREFIX,
        compiler,
        tester,
        bitJson: componentConfig,
        mainFile: componentMap.mainFile,
        files: yield getLoadedFiles(),
        loadedFromFileSystem: true,
        componentMap,
        dists,
        mainDistFile: mainDistFile ? _path().default.normalize(mainDistFile) : null,
        compilerPackageDependencies,
        testerPackageDependencies,
        deprecated,
        origin: componentMap.origin,
        overrides,
        packageJsonFile,
        packageJsonChangedProps
      });
    })();
  }

}

exports.default = Component;