'use strict';

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

var _regenerator;

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

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

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 _chalk;

function _load_chalk() {
  return _chalk = _interopRequireDefault(require('chalk'));
}

var _utils;

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

var _bitJson;

function _load_bitJson() {
  return _bitJson = _interopRequireDefault(require('../bit-json'));
}

var _sources;

function _load_sources() {
  return _sources = require('../component/sources');
}

var _consumerBitJson;

function _load_consumerBitJson() {
  return _consumerBitJson = _interopRequireDefault(require('../bit-json/consumer-bit-json'));
}

var _consumer;

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

var _bitId;

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

var _scope;

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

var _bitIds;

function _load_bitIds() {
  return _bitIds = _interopRequireDefault(require('../../bit-id/bit-ids'));
}

var _parser;

function _load_parser() {
  return _parser = _interopRequireDefault(require('../../jsdoc/parser'));
}

var _parser2;

function _load_parser2() {
  return _parser2 = require('../../jsdoc/parser');
}

var _specsRunner;

function _load_specsRunner() {
  return _specsRunner = _interopRequireDefault(require('../../specs-runner'));
}

var _specsResults;

function _load_specsResults() {
  return _specsResults = _interopRequireDefault(require('../specs-results'));
}

var _componentSpecsFailed;

function _load_componentSpecsFailed() {
  return _componentSpecsFailed = _interopRequireDefault(require('../exceptions/component-specs-failed'));
}

var _missingFilesFromComponent;

function _load_missingFilesFromComponent() {
  return _missingFilesFromComponent = _interopRequireDefault(require('./exceptions/missing-files-from-component'));
}

var _componentNotFoundInPath;

function _load_componentNotFoundInPath() {
  return _componentNotFoundInPath = _interopRequireDefault(require('./exceptions/component-not-found-in-path'));
}

var _environment;

function _load_environment() {
  return _environment = _interopRequireDefault(require('../../environment'));
}

var _environment2;

function _load_environment2() {
  return _environment2 = require('../../environment');
}

var _bitMap;

function _load_bitMap() {
  return _bitMap = _interopRequireDefault(require('../bit-map'));
}

var _componentMap;

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

var _logger;

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

var _loader;

function _load_loader() {
  return _loader = _interopRequireDefault(require('../../cli/loader'));
}

var _compilerExtension;

function _load_compilerExtension() {
  return _compilerExtension = _interopRequireDefault(require('../../extensions/compiler-extension'));
}

var _testerExtension;

function _load_testerExtension() {
  return _testerExtension = _interopRequireDefault(require('../../extensions/tester-extension'));
}

var _driver;

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

var _loaderMessages;

function _load_loaderMessages() {
  return _loaderMessages = require('../../cli/loader/loader-messages');
}

var _fileSourceNotFound;

function _load_fileSourceNotFound() {
  return _fileSourceNotFound = _interopRequireDefault(require('./exceptions/file-source-not-found'));
}

var _constants;

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

var _componentDependencies;

function _load_componentDependencies() {
  return _componentDependencies = _interopRequireDefault(require('../../scope/component-dependencies'));
}

var _packageJson;

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

var _dependencies;

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

var _dists;

function _load_dists() {
  return _dists = _interopRequireDefault(require('./sources/dists'));
}

var _chalkBox;

function _load_chalkBox() {
  return _chalkBox = require('../../cli/chalk-box');
}

var _externalTestError;

function _load_externalTestError() {
  return _externalTestError = _interopRequireDefault(require('./exceptions/external-test-error'));
}

var _externalBuildError;

function _load_externalBuildError() {
  return _externalBuildError = _interopRequireDefault(require('./exceptions/external-build-error'));
}

var _invalidCompilerInterface;

function _load_invalidCompilerInterface() {
  return _invalidCompilerInterface = _interopRequireDefault(require('./exceptions/invalid-compiler-interface'));
}

var _generalError;

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

var _abstractBitJson;

function _load_abstractBitJson() {
  return _abstractBitJson = _interopRequireDefault(require('../bit-json/abstract-bit-json'));
}

var _analytics;

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

var _;

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

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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Component = function () {
  _createClass(Component, [{
    key: 'files',
    // whether a component was loaded from the filesystem or converted from the model
    // always populated when the loadedFromFileSystem is true
    // populated when loadedFromFileSystem is true and it exists in the model
    // needed for generate links
    set: function set(val) {
      this._files = val;
    } // whether stripOriginallySharedDir() method had been called, we don't want to strip it twice
    // otherwise they're saved as npm packages
    // needed to reduce a potentially long path that was used by the author
    ,
    get: function get() {
      if (!this._files) return null;
      if (this._files instanceof Array) return this._files;

      if ((_ramda || _load_ramda()).default.is(Object, this._files)) {
        // $FlowFixMe
        this._files = (_sources || _load_sources()).SourceFile.load(this._files);
      }
      // $FlowFixMe
      return this._files;
    }
  }, {
    key: 'id',
    get: function get() {
      return new (_bitId || _load_bitId()).default({
        scope: this.scope,
        box: this.box,
        name: this.name,
        version: this.version
      });
    }
  }, {
    key: 'docs',
    get: function get() {
      if (!this._docs) {
        this._docs = this.files ? (_ramda || _load_ramda()).default.flatten(this.files.map(function (file) {
          return (0, (_parser || _load_parser()).default)(file.contents.toString(), file.relative);
        })) : [];
      }
      return this._docs;
    }
  }, {
    key: 'driver',
    get: function get() {
      if (!this._driver) {
        this._driver = (_driver || _load_driver()).Driver.load(this.lang);
      }
      return this._driver;
    }
  }]);

  function Component(_ref) {
    var name = _ref.name,
        box = _ref.box,
        version = _ref.version,
        scope = _ref.scope,
        lang = _ref.lang,
        bindingPrefix = _ref.bindingPrefix,
        mainFile = _ref.mainFile,
        compiler = _ref.compiler,
        tester = _ref.tester,
        bitJson = _ref.bitJson,
        dependencies = _ref.dependencies,
        devDependencies = _ref.devDependencies,
        flattenedDependencies = _ref.flattenedDependencies,
        flattenedDevDependencies = _ref.flattenedDevDependencies,
        packageDependencies = _ref.packageDependencies,
        devPackageDependencies = _ref.devPackageDependencies,
        peerPackageDependencies = _ref.peerPackageDependencies,
        envsPackageDependencies = _ref.envsPackageDependencies,
        files = _ref.files,
        docs = _ref.docs,
        dists = _ref.dists,
        specsResults = _ref.specsResults,
        license = _ref.license,
        log = _ref.log,
        deprecated = _ref.deprecated,
        customResolvedPaths = _ref.customResolvedPaths;

    _classCallCheck(this, Component);

    this.dependenciesSavedAsComponents = true;
    this.loadedFromFileSystem = false;

    this.name = name;
    this.box = box || (_constants || _load_constants()).DEFAULT_BOX_NAME;
    this.version = version;
    this.scope = scope;
    this.lang = lang || (_constants || _load_constants()).DEFAULT_LANGUAGE;
    this.bindingPrefix = bindingPrefix || (_constants || _load_constants()).DEFAULT_BINDINGS_PREFIX;
    this.mainFile = (_path || _load_path()).default.normalize(mainFile);
    this.compiler = compiler;
    this.tester = tester;
    this.bitJson = bitJson;
    this.setDependencies(dependencies);
    this.setDevDependencies(devDependencies);
    this.flattenedDependencies = flattenedDependencies || new (_bitIds || _load_bitIds()).default();
    this.flattenedDevDependencies = flattenedDevDependencies || new (_bitIds || _load_bitIds()).default();
    this.packageDependencies = packageDependencies || {};
    this.devPackageDependencies = devPackageDependencies || {};
    this.peerPackageDependencies = peerPackageDependencies || {};
    this.envsPackageDependencies = envsPackageDependencies || {};
    this._files = files;
    this._docs = docs;
    this.setDists(dists);
    this.specsResults = specsResults;
    this.license = license;
    this.log = log;
    this.deprecated = deprecated || false;
    this.customResolvedPaths = customResolvedPaths || [];
    this.validateComponent();
  }

  _createClass(Component, [{
    key: 'validateComponent',
    value: function validateComponent() {
      var _this = this;

      var nonEmptyFields = ['name', 'box', 'mainFile'];
      nonEmptyFields.forEach(function (field) {
        if (!_this[field]) {
          throw new (_generalError || _load_generalError()).default(`failed loading a component ${_this.id}, the field "${field}" can't be empty`);
        }
      });
    }
  }, {
    key: 'setDependencies',
    value: function setDependencies(dependencies) {
      this.dependencies = new (_dependencies || _load_dependencies()).Dependencies(dependencies);
    }
  }, {
    key: 'setDevDependencies',
    value: function setDevDependencies(devDependencies) {
      this.devDependencies = new (_dependencies || _load_dependencies()).Dependencies(devDependencies);
    }
  }, {
    key: 'setDists',
    value: function setDists(dists) {
      this.dists = new (_dists || _load_dists()).default(dists);
    }
  }, {
    key: 'getFileExtension',
    value: function getFileExtension() {
      switch (this.lang) {
        case (_constants || _load_constants()).DEFAULT_LANGUAGE:
        default:
          return 'js';
      }
    }
  }, {
    key: '_getHomepage',
    value: function _getHomepage() {
      // TODO: Validate somehow that this scope is really on bitsrc (maybe check if it contains . ?)
      var homepage = this.scope ? `https://bitsrc.io/${this.scope.replace('.', '/')}/${this.box}/${this.name}` : undefined;
      return homepage;
    }
  }, {
    key: 'writeConfig',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(bitDir, ejectedEnvsDirectory) {
        var override = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

        var ejectedCompilerDirectoryP, ejectedTesterDirectoryP, _ref3, _ref4, ejectedCompilerDirectory, ejectedTesterDirectory;

        return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                if (!this.compiler) {
                  _context.next = 6;
                  break;
                }

                _context.next = 3;
                return this.compiler.writeFilesToFs({ bitDir, ejectedEnvsDirectory });

              case 3:
                _context.t0 = _context.sent;
                _context.next = 7;
                break;

              case 6:
                _context.t0 = '';

              case 7:
                ejectedCompilerDirectoryP = _context.t0;

                if (!this.tester) {
                  _context.next = 14;
                  break;
                }

                _context.next = 11;
                return this.tester.writeFilesToFs({ bitDir, ejectedEnvsDirectory });

              case 11:
                _context.t1 = _context.sent;
                _context.next = 15;
                break;

              case 14:
                _context.t1 = '';

              case 15:
                ejectedTesterDirectoryP = _context.t1;
                _context.next = 18;
                return Promise.all([ejectedCompilerDirectoryP, ejectedTesterDirectoryP]);

              case 18:
                _ref3 = _context.sent;
                _ref4 = _slicedToArray(_ref3, 2);
                ejectedCompilerDirectory = _ref4[0];
                ejectedTesterDirectory = _ref4[1];
                return _context.abrupt('return', this.writeBitJson(bitDir, ejectedCompilerDirectory, ejectedTesterDirectory, override));

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

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

      return writeConfig;
    }()
  }, {
    key: 'writeBitJson',
    value: function writeBitJson(bitDir, ejectedCompilerDirectory, ejectedTesterDirectory) {
      var override = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;

      return new (_bitJson || _load_bitJson()).default({
        version: this.version,
        scope: this.scope,
        lang: this.lang,
        bindingPrefix: this.bindingPrefix,
        compiler: this.compiler ? this.compiler.toBitJsonObject(ejectedCompilerDirectory) : {},
        tester: this.tester ? this.tester.toBitJsonObject(ejectedTesterDirectory) : {},
        dependencies: this.dependencies.asWritableObject(),
        devDependencies: this.devDependencies.asWritableObject(),
        packageDependencies: this.packageDependencies,
        devPackageDependencies: this.devPackageDependencies,
        peerPackageDependencies: this.peerPackageDependencies
      }).write({ bitDir, override });
    }
  }, {
    key: 'getPackageNameAndPath',
    value: function getPackageNameAndPath() {
      var packagePath = `${this.bindingPrefix}/${this.id.box}/${this.id.name}`;
      var packageName = this.id.toStringWithoutVersion();
      return { packageName, packagePath };
    }
  }, {
    key: 'writePackageJson',
    value: function () {
      var _ref5 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(consumer, bitDir) {
        var override = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var writeBitDependencies = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
        var excludeRegistryPrefix = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
        var packageJsonInstance;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                _context2.next = 2;
                return (_packageJson || _load_packageJson()).write(consumer, this, bitDir, override, writeBitDependencies, excludeRegistryPrefix);

              case 2:
                packageJsonInstance = _context2.sent;

                this.packageJsonInstance = packageJsonInstance;

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

      function writePackageJson(_x8, _x9) {
        return _ref5.apply(this, arguments);
      }

      return writePackageJson;
    }()
  }, {
    key: 'flattenedDependencies',
    value: function flattenedDependencies() {
      return (_bitIds || _load_bitIds()).default.fromObject(this.flattenedDependencies);
    }
  }, {
    key: 'flattenedDevDependencies',
    value: function flattenedDevDependencies() {
      return (_bitIds || _load_bitIds()).default.fromObject(this.flattenedDevDependencies);
    }
  }, {
    key: 'getAllDependencies',
    value: function getAllDependencies() {
      return this.dependencies.dependencies.concat(this.devDependencies.dependencies);
    }
  }, {
    key: 'hasDependencies',
    value: function hasDependencies() {
      return !this.dependencies.isEmpty() || !this.devDependencies.isEmpty();
    }
  }, {
    key: 'getAllFlattenedDependencies',
    value: function getAllFlattenedDependencies() {
      return this.flattenedDependencies.concat(this.flattenedDevDependencies);
    }
  }, {
    key: 'buildIfNeeded',
    value: function () {
      var _ref7 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee5(_ref6) {
        var _this2 = this;

        var compiler = _ref6.compiler,
            consumer = _ref6.consumer,
            componentMap = _ref6.componentMap,
            scope = _ref6.scope,
            verbose = _ref6.verbose,
            directory = _ref6.directory,
            keep = _ref6.keep;
        var files, runBuild, isolatedEnvironment, isolateOpts, componentWithDependencies, component, result;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                if (compiler) {
                  _context5.next = 2;
                  break;
                }

                return _context5.abrupt('return', Promise.resolve({ code: '' }));

              case 2:
                files = this.files.map(function (file) {
                  return file.clone();
                });

                runBuild = function () {
                  var _ref8 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee4(componentRoot) {
                    var rootDistFolder, componentDir;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee4$(_context4) {
                      while (1) {
                        switch (_context4.prev = _context4.next) {
                          case 0:
                            rootDistFolder = (_path || _load_path()).default.join(componentRoot, (_constants || _load_constants()).DEFAULT_DIST_DIRNAME);
                            componentDir = void 0;

                            if (componentMap) {
                              // $FlowFixMe
                              rootDistFolder = _this2.dists.getDistDirForConsumer(consumer, componentMap.rootDir);
                              componentDir = consumer && componentMap.rootDir ? (_path || _load_path()).default.join(consumer.getPath(), componentMap.rootDir) : undefined;
                            }
                            return _context4.abrupt('return', Promise.resolve().then(_asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee3() {
                              var context, actionParams, result;
                              return (_regenerator || _load_regenerator()).default.wrap(function _callee3$(_context3) {
                                while (1) {
                                  switch (_context3.prev = _context3.next) {
                                    case 0:
                                      context = {
                                        componentObject: _this2.toObject(),
                                        rootDistFolder,
                                        componentDir
                                      };

                                      // Change the cwd to make sure we found the needed files

                                      process.chdir(componentRoot);

                                      if (!compiler.action) {
                                        _context3.next = 10;
                                        break;
                                      }

                                      actionParams = {
                                        files,
                                        rawConfig: compiler.rawConfig,
                                        dynamicConfig: compiler.dynamicConfig,
                                        configFiles: compiler.files,
                                        api: compiler.api,
                                        context
                                      };
                                      _context3.next = 6;
                                      return compiler.action(actionParams);

                                    case 6:
                                      result = _context3.sent;

                                      if (!(!result || !result.files)) {
                                        _context3.next = 9;
                                        break;
                                      }

                                      throw new Error('compiler return invalid response');

                                    case 9:
                                      return _context3.abrupt('return', result.files);

                                    case 10:
                                      return _context3.abrupt('return', compiler.oldAction(files, rootDistFolder, context));

                                    case 11:
                                    case 'end':
                                      return _context3.stop();
                                  }
                                }
                              }, _callee3, _this2);
                            }))).catch(function (e) {
                              throw new (_externalBuildError || _load_externalBuildError()).default(e, _this2.id.toString());
                            }));

                          case 4:
                          case 'end':
                            return _context4.stop();
                        }
                      }
                    }, _callee4, _this2);
                  }));

                  return function runBuild(_x11) {
                    return _ref8.apply(this, arguments);
                  };
                }();

                if (!(!compiler.action && !compiler.oldAction)) {
                  _context5.next = 6;
                  break;
                }

                return _context5.abrupt('return', Promise.reject(new (_invalidCompilerInterface || _load_invalidCompilerInterface()).default(compiler.name)));

              case 6:
                if (!consumer) {
                  _context5.next = 8;
                  break;
                }

                return _context5.abrupt('return', runBuild(consumer.getPath()));

              case 8:
                if (!this.isolatedEnvironment) {
                  _context5.next = 10;
                  break;
                }

                return _context5.abrupt('return', runBuild(this.writtenPath));

              case 10:
                isolatedEnvironment = new (_environment || _load_environment()).default(scope, directory);
                _context5.prev = 11;
                _context5.next = 14;
                return isolatedEnvironment.create();

              case 14:
                isolateOpts = {
                  verbose,
                  installPackages: true,
                  noPackageJson: false
                };
                _context5.next = 17;
                return isolatedEnvironment.isolateComponent(this.id.toString(), isolateOpts);

              case 17:
                componentWithDependencies = _context5.sent;
                component = componentWithDependencies.component;
                _context5.next = 21;
                return runBuild(component.writtenPath);

              case 21:
                result = _context5.sent;

                if (keep) {
                  _context5.next = 25;
                  break;
                }

                _context5.next = 25;
                return isolatedEnvironment.destroy();

              case 25:
                return _context5.abrupt('return', result);

              case 28:
                _context5.prev = 28;
                _context5.t0 = _context5['catch'](11);
                _context5.next = 32;
                return isolatedEnvironment.destroy();

              case 32:
                return _context5.abrupt('return', Promise.reject(_context5.t0));

              case 33:
              case 'end':
                return _context5.stop();
            }
          }
        }, _callee5, this, [[11, 28]]);
      }));

      function buildIfNeeded(_x10) {
        return _ref7.apply(this, arguments);
      }

      return buildIfNeeded;
    }()
  }, {
    key: '_writeToComponentDir',
    value: function () {
      var _ref11 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee6(_ref10) {
        var bitDir = _ref10.bitDir,
            writeBitJson = _ref10.writeBitJson,
            writePackageJson = _ref10.writePackageJson,
            consumer = _ref10.consumer,
            _ref10$override = _ref10.override,
            override = _ref10$override === undefined ? true : _ref10$override,
            _ref10$writeBitDepend = _ref10.writeBitDependencies,
            writeBitDependencies = _ref10$writeBitDepend === undefined ? false : _ref10$writeBitDepend,
            _ref10$deleteBitDirCo = _ref10.deleteBitDirContent,
            deleteBitDirContent = _ref10$deleteBitDirCo === undefined ? false : _ref10$deleteBitDirCo,
            _ref10$excludeRegistr = _ref10.excludeRegistryPrefix,
            excludeRegistryPrefix = _ref10$excludeRegistr === undefined ? false : _ref10$excludeRegistr;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                if (!deleteBitDirContent) {
                  _context6.next = 4;
                  break;
                }

                (_fsExtra || _load_fsExtra()).default.emptyDirSync(bitDir);
                _context6.next = 6;
                break;

              case 4:
                _context6.next = 6;
                return (0, (_utils || _load_utils()).mkdirp)(bitDir);

              case 6:
                if (!this.files) {
                  _context6.next = 9;
                  break;
                }

                _context6.next = 9;
                return Promise.all(this.files.map(function (file) {
                  return file.write(undefined, override);
                }));

              case 9:
                _context6.next = 11;
                return this.dists.writeDists(this, consumer, false);

              case 11:
                if (!writeBitJson) {
                  _context6.next = 14;
                  break;
                }

                _context6.next = 14;
                return this.writeConfig(bitDir, consumer.dirStructure.ejectedEnvsDirStructure, override);

              case 14:
                if (!(writePackageJson && (consumer.isolated || bitDir !== consumer.getPath()))) {
                  _context6.next = 17;
                  break;
                }

                _context6.next = 17;
                return this.writePackageJson(consumer, bitDir, override, writeBitDependencies, excludeRegistryPrefix);

              case 17:
                if (!(this.license && this.license.src)) {
                  _context6.next = 20;
                  break;
                }

                _context6.next = 20;
                return this.license.write(bitDir, override);

              case 20:
                (_logger || _load_logger()).default.debug('component has been written successfully');
                return _context6.abrupt('return', this);

              case 22:
              case 'end':
                return _context6.stop();
            }
          }
        }, _callee6, this);
      }));

      function _writeToComponentDir(_x12) {
        return _ref11.apply(this, arguments);
      }

      return _writeToComponentDir;
    }()
  }, {
    key: 'getComponentMap',
    value: function getComponentMap(bitMap) {
      return bitMap.getComponent(this.id);
    }
  }, {
    key: '_addComponentToBitMap',
    value: function _addComponentToBitMap(bitMap, rootDir, origin, parent) {
      var filesForBitMap = this.files.map(function (file) {
        return { name: file.basename, relativePath: (0, (_utils || _load_utils()).pathNormalizeToLinux)(file.relative), test: file.test };
      });

      return bitMap.addComponent({
        componentId: this.id,
        files: filesForBitMap,
        mainFile: this.mainFile,
        rootDir,
        origin,
        parent,
        originallySharedDir: this.originallySharedDir
      });
    }

    /**
     * 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 components only as the author may have long paths that are not needed for whoever
     * imports it. NESTED and AUTHORED components are written as is.
     */

  }, {
    key: 'stripOriginallySharedDir',
    value: function stripOriginallySharedDir(bitMap) {
      if (this._wasOriginallySharedDirStripped) return;
      this.setOriginallySharedDir();
      var originallySharedDir = this.originallySharedDir;
      if (originallySharedDir) {
        (_logger || _load_logger()).default.debug(`stripping originallySharedDir "${originallySharedDir}" from ${this.id}`);
      }
      var pathWithoutSharedDir = function pathWithoutSharedDir(pathStr, sharedDir) {
        if (!sharedDir) return pathStr;
        var partToRemove = (_path || _load_path()).default.normalize(sharedDir) + (_path || _load_path()).default.sep;
        return pathStr.replace(partToRemove, '');
      };
      this.files.forEach(function (file) {
        var newRelative = pathWithoutSharedDir(file.relative, originallySharedDir);
        file.updatePaths({ newBase: file.base, newRelative });
      });
      this.dists.stripOriginallySharedDir(originallySharedDir, pathWithoutSharedDir);
      this.mainFile = pathWithoutSharedDir(this.mainFile, originallySharedDir);
      this.dependencies.stripOriginallySharedDir(bitMap, originallySharedDir);
      this.devDependencies.stripOriginallySharedDir(bitMap, originallySharedDir);
      this.customResolvedPaths.forEach(function (customPath) {
        customPath.destinationPath = (0, (_utils || _load_utils()).pathNormalizeToLinux)(pathWithoutSharedDir((_path || _load_path()).default.normalize(customPath.destinationPath), originallySharedDir));
      });
      this._wasOriginallySharedDirStripped = true;
    }
  }, {
    key: 'addSharedDir',
    value: function addSharedDir(pathStr) {
      var withSharedDir = this.originallySharedDir ? (_path || _load_path()).default.join(this.originallySharedDir, pathStr) : pathStr;
      return (0, (_utils || _load_utils()).pathNormalizeToLinux)(withSharedDir);
    }
  }, {
    key: 'cloneFilesWithSharedDir',
    value: function cloneFilesWithSharedDir() {
      var _this3 = this;

      return this.files.map(function (file) {
        var newFile = file.clone();
        var newRelative = _this3.addSharedDir(file.relative);
        newFile.updatePaths({ newBase: file.base, newRelative });
        return newFile;
      });
    }

    /**
     * When using this function please check if you really need to pass the bitDir or not
     * It's better to init the files with the correct base, cwd and path than pass it here
     * It's mainly here for cases when we write from the model so this is the first point we actually have the dir
     */

  }, {
    key: 'write',
    value: function () {
      var _ref13 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee7(_ref12) {
        var bitDir = _ref12.bitDir,
            _ref12$writeBitJson = _ref12.writeBitJson,
            writeBitJson = _ref12$writeBitJson === undefined ? true : _ref12$writeBitJson,
            _ref12$writePackageJs = _ref12.writePackageJson,
            writePackageJson = _ref12$writePackageJs === undefined ? true : _ref12$writePackageJs,
            _ref12$override = _ref12.override,
            override = _ref12$override === undefined ? true : _ref12$override,
            origin = _ref12.origin,
            parent = _ref12.parent,
            consumer = _ref12.consumer,
            _ref12$writeBitDepend = _ref12.writeBitDependencies,
            writeBitDependencies = _ref12$writeBitDepend === undefined ? false : _ref12$writeBitDepend,
            deleteBitDirContent = _ref12.deleteBitDirContent,
            componentMap = _ref12.componentMap,
            _ref12$excludeRegistr = _ref12.excludeRegistryPrefix,
            excludeRegistryPrefix = _ref12$excludeRegistr === undefined ? false : _ref12$excludeRegistr;
        var consumerPath, bitMap, calculatedBitDir, oldLocation, newBase, rootDir, componentMapExistWithSameVersion, updateBitMap, actualWithPackageJson;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee7$(_context7) {
          while (1) {
            switch (_context7.prev = _context7.next) {
              case 0:
                (_logger || _load_logger()).default.debug(`consumer-component.write, id: ${this.id.toString()}`);
                consumerPath = consumer ? consumer.getPath() : undefined;
                bitMap = consumer ? consumer.bitMap : undefined;

                if (this.files) {
                  _context7.next = 5;
                  break;
                }

                throw new (_generalError || _load_generalError()).default(`Component ${this.id.toString()} is invalid as it has no files`);

              case 5:
                // Take the bitdir from the files (it will be the same for all the files of course)
                calculatedBitDir = bitDir || this.files[0].base;
                // Update files base dir according to bitDir

                if (this.files && bitDir) this.files.forEach(function (file) {
                  return file.updatePaths({ newBase: bitDir });
                });
                if (!this.dists.isEmpty() && bitDir) this.dists.get().forEach(function (dist) {
                  return dist.updatePaths({ newBase: bitDir });
                });

                // if bitMap parameter is empty, for instance, when it came from the scope, ignore bitMap altogether.
                // otherwise, check whether this component is in bitMap:
                // if it's there, write the files according to the paths in bit.map.
                // Otherwise, write to bitDir and update bitMap with the new paths.

                if (bitMap) {
                  _context7.next = 10;
                  break;
                }

                return _context7.abrupt('return', this._writeToComponentDir({
                  bitDir: calculatedBitDir,
                  writeBitJson,
                  writePackageJson,
                  consumer,
                  override,
                  writeBitDependencies,
                  excludeRegistryPrefix
                }));

              case 10:
                if (!componentMap) {
                  // if there is no componentMap, the component is new to this project and should be written to bit.map
                  componentMap = this._addComponentToBitMap(bitMap, calculatedBitDir, origin, parent);
                }
                if (!consumer.shouldDistsBeInsideTheComponent() && this.dists.isEmpty()) {
                  // since the dists are set to be outside the components dir, the source files must be saved there
                  // otherwise, other components in dists won't be able to link to this component
                  this.copyFilesIntoDists();
                }
                // For IMPORTED component we have to delete the content of the directory before importing.
                // Otherwise, when the author adds new files outside of the previous originallySharedDir and this user imports them
                // the environment will contain both copies, the old one with the old originallySharedDir and the new one.
                // If a user made changes to the imported component, it will show a warning and stop the process.
                if (typeof deleteBitDirContent === 'undefined') {
                  deleteBitDirContent = origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED;
                }
                // when there is componentMap, this component (with this version or other version) is already part of the project.
                // There are several options as to what was the origin before and what is the origin now and according to this,
                // we update/remove/don't-touch the record in bit.map.
                // The current origin can't be AUTHORED because when the author creates a component for the first time,
                // 1) current origin is AUTHORED - If the version is the same as before, don't update bit.map. Otherwise, update.
                // 2) current origin is IMPORTED - If the version is the same as before, don't update bit.map. Otherwise, update.
                // one exception is where the origin was NESTED before, in this case, remove the current record and add a new one.
                // 3) current origin is NESTED - the version can't be the same as before (otherwise it would be ignored before and
                // never reach this function, see @write-components.writeToComponentsDir). Therefore, always add to bit.map.
                if (origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED && componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.NESTED) {
                  // when a user imports a component that was a dependency before, write the component directly into the components
                  // directory for an easy access/change. Then, remove the current record from bit.map and add an updated one.
                  oldLocation = (_path || _load_path()).default.join(consumerPath, componentMap.rootDir);

                  (_logger || _load_logger()).default.debug(`deleting the old directory of a component at ${oldLocation}, the new directory is ${calculatedBitDir}`);
                  (_fsExtra || _load_fsExtra()).default.removeSync(oldLocation);
                  bitMap.removeComponent(this.id.toString());
                  componentMap = this._addComponentToBitMap(bitMap, calculatedBitDir, origin, parent);
                }
                (_logger || _load_logger()).default.debug('component is in bit.map, write the files according to bit.map');
                if (componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED) writeBitJson = false;
                newBase = componentMap.rootDir ? (_path || _load_path()).default.join(consumerPath, componentMap.rootDir) : consumerPath;

                this.writtenPath = newBase;
                this.files.forEach(function (file) {
                  return file.updatePaths({ newBase });
                });
                rootDir = componentMap.rootDir;
                componentMapExistWithSameVersion = bitMap.isExistWithSameVersion(this.id);
                updateBitMap = !componentMapExistWithSameVersion || componentMap.originallySharedDir !== this.originallySharedDir;
                // update bitMap before writing the files to the filesystem, because as part of writing the
                // package-json file, the componentMap is needed to be stored with the updated version

                if (updateBitMap) {
                  if (componentMapExistWithSameVersion) {
                    // originallySharedDir has been changed. it affects also the relativePath of the files
                    // so it's better to just remove the old record and add a new one
                    bitMap.removeComponent(this.id);
                  }
                  this._addComponentToBitMap(bitMap, rootDir, origin, parent);
                }

                // Don't write the package.json for an authored component, because it's dependencies probably managed
                // By the root package.json
                actualWithPackageJson = writePackageJson && origin !== (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED;
                _context7.next = 26;
                return this._writeToComponentDir({
                  bitDir: newBase,
                  writeBitJson,
                  writePackageJson: actualWithPackageJson,
                  consumer,
                  override,
                  writeBitDependencies,
                  deleteBitDirContent,
                  excludeRegistryPrefix
                });

              case 26:
                return _context7.abrupt('return', this);

              case 27:
              case 'end':
                return _context7.stop();
            }
          }
        }, _callee7, this);
      }));

      function write(_x13) {
        return _ref13.apply(this, arguments);
      }

      return write;
    }()
  }, {
    key: 'runSpecs',
    value: function () {
      var _ref15 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee10(_ref14) {
        var _this4 = this;

        var scope = _ref14.scope,
            _ref14$rejectOnFailur = _ref14.rejectOnFailure,
            rejectOnFailure = _ref14$rejectOnFailur === undefined ? false : _ref14$rejectOnFailur,
            consumer = _ref14.consumer,
            save = _ref14.save,
            verbose = _ref14.verbose,
            isolated = _ref14.isolated,
            directory = _ref14.directory,
            keep = _ref14.keep;
        var testFiles, tester, testerFilePath, run, isolatedEnvironment, isolateOpts, localTesterPath, componentWithDependencies, component, specDistWrite, results;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee10$(_context10) {
          while (1) {
            switch (_context10.prev = _context10.next) {
              case 0:
                testFiles = this.files.filter(function (file) {
                  return file.test;
                });

                if (!(!this.tester || !testFiles || (_ramda || _load_ramda()).default.isEmpty(testFiles))) {
                  _context10.next = 3;
                  break;
                }

                return _context10.abrupt('return', null);

              case 3:

                (_logger || _load_logger()).default.debug('tester found, start running tests');
                (_analytics || _load_analytics()).Analytics.addBreadCrumb('runSpecs', 'tester found, start running tests');
                tester = this.tester;

                if (tester.loaded) {
                  _context10.next = 11;
                  break;
                }

                (_analytics || _load_analytics()).Analytics.addBreadCrumb('runSpecs', 'installing missing tester');
                _context10.next = 10;
                return tester.install(scope, { verbose });

              case 10:
                (_logger || _load_logger()).default.debug('Environment components are installed');

              case 11:
                testerFilePath = tester.filePath;

                run = function () {
                  var _ref16 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee9(component, cwd) {
                    var testFilesList, specsResults, context, actionParams, oneFileSpecResult, specsResultsP, specsResultsPretty, componentIdPretty, specsResultsAndIdPretty;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee9$(_context9) {
                      while (1) {
                        switch (_context9.prev = _context9.next) {
                          case 0:
                            // Change the cwd to make sure we found the needed files
                            if (cwd) {
                              (_logger || _load_logger()).default.debug(`changing process cwd to ${cwd}`);
                              (_analytics || _load_analytics()).Analytics.addBreadCrumb('runSpecs.run', 'changing process cwd');
                              process.chdir(cwd);
                            }
                            (_loader || _load_loader()).default.start((_loaderMessages || _load_loaderMessages()).BEFORE_RUNNING_SPECS);
                            testFilesList = !component.dists.isEmpty() ? component.dists.get().filter(function (dist) {
                              return dist.test;
                            }) : component.files.filter(function (file) {
                              return file.test;
                            });
                            specsResults = void 0;
                            _context9.prev = 4;

                            if (!tester.action) {
                              _context9.next = 15;
                              break;
                            }

                            (_logger || _load_logger()).default.debug('running tests using new format');
                            (_analytics || _load_analytics()).Analytics.addBreadCrumb('runSpecs.run', 'running tests using new format');
                            context = {
                              componentObject: component.toObject()
                            };
                            actionParams = {
                              testFiles: testFilesList,
                              rawConfig: tester.rawConfig,
                              dynamicConfig: tester.dynamicConfig,
                              configFiles: tester.files,
                              api: tester.api,
                              context
                            };
                            _context9.next = 12;
                            return tester.action(actionParams);

                          case 12:
                            specsResults = _context9.sent;
                            _context9.next = 22;
                            break;

                          case 15:
                            (_logger || _load_logger()).default.debug('running tests using old format');
                            (_analytics || _load_analytics()).Analytics.addBreadCrumb('runSpecs.run', 'running tests using old format');

                            oneFileSpecResult = function () {
                              var _ref17 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee8(testFile) {
                                var testFilePath, results, failures, _results;

                                return (_regenerator || _load_regenerator()).default.wrap(function _callee8$(_context8) {
                                  while (1) {
                                    switch (_context8.prev = _context8.next) {
                                      case 0:
                                        testFilePath = testFile.path;
                                        _context8.prev = 1;
                                        _context8.next = 4;
                                        return tester.oldAction(testFilePath);

                                      case 4:
                                        results = _context8.sent;

                                        results.specPath = testFile.relative;
                                        return _context8.abrupt('return', results);

                                      case 9:
                                        _context8.prev = 9;
                                        _context8.t0 = _context8['catch'](1);
                                        failures = [{
                                          title: _context8.t0.message,
                                          err: _context8.t0
                                        }];
                                        _results = {
                                          specPath: testFile.relative,
                                          pass: false,
                                          tests: [],
                                          failures
                                        };
                                        return _context8.abrupt('return', _results);

                                      case 14:
                                      case 'end':
                                        return _context8.stop();
                                    }
                                  }
                                }, _callee8, _this4, [[1, 9]]);
                              }));

                              return function oneFileSpecResult(_x17) {
                                return _ref17.apply(this, arguments);
                              };
                            }();

                            specsResultsP = testFilesList.map(oneFileSpecResult);
                            _context9.next = 21;
                            return Promise.all(specsResultsP);

                          case 21:
                            specsResults = _context9.sent;

                          case 22:
                            _context9.next = 27;
                            break;

                          case 24:
                            _context9.prev = 24;
                            _context9.t0 = _context9['catch'](4);
                            throw new (_externalTestError || _load_externalTestError()).default(_context9.t0, _this4.id.toString());

                          case 27:

                            _this4.specsResults = specsResults.map(function (specRes) {
                              return (_specsResults || _load_specsResults()).default.createFromRaw(specRes);
                            });

                            if (!(rejectOnFailure && !_this4.specsResults.every(function (element) {
                              return element.pass;
                            }))) {
                              _context9.next = 36;
                              break;
                            }

                            // some or all the tests were failed.
                            (_loader || _load_loader()).default.stop();

                            if (!verbose) {
                              _context9.next = 35;
                              break;
                            }

                            // $FlowFixMe this.specsResults is not null at this point
                            specsResultsPretty = (0, (_chalkBox || _load_chalkBox()).paintSpecsResults)(_this4.specsResults).join('\n');
                            componentIdPretty = (_chalk || _load_chalk()).default.bold.white(_this4.id.toString());
                            specsResultsAndIdPretty = `${componentIdPretty}${specsResultsPretty}\n`;
                            return _context9.abrupt('return', Promise.reject(new (_componentSpecsFailed || _load_componentSpecsFailed()).default(specsResultsAndIdPretty)));

                          case 35:
                            return _context9.abrupt('return', Promise.reject(new (_componentSpecsFailed || _load_componentSpecsFailed()).default()));

                          case 36:
                            if (!save) {
                              _context9.next = 39;
                              break;
                            }

                            _context9.next = 39;
                            return scope.sources.modifySpecsResults({
                              source: _this4,
                              specsResults: _this4.specsResults
                            });

                          case 39:
                            return _context9.abrupt('return', _this4.specsResults);

                          case 40:
                          case 'end':
                            return _context9.stop();
                        }
                      }
                    }, _callee9, _this4, [[4, 24]]);
                  }));

                  return function run(_x15, _x16) {
                    return _ref16.apply(this, arguments);
                  };
                }();

                if (!(!isolated && consumer)) {
                  _context10.next = 20;
                  break;
                }

                (_logger || _load_logger()).default.debug('Building the component before running the tests');
                _context10.next = 17;
                return this.build({ scope, verbose, consumer });

              case 17:
                _context10.next = 19;
                return this.dists.writeDists(this, consumer);

              case 19:
                return _context10.abrupt('return', run(this, consumer.getPath()));

              case 20:
                isolatedEnvironment = new (_environment || _load_environment()).default(scope, directory);
                _context10.prev = 21;
                _context10.next = 24;
                return isolatedEnvironment.create();

              case 24:
                isolateOpts = {
                  verbose,
                  dist: true,
                  installPackages: true,
                  installPeerDependencies: true,
                  noPackageJson: false
                };
                localTesterPath = (_path || _load_path()).default.join(isolatedEnvironment.getPath(), 'tester');
                _context10.next = 28;
                return isolatedEnvironment.isolateComponent(this.id.toString(), isolateOpts);

              case 28:
                componentWithDependencies = _context10.sent;


                (0, (_utils || _load_utils()).createSymlinkOrCopy)(testerFilePath, localTesterPath);
                component = componentWithDependencies.component;

                component.isolatedEnvironment = isolatedEnvironment;
                (_logger || _load_logger()).default.debug(`the component ${this.id.toString()} has been imported successfully into an isolated environment`);

                _context10.next = 35;
                return component.build({ scope, verbose });

              case 35:
                if (component.dists.isEmpty()) {
                  _context10.next = 39;
                  break;
                }

                specDistWrite = component.dists.get().map(function (file) {
                  return file.write();
                });
                _context10.next = 39;
                return Promise.all(specDistWrite);

              case 39:
                _context10.next = 41;
                return run(component);

              case 41:
                results = _context10.sent;

                if (keep) {
                  _context10.next = 45;
                  break;
                }

                _context10.next = 45;
                return isolatedEnvironment.destroy();

              case 45:
                return _context10.abrupt('return', results);

              case 48:
                _context10.prev = 48;
                _context10.t0 = _context10['catch'](21);
                _context10.next = 52;
                return isolatedEnvironment.destroy();

              case 52:
                return _context10.abrupt('return', Promise.reject(_context10.t0));

              case 53:
              case 'end':
                return _context10.stop();
            }
          }
        }, _callee10, this, [[21, 48]]);
      }));

      function runSpecs(_x14) {
        return _ref15.apply(this, arguments);
      }

      return runSpecs;
    }()
  }, {
    key: 'build',
    value: function () {
      var _ref19 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee12(_ref18) {
        var _this5 = this;

        var scope = _ref18.scope,
            save = _ref18.save,
            consumer = _ref18.consumer,
            verbose = _ref18.verbose,
            keep = _ref18.keep;
        var isNeededToReBuild, bitMap, consumerPath, componentMap, componentDir, needToRebuild, builtFiles;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee12$(_context12) {
          while (1) {
            switch (_context12.prev = _context12.next) {
              case 0:
                (_logger || _load_logger()).default.debug(`consumer-component.build ${this.id.toString()}`);
                // @TODO - write SourceMap Type

                if (this.compiler) {
                  _context12.next = 8;
                  break;
                }

                if (!(!consumer || consumer.shouldDistsBeInsideTheComponent())) {
                  _context12.next = 5;
                  break;
                }

                (_logger || _load_logger()).default.debug('compiler was not found, nothing to build');
                return _context12.abrupt('return', null);

              case 5:
                (_logger || _load_logger()).default.debug('compiler was not found, however, because the dists are set to be outside the components directory, save the source file as dists');
                this.copyFilesIntoDists();
                return _context12.abrupt('return', this.dists);

              case 8:
                // Ideally it's better to use the dists from the model.
                // If there is no consumer, it comes from the scope or isolated environment, which the dists are already saved.
                // If there is consumer, check whether the component was modified. If it wasn't, no need to re-build.
                isNeededToReBuild = function () {
                  var _ref20 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee11() {
                    var componentStatus;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee11$(_context11) {
                      while (1) {
                        switch (_context11.prev = _context11.next) {
                          case 0:
                            if (consumer) {
                              _context11.next = 2;
                              break;
                            }

                            return _context11.abrupt('return', false);

                          case 2:
                            _context11.next = 4;
                            return consumer.getComponentStatusById(_this5.id);

                          case 4:
                            componentStatus = _context11.sent;
                            return _context11.abrupt('return', componentStatus.modified);

                          case 6:
                          case 'end':
                            return _context11.stop();
                        }
                      }
                    }, _callee11, _this5);
                  }));

                  return function isNeededToReBuild() {
                    return _ref20.apply(this, arguments);
                  };
                }();

                bitMap = consumer ? consumer.bitMap : undefined;
                consumerPath = consumer ? consumer.getPath() : '';
                componentMap = bitMap && bitMap.getComponent(this.id.toString());
                componentDir = consumerPath;

                if (componentMap) {
                  componentDir = consumerPath && componentMap.rootDir ? (_path || _load_path()).default.join(consumerPath, componentMap.rootDir) : undefined;
                }
                _context12.next = 16;
                return isNeededToReBuild();

              case 16:
                needToRebuild = _context12.sent;

                if (!(!needToRebuild && !this.dists.isEmpty())) {
                  _context12.next = 21;
                  break;
                }

                (_logger || _load_logger()).default.debug('skip the build process as the component was not modified, use the dists saved in the model');
                if (componentMap && componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.IMPORTED) {
                  this.stripOriginallySharedDir(bitMap);
                  // don't worry about the dist.entry and dist.target at this point. It'll be done later on once the files are
                  // written, probably by this.dists.writeDists()
                }

                return _context12.abrupt('return', this.dists);

              case 21:
                (_logger || _load_logger()).default.debug('compiler found, start building');

                if (this.compiler.loaded) {
                  _context12.next = 25;
                  break;
                }

                _context12.next = 25;
                return this.compiler.install(scope, { verbose }, { workspaceDir: consumerPath, componentDir, dependentId: this.id });

              case 25:
                _context12.next = 27;
                return this.buildIfNeeded({
                  compiler: this.compiler,
                  consumer,
                  componentMap,
                  scope,
                  keep,
                  verbose
                });

              case 27:
                builtFiles = _context12.sent;

                // return buildFilesP.then((buildedFiles) => {
                builtFiles.forEach(function (file) {
                  if (file && (!file.contents || !(0, (_utils || _load_utils()).isString)(file.contents.toString()))) {
                    throw new (_generalError || _load_generalError()).default('builder interface has to return object with a code attribute that contains string');
                  }
                });
                this.setDists(builtFiles.map(function (file) {
                  return new (_sources || _load_sources()).Dist(file);
                }));

                if (!save) {
                  _context12.next = 33;
                  break;
                }

                _context12.next = 33;
                return scope.sources.updateDist({ source: this });

              case 33:
                return _context12.abrupt('return', this.dists);

              case 34:
              case 'end':
                return _context12.stop();
            }
          }
        }, _callee12, this);
      }));

      function build(_x18) {
        return _ref19.apply(this, arguments);
      }

      return build;
    }()
  }, {
    key: 'isolate',
    value: function () {
      var _ref21 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee13(scope, opts) {
        var isolatedEnvironment;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee13$(_context13) {
          while (1) {
            switch (_context13.prev = _context13.next) {
              case 0:
                isolatedEnvironment = new (_environment || _load_environment()).default(scope, opts.writeToPath);
                _context13.prev = 1;
                _context13.next = 4;
                return isolatedEnvironment.create();

              case 4:
                _context13.next = 6;
                return isolatedEnvironment.isolateComponent(this.id.toString(), opts);

              case 6:
                return _context13.abrupt('return', isolatedEnvironment.path);

              case 9:
                _context13.prev = 9;
                _context13.t0 = _context13['catch'](1);
                _context13.next = 13;
                return isolatedEnvironment.destroy();

              case 13:
                throw new (_generalError || _load_generalError()).default(_context13.t0);

              case 14:
              case 'end':
                return _context13.stop();
            }
          }
        }, _callee13, this, [[1, 9]]);
      }));

      function isolate(_x19, _x20) {
        return _ref21.apply(this, arguments);
      }

      return isolate;
    }()
  }, {
    key: 'toObject',
    value: function toObject() {
      return {
        name: this.name,
        box: this.box,
        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(),
        packageDependencies: this.packageDependencies,
        devPackageDependencies: this.devPackageDependencies,
        peerPackageDependencies: this.peerPackageDependencies,
        envsPackageDependencies: this.envsPackageDependencies,
        files: this.files,
        docs: this.docs,
        dists: this.dists,
        specsResults: this.specsResults ? this.specsResults.map(function (res) {
          return res.serialize();
        }) : null,
        license: this.license ? this.license.serialize() : null,
        log: this.log,
        deprecated: this.deprecated
      };
    }
  }, {
    key: 'toString',
    value: function toString() {
      return JSON.stringify(this.toObject());
    }
  }, {
    key: 'copyFilesIntoDists',
    value: function copyFilesIntoDists() {
      var dists = this.files.map(function (file) {
        return new (_sources || _load_sources()).Dist({ base: file.base, path: file.path, contents: file.contents });
      });
      this.setDists(dists);
    }

    /**
     * find a shared directory among the files of the main component and its dependencies
     */

  }, {
    key: 'setOriginallySharedDir',
    value: function setOriginallySharedDir() {
      if (this.originallySharedDir !== undefined) return;
      // taken from https://stackoverflow.com/questions/1916218/find-the-longest-common-starting-substring-in-a-set-of-strings
      // It sorts the array, and then looks just at the first and last items
      var sharedStartOfArray = function sharedStartOfArray(array) {
        var sortedArray = array.concat().sort();
        var firstItem = sortedArray[0];
        var lastItem = sortedArray[sortedArray.length - 1];
        var i = 0;
        while (i < firstItem.length && firstItem.charAt(i) === lastItem.charAt(i)) {
          i += 1;
        }return firstItem.substring(0, i);
      };
      var pathSep = '/'; // it works for Windows as well as all paths are normalized to Linux
      var filePaths = this.files.map(function (file) {
        return (0, (_utils || _load_utils()).pathNormalizeToLinux)(file.relative);
      });
      var dependenciesPaths = this.dependencies.getSourcesPaths();
      var devDependenciesPaths = this.devDependencies.getSourcesPaths();
      var allPaths = [].concat(_toConsumableArray(filePaths), _toConsumableArray(dependenciesPaths), _toConsumableArray(devDependenciesPaths));
      var sharedStart = sharedStartOfArray(allPaths);
      if (!sharedStart || !sharedStart.includes(pathSep)) return;
      var lastPathSeparator = sharedStart.lastIndexOf(pathSep);
      this.originallySharedDir = sharedStart.substring(0, lastPathSeparator);
    }
  }, {
    key: 'toComponentWithDependencies',
    value: function () {
      var _ref22 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee14(consumer) {
        var _this6 = this;

        var getFlatten, getDependenciesComponents, dependencies, devDependencies;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee14$(_context14) {
          while (1) {
            switch (_context14.prev = _context14.next) {
              case 0:
                getFlatten = function getFlatten() {
                  var dev = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;

                  var field = dev ? 'flattenedDevDependencies' : 'flattenedDependencies';
                  // when loaded from filesystem, it doesn't have the flatten, fetch them from model.
                  return _this6.loadedFromFileSystem ? _this6.componentFromModel[field] : _this6[field];
                };

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

                _context14.next = 4;
                return getDependenciesComponents(getFlatten());

              case 4:
                dependencies = _context14.sent;
                _context14.next = 7;
                return getDependenciesComponents(getFlatten(true));

              case 7:
                devDependencies = _context14.sent;
                return _context14.abrupt('return', new (_componentDependencies || _load_componentDependencies()).default({ component: this, dependencies, devDependencies }));

              case 9:
              case 'end':
                return _context14.stop();
            }
          }
        }, _callee14, this);
      }));

      function toComponentWithDependencies(_x21) {
        return _ref22.apply(this, arguments);
      }

      return toComponentWithDependencies;
    }()
  }, {
    key: 'copyDependenciesFromModel',
    value: function copyDependenciesFromModel(ids) {
      var _this7 = this;

      var componentFromModel = this.componentFromModel;
      if (!componentFromModel) throw new Error('copyDependenciesFromModel: component is missing from the model');
      ids.forEach(function (id) {
        var dependency = componentFromModel.dependencies.getById(id);
        if (dependency) _this7.dependencies.add(dependency);else {
          var devDependency = componentFromModel.devDependencies.getById(id);
          if (!devDependency) throw new Error(`copyDependenciesFromModel unable to find dependency ${id} in the model`);
          _this7.devDependencies.add(dependency);
        }
      });
    }
  }], [{
    key: 'fromObject',
    value: function fromObject(object) {
      var name = object.name,
          box = object.box,
          version = object.version,
          scope = object.scope,
          lang = object.lang,
          bindingPrefix = object.bindingPrefix,
          compiler = object.compiler,
          tester = object.tester,
          dependencies = object.dependencies,
          devDependencies = object.devDependencies,
          packageDependencies = object.packageDependencies,
          devPackageDependencies = object.devPackageDependencies,
          peerPackageDependencies = object.peerPackageDependencies,
          envsPackageDependencies = object.envsPackageDependencies,
          docs = object.docs,
          mainFile = object.mainFile,
          dists = object.dists,
          files = object.files,
          specsResults = object.specsResults,
          license = object.license,
          deprecated = object.deprecated;

      return new Component({
        name,
        box,
        version,
        scope,
        lang,
        bindingPrefix,
        compiler: compiler ? (_compilerExtension || _load_compilerExtension()).default.loadFromModelObject(compiler) : null,
        tester: tester ? (_testerExtension || _load_testerExtension()).default.loadFromModelObject(tester) : null,
        dependencies,
        devDependencies,
        packageDependencies,
        devPackageDependencies,
        peerPackageDependencies,
        envsPackageDependencies,
        mainFile,
        files,
        docs,
        dists,
        specsResults: specsResults ? (_specsResults || _load_specsResults()).default.deserialize(specsResults) : null,
        license: license ? (_sources || _load_sources()).License.deserialize(license) : null,
        deprecated: deprecated || false
      });
    }
  }, {
    key: 'fromString',
    value: function fromString(str) {
      var object = JSON.parse(str);
      object.files = (_sources || _load_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 || _load_sources()).Dist.loadFromParsedStringArray(object.dists);
      } else if (object.dists && object.dists.dists) {
        object.dists = (_sources || _load_sources()).Dist.loadFromParsedStringArray(object.dists.dists);
      }
      return this.fromObject(object);
    }
  }, {
    key: 'loadFromFileSystem',
    value: function () {
      var _ref24 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee16(_ref23) {
        var _this8 = this;

        var bitDir = _ref23.bitDir,
            componentMap = _ref23.componentMap,
            id = _ref23.id,
            consumer = _ref23.consumer,
            componentFromModel = _ref23.componentFromModel;

        var consumerPath, consumerBitJson, bitMap, deprecated, dists, packageDependencies, devPackageDependencies, peerPackageDependencies, getLoadedFiles, componentBitJson, componentBitJsonFileExist, rawComponentBitJson, bitJson, envsContext, propsToLoadEnvs, compilerP, testerP, _ref26, _ref27, compiler, tester, compilerDynamicPackageDependencies, testerDynamicPackageDependencies, modelEnvsPackageDependencies, envsPackageDependencies;

        return (_regenerator || _load_regenerator()).default.wrap(function _callee16$(_context16) {
          while (1) {
            switch (_context16.prev = _context16.next) {
              case 0:
                consumerPath = consumer.getPath();
                consumerBitJson = consumer.bitJson;
                bitMap = consumer.bitMap;
                deprecated = componentFromModel ? componentFromModel.deprecated : false;
                dists = componentFromModel ? componentFromModel.dists.get() : undefined;
                packageDependencies = void 0;
                devPackageDependencies = void 0;
                peerPackageDependencies = void 0;

                getLoadedFiles = function () {
                  var _ref25 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee15() {
                    var sourceFiles, filesToDelete;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee15$(_context15) {
                      while (1) {
                        switch (_context15.prev = _context15.next) {
                          case 0:
                            sourceFiles = [];
                            _context15.next = 3;
                            return componentMap.trackDirectoryChanges(consumer, id);

                          case 3:
                            filesToDelete = [];

                            componentMap.files.forEach(function (file) {
                              var filePath = (_path || _load_path()).default.join(bitDir, file.relativePath);
                              try {
                                var sourceFile = (_sources || _load_sources()).SourceFile.load(filePath, consumerBitJson.distTarget, bitDir, consumerPath, {
                                  test: file.test
                                });
                                sourceFiles.push(sourceFile);
                              } catch (err) {
                                if (!(err instanceof (_fileSourceNotFound || _load_fileSourceNotFound()).default)) throw err;
                                (_logger || _load_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 && !sourceFiles.length)) {
                              _context15.next = 7;
                              break;
                            }

                            throw new (_missingFilesFromComponent || _load_missingFilesFromComponent()).default(id.toString());

                          case 7:
                            if (filesToDelete.length) {
                              componentMap.removeFiles(filesToDelete);
                              bitMap.hasChanged = true;
                            }
                            return _context15.abrupt('return', sourceFiles);

                          case 9:
                          case 'end':
                            return _context15.stop();
                        }
                      }
                    }, _callee15, _this8);
                  }));

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

                if ((_fsExtra || _load_fsExtra()).default.existsSync(bitDir)) {
                  _context16.next = 11;
                  break;
                }

                throw new (_componentNotFoundInPath || _load_componentNotFoundInPath()).default(bitDir);

              case 11:
                // 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
                componentBitJson = void 0;
                componentBitJsonFileExist = false;
                rawComponentBitJson = void 0;

                if (!(bitDir !== consumerPath)) {
                  _context16.next = 24;
                  break;
                }

                componentBitJson = (_bitJson || _load_bitJson()).default.loadSync(bitDir, consumerBitJson);
                packageDependencies = componentBitJson.packageDependencies;
                devPackageDependencies = componentBitJson.devPackageDependencies;
                peerPackageDependencies = componentBitJson.peerPackageDependencies;
                // by default, imported components are not written with bit.json file.
                // use the component from the model to get their bit.json values
                _context16.next = 21;
                return (_abstractBitJson || _load_abstractBitJson()).default.hasExisting(bitDir);

              case 21:
                componentBitJsonFileExist = _context16.sent;

                if (componentBitJsonFileExist) {
                  rawComponentBitJson = componentBitJson;
                }
                if (!componentBitJsonFileExist && componentFromModel) {
                  componentBitJson.mergeWithComponentData(componentFromModel);
                }

              case 24:
                // for authored componentBitJson is normally undefined
                bitJson = componentBitJson || consumerBitJson;

                // Remove dists if compiler has been deleted

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

                envsContext = {
                  componentDir: bitDir,
                  workspaceDir: consumerPath
                };
                propsToLoadEnvs = {
                  consumerPath,
                  scopePath: consumer.scope.getPath(),
                  componentOrigin: componentMap.origin,
                  componentFromModel,
                  consumerBitJson,
                  componentBitJson: rawComponentBitJson,
                  context: envsContext
                };
                compilerP = (_compilerExtension || _load_compilerExtension()).default.loadFromCorrectSource(propsToLoadEnvs);
                testerP = (_testerExtension || _load_testerExtension()).default.loadFromCorrectSource(propsToLoadEnvs);
                _context16.next = 32;
                return Promise.all([compilerP, testerP]);

              case 32:
                _ref26 = _context16.sent;
                _ref27 = _slicedToArray(_ref26, 2);
                compiler = _ref27[0];
                tester = _ref27[1];


                // Load the envsPackageDependencies 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)
                compilerDynamicPackageDependencies = compiler && compiler.loaded ? compiler.dynamicPackageDependencies : {};
                testerDynamicPackageDependencies = tester && tester.loaded ? tester.dynamicPackageDependencies : {};
                modelEnvsPackageDependencies = componentFromModel ? componentFromModel.envsPackageDependencies || {} : {};
                envsPackageDependencies = _extends({}, modelEnvsPackageDependencies, testerDynamicPackageDependencies, compilerDynamicPackageDependencies);
                _context16.t0 = Component;
                _context16.t1 = id.name;
                _context16.t2 = id.box;
                _context16.t3 = id.scope;
                _context16.t4 = id.version;
                _context16.t5 = bitJson.lang;
                _context16.t6 = bitJson.bindingPrefix || (_constants || _load_constants()).DEFAULT_BINDINGS_PREFIX;
                _context16.t7 = compiler;
                _context16.t8 = tester;
                _context16.t9 = componentBitJsonFileExist ? componentBitJson : undefined;
                _context16.t10 = componentMap.mainFile;
                _context16.next = 53;
                return getLoadedFiles();

              case 53:
                _context16.t11 = _context16.sent;
                _context16.t12 = dists;
                _context16.t13 = packageDependencies;
                _context16.t14 = devPackageDependencies;
                _context16.t15 = peerPackageDependencies;
                _context16.t16 = envsPackageDependencies;
                _context16.t17 = deprecated;
                _context16.t18 = {
                  name: _context16.t1,
                  box: _context16.t2,
                  scope: _context16.t3,
                  version: _context16.t4,
                  lang: _context16.t5,
                  bindingPrefix: _context16.t6,
                  compiler: _context16.t7,
                  tester: _context16.t8,
                  bitJson: _context16.t9,
                  mainFile: _context16.t10,
                  files: _context16.t11,
                  dists: _context16.t12,
                  packageDependencies: _context16.t13,
                  devPackageDependencies: _context16.t14,
                  peerPackageDependencies: _context16.t15,
                  envsPackageDependencies: _context16.t16,
                  deprecated: _context16.t17
                };
                return _context16.abrupt('return', new _context16.t0(_context16.t18));

              case 62:
              case 'end':
                return _context16.stop();
            }
          }
        }, _callee16, this);
      }));

      function loadFromFileSystem(_x23) {
        return _ref24.apply(this, arguments);
      }

      return loadFromFileSystem;
    }()
  }]);

  return Component;
}();

exports.default = Component;