# [dep-graph](http://github.com/TrevorBurnham/dep-graph) _ = require 'underscore' class DepGraph constructor: -> # The internal representation of the dependency graph in the format # `id: [ids]`, indicating only *direct* dependencies. @map = {} # Add a direct dependency. Returns `false` if that dependency is a duplicate. add: (id, depId) -> @map[id] ?= [] return false if depId in @map[id] @map[id].push depId @map[id] # Generate a list of all dependencies (direct and indirect) for the given id, # in logical order with no duplicates. getChain: (id) -> # First, get a list of all dependencies (unordered) deps = @descendantsOf id # Second, order them (using the Tarjan algorithm) chain = [] visited = {} visit = (node) => return if visited[node] or node is id visited[node] = true visit parent for parent in @parentsOf(node) when parent in deps chain.unshift node for leafNode in _.intersection(deps, @leafNodes()).reverse() visit leafNode chain leafNodes: -> allNodes = _.uniq _.flatten _.values @map node for node in allNodes when !@map[node]?.length parentsOf: (child) -> node for node in _.keys(@map) when child in @map[node] descendantsOf: (parent, descendants = [], branch = []) -> descendants.push parent branch.push parent for child in @map[parent] ? [] if child in branch # cycle throw new Error("Cyclic dependency from #{parent} to #{child}") continue if child in descendants # duplicate @descendantsOf child, descendants, branch.slice(0) descendants[1..] # Export the class in Node, make it global in the browser. if module?.exports? module.exports = DepGraph else @DepGraph = DepGraph