TrevorBurnham/dep-graph

Major algorithm rewrite, using underscore.js (fixes #3)

1 parent c7677bc commit 3914db2b1f3a6a14c251da1089909e3211600fa5 committed Nov 3, 2011
Showing with 138 additions and 59 deletions.
1. +30 −16 docs/dep-graph.html
2. +67 −24 lib/dep-graph.js
3. +4 −1 package.json
4. +37 −18 src/dep-graph.coffee
 @@ -1,28 +1,42 @@ - dep-graph.coffee

dep-graph.coffee

dep-graph

class DepGraph
+      dep-graph.coffee

dep-graph.coffee

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.

@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, traversedPaths = [], traversedBranch = []) ->
-    traversedPaths.unshift id
-    traversedBranch.unshift id
-    return [] unless @map[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
+      for parent in @parentsOf(node)
+        visit parent
+      chain.unshift node
+
+    for leafNode in _.intersection(deps, @leafNodes()).reverse()
+      visit leafNode
+
+    chain

-    depIds = @map[id]
-    for depId in depIds.slice(0).reverse()
-      if depId in traversedBranch          # cycle
-        throw new Error("Cyclic dependency from #{id} to #{depId}")
-      if depId in traversedPaths          # duplicate, push to front
-        depIdIndex = traversedPaths.indexOf depId
-        traversedPaths[depIdIndex..depIdIndex] = []
-        traversedPaths.unshift depId
-        continue
+  leafNodes: ->
+    allNodes = _.uniq _.flatten _.values @map
+    node for node in allNodes when !@map[node]?.length

-      @getChain depId, traversedPaths, traversedBranch.slice(0)
+  parentsOf: (child) ->
+    node for node in _.keys(@map) when child in @map[node]

-    traversedPaths[0...-1]

Export the class in Node, make it global in the browser.

if module?.exports?
+  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
 @@ -6,9 +6,12 @@ "homepage": "http://github.com/TrevorBurnham/dep-graph", "repository": { "type": "git", - "url": "git://github.com/TrevorBurnham/dep-graph.git" + "url": "git://github.com/TrevorBurnham/dep-graph.git", }, "main": "lib/dep-graph.js", + "dependencies": { + "underscore": "1.2.1" + }, "devDependencies": { "coffee-script": "1.1.2", "nodeunit": "0.5.4",