This project has been archived. clj-kondo
can now check for unsorted and unused namespace declarations, so please switch to that for all your namespace declaration liniting needs.
(or if you're using deps.edn
)
{lein-check-namespace-decls/lein-check-namespace-decls {:mvn/version "1.0.4"}}
A Leiningen (or deps.edn
) plugin that lints source files in your Clojure project to
check whether the ns
declarations are cleaned the way
refactor-nrepl
and
cljr-refactor
would clean them (such as with the M-x cljr-clean-ns
command in
Emacs).
Checks the following:
- Namespaces and imports in the
ns
declaration are sorted - No unused namespaces are present (configurable)
:require
forms are used instead of:use
- The top-level forms inside the
ns
form follow the conventional order::gen-class
,:refer-clojure
,:require
,:import
- Namespaces in
:require
use shared prefixes (e.g.(:require [clojure [string :as str] [data :as data]])
)
For files with ns
declarations that don't satisfy these rules, the
linter tells you how to fix namespace declarations that aren't cleaned
properly.
What happened? The linter detected an unused namespace,
clojure.string
, and removed it; it sorted the namespaces as well.
For each ns
declaration it finds that isn't "clean" (i.e. not
properly sorted or with unused namespaces), it will print a message
like the one above; if any unclean namespaces were found, the linter
will exit with a nonzero status.
As of 1.0.4, this linter works with either Leiningen or deps.edn
:
Add [lein-check-namespace-decls "1.0.2"]
into the :plugins
vector of your
project.clj
or ~/.lein/profiles.clj
.
(defproject my-project
:plugins [[lein-check-namespace-decls "1.0.2"]])
{:aliases
{:namespace-checker
{:extra-deps {lein-check-namespace-decls/lein-check-namespace-decls {:mvn/version "1.0.4"}}
:exec-fn check-namespace-decls.core/check-namespace-decls
:exec-args {:prefix-rewriting false
:source-paths ["src" "test"]}}}}
:exec-args
taks the same options you can specify in your Leiningen project, with the additional requirement that you must pass :source-paths
(a list of directories to lint) as well as in the example above.
Run the linter like this:
# Leiningen
lein check-namespace-decls
or
# deps.edn
clojure -X:namespace-checker
This will check ns
declaration forms for all Clojure source files in
the :source-paths
of your project (usually ./src/
).
Add a :check-namespace-decls
key to your project.clj
to configure
the way refactor-nrepl
cleans namespaces. All options are passed
directly to refactor-nrepl
.
(defproject my-project
:check-namespace-decls {:prefix-rewriting false})
The complete list of available options can be found here. The most interesting ones when using this as a linter are:
By setting {:prefix-rewriting false}
the ns
form will not be
expected to use prefix lists when including several libs whose names
have the same prefix. The default behavior uses prefixes:
;; Cleaned ns form with :prefix-rewriting true (default)
(ns my-project.core
(:require [clojure.tools.namespace
[find :as ns.find]
[parse :as ns.parse]]))
Contrast this to ns
forms without prefixes:
;; Cleaned ns form with :prefix-rewriting false
(ns my-project.core
(:require [clojure.tools.namespace.find :as ns.find]
[clojure.tools.namespace.parse :as ns.parse]))
Opinions on whether or not to use prefixes in :require
forms vary in
the Clojure community; I (@camsaul)
personally like them, so I stuck with the default behavior of
refactor-nrepl
, which is to use them.
Specify a collection of regexes of filenames to ignore.
;; ignore any files ending in core.clj
(defproject my-project
:check-namespace-decls {:ignore-paths [#".*core\.clj$"]})
Whether to remove unused namespaces from the ns
form. Defaults to
true
; if you don't want unused namespaces to be considered an error,
set this to false
.
lein-check-namespace-decls
simply checks any Clojure source files it finds in :source-paths
, excluding any that match a pattern in :ignore-paths
.
To include or exclude entire directories from the linter you can
modify or ^:replace
:source-paths
; the easiest way to do this without
affecting the rest of your project is to add a profile for
lein-check-namespace-decls
and an alias that automatically applies
it:
;; Check the sources under `./test/` in addition to the normal :source-paths (e.g. `./src/`)
(defproject my-project
:aliases {"check-namespace-decls" ["with-profile" "+check-namespace-decls" "check-namespace-decls"]}
:plugins [[lein-check-namespace-decls "1.0.2"]]
:profiles {:check-namespace-decls {:source-paths ["test"]}})
If the above seems like black magic, the Leiningen documentation does a great job of explaining how Leiningen plugins work in more detail.
Like Leiningen itself, setting the environment variable DEBUG=true
will add additional log messages to linter output -- specifically, it
will log messages about each file it checks and files that are skipped
due to patterns in :ignore-paths
(and the patterns that matched
those files). This is useful for debugging which files are checked by the linter.
Copyright © 2021 Cam Saul.
Distributed under the Eclipse Public License, same as Clojure.