index.js 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /**
  2. * Topological sorting function
  3. *
  4. * @param {Array} edges
  5. * @returns {Array}
  6. */
  7. module.exports = function(edges){
  8. return toposort(uniqueNodes(edges), edges)
  9. }
  10. module.exports.array = toposort
  11. function toposort(nodes, edges) {
  12. var cursor = nodes.length
  13. , sorted = new Array(cursor)
  14. , visited = {}
  15. , i = cursor
  16. while (i--) {
  17. if (!visited[i]) visit(nodes[i], i, [])
  18. }
  19. return sorted
  20. function visit(node, i, predecessors) {
  21. if(predecessors.indexOf(node) >= 0) {
  22. var nodeRep
  23. try {
  24. nodeRep = ", node was:" + JSON.stringify(node)
  25. } catch(e) {
  26. nodeRep = ""
  27. }
  28. throw new Error('Cyclic dependency' + nodeRep)
  29. }
  30. if (!~nodes.indexOf(node)) {
  31. throw new Error('Found unknown node. Make sure to provided all involved nodes. Unknown node: '+JSON.stringify(node))
  32. }
  33. if (visited[i]) return;
  34. visited[i] = true
  35. // outgoing edges
  36. var outgoing = edges.filter(function(edge){
  37. return edge[0] === node
  38. })
  39. if (i = outgoing.length) {
  40. var preds = predecessors.concat(node)
  41. do {
  42. var child = outgoing[--i][1]
  43. visit(child, nodes.indexOf(child), preds)
  44. } while (i)
  45. }
  46. sorted[--cursor] = node
  47. }
  48. }
  49. function uniqueNodes(arr){
  50. var res = []
  51. for (var i = 0, len = arr.length; i < len; i++) {
  52. var edge = arr[i]
  53. if (res.indexOf(edge[0]) < 0) res.push(edge[0])
  54. if (res.indexOf(edge[1]) < 0) res.push(edge[1])
  55. }
  56. return res
  57. }