UNPKG

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