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
430 lines (334 loc) • 10.4 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 _defineProperty2() {
const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
_defineProperty2 = function () {
return data;
};
return data;
}
function path() {
const data = _interopRequireWildcard(require("path"));
path = function () {
return data;
};
return data;
}
function semver() {
const data = _interopRequireWildcard(require("semver"));
semver = function () {
return data;
};
return data;
}
function _decamelize() {
const data = _interopRequireDefault(require("decamelize"));
_decamelize = function () {
return data;
};
return data;
}
function _ramda() {
const data = _interopRequireDefault(require("ramda"));
_ramda = function () {
return data;
};
return data;
}
function _exceptions() {
const data = require("./exceptions");
_exceptions = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../constants");
_constants = function () {
return data;
};
return data;
}
function _isValidIdChunk() {
const data = _interopRequireDefault(require("../utils/is-valid-id-chunk"));
_isValidIdChunk = function () {
return data;
};
return data;
}
function _isValidScopeName() {
const data = _interopRequireDefault(require("../utils/is-valid-scope-name"));
_isValidScopeName = 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;
}
class BitId {
constructor({
scope,
box,
name,
version
}) {
(0, _defineProperty2().default)(this, "scope", void 0);
(0, _defineProperty2().default)(this, "box", void 0);
(0, _defineProperty2().default)(this, "name", void 0);
(0, _defineProperty2().default)(this, "version", void 0);
// don't validate the id parts using isValidIdChunk here. we instance this class tons of times
// and running regex so many times impact the performance
if (!name) throw new (_exceptions().InvalidName)(name);
this.scope = scope || null;
this.box = undefined;
this.name = box ? `${box}/${name}` : name;
this.version = version || undefined;
Object.freeze(this);
}
clone() {
return new BitId(this);
}
changeScope(newScope) {
return new BitId({
scope: newScope,
name: this.name,
version: this.version
});
}
changeVersion(newVersion) {
return new BitId({
scope: this.scope,
name: this.name,
version: newVersion
});
}
isLocal(scopeName) {
return !this.scope || Boolean(scopeName && scopeName === this.scope);
}
getVersion() {
return (0, _versionParser().default)(this.version);
}
hasVersion() {
return Boolean(this.version && this.version !== _constants().LATEST_BIT_VERSION);
}
hasScope() {
return Boolean(this.scope);
}
hasSameName(id) {
return this.name === id.name;
}
hasSameScope(id) {
if (this.hasScope() && id.hasScope()) return this.scope === id.scope;
if (!this.hasScope() && !id.hasScope()) return true;
return false; // one has scope but not the other
}
hasSameVersion(id) {
if (this.hasVersion() && id.hasVersion()) return this.version === id.version;
if (!this.hasVersion() && !id.hasVersion()) return true;
return false; // one has version but not the other
}
toString(ignoreScope = false, ignoreVersion = false) {
const {
name,
version
} = this;
const scope = this.scope;
const componentStr = ignoreScope || !scope ? name : [scope, name].join('/'); // when there is no scope and the version is latest, omit the version.
if (ignoreVersion || !this.hasVersion()) return componentStr; // $FlowFixMe version here is a string because this.hasVersion() is true
return componentStr.concat(`${_constants().VERSION_DELIMITER}${version}`);
}
toStringWithoutScope() {
return this.toString(true);
}
toStringWithoutVersion() {
return this.toString(false, true);
}
toStringWithoutScopeAndVersion() {
return this.toString(true, true);
}
isEqual(bitId) {
return this.hasSameName(bitId) && this.hasSameScope(bitId) && this.hasSameVersion(bitId);
}
isEqualWithoutVersion(bitId) {
return this.hasSameName(bitId) && this.hasSameScope(bitId);
}
isEqualWithoutScopeAndVersion(bitId) {
return this.hasSameName(bitId);
}
serialize() {
const obj = {
scope: this.scope,
name: this.name,
version: this.version
};
if (!this.hasVersion()) delete obj.version;
if (!this.hasScope()) delete obj.scope;
return obj;
}
toObject() {
const key = this.scope ? [this.scope, this.name].join('/') : this.name;
const value = this.version;
return {
[key]: value
};
}
toFullPath() {
if (!this.scope || !this.version) {
throw new Error('BitId.toFullPath is unable to generate a path without a scope or a version');
}
return path().join(this.name, this.scope, this.version);
}
/**
* Get a string id and return a string without the version part
* @param {string} id
* @return {string} id - id without version
*/
static getStringWithoutVersion(id) {
const splitted = id.split(_constants().VERSION_DELIMITER);
let res = splitted[0]; // the delimiter is @. now with the new owner prefix
// many times the id starts with the @ sign as part of the @owner prefix
// do not treat this @ at the beginning as the version delimiter
if (id.startsWith(_constants().VERSION_DELIMITER)) {
res = `${_constants().VERSION_DELIMITER}${splitted[1]}`;
}
return res;
}
static getVersionOnlyFromString(id) {
return id.split(_constants().VERSION_DELIMITER)[1];
}
static parse(id, hasScope = true, version = _constants().LATEST_BIT_VERSION) {
if (!_ramda().default.is(String, id)) {
throw new TypeError(`BitId.parse expects to get "id" as a string, instead, got ${typeof id}`);
}
if (id.includes(_constants().VERSION_DELIMITER)) {
const [newId, newVersion] = id.split(_constants().VERSION_DELIMITER);
id = newId;
version = newVersion;
}
const getScopeAndName = () => {
if (hasScope) {
const delimiterIndex = id.indexOf('/');
if (delimiterIndex < 0) throw new (_exceptions().InvalidBitId)();
const scope = id.substring(0, delimiterIndex);
const name = id.substring(delimiterIndex + 1);
return {
scope,
name
};
}
return {
scope: undefined,
name: id
};
};
const {
scope,
name
} = getScopeAndName();
if (!(0, _isValidIdChunk().default)(name)) throw new (_exceptions().InvalidName)(name);
if (scope && !(0, _isValidScopeName().default)(scope)) throw new (_exceptions().InvalidScopeName)(scope);
return new BitId({
scope,
name,
version
});
}
static parseObsolete(id, version = _constants().LATEST_BIT_VERSION) {
if (id.includes(_constants().VERSION_DELIMITER)) {
const [newId, newVersion] = id.split(_constants().VERSION_DELIMITER);
id = newId;
version = newVersion;
}
const idSplit = id.split('/');
if (idSplit.length === 3) {
const [scope, box, name] = idSplit;
if (!(0, _isValidIdChunk().default)(name, false) || !(0, _isValidIdChunk().default)(box, false) || !(0, _isValidScopeName().default)(scope)) {
throw new (_exceptions().InvalidIdChunk)(`${scope}/${box}/${name}`);
} // $FlowFixMe (in this case the realScopeName is not undefined)
return new BitId({
scope,
box,
name,
version
});
}
if (idSplit.length === 2) {
const [box, name] = idSplit;
if (!(0, _isValidIdChunk().default)(name, false) || !(0, _isValidIdChunk().default)(box, false)) {
throw new (_exceptions().InvalidIdChunk)(`${box}/${name}`);
}
return new BitId({
box,
name,
version
});
}
if (idSplit.length === 1) {
const [name] = idSplit;
if (!(0, _isValidIdChunk().default)(name)) {
throw new (_exceptions().InvalidIdChunk)(name);
}
return new BitId({
name,
version
});
}
throw new (_exceptions().InvalidBitId)();
}
/**
* before version 13.0.3 bitmap and component-dependencies ids were written as strings (e.g. scope/box/name@version)
* since that version the ids are written as objects ({ scope: scopeName, name: compName, version: 0.0.1 })
*/
static parseBackwardCompatible(id) {
return typeof id === 'string' ? BitId.parseObsolete(id) : new BitId(id);
}
static getValidScopeName(scope) {
const suggestedName = scope.toLowerCase();
let cleanName = suggestedName.split('').map(char => {
if (/^[$\-_!.a-z0-9]+$/.test(char)) return char;
return '';
}).join(''); // allow only one dot
const nameSplitByDot = cleanName.split('.');
if (nameSplitByDot.length > 1) {
cleanName = `${_ramda().default.head(nameSplitByDot)}.${_ramda().default.tail(nameSplitByDot).join('')}`;
}
if (!cleanName) {
throw new (_generalError().default)('scope name created by directory name have to contains at least one character or number');
}
return cleanName;
}
static getValidIdChunk(chunk) {
if (!(0, _isValidIdChunk().default)(chunk)) {
chunk = chunk.replace(/\./g, '');
chunk = (0, _decamelize().default)(chunk, '-');
}
return chunk;
}
static getValidBitId(box, name) {
return new BitId({
name: BitId.getValidIdChunk(name),
box: box ? BitId.getValidIdChunk(box) : undefined
});
}
static isValidVersion(version) {
return Boolean(semver().valid(version));
}
}
exports.default = BitId;