diff --git a/package.json b/package.json index 6a7092d8e..f42f49ac9 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,6 @@ "swarm-api": "0.1.2", "tar": "3.2.1", "term.js": "0.0.7", - "toposort": "1.0.7", "url-loader": "1.1.2", "uuid": "3.3.2", "viz.js": "1.8.2", diff --git a/src/lib/modules/contracts_manager/index.js b/src/lib/modules/contracts_manager/index.js index 72b9c95aa..6ebc780b5 100644 --- a/src/lib/modules/contracts_manager/index.js +++ b/src/lib/modules/contracts_manager/index.js @@ -1,4 +1,3 @@ -let toposort = require('toposort'); let async = require('async'); const cloneDeep = require('clone-deep'); @@ -544,7 +543,7 @@ class ContractsManager { let orderedDependencies; try { - orderedDependencies = toposort(converted_dependencies.filter((x) => x[0] !== x[1])).reverse(); + orderedDependencies = utils.toposort(converted_dependencies.filter((x) => x[0] !== x[1])).reverse(); } catch (e) { this.logger.error((__("Error: ") + e.message).red); this.logger.error(__("there are two or more contracts that depend on each other in a cyclic manner").bold.red); diff --git a/src/lib/utils/toposort.js b/src/lib/utils/toposort.js new file mode 100644 index 000000000..8d52a4824 --- /dev/null +++ b/src/lib/utils/toposort.js @@ -0,0 +1,93 @@ +// from https://github.com/marcelklehr/toposort +/** + * Topological sorting function + * + * @param {Array} edges + * @returns {Array} + */ + +module.exports = function(edges) { + return toposort(uniqueNodes(edges), edges); +}; + +module.exports.array = toposort; + +function toposort(nodes, edges) { + var cursor = nodes.length, sorted = new Array(cursor), visited = {}, i = cursor, outgoingEdges = makeOutgoingEdges(edges), nodesHash = makeNodesHash(nodes); + + // check for unknown nodes + edges.forEach(function(edge) { + if (!nodesHash.has(edge[0]) || !nodesHash.has(edge[1])) { + throw new Error('Unknown node. There is an unknown node in the supplied edges.'); + } + }); + + while (i--) { + if (!visited[i]) visit(nodes[i], i, new Set()); + } + + return sorted; + + function visit(node, i, predecessors) { + if(predecessors.has(node)) { + var nodeRep; + try { + nodeRep = ", node was:" + JSON.stringify(node); + } catch(e) { + nodeRep = ""; + } + throw new Error('Cyclic dependency' + nodeRep); + } + + if (!nodesHash.has(node)) { + throw new Error('Found unknown node. Make sure to provided all involved nodes. Unknown node: '+JSON.stringify(node)); + } + + if (visited[i]) return; + visited[i] = true; + + var outgoing = outgoingEdges.get(node) || new Set(); + outgoing = Array.from(outgoing); + + i = outgoing.length; + if (i) { + predecessors.add(node); + do { + var child = outgoing[--i]; + visit(child, nodesHash.get(child), predecessors); + } while (i); + predecessors.delete(node); + } + + sorted[--cursor] = node; + } +} + +function uniqueNodes(arr){ + var res = new Set(); + for (var i = 0, len = arr.length; i < len; i++) { + var edge = arr[i]; + res.add(edge[0]); + res.add(edge[1]); + } + return Array.from(res); +} + +function makeOutgoingEdges(arr){ + var edges = new Map(); + for (var i = 0, len = arr.length; i < len; i++) { + var edge = arr[i]; + if (!edges.has(edge[0])) edges.set(edge[0], new Set()); + if (!edges.has(edge[1])) edges.set(edge[1], new Set()); + edges.get(edge[0]).add(edge[1]); + } + return edges; +} + +function makeNodesHash(arr){ + var res = new Map(); + for (var i = 0, len = arr.length; i < len; i++) { + res.set(arr[i], i); + } + return res; +} diff --git a/src/lib/utils/utils.js b/src/lib/utils/utils.js index 65736a6f3..22a359a36 100644 --- a/src/lib/utils/utils.js +++ b/src/lib/utils/utils.js @@ -1,5 +1,6 @@ let http = require('follow-redirects').http; let https = require('follow-redirects').https; +let toposortGraph = require('./toposort.js'); const {canonicalHost} = require('./host'); const balanceRegex = /([0-9]+) ?([a-zA-Z]*)/; @@ -570,6 +571,10 @@ function getWindowSize() { return windowSize.get(); } +function toposort(graph) { + return toposortGraph(graph); +} + module.exports = { joinPath, dirname, @@ -617,5 +622,6 @@ module.exports = { copyToClipboard, fuzzySearch, jsonFunctionReplacer, - getWindowSize + getWindowSize, + toposort }; diff --git a/yarn.lock b/yarn.lock index fe62a406d..b6bca2818 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11369,11 +11369,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -toposort@1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" - integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= - tough-cookie@~2.3.3: version "2.3.4" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"