Last active
November 16, 2023 23:17
-
-
Save MrEbbinghaus/a890f93906b499fba72d1ff508791e2d to your computer and use it in GitHub Desktop.
Generate a graph of all symbols in your project from clj-kondos analyis output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns graph | |
| (:require | |
| [clj-kondo.core :as kondo] | |
| [clojure.string :as str] | |
| [dorothy.core :as dot])) | |
| (def kondo-output | |
| (kondo/run! {:lint ["/Users/bjebb/Development/decide3/src/main/decide"] | |
| :config {:output {:analysis true} | |
| :lint-as | |
| '{com.fulcrologic.guardrails.core/>def clojure.core/def | |
| com.fulcrologic.guardrails.core/>defn clojure.core/defn | |
| com.fulcrologic.guardrails.core/>defn- clojure.core/defn- | |
| com.wsscode.pathom.connect/defmutation clojure.core/defn | |
| com.wsscode.pathom.connect/defresolver clojure.core/defn}}})) | |
| (defn init-graph [var-definitions] | |
| (let [vars (map (juxt :ns :name) var-definitions)] | |
| (reduce (fn [graph var] (assoc graph var #{})) {} vars))) | |
| (defn start-with-some? [s substr-set] | |
| (some #(str/starts-with? s %) substr-set)) | |
| (defn depend [m [dependant dependency]] | |
| (cond | |
| (= dependency dependant) m | |
| (contains? m dependant) (update m dependant conj dependency) | |
| :else (assoc m dependant #{dependency}))) | |
| (def built-in (complement :to)) | |
| (def top-level (complement :from-var)) | |
| (defn dep-graph | |
| ([analysis] (dep-graph analysis {:ignore-prefix #{"clojure" "cljs" "com.fulcrologic" "mui." "@mui" "com.wsscode.pathom.connect"} | |
| :remove-langs #{:cljs}})) | |
| ([analysis {:keys [ignore-prefix remove-langs]}] | |
| (let [{:keys [var-usages var-definitions]} analysis | |
| ignored-ns-prefix #(start-with-some? % ignore-prefix) | |
| _ (printf "Variable definitions: %d\n" (count var-definitions)) | |
| _ (printf "Number of variable usages: %d\n" (count var-usages)) | |
| var-definitions | |
| (->> var-definitions | |
| (remove #(some-> % :file (str/ends-with? ".cljs"))) | |
| (remove (complement :ns)) | |
| (remove #(remove-langs (:lang %))) | |
| (remove (comp ignored-ns-prefix :ns))) | |
| var-def-set (set (map (juxt :ns :name) var-definitions)) | |
| var-usages | |
| (cond->> var-usages | |
| :always (filter :name) ; no ns declerations | |
| :always (remove built-in) | |
| :always (remove #(some-> % :file (str/ends-with? ".cljs"))) | |
| :always (remove #(#{:clj-kondo/unknown-namespace} (:to %))) | |
| remove-langs (remove #(remove-langs (:lang %))) | |
| ignore-prefix (remove (comp ignored-ns-prefix :to))) | |
| empty-deps-graph (init-graph var-definitions)] | |
| (printf "Number of elements to squash: %d\n" (count var-usages)) | |
| (->> var-usages | |
| (filter #(contains? var-def-set ((juxt :to :name) %))) | |
| (map (juxt (juxt :from :from-var) (juxt :to :name))) | |
| (reduce depend empty-deps-graph))))) | |
| (defn escape [s] | |
| (str/escape (str s) {\" ""})) | |
| (defn fqvec->str [fqvec] | |
| (escape (str/join "/" (remove nil? fqvec)))) | |
| ;; => #'graph/fqvec->str | |
| (defn edges [[var depends-on]] | |
| (let [dep->edge #(vector (fqvec->str var) (fqvec->str %))] | |
| (mapv dep->edge depends-on))) | |
| (defn hash-color | |
| "Return a #12DE32 hex color for a given string." | |
| [s] | |
| (let [color-number (-> s hash (bit-and 0xFFFFFF))] | |
| (format "#%06x" color-number))) | |
| (defn namespace->subgraph [[namespace vars]] | |
| (mapcat edges vars) | |
| (dot/subgraph {:id (str namespace) | |
| :color (hash-color (str namespace))} | |
| (mapcat edges vars))) | |
| (defn var->node [var] | |
| [(fqvec->str var) {:label (fqvec->str var) | |
| :shape "rectangle" | |
| :fontcolor "black" | |
| :group (escape (first var)) | |
| :color (hash-color (escape (first var)))}]) | |
| (defn dep-graph->dot [dep-graph] | |
| (let [nodes (keys dep-graph) | |
| grouped-by-ns (group-by ffirst dep-graph)] | |
| (dot/dot | |
| (dot/digraph | |
| {} | |
| (concat | |
| (map var->node nodes) | |
| (map namespace->subgraph grouped-by-ns)))))) | |
| (defn -main [] | |
| (let [{:keys [analysis]} kondo-output] | |
| (->> analysis | |
| dep-graph | |
| dep-graph->dot | |
| (spit "var-graph.dot")))) | |
| (comment | |
| (time (-main)) | |
| ) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {:paths ["."] | |
| :deps {org.clojure/tools.namespace {:mvn/version "1.1.0"} | |
| clj-kondo/clj-kondo {:mvn/version "2021.10.19"} | |
| dorothy/dorothy {:mvn/version "0.0.7"}}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment