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
424 lines (329 loc) • 13.4 kB
JavaScript
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 _graphlib() {
const data = _interopRequireWildcard(require("graphlib"));
_graphlib = function () {
return data;
};
return data;
}
function _bitId() {
const data = require("../../bit-id");
_bitId = function () {
return data;
};
return data;
}
function _constants() {
const data = require("../../constants");
_constants = function () {
return data;
};
return data;
}
function _dependencies() {
const data = require("../../consumer/component/dependencies/dependencies");
_dependencies = function () {
return data;
};
return data;
}
function _utils() {
const data = require("../../utils");
_utils = function () {
return data;
};
return data;
}
function _componentsList() {
const data = _interopRequireDefault(require("../../consumer/component/components-list"));
_componentsList = function () {
return data;
};
return data;
}
class DependencyGraph {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
constructor(graph) {
(0, _defineProperty2().default)(this, "graph", void 0);
(0, _defineProperty2().default)(this, "scopeName", void 0);
this.graph = graph;
}
setScopeName(scopeName) {
this.scopeName = scopeName;
}
static loadAllVersions(scope) {
return (0, _bluebird().coroutine)(function* () {
const graph = yield DependencyGraph.buildGraphWithAllVersions(scope);
return new DependencyGraph(graph);
})();
}
static loadLatest(scope) {
return (0, _bluebird().coroutine)(function* () {
const graph = yield DependencyGraph.buildGraphFromScope(scope);
return new DependencyGraph(graph);
})();
}
static loadFromString(str) {
const graph = _graphlib().default.json.read(str); // when getting a graph from a remote scope, the class BitId is gone and only the object is received
graph.nodes().forEach(node => {
const id = graph.node(node);
if (!(id instanceof _bitId().BitId)) {
graph.setNode(node, new (_bitId().BitId)(id));
}
});
return new DependencyGraph(graph);
}
/**
* @todo: refactor this to work with the newer method `buildGraphFromScope`.
*/
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
static buildGraphWithAllVersions(scope) {
return (0, _bluebird().coroutine)(function* () {
const graph = new (_graphlib().Graph)({
compound: true
});
const depObj = {};
const allComponents = yield scope.list(); // build all nodes. a node is either a Version object or Component object.
// each Version node has a parent of Component node. Component node doesn't have a parent.
yield Promise.all(allComponents.map( /*#__PURE__*/function () {
var _ref = (0, _bluebird().coroutine)(function* (component) {
graph.setNode(component.id(), component);
yield Promise.all(Object.keys(component.versions).map( /*#__PURE__*/function () {
var _ref2 = (0, _bluebird().coroutine)(function* (version) {
const componentVersion = yield component.loadVersion(version, scope.objects);
if (!componentVersion) return;
const idWithVersion = `${component.id()}${_constants().VERSION_DELIMITER}${version}`;
graph.setNode(idWithVersion, componentVersion);
graph.setParent(idWithVersion, component.id()); // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
componentVersion.id = component.toBitId();
depObj[idWithVersion] = componentVersion;
});
return function (_x2) {
return _ref2.apply(this, arguments);
};
}()));
});
return function (_x) {
return _ref.apply(this, arguments);
};
}())); // set all edges
// @todo: currently the label is "require". Change it to be "direct" and "indirect" depends on whether it comes from
// flattenedDependencies or from dependencies.
Object.keys(depObj).forEach(id => depObj[id].flattenedDependencies.forEach(dep => graph.setEdge(id, dep.toString(), 'require')));
return graph;
})();
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
static buildGraphFromScope(scope) {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
const graph = new (_graphlib().Graph)();
const allModelComponents = yield scope.list();
const buildGraphP = allModelComponents.map( /*#__PURE__*/function () {
var _ref3 = (0, _bluebird().coroutine)(function* (modelComponent) {
const buildVersionP = modelComponent.listVersions().map( /*#__PURE__*/function () {
var _ref4 = (0, _bluebird().coroutine)(function* (versionNum) {
const version = yield modelComponent.loadVersion(versionNum, scope.objects);
if (!version) {
// a component might be in the scope with only the latest version
return;
}
const id = modelComponent.toBitId().changeVersion(versionNum);
_this._addDependenciesToGraph(id, graph, version);
});
return function (_x4) {
return _ref4.apply(this, arguments);
};
}());
yield Promise.all(buildVersionP);
});
return function (_x3) {
return _ref3.apply(this, arguments);
};
}());
yield Promise.all(buildGraphP);
return graph;
})();
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
static buildGraphFromWorkspace(consumer, onlyLatest = false, reverse = false) {
var _this2 = this;
return (0, _bluebird().coroutine)(function* () {
const componentsList = new (_componentsList().default)(consumer);
const workspaceComponents = yield componentsList.getFromFileSystem();
const graph = new (_graphlib().Graph)();
const allModelComponents = yield consumer.scope.list();
const buildGraphP = allModelComponents.map( /*#__PURE__*/function () {
var _ref5 = (0, _bluebird().coroutine)(function* (modelComponent) {
const latestVersion = modelComponent.latest();
const buildVersionP = modelComponent.listVersions().map( /*#__PURE__*/function () {
var _ref6 = (0, _bluebird().coroutine)(function* (versionNum) {
if (onlyLatest && latestVersion !== versionNum) return;
const id = modelComponent.toBitId().changeVersion(versionNum);
const componentFromWorkspace = workspaceComponents.find(comp => comp.id.isEqual(id)); // if the same component exists in the workspace, use it as it might be modified
const version = componentFromWorkspace || (yield modelComponent.loadVersion(versionNum, consumer.scope.objects));
if (!version) {
// a component might be in the scope with only the latest version (happens when it's a nested dep)
return;
}
_this2._addDependenciesToGraph(id, graph, version, reverse);
});
return function (_x6) {
return _ref6.apply(this, arguments);
};
}());
yield Promise.all(buildVersionP);
});
return function (_x5) {
return _ref5.apply(this, arguments);
};
}());
yield Promise.all(buildGraphP);
workspaceComponents.forEach(component => {
const id = component.id;
_this2._addDependenciesToGraph(id, graph, component, reverse);
});
return graph;
})();
}
/**
* ignore nested dependencies. build the graph from only imported and authored components
* according to currently used versions (.bitmap versions)
*/
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
static buildGraphFromCurrentlyUsedComponents(consumer) {
var _this3 = this;
return (0, _bluebird().coroutine)(function* () {
const componentsList = new (_componentsList().default)(consumer);
const workspaceComponents = yield componentsList.getAuthoredAndImportedFromFS();
const graph = new (_graphlib().Graph)();
workspaceComponents.forEach(component => {
const id = component.id;
_this3._addDependenciesToGraph(id, graph, component);
});
return graph;
})();
} // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
static _addDependenciesToGraph(id, graph, component, reverse = false) {
const idStr = id.toString(); // save the full BitId of a string id to be able to retrieve it later with no confusion
if (!graph.hasNode(idStr)) graph.setNode(idStr, id);
Object.entries(component.depsIdsGroupedByType).forEach(([depType, depIds]) => {
depIds.forEach(dependencyId => {
const depIdStr = dependencyId.toString();
if (!graph.hasNode(depIdStr)) graph.setNode(depIdStr, dependencyId);
if (reverse) {
graph.setEdge(depIdStr, idStr, depType);
} else {
graph.setEdge(idStr, depIdStr, depType);
}
});
});
}
/**
* returns a new Graph that has only nodes that are related to the given id.
* (meaning, they're either dependents or dependencies)
*/
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
getSubGraphOfConnectedComponents(id) {
const connectedGraphs = _graphlib().default.alg.components(this.graph);
const idWithVersion = this._getIdWithLatestVersion(id);
const graphWithId = connectedGraphs.find(graph => graph.includes(idWithVersion.toString()));
if (!graphWithId) {
throw new Error(`${id.toString()} is missing from the dependency graph`);
}
return this.graph.filterNodes(node => graphWithId.includes(node));
}
getDependenciesInfo(id) {
const idWithVersion = this._getIdWithLatestVersion(id);
const dijkstraResults = _graphlib().default.alg.dijkstra(this.graph, idWithVersion.toString());
const dependencies = [];
Object.keys(dijkstraResults).forEach(idStr => {
const distance = dijkstraResults[idStr].distance;
if (distance === Infinity || distance === 0) {
// there is no dependency or it's the same component (distance zero)
return;
}
const predecessor = dijkstraResults[idStr].predecessor;
const dependencyType = this.graph.edge(predecessor, idStr);
dependencies.push({
id: this.graph.node(idStr),
depth: distance,
parent: predecessor,
dependencyType: _dependencies().DEPENDENCIES_TYPES_UI_MAP[dependencyType]
});
});
dependencies.sort((a, b) => a.depth - b.depth);
return dependencies;
}
getDependentsInfo(id) {
const idWithVersion = this._getIdWithLatestVersion(id);
const edgeFunc = v => this.graph.inEdges(v); // @ts-ignore (incorrect types in @types/graphlib)
const dijkstraResults = _graphlib().default.alg.dijkstra(this.graph, idWithVersion.toString(), undefined, edgeFunc);
const dependents = [];
Object.keys(dijkstraResults).forEach(idStr => {
const distance = dijkstraResults[idStr].distance;
if (distance === Infinity || distance === 0) {
// there is no dependency or it's the same component (distance zero)
return;
}
const predecessor = dijkstraResults[idStr].predecessor;
const dependencyType = this.graph.edge(idStr, predecessor);
dependents.push({
id: this.graph.node(idStr),
depth: distance,
parent: predecessor,
dependencyType: _dependencies().DEPENDENCIES_TYPES_UI_MAP[dependencyType]
});
});
dependents.sort((a, b) => a.depth - b.depth);
return dependents;
}
_getIdWithLatestVersion(id) {
if (id.hasVersion()) {
return id;
}
const nodes = this.graph.nodes();
const ids = nodes.filter(n => n.startsWith(id.toString()));
if (!ids.length) {
throw new Error(`failed finding ${id.toString()} in the graph`);
}
const bitIds = ids.map(idStr => this.graph.node(idStr));
return (0, _utils().getLatestVersionNumber)(_bitId().BitIds.fromArray(bitIds), id);
}
getComponent(id) {
return this.graph.node(id.toStringWithoutVersion());
}
getImmediateDependentsPerId(id, returnNodeValue = false) {
const nodeEdges = this.graph.inEdges(id.toString());
if (!nodeEdges) return [];
const idsStr = nodeEdges.map(node => node.v);
return returnNodeValue ? idsStr.map(idStr => this.graph.node(idStr)) : idsStr;
}
getImmediateDependenciesPerId(id) {
const nodeEdges = this.graph.outEdges(id.toString());
if (!nodeEdges) return [];
return nodeEdges.map(node => node.v);
}
serialize(graph = this.graph) {
return _graphlib().default.json.write(graph);
}
}
exports.default = DependencyGraph;
;