TL;DR Use codegraph to visualize dependencies within a Clojure file. Codegraph applied to itself will for example generate this graph:
Here is how it works.
The other day I wished I had a visualization of the dependencies in a piece of ClojureScript code that over the course of the year has gotten a bit unwieldy. I did some thinking and some codeing and it turns out it's quite easy. Here are some of the highlights in code & images, but mostly code.
Reading a string and have it evaluates in Clojure is done with
read-string
. Reading a string and have it not evaluated is as
easy as wrapping the string in an additional set of square brackets.
(read-string (str "[" (slurp path) "]")))
This returns the content of the file given by path
as a Clojure data
structure. In less homoiconic languages you would probably call this
an Abstract Syntax Tree. Homoiconicity for the win!
The data structure is a tree that we want to walk to find dependencies
in the code. Here clojure.walk/prewalk
comes in handy. We'll pass it
a function which will be called for every node in the tree. I went
with a multimethod since I initially expected that different typo of
nodes would require different action, but it turns out the only thing
we're actually interested in are symbols.
If the symbol is member of a given set, namely def
, defn
, defn-
,
defmulti
, and defmethod
, we will pay special attention to the next
symbol, because it will be the dependant of the upcoming dependencies
that we will record. Every subsequent occurrence of a symbol will then
constitute a dependency.
From there the only thing left to do is to limit the dependencies to those where the dependee is also the dependant of another dependency; and render the remainder in dot syntax to be visualized by graphviz.
Check out the code for more details.