https://github.com/camsaul/lein-check-namespace-decls.git
git clone 'https://github.com/camsaul/lein-check-namespace-decls.git'
(ql:quickload :camsaul.lein-check-namespace-decls)
A Leiningen 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:
ns
declaration are sorted:require
forms are used instead of :use
ns
form follow the conventional
order:
:gen-class
, :refer-clojure
, :require
, :import
: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.
:plugins
Add [lein-check-namespace-decls "1.0.1"]
into the :plugins
vector of your
project.clj
or ~/.lein/profiles.clj
.
(defproject my-project
:plugins [[lein-check-namespace-decls "1.0.1"]])
Run the linter like this:
lein check-namespace-decls
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:
:prefix-rewriting
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.
:ignore-paths
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$"]})
:prune-ns-form
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.1"]]
: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 © 2019 Cam Saul.
Distributed under the Eclipse Public License, same as Clojure.