bit-bin
Version:
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="apache" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> <a href="https://github.com/teambit/bit/blob/master/CONTRIBUTING.md"><img alt="prs" src="https://img.shields.io/b
782 lines (609 loc) • 24.2 kB
JavaScript
"use strict";
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _bluebird() {
const data = require("bluebird");
_bluebird = function () {
return data;
};
return data;
}
function _defineProperty2() {
const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
_defineProperty2 = function () {
return data;
};
return data;
}
function semver() {
const data = _interopRequireWildcard(require("semver"));
semver = function () {
return data;
};
return data;
}
function _ramda() {
const data = require("ramda");
_ramda = function () {
return data;
};
return data;
}
function _objects() {
const data = require("../objects");
_objects = function () {
return data;
};
return data;
}
function _scopeMeta() {
const data = _interopRequireDefault(require("./scopeMeta"));
_scopeMeta = function () {
return data;
};
return data;
}
function _exceptions() {
const data = require("../exceptions");
_exceptions = function () {
return data;
};
return data;
}
function _utils() {
const data = require("../../utils");
_utils = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../../constants");
_constants = function () {
return data;
};
return data;
}
function _bitId() {
const data = _interopRequireDefault(require("../../bit-id/bit-id"));
_bitId = function () {
return data;
};
return data;
}
function _component() {
const data = _interopRequireDefault(require("../../consumer/component"));
_component = function () {
return data;
};
return data;
}
function _componentVersion() {
const data = _interopRequireDefault(require("../component-version"));
_componentVersion = function () {
return data;
};
return data;
}
function _sources() {
const data = require("../../consumer/component/sources");
_sources = function () {
return data;
};
return data;
}
function _componentObjects() {
const data = _interopRequireDefault(require("../component-objects"));
_componentObjects = function () {
return data;
};
return data;
}
function _specsResults() {
const data = _interopRequireDefault(require("../../consumer/specs-results"));
_specsResults = function () {
return data;
};
return data;
}
function _logger() {
const data = _interopRequireDefault(require("../../logger/logger"));
_logger = function () {
return data;
};
return data;
}
function _generalError() {
const data = _interopRequireDefault(require("../../error/general-error"));
_generalError = function () {
return data;
};
return data;
}
function _versionParser() {
const data = _interopRequireDefault(require("../../version/version-parser"));
_versionParser = function () {
return data;
};
return data;
}
function _componentOverrides() {
const data = _interopRequireDefault(require("../../consumer/config/component-overrides"));
_componentOverrides = function () {
return data;
};
return data;
}
function _envFactory() {
const data = require("../../legacy-extensions/env-factory");
_envFactory = function () {
return data;
};
return data;
}
function _showDoctorError() {
const data = _interopRequireDefault(require("../../error/show-doctor-error"));
_showDoctorError = function () {
return data;
};
return data;
}
function _validationError() {
const data = _interopRequireDefault(require("../../error/validation-error"));
_validationError = function () {
return data;
};
return data;
}
function _artifact() {
const data = require("../../consumer/component/sources/artifact");
_artifact = function () {
return data;
};
return data;
}
const VERSION_ZERO = '0.0.0';
/**
* we can't rename the class as ModelComponent because old components are already saved in the model
* with 'Component' in their headers. see object-registrar.types()
*/
// TODO: FIX me .parser
// @ts-ignore
class Component extends _objects().BitObject {
constructor(props) {
super();
(0, _defineProperty2().default)(this, "scope", void 0);
(0, _defineProperty2().default)(this, "name", void 0);
(0, _defineProperty2().default)(this, "versions", void 0);
(0, _defineProperty2().default)(this, "lang", void 0);
(0, _defineProperty2().default)(this, "deprecated", void 0);
(0, _defineProperty2().default)(this, "bindingPrefix", void 0);
(0, _defineProperty2().default)(this, "local", void 0);
(0, _defineProperty2().default)(this, "state", void 0);
(0, _defineProperty2().default)(this, "scopesList", void 0);
if (!props.name) throw new TypeError('Model Component constructor expects to get a name parameter');
this.scope = props.scope || null;
this.name = props.name;
this.versions = props.versions || {};
this.lang = props.lang || _constants().DEFAULT_LANGUAGE;
this.deprecated = props.deprecated || false;
this.bindingPrefix = props.bindingPrefix || _constants().DEFAULT_BINDINGS_PREFIX;
this.local = props.local;
this.state = props.state || {};
this.scopesList = props.scopesList || [];
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
get versionArray() {
return Object.values(this.versions);
}
listVersions(sort) {
const versions = Object.keys(this.versions);
if (!sort) return versions;
if (sort === 'ASC') {
return versions.sort(semver().compare);
}
return versions.sort(semver().compare).reverse();
}
hasVersion(version) {
return Boolean(this.versions[version]);
}
/**
* add a new remote if it is not there already
*/
addScopeListItem(scopeListItem) {
if (!scopeListItem.name || !scopeListItem.url || !scopeListItem.date) {
throw new TypeError(`model-component.addRemote get an invalid remote. name: ${scopeListItem.name}, url: ${scopeListItem.url}, date: ${scopeListItem.date}`);
}
if (!this.scopesList.find(r => r.url === scopeListItem.url)) {
this.scopesList.push(scopeListItem);
}
}
/**
* returns only the versions that exist in both components (regardless whether the hash are the same)
* e.g. this.component = [0.0.1, 0.0.2, 0.0.3], other component = [0.0.3, 0.0.4]. it returns only [0.0.3].
* also, in case it is coming from 'bit import', the version must be locally changed.
* otherwise, it doesn't matter whether the hashes are different.
*/
_getComparableVersionsObjects(otherComponent, // in case of merging, the otherComponent is the existing component, and "this" is the incoming component
local) {
const otherLocalVersion = otherComponent.getLocalVersions();
const otherComponentVersions = (0, _utils().filterObject)(otherComponent.versions, (val, key) => Object.keys(this.versions).includes(key) && (!local || otherLocalVersion.includes(key)));
const thisComponentVersions = (0, _utils().filterObject)(this.versions, (val, key) => Object.keys(otherComponentVersions).includes(key) && (!local || otherLocalVersion.includes(key)));
return {
thisComponentVersions,
otherComponentVersions
};
}
compatibleWith(component, local) {
const {
thisComponentVersions,
otherComponentVersions
} = this._getComparableVersionsObjects(component, local);
return (0, _ramda().equals)(thisComponentVersions, otherComponentVersions);
}
diffWith(component, local) {
const {
thisComponentVersions,
otherComponentVersions
} = this._getComparableVersionsObjects(component, local);
return Object.keys(thisComponentVersions).filter(version => thisComponentVersions[version].hash !== otherComponentVersions[version].hash);
}
latest() {
if ((0, _utils().empty)(this.versions)) return VERSION_ZERO; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return semver().maxSatisfying(this.listVersions(), '*');
}
/**
* Return the lateset version which actuall exists in the scope
* (exists means the object itself exists)
* This relevant for cases when the component version array has few versions
* but we don't have all the refs in the object
*
* @returns {number}
* @memberof Component
*/
latestExisting(repository) {
if ((0, _utils().empty)(this.versions)) return VERSION_ZERO;
const versions = this.listVersions('ASC');
let version = null;
let versionStr = null;
while (!version && versions && versions.length) {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
versionStr = versions.pop(); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
version = this.loadVersionSync(versionStr, repository, false);
}
return versionStr || VERSION_ZERO;
}
collectLogs(repo) {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const versions = yield repo.findMany(_this.versionArray);
const logValues = versions.map(version => version ? version.log : {
message: '<no-data-available>'
});
const indexedLogs = (0, _ramda().fromPairs)((0, _ramda().zip)((0, _ramda().keys)(_this.versions), logValues));
return indexedLogs;
})();
}
/**
* when bitMap is passed, it got called from the consumer and as such it strips the sharedDir
*/
collectVersions(repo) {
return Promise.all(this.listVersions().map(versionNum => {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return this.toConsumerComponent(versionNum, this.scope, repo);
}));
}
/**
* if exactVersion is defined, add exact version instead of using the semver mechanism
*/
getVersionToAdd(releaseType = _constants().DEFAULT_BIT_RELEASE_TYPE, exactVersion) {
if (exactVersion && this.versions[exactVersion]) {
throw new (_exceptions().VersionAlreadyExists)(exactVersion, this.id());
}
return exactVersion || this.version(releaseType);
}
addVersion(version, versionToAdd) {
this.versions[versionToAdd] = version.hash();
this.markVersionAsLocal(versionToAdd);
return versionToAdd;
}
version(releaseType = _constants().DEFAULT_BIT_RELEASE_TYPE) {
const latest = this.latest(); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (latest) return semver().inc(latest, releaseType);
return _constants().DEFAULT_BIT_VERSION;
}
id() {
return this.scope ? [this.scope, this.name].join('/') : this.name;
}
toBitId() {
return new (_bitId().default)({
scope: this.scope,
name: this.name
});
}
toBitIdWithLatestVersion() {
return new (_bitId().default)({
scope: this.scope,
name: this.name,
version: this.latest()
});
}
toBitIdWithLatestVersionAllowNull() {
const id = this.toBitIdWithLatestVersion();
return id.version === VERSION_ZERO ? id.changeVersion(undefined) : id;
}
toObject() {
function versions(vers) {
const obj = {};
(0, _utils().forEach)(vers, (ref, version) => {
obj[version] = ref.toString();
});
return obj;
}
const componentObject = {
name: this.name,
scope: this.scope,
versions: versions(this.versions),
lang: this.lang,
deprecated: this.deprecated,
bindingPrefix: this.bindingPrefix,
remotes: this.scopesList
}; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (this.local) componentObject.local = this.local; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (!(0, _ramda().isEmpty)(this.state)) componentObject.state = this.state;
return componentObject;
}
loadVersion(version, repository) {
var _this2 = this;
return (0, _bluebird().coroutine)(function* () {
const versionRef = _this2.versions[version];
if (!versionRef) throw new (_exceptions().VersionNotFound)(version); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return versionRef.load(repository);
})();
}
loadVersionSync(version, repository, throws = true) {
const versionRef = this.versions[version];
if (!versionRef) throw new (_exceptions().VersionNotFound)(version); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return versionRef.loadSync(repository, throws);
}
collectVersionsObjects(repo, versions) {
var _this3 = this;
return (0, _bluebird().coroutine)(function* () {
const collectRefs = /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* () {
const refsCollection = [];
function addRefs(_x) {
return _addRefs.apply(this, arguments);
}
function _addRefs() {
_addRefs = (0, _bluebird().coroutine)(function* (object) {
const refs = object.refs();
const objs = yield Promise.all(refs.map(ref => ref.load(repo, true)));
refsCollection.push(...refs);
yield Promise.all(objs.map(obj => addRefs(obj)));
});
return _addRefs.apply(this, arguments);
}
const versionsRefs = versions.map(version => _this3.versions[version]);
refsCollection.push(...versionsRefs);
const versionsObjects = yield Promise.all(versions.map(version => _this3.versions[version].load(repo)));
yield Promise.all(versionsObjects.map(versionObject => addRefs(versionObject)));
return refsCollection;
});
return function collectRefs() {
return _ref.apply(this, arguments);
};
}();
const refs = yield collectRefs();
return Promise.all(refs.map(ref => ref.loadRaw(repo)));
})();
}
collectObjects(repo) {
return Promise.all([this.asRaw(repo), this.collectRaw(repo)]).then(([rawComponent, objects]) => new (_componentObjects().default)(rawComponent, objects)).catch(err => {
if (err.code === 'ENOENT') {
throw new Error(`fatal: an object of "${this.id()}" was not found at ${err.path}\nplease try to re-import the component`);
}
throw err;
});
}
/**
* to delete a version from a component, don't call this method directly. Instead, use sources.removeVersion()
*/
removeVersion(version) {
const objectRef = this.versions[version];
delete this.versions[version];
if (this.state.versions && this.state.versions[version]) delete this.state.versions[version];
return objectRef;
}
toComponentVersion(versionStr) {
const versionNum = (0, _versionParser().default)(versionStr).resolve(this.listVersions()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (!this.versions[versionNum]) {
throw new (_showDoctorError().default)(`the version ${versionNum} does not exist in ${this.listVersions().join('\n')}, versions array`);
} // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return new (_componentVersion().default)(this, versionNum);
}
/**
* convert a ModelComponent of a specific version to ConsumerComponent
* when it's being called from the Consumer, some manipulation are done on the component, such
* as stripping the originallySharedDir and adding wrapDir.
* when it's being called from the Scope, no manipulations are done.
*
* @see sources.consumerComponentToVersion() for the opposite action.
*/
toConsumerComponent(versionStr, scopeName, repository, manipulateDirData) {
var _this4 = this;
return (0, _bluebird().coroutine)(function* () {
_logger().default.debug(`model-component, converting ${_this4.id()}, version: ${versionStr} to ConsumerComponent`);
const componentVersion = _this4.toComponentVersion(versionStr);
const version = yield componentVersion.getVersion(repository);
const loadFileInstance = ClassName => /*#__PURE__*/function () {
var _ref2 = (0, _bluebird().coroutine)(function* (file) {
const loadP = file.file.load(repository);
const content = yield loadP;
if (!content) throw new (_showDoctorError().default)(`failed loading file ${file.relativePath} from the model`);
return new ClassName({
base: '.',
path: file.relativePath,
contents: content.contents,
test: file.test
});
});
return function (_x2) {
return _ref2.apply(this, arguments);
};
}();
const filesP = version.files ? Promise.all(version.files.map(loadFileInstance(_sources().SourceFile))) : null;
const distsP = version.dists ? Promise.all(version.dists.map(loadFileInstance(_sources().Dist))) : null;
const scopeMetaP = scopeName ? _scopeMeta().default.fromScopeName(scopeName).load(repository) : Promise.resolve();
const log = version.log || null; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const compilerP = (0, _envFactory().makeEnvFromModel)(_constants().COMPILER_ENV_TYPE, version.compiler, repository); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const testerP = (0, _envFactory().makeEnvFromModel)(_constants().TESTER_ENV_TYPE, version.tester, repository); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const [files, dists, scopeMeta, compiler, tester] = yield Promise.all([filesP, distsP, scopeMetaP, compilerP, testerP]);
const extensions = version.extensions.clone();
yield Promise.all(extensions.map( /*#__PURE__*/function () {
var _ref3 = (0, _bluebird().coroutine)(function* (extension) {
extension.artifacts = yield Promise.all(extension.artifacts.map(loadFileInstance(_artifact().Artifact)));
});
return function (_x3) {
return _ref3.apply(this, arguments);
};
}()));
const bindingPrefix = _this4.bindingPrefix === 'bit' ? '@bit' : _this4.bindingPrefix; // when generating a new ConsumerComponent out of Version, it is critical to make sure that
// all objects are cloned and not copied by reference. Otherwise, every time the
// ConsumerComponent instance is changed, the Version will be changed as well, and since
// the Version instance is saved in the Repository._cache, the next time a Version instance
// is retrieved, it'll be different than the first time.
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
const consumerComponent = new (_component().default)({
name: _this4.name,
version: componentVersion.version,
scope: _this4.scope,
lang: _this4.lang,
bindingPrefix,
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
mainFile: version.mainFile || null,
compiler,
tester,
dependencies: version.dependencies.getClone(),
devDependencies: version.devDependencies.getClone(),
flattenedDependencies: version.flattenedDependencies.clone(),
flattenedDevDependencies: version.flattenedDevDependencies.clone(),
packageDependencies: (0, _ramda().clone)(version.packageDependencies),
devPackageDependencies: (0, _ramda().clone)(version.devPackageDependencies),
peerPackageDependencies: (0, _ramda().clone)(version.peerPackageDependencies),
compilerPackageDependencies: (0, _ramda().clone)(version.compilerPackageDependencies),
testerPackageDependencies: (0, _ramda().clone)(version.testerPackageDependencies),
files,
dists,
mainDistFile: version.mainDistFile,
docs: version.docs,
license: scopeMeta ? _sources().License.deserialize(scopeMeta.license) : undefined,
// todo: make sure we have license in case of local scope
// @ts-ignore
specsResults: version.specsResults ? version.specsResults.map(res => _specsResults().default.deserialize(res)) : null,
log,
customResolvedPaths: (0, _ramda().clone)(version.customResolvedPaths),
overrides: _componentOverrides().default.loadFromScope(version.overrides),
packageJsonChangedProps: (0, _ramda().clone)(version.packageJsonChangedProps),
deprecated: _this4.deprecated,
scopesList: (0, _ramda().clone)(_this4.scopesList),
extensions
});
if (manipulateDirData) {
consumerComponent.stripOriginallySharedDir(manipulateDirData);
consumerComponent.addWrapperDir(manipulateDirData);
}
return consumerComponent;
})();
}
refs() {
return Object.values(this.versions);
}
replaceRef(oldRef, newRef) {
const replace = (value, key) => {
if (value === oldRef.hash) {
// @ts-ignore
this.versions[key] = newRef.hash;
}
};
(0, _ramda().forEachObjIndexed)(replace, this.versions);
}
validateBeforePersisting(componentStr) {
_logger().default.silly(`validating component object: ${this.hash().hash} ${this.id()}`);
const component = Component.parse(componentStr);
component.validate();
}
toBuffer(pretty) {
const args = (0, _utils().getStringifyArgs)(pretty);
const obj = this.toObject();
const str = JSON.stringify(obj, ...args);
if (this.validateBeforePersist) this.validateBeforePersisting(str);
return Buffer.from(str);
}
/**
* Clear data that is relevant only for the local scope and should not be moved to the remote scope
*/
clearStateData() {
this.local = false; // backward compatibility for components created before 0.12.6
this.state = {};
}
markVersionAsLocal(version) {
if (!this.state.versions) this.state = {
versions: {}
}; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
if (!this.state.versions[version]) this.state.versions[version] = {}; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
this.state.versions[version].local = true;
}
getLocalVersions() {
if ((0, _ramda().isEmpty)(this.state) || (0, _ramda().isEmpty)(this.state.versions)) return []; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return Object.keys(this.state.versions).filter(version => this.state.versions[version].local);
}
isLocallyChanged() {
if (this.local) return true; // backward compatibility for components created before 0.12.6
if ((0, _ramda().isEmpty)(this.state) || (0, _ramda().isEmpty)(this.state.versions)) return false;
const localVersions = this.getLocalVersions();
return localVersions.length > 0;
}
static parse(contents) {
const rawComponent = JSON.parse(contents);
return Component.from({
name: rawComponent.box ? `${rawComponent.box}/${rawComponent.name}` : rawComponent.name,
scope: rawComponent.scope,
versions: (0, _utils().mapObject)(rawComponent.versions, val => _objects().Ref.from(val)),
lang: rawComponent.lang,
deprecated: rawComponent.deprecated,
bindingPrefix: rawComponent.bindingPrefix,
local: rawComponent.local,
state: rawComponent.state,
scopesList: rawComponent.remotes
});
}
static from(props) {
return new Component(props);
}
static fromBitId(bitId) {
if (bitId.box) throw new Error('component.fromBitId, bitId should not have the "box" property populated'); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return new Component({
name: bitId.name,
scope: bitId.scope
});
}
validate() {
const message = `unable to save Component object "${this.id()}"`;
if (!this.name) throw new (_generalError().default)(`${message} the name is missing`);
if (this.state && this.state.versions) {
Object.keys(this.state.versions).forEach(version => {
if (!this.versions[version]) {
throw new (_validationError().default)(`${message}, the version ${version} is marked as staged but is not available`);
}
});
}
}
}
exports.default = Component;