Clj-kondo can provide data that was collected during linting, which enables writing tools and linters that are not yet in clj-kondo itself. To get this data, use the following configuration:
{:output {:analysis true}}
When using clj-kondo from the command line, the analysis data will be exported
with {:output {:format ...}}
set to :json
or :edn
.
The analysis output consists of a map with:
-
:namespace-definitions
, a list of maps with::filename
,:row
,:col
:name
: the name of the namespace
Optional:
:lang
: if definition occurred in a.cljc
file, the language in which the definition was done::clj
or:cljs
- several metadata values:
:deprecated
,:doc
,:author
,:added
,:no-doc
(used by codox).
-
:namespace-usages
, a list of maps with::filename
,:row
,:col
:from
: the namespace which uses:to
: the used namespace:alias
: the alias of namespace, if used
Optional
:lang
: if usage occurred in a.cljc
file, the language in which it was resolved::clj
or:cljs
-
:var-definitions
, a list of maps with::filename
,:row
,:col
:ns
: the namespace of the var:name
: the name of the var
Optional:
:fixed-arities
: a set of fixed arities:varargs-min-arity
: the minimal number of arguments of a varargs signature- several metadata values:
:private
,:macro
,:deprecated
,:doc
,:added
:lang
: if definition occurred in a.cljc
file, the language in which the definition was done::clj
or:cljs
-
:var-usages
, a list of maps with::filename
,:row
,:col
:name
: the name of the used var:from
: the namespace from which the var was used:to
: the namespace of the used var
Optional:
:arity
: if the usage was a function call, the amount of arguments passed:lang
: if usage occurred in a.cljc
file, the language in which the call was resolved::clj
or:cljs
- several attributes of the used var:
:private
,:macro
,:fixed-arities
,:varargs-min-arity
,:deprecated
.
Example output after linting this code:
(ns foo
"This is a useful namespace."
{:deprecated "1.3"
:author "Michiel Borkent"
:no-doc true}
(:require [clojure.set :as set]))
(defn- f [x]
(inc x))
(defmacro g
"No longer used."
{:added "1.2"
:deprecated "1.3"}
[x & xs]
`(comment ~x ~@xs))
$ clj-kondo --lint /tmp/foo.clj --config '{:output {:analysis true :format :edn}}'
| jet --pretty --query ':analysis'
{:namespace-definitions [{:filename "/tmp/foo.clj",
:row 1,
:col 1,
:name foo,
:deprecated "1.3",
:doc "This is a useful namespace.",
:no-doc true,
:author "Michiel Borkent"}],
:namespace-usages [{:filename "/tmp/foo.clj",
:row 6,
:col 14,
:from foo,
:to clojure.set,
:alias set}],
:var-definitions [{:filename "/tmp/foo.clj",
:row 8,
:col 1,
:ns foo,
:name f,
:private true,
:fixed-arities #{1}}
{:added "1.2",
:ns foo,
:name g,
:varargs-min-arity 1,
:filename "/tmp/foo.clj",
:macro true,
:col 1,
:deprecated "1.3",
:doc "No longer used.",
:row 11}],
:var-usages [{:filename "/tmp/foo.clj",
:row 9,
:col 3,
:from foo,
:to clojure.core,
:name inc,
:fixed-arities #{1},
:arity 1}
{:name defn-,
:varargs-min-arity 2,
:filename "/tmp/foo.clj",
:from foo,
:macro true,
:col 1,
:arity 3,
:row 8,
:to clojure.core}
{:filename "/tmp/foo.clj",
:row 16,
:col 5,
:from foo,
:to clojure.core,
:name comment,
:macro true,
:varargs-min-arity 0}
{:name defmacro,
:varargs-min-arity 2,
:filename "/tmp/foo.clj",
:from foo,
:macro true,
:col 1,
:arity 5,
:row 11,
:to clojure.core}]}
NOTE: breaking changes may occur as result of feedback in the next few weeks (2019-07-30).
These are examples of what you can do with the analysis data that clj-kondo provides as a result of linting your sources.
To run the tools on your system you will need the Clojure CLI tool version 1.10.1.466 or higher and then use this repo as a git dep:
{:deps {clj-kondo/tools {:git/url "https://github.com/borkdude/clj-kondo"
:sha "1ed3b11025b7f3a582e6db099ba10a888fe0fc2c"
:deps/root "analysis"}}}
Replace the :sha
with the latest SHA of this repo.
You can create an alias for a tool in your ~/.clojure/deps.edn
:
{
:aliases {:unused-vars
{:extra-deps {clj-kondo/tools {:git/url "https://github.com/borkdude/clj-kondo"
:sha "1ed3b11025b7f3a582e6db099ba10a888fe0fc2c"
:deps/root "analysis"}}
:main-opts ["-m" "clj-kondo.tools.unused-vars"]}
}
}
and then call it from anywhere in your system with:
$ clj -A:unused-vars src
$ clj -m clj-kondo.tools.unused-vars src
The following vars are unused:
clj-kondo.tools.namespace-graph/-main
clj-kondo.tools.unused-vars/-main
A planck port of this example is available in the
script
directory. You can invoke it like this:
script/unused_vars.cljs src
A variation on the above tool, which looks at private vars and reports unused private vars or illegally accessed private vars.
Example code:
(ns foo)
(defn- foo [])
(defn- bar []) ;; unused
(ns bar (:require [foo :as f]))
(f/foo) ;; illegal call
$ clj -m clj-kondo.tools.private-vars /tmp/private.clj
/tmp/private.clj:4:8 warning: foo/bar is private but never used
/tmp/private.clj:8:1 warning: foo/foo is private and cannot be accessed from namespace bar
A planck port of this example is available in the
script
directory. You can invoke it like this:
script/private_vars.cljs /tmp/private.clj
This example requires GraphViz. Install with e.g. brew install graphviz
.
$ clj -m clj-kondo.tools.namespace-graph src
$ clj -m clj-kondo.tools.find-var clj-kondo.core/run! src ../src
clj-kondo.core/run! is defined at ../src/clj_kondo/core.clj:51:7
clj-kondo.core/run! is used at ../src/clj_kondo/core.clj:120:12
clj-kondo.core/run! is used at ../src/clj_kondo/main.clj:81:44
clj-kondo.core/run! is used at src/clj_kondo/tools/find_var_usages.clj:8:29
clj-kondo.core/run! is used at src/clj_kondo/tools/namespace_graph.clj:7:29
clj-kondo.core/run! is used at src/clj_kondo/tools/unused_vars.clj:9:31
$ clj -m clj-kondo.tools.popular-vars 10 ../src
clojure.core/let: 196
clojure.core/defn: 183
clojure.core/when: 115
clojure.core/=: 86
clojure.core/if: 86
clojure.core/recur: 79
clojure.core/assoc: 70
clojure.core/or: 68
clojure.core/->: 68
clojure.core/first: 62
$ clj -m clj-kondo.tools.missing-docstrings ../src
clj-kondo.impl.findings/reg-finding!: missing docstring
clj-kondo.impl.findings/reg-findings!: missing docstring
clj-kondo.impl.namespace/reg-var!: missing docstring
clj-kondo.impl.namespace/reg-var-usage!: missing docstring
clj-kondo.impl.namespace/reg-alias!: missing docstring
...
Example code:
(ns a (:require b c))
(ns b (:require a)) ;; circular dependency
(ns c (:require a)) ;; circular dependency
$ clj -m clj-kondo.tools.circular-dependencies /tmp/circular.clj
/tmp/circular.clj:3:17: circular dependendy from namespace b to a
/tmp/circular.clj:5:17: circular dependendy from namespace c to a