'use strict';

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

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

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

var _semver;

function _load_semver() {
  return _semver = _interopRequireDefault(require('semver'));
}

var _validateNpmPackageName;

function _load_validateNpmPackageName() {
  return _validateNpmPackageName = _interopRequireDefault(require('validate-npm-package-name'));
}

var _objects;

function _load_objects() {
  return _objects = require('../objects');
}

var _scope;

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

var _source;

function _load_source() {
  return _source = _interopRequireDefault(require('./source'));
}

var _utils;

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

var _component;

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

var _bitId;

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

var _componentVersion;

function _load_componentVersion() {
  return _componentVersion = _interopRequireDefault(require('../component-version'));
}

var _constants;

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

var _dependencies;

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

var _extensionFile;

function _load_extensionFile() {
  return _extensionFile = _interopRequireDefault(require('../../extensions/extension-file'));
}

var _sources;

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

var _repository;

function _load_repository() {
  return _repository = _interopRequireDefault(require('../objects/repository'));
}

var _versionInvalid;

function _load_versionInvalid() {
  return _versionInvalid = _interopRequireDefault(require('../exceptions/version-invalid'));
}

var _logger;

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

var _validateType;

function _load_validateType() {
  return _validateType = _interopRequireDefault(require('../../utils/validate-type'));
}

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

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

/**
 * Represent a version model in the scope
 */
var Version = function (_BitObject) {
  _inherits(Version, _BitObject);

  function Version(_ref) {
    var mainFile = _ref.mainFile,
        files = _ref.files,
        dists = _ref.dists,
        compiler = _ref.compiler,
        tester = _ref.tester,
        log = _ref.log,
        dependencies = _ref.dependencies,
        devDependencies = _ref.devDependencies,
        docs = _ref.docs,
        ci = _ref.ci,
        specsResults = _ref.specsResults,
        flattenedDependencies = _ref.flattenedDependencies,
        flattenedDevDependencies = _ref.flattenedDevDependencies,
        packageDependencies = _ref.packageDependencies,
        devPackageDependencies = _ref.devPackageDependencies,
        peerPackageDependencies = _ref.peerPackageDependencies,
        envsPackageDependencies = _ref.envsPackageDependencies,
        bindingPrefix = _ref.bindingPrefix,
        customResolvedPaths = _ref.customResolvedPaths;

    _classCallCheck(this, Version);

    var _this = _possibleConstructorReturn(this, (Version.__proto__ || Object.getPrototypeOf(Version)).call(this));

    _this.mainFile = mainFile;
    _this.files = files;
    _this.dists = dists;
    _this.compiler = compiler;
    _this.tester = tester;
    _this.log = log;
    _this.dependencies = new (_dependencies || _load_dependencies()).Dependencies(dependencies);
    _this.devDependencies = new (_dependencies || _load_dependencies()).Dependencies(devDependencies);
    _this.docs = docs;
    _this.ci = ci || {};
    _this.specsResults = specsResults;
    _this.flattenedDependencies = flattenedDependencies || new (_bitId || _load_bitId()).BitIds();
    _this.flattenedDevDependencies = flattenedDevDependencies || new (_bitId || _load_bitId()).BitIds();
    _this.packageDependencies = packageDependencies || {};
    _this.devPackageDependencies = devPackageDependencies || {};
    _this.peerPackageDependencies = peerPackageDependencies || {};
    _this.envsPackageDependencies = envsPackageDependencies || {};
    _this.bindingPrefix = bindingPrefix;
    _this.customResolvedPaths = customResolvedPaths;
    _this.validateVersion();
    return _this;
  }

  _createClass(Version, [{
    key: 'validateVersion',
    value: function validateVersion() {
      var _this2 = this;

      var nonEmptyFields = ['mainFile', 'files'];
      nonEmptyFields.forEach(function (field) {
        if (!_this2[field]) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`failed creating a version object, the field "${field}" can't be empty`);
        }
      });
    }
  }, {
    key: 'id',
    value: function id() {
      var obj = this.toObject();

      // @todo: remove the entire dependencies.relativePaths from the ID (it's going to be a breaking change)
      var getDependencies = function getDependencies(deps) {
        var clonedDependencies = (_ramda || _load_ramda()).default.clone(deps);
        if (!clonedDependencies) return clonedDependencies;
        return clonedDependencies.map(function (dependency) {
          return {
            id: dependency.id,
            relativePaths: dependency.relativePaths.map(function (relativePath) {
              return {
                sourceRelativePath: relativePath.sourceRelativePath,
                destinationRelativePath: relativePath.destinationRelativePath
              };
            })
          };
        });
      };

      var filterFunction = function filterFunction(val, key) {
        if (key === 'devDependencies' || key === 'devPackageDependencies' || key === 'peerPackageDependencies' || key === 'envsPackageDependencies') {
          return !(_ramda || _load_ramda()).default.isEmpty(val);
        }
        return !!val;
      };

      return JSON.stringify((0, (_utils || _load_utils()).filterObject)({
        mainFile: obj.mainFile,
        files: obj.files,
        compiler: obj.compiler,
        tester: obj.tester,
        log: obj.log,
        dependencies: getDependencies(obj.dependencies),
        devDependencies: getDependencies(obj.devDependencies),
        packageDependencies: obj.packageDependencies,
        devPackageDependencies: obj.devPackageDependencies,
        peerPackageDependencies: obj.peerPackageDependencies,
        envsPackageDependencies: obj.envsPackageDependencies,
        bindingPrefix: obj.bindingPrefix
      }, filterFunction));
    }
  }, {
    key: 'getAllFlattenedDependencies',
    value: function getAllFlattenedDependencies() {
      return this.flattenedDependencies.concat(this.flattenedDevDependencies);
    }
  }, {
    key: 'getAllDependencies',
    value: function getAllDependencies() {
      return this.dependencies.dependencies.concat(this.devDependencies.dependencies);
    }
  }, {
    key: 'collectDependencies',
    value: function collectDependencies(scope, withEnvironments) {
      var dev = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

      var envDependencies = [this.compiler, this.tester];
      var flattenedDependencies = dev ? this.flattenedDevDependencies : this.flattenedDependencies;
      var dependencies = withEnvironments ? flattenedDependencies.concat(envDependencies) : flattenedDependencies;
      var allDependencies = dependencies.concat(this.flattenedDevDependencies);
      return scope.importManyOnes(allDependencies);
    }
  }, {
    key: 'refs',
    value: function refs() {
      var extractRefsFromFiles = function extractRefsFromFiles(files) {
        var refs = files ? files.map(function (file) {
          return file.file;
        }) : [];
        return refs;
      };
      var files = extractRefsFromFiles(this.files);
      var dists = extractRefsFromFiles(this.dists);
      var compilerFiles = this.compiler ? extractRefsFromFiles(this.compiler.files) : [];
      var testerFiles = this.tester ? extractRefsFromFiles(this.tester.files) : [];
      return [].concat(_toConsumableArray(dists), _toConsumableArray(files), _toConsumableArray(compilerFiles), _toConsumableArray(testerFiles)).filter(function (ref) {
        return ref;
      });
    }
  }, {
    key: 'toObject',
    value: function toObject() {
      var _convertFileToObject = function _convertFileToObject(file) {
        return {
          file: file.file.toString(),
          relativePath: file.relativePath,
          name: file.name,
          test: file.test
        };
      };

      var _convertEnvToObject = function _convertEnvToObject(env) {
        if (typeof env === 'string') {
          return env;
        }
        // Store the env as string in case there is no config and files (for backward compatibility)
        if (envNameOnly(env)) {
          return env.name;
        }
        var result = {
          name: env.name,
          config: env.config,
          files: []
        };
        if (env.files && !(_ramda || _load_ramda()).default.isEmpty(env.files)) {
          result.files = env.files.map((_extensionFile || _load_extensionFile()).default.fromModelObjectToObject);
        }
        return result;
      };

      return (0, (_utils || _load_utils()).filterObject)({
        files: this.files ? this.files.map(_convertFileToObject) : null,
        mainFile: this.mainFile,
        dists: this.dists ? this.dists.map(_convertFileToObject) : null,
        compiler: this.compiler ? _convertEnvToObject(this.compiler) : null,
        bindingPrefix: this.bindingPrefix || (_constants || _load_constants()).DEFAULT_BINDINGS_PREFIX,
        tester: this.tester ? _convertEnvToObject(this.tester) : null,
        log: {
          message: this.log.message,
          date: this.log.date,
          username: this.log.username,
          email: this.log.email
        },
        ci: this.ci,
        specsResults: this.specsResults,
        docs: this.docs,
        dependencies: this.dependencies.cloneAsString(),
        devDependencies: this.devDependencies.cloneAsString(),
        flattenedDependencies: this.flattenedDependencies.map(function (dep) {
          return dep.toString();
        }),
        flattenedDevDependencies: this.flattenedDevDependencies.map(function (dep) {
          return dep.toString();
        }),
        packageDependencies: this.packageDependencies,
        devPackageDependencies: this.devPackageDependencies,
        peerPackageDependencies: this.peerPackageDependencies,
        envsPackageDependencies: this.envsPackageDependencies,
        customResolvedPaths: this.customResolvedPaths
      }, function (val) {
        return !!val;
      });
    }
  }, {
    key: 'validateBeforePersisting',
    value: function validateBeforePersisting(versionStr) {
      (_logger || _load_logger()).default.debug('validating version object: ', this.hash().hash);
      var version = Version.parse(versionStr);
      version.validate();
    }
  }, {
    key: 'toBuffer',
    value: function toBuffer(pretty) {
      var obj = this.toObject();
      var args = (0, (_utils || _load_utils()).getStringifyArgs)(pretty);
      var str = JSON.stringify.apply(JSON, [obj].concat(_toConsumableArray(args)));
      if (this.validateBeforePersist) this.validateBeforePersisting(str);
      return (0, (_utils || _load_utils()).bufferFrom)(str);
    }

    /**
     * used by the super class BitObject
     */

  }, {
    key: 'setSpecsResults',
    value: function setSpecsResults(specsResults) {
      this.specsResults = specsResults;
    }
  }, {
    key: 'setDist',
    value: function setDist(dist) {
      this.dist = dist ? {
        file: dist.hash(),
        name: (_constants || _load_constants()).DEFAULT_BUNDLE_FILENAME
      } : null;
    }
  }, {
    key: 'setCIProps',
    value: function setCIProps(ci) {
      this.ci = ci;
    }
  }, {
    key: 'modelFilesToSourceFiles',
    value: function modelFilesToSourceFiles(repository) {
      return Promise.all(this.files.map(function (file) {
        return (_sources || _load_sources()).SourceFile.loadFromSourceFileModel(file, repository);
      }));
    }
    /**
     * Validate the version model properties, to make sure we are not inserting something
     * in the wrong format
     */

  }, {
    key: 'validate',
    value: function validate() {
      var _this3 = this;

      var message = 'unable to save Version object';
      var validateBitIdStr = function validateBitIdStr(bitIdStr, field) {
        var validateVersion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

        (0, (_validateType || _load_validateType()).default)(message, bitIdStr, field, 'string');
        var bitId = void 0;
        try {
          bitId = (_bitId || _load_bitId()).BitId.parse(bitIdStr);
        } catch (err) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} has an invalid Bit id`);
        }
        if (validateVersion && !bitId.hasVersion()) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${bitIdStr} does not have a version`);
        }
        if (!bitId.scope) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${bitIdStr} does not have a scope`);
      };
      var _validateEnv = function _validateEnv(env) {
        if (!env) return;
        if (typeof env === 'string') {
          // Do not validate version - for backward compatibility
          validateBitIdStr(env, 'environment-id', false);
          return;
        }
        (0, (_validateType || _load_validateType()).default)(message, env, 'env', 'object');
        if (!env.name) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the environment is missing the name attribute`);
        }
        validateBitIdStr(env.name, 'env.name');
        if (env.files) {
          var compilerName = env.name || '';
          env.files.forEach(function (file) {
            if (!file.name) {
              throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the environment ${compilerName} has a file which missing the name attribute`);
            }
          });
        }
      };

      /**
       * Validate that the package name and version are valid
       * @param {*} packageName
       * @param {*} packageVersion
       */
      var _validatePackageDependency = function _validatePackageDependency(packageVersion, packageName) {
        var packageNameValidateResult = (0, (_validateNpmPackageName || _load_validateNpmPackageName()).default)(packageName);
        if (!packageNameValidateResult.validForNewPackages && !packageNameValidateResult.validForOldPackages) {
          var errors = packageNameValidateResult.errors || [];
          throw new (_versionInvalid || _load_versionInvalid()).default(`${packageName} is invalid package name, errors:  ${errors.join()}`);
        }
        // don't use semver.valid and semver.validRange to validate the package version because it
        // can be also a URL, Git URL or Github URL. see here: https://docs.npmjs.com/files/package.json#dependencies
        (0, (_validateType || _load_validateType()).default)(message, packageVersion, `version of "${packageName}"`, 'string');
      };
      var _validatePackageDependencies = function _validatePackageDependencies(packageDependencies) {
        (0, (_validateType || _load_validateType()).default)(message, packageDependencies, 'packageDependencies', 'object');
        (_ramda || _load_ramda()).default.forEachObjIndexed(_validatePackageDependency, packageDependencies);
      };
      var validateFile = function validateFile(file) {
        var isDist = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

        var field = isDist ? 'dist-file' : 'file';
        (0, (_validateType || _load_validateType()).default)(message, file, field, 'object');
        if (!(0, (_utils || _load_utils()).isValidPath)(file.relativePath)) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is invalid`);
        }
        if (!file.name) {
          throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is missing the name attribute`);
        }
        if (!file.file) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the ${field} ${file.relativePath} is missing the hash`);
        (0, (_validateType || _load_validateType()).default)(message, file.name, `${field}.name`, 'string');
        (0, (_validateType || _load_validateType()).default)(message, file.file, `${field}.file`, 'object');
        (0, (_validateType || _load_validateType()).default)(message, file.file.hash, `${field}.file.hash`, 'string');
      };

      if (!this.mainFile) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the mainFile is missing`);
      if (!(0, (_utils || _load_utils()).isValidPath)(this.mainFile)) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the mainFile ${this.mainFile} is invalid`);
      if (!this.files || !this.files.length) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the files are missing`);
      var foundMainFile = false;
      (0, (_validateType || _load_validateType()).default)(message, this.files, 'files', 'array');
      var filesPaths = [];
      this.files.forEach(function (file) {
        validateFile(file);
        filesPaths.push(file.relativePath);
        if (file.relativePath === _this3.mainFile) foundMainFile = true;
      });
      if (!foundMainFile) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, unable to find the mainFile ${this.mainFile} in the files list`);
      }
      var duplicateFiles = filesPaths.filter(function (file) {
        return filesPaths.filter(function (f) {
          return file.toLowerCase() === f.toLowerCase();
        }).length > 1;
      });
      if (duplicateFiles.length) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message} the following files are duplicated ${duplicateFiles.join(', ')}`);
      }
      _validateEnv(this.compiler);
      _validateEnv(this.tester);
      _validatePackageDependencies(this.packageDependencies);
      _validatePackageDependencies(this.devPackageDependencies);
      _validatePackageDependencies(this.peerPackageDependencies);
      _validatePackageDependencies(this.envsPackageDependencies);
      if (this.dists && this.dists.length) {
        (0, (_validateType || _load_validateType()).default)(message, this.dists, 'dist', 'array');
        // $FlowFixMe
        this.dists.forEach(function (file) {
          validateFile(file, true);
        });
      }
      if (!(this.dependencies instanceof (_dependencies || _load_dependencies()).Dependencies)) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, dependencies must be an instance of Dependencies, got ${typeof this.dependencies}`);
      }
      if (!(this.devDependencies instanceof (_dependencies || _load_dependencies()).Dependencies)) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, devDependencies must be an instance of Dependencies, got ${typeof this.devDependencies}`);
      }
      this.dependencies.validate();
      this.devDependencies.validate();
      if (!this.dependencies.isEmpty() && !this.flattenedDependencies.length) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has dependencies but its flattenedDependencies is empty`);
      }
      if (!this.devDependencies.isEmpty() && !this.flattenedDevDependencies.length) {
        throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, it has devDependencies but its flattenedDevDependencies is empty`);
      }
      var validateFlattenedDependencies = function validateFlattenedDependencies(dependencies) {
        (0, (_validateType || _load_validateType()).default)(message, dependencies, 'dependencies', 'array');
        dependencies.forEach(function (dependency) {
          if (!(dependency instanceof (_bitId || _load_bitId()).BitId)) {
            throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, a flattenedDependency expected to be BitId, got ${typeof dependency}`);
          }
          if (!dependency.hasVersion()) {
            throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the flattenedDependency ${dependency.toString()} does not have a version`);
          }
        });
      };
      validateFlattenedDependencies(this.flattenedDependencies);
      validateFlattenedDependencies(this.flattenedDevDependencies);
      if (!this.log) throw new (_versionInvalid || _load_versionInvalid()).default(`${message}, the log object is missing`);
      (0, (_validateType || _load_validateType()).default)(message, this.log, 'log', 'object');
      if (this.bindingPrefix) {
        (0, (_validateType || _load_validateType()).default)(message, this.bindingPrefix, 'bindingPrefix', 'string');
      }
    }
  }], [{
    key: 'parse',
    value: function parse(contents) {
      var _JSON$parse = JSON.parse(contents),
          mainFile = _JSON$parse.mainFile,
          dists = _JSON$parse.dists,
          files = _JSON$parse.files,
          compiler = _JSON$parse.compiler,
          bindingPrefix = _JSON$parse.bindingPrefix,
          tester = _JSON$parse.tester,
          log = _JSON$parse.log,
          docs = _JSON$parse.docs,
          ci = _JSON$parse.ci,
          specsResults = _JSON$parse.specsResults,
          dependencies = _JSON$parse.dependencies,
          flattenedDependencies = _JSON$parse.flattenedDependencies,
          devDependencies = _JSON$parse.devDependencies,
          flattenedDevDependencies = _JSON$parse.flattenedDevDependencies,
          devPackageDependencies = _JSON$parse.devPackageDependencies,
          peerPackageDependencies = _JSON$parse.peerPackageDependencies,
          envsPackageDependencies = _JSON$parse.envsPackageDependencies,
          packageDependencies = _JSON$parse.packageDependencies,
          customResolvedPaths = _JSON$parse.customResolvedPaths;

      var _getDependencies = function _getDependencies() {
        var deps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];

        if (deps.length && (_ramda || _load_ramda()).default.is(String, (0, (_utils || _load_utils()).first)(deps))) {
          // backward compatibility
          return deps.map(function (dependency) {
            return { id: (_bitId || _load_bitId()).BitId.parse(dependency) };
          });
        }

        var getRelativePath = function getRelativePath(relativePath) {
          if (relativePath.importSpecifiers) {
            // backward compatibility. Before the massive validation was added, an item of
            // relativePath.importSpecifiers array could be missing the mainFile property, which is
            // an invalid ImportSpecifier. (instead the mainFile it had another importSpecifiers object).
            relativePath.importSpecifiers = relativePath.importSpecifiers.filter(function (importSpecifier) {
              return importSpecifier.mainFile;
            });
            if (!relativePath.importSpecifiers.length) delete relativePath.importSpecifiers;
          }

          return relativePath;
        };

        return deps.map(function (dependency) {
          return {
            id: (_bitId || _load_bitId()).BitId.parse(dependency.id),
            relativePaths: Array.isArray(dependency.relativePaths) ? dependency.relativePaths.map(getRelativePath) : dependency.relativePaths
          };
        });
      };

      var parseFile = function parseFile(file) {
        return {
          file: (_objects || _load_objects()).Ref.from(file.file),
          relativePath: file.relativePath,
          name: file.name,
          test: file.test
        };
      };

      return new Version({
        mainFile,
        files: files ? files.map(parseFile) : null,
        dists: dists ? dists.map(parseFile) : null,
        compiler: compiler ? parseEnv(compiler) : null,
        bindingPrefix: bindingPrefix || null,
        tester: tester ? parseEnv(tester) : null,
        log: {
          message: log.message,
          date: log.date,
          username: log.username,
          email: log.email
        },
        ci,
        specsResults,
        docs,
        dependencies: _getDependencies(dependencies),
        flattenedDependencies: (_bitId || _load_bitId()).BitIds.deserialize(flattenedDependencies),
        devDependencies: _getDependencies(devDependencies),
        flattenedDevDependencies: (_bitId || _load_bitId()).BitIds.deserialize(flattenedDevDependencies),
        devPackageDependencies,
        peerPackageDependencies,
        envsPackageDependencies,
        packageDependencies,
        customResolvedPaths
      });
    }

    /**
     * used by raw-object.toRealObject()
     */

  }, {
    key: 'from',
    value: function from(versionProps) {
      var compiler = versionProps.compiler ? parseEnv(versionProps.compiler) : null;
      var tester = versionProps.tester ? parseEnv(versionProps.tester) : null;
      var actualVersionProps = _extends({}, versionProps, { compiler, tester });
      return new Version(actualVersionProps);
    }

    /**
     * Create version model object from consumer component
     * @param {*} param0
     */

  }, {
    key: 'fromComponent',
    value: function fromComponent(_ref2) {
      var component = _ref2.component,
          files = _ref2.files,
          dists = _ref2.dists,
          flattenedDependencies = _ref2.flattenedDependencies,
          flattenedDevDependencies = _ref2.flattenedDevDependencies,
          message = _ref2.message,
          specsResults = _ref2.specsResults,
          username = _ref2.username,
          email = _ref2.email;

      var parseFile = function parseFile(file) {
        return {
          file: file.file.hash(),
          relativePath: file.relativePath,
          name: file.name,
          test: file.test
        };
      };

      var mergePackageDependencies = function mergePackageDependencies() {
        var envsPackageDependencies = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var compilerDynamicPakageDependencies = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        var testerDynamicPakageDependencies = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

        return _extends({}, envsPackageDependencies, testerDynamicPakageDependencies, compilerDynamicPakageDependencies);
      };

      var compilerDynamicPakageDependencies = component.compiler ? component.compiler.dynamicPackageDependencies : undefined;
      var testerDynamicPakageDependencies = component.tester ? component.tester.dynamicPackageDependencies : undefined;

      return new Version({
        mainFile: component.mainFile,
        files: files ? files.map(parseFile) : null,
        dists: dists ? dists.map(parseFile) : null,
        compiler: component.compiler ? component.compiler.toModelObject() : undefined,
        bindingPrefix: component.bindingPrefix,
        tester: component.tester ? component.tester.toModelObject() : undefined,
        log: {
          message,
          username,
          email,
          date: Date.now().toString()
        },
        specsResults,
        docs: component.docs,
        packageDependencies: component.packageDependencies,
        devPackageDependencies: component.devPackageDependencies,
        peerPackageDependencies: component.peerPackageDependencies,
        envsPackageDependencies: mergePackageDependencies(component.envsPackageDependencies, compilerDynamicPakageDependencies, testerDynamicPakageDependencies),
        flattenedDependencies,
        flattenedDevDependencies,
        dependencies: component.dependencies.get(),
        devDependencies: component.devDependencies.get(),
        customResolvedPaths: component.customResolvedPaths
      });
    }
  }]);

  return Version;
}((_objects || _load_objects()).BitObject);

exports.default = Version;


var parseEnv = function parseEnv(env) {
  if (typeof env === 'string') {
    return env;
  }
  // Store the env as string in case there is no config and files (for backward compatibility)
  if (envNameOnly(env)) {
    return env.name;
  }
  return {
    name: env.name,
    config: env.config,
    files: env.files ? env.files.map((_extensionFile || _load_extensionFile()).default.fromObjectToModelObject) : []
  };
};

var envNameOnly = function envNameOnly(env) {
  if ((!env.config || (_ramda || _load_ramda()).default.isEmpty(env.config)) && (!env.files || (_ramda || _load_ramda()).default.isEmpty(env.files))) {
    return true;
  }
  return false;
};