Skip to content

Commit

Permalink
Honor clj-kondo :unused-namespace config, if present (#361)
Browse files Browse the repository at this point in the history
  • Loading branch information
vemv committed Feb 7, 2022
1 parent 7930b3b commit fb975c6
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 14 deletions.
5 changes: 4 additions & 1 deletion .clj-kondo/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@
clojure.tools.namespace.track tracker}}
:unresolved-symbol {:exclude [(refactor-nrepl.ns.ns-parser/with-libspecs-from [libspecs])
(refactor-nrepl.middleware/set-descriptor! [set-descriptor!])]}
:unresolved-namespace {:exclude [clojure.main]}}}
:unresolved-namespace {:exclude [clojure.main]}
;; for integration tests:
:unused-namespace {:exclude [sample.unused.namespace
"more.unused.namespaces*"]}}}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* [#361](https://github.com/clojure-emacs/refactor-nrepl/pull/361) Honor clj-kondo `:unused-namespace` config, if present
* This piece of config can inform/complement refactor-nrepl's own config.

## 3.2.2 (2022-01-29)

* Fix a minor artifact in the previous release (the version would be reported as 0.0.0).
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Be aware that this isn't the case if you connect to an already running REPL proc
Add the following, either in your project's `project.clj`, or in the `:user` profile found at `~/.lein/profiles.clj`:

```clojure
:plugins [[refactor-nrepl "3.2.1"]
:plugins [[refactor-nrepl "3.3.0"]
[cider/cider-nrepl "0.25.9"]]
```

Expand All @@ -37,7 +37,7 @@ Add the following in `~/.boot/profile.boot`:
(require 'boot.repl)

(swap! boot.repl/*default-dependencies* conj
'[refactor-nrepl "3.2.1"]
'[refactor-nrepl "3.3.0"]
'[cider/cider-nrepl "0.25.9"])

(swap! boot.repl/*default-middleware* conj
Expand Down Expand Up @@ -121,6 +121,7 @@ Configuration settings are passed along with each msg, currently the recognized
;; even if they're otherwise unused.
;; This seq of strings will be used as regexp patterns to match
;; against the libspec name.
;; This value is automatically augmented with configured clj-kondo's :unused-namespace config.
:libspec-whitelist ["^cljsjs"]

;; Regexes matching paths that are to be ignored
Expand Down Expand Up @@ -370,12 +371,12 @@ If you want to use `mranderson` while developing locally with the REPL, the sour

When you want to release locally to the following:

PROJECT_VERSION=3.2.1 make install
PROJECT_VERSION=3.3.0 make install

And here's how to deploy to Clojars:

```bash
git tag -a v3.2.1 -m "3.2.1"
git tag -a v3.3.0 -m "3.3.0"
git push --tags
```

Expand Down
10 changes: 6 additions & 4 deletions src/refactor_nrepl/middleware.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[clojure.walk :as walk]
[refactor-nrepl.config :as config]
[refactor-nrepl.core :as core]
[refactor-nrepl.ns.libspec-allowlist :as libspec-allowlist]
[refactor-nrepl.ns.libspecs :refer [namespace-aliases]]
[refactor-nrepl.stubs-for-interface :refer [stubs-for-interface]]))

Expand Down Expand Up @@ -59,10 +60,11 @@
~transport (response-for ~msg (err-info e# :refactor-nrepl-error))))))

(defmacro ^:private reply [transport msg & kvs]
`(with-errors-being-passed-on ~transport ~msg
(config/with-config ~msg
(transport/send ~transport
(response-for ~msg ~(apply hash-map kvs))))))
`(libspec-allowlist/with-memoized-libspec-allowlist
(with-errors-being-passed-on ~transport ~msg
(config/with-config ~msg
(transport/send ~transport
(response-for ~msg ~(apply hash-map kvs)))))))

(defn- bencode-friendly-data [data]
;; Bencode only supports byte strings, integers, lists and maps.
Expand Down
49 changes: 49 additions & 0 deletions src/refactor_nrepl/ns/libspec_allowlist.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
(ns refactor-nrepl.ns.libspec-allowlist
(:require
[clojure.java.io :as io]
[refactor-nrepl.config :as config])
(:import
(java.util.regex Pattern)))

(defn- libspec-allowlist* []
(let [kondo-file (io/file ".clj-kondo" "config.edn")
exclude (when (.exists kondo-file)
(try
(-> kondo-file slurp read-string :linters :unused-namespace :exclude)
(catch Exception e
(when (System/getenv "CI")
(throw e)))))]
(->> exclude
(mapv (fn [entry]
(if (symbol? entry)
(str "^" (Pattern/quote (str entry)) "$")
entry)))
(into (:libspec-whitelist config/*config*)))))

(def ^:private ^:dynamic *libspec-allowlist* nil)

(defn with-memoized-libspec-allowlist* [f]
(binding [*libspec-allowlist* (memoize libspec-allowlist*)]
(f)))

(defn libspec-allowlist
"Obtains a libspec allowlist, which is the result of merging clj-refactor's own `:libspec-whitelist`
with clj-kondo's `:unused-namespace` config.
Uses a memoized version if available."
[]
(or *libspec-allowlist*
(libspec-allowlist*)))

(defmacro with-memoized-libspec-allowlist
"Memoizes the libspec-allowlist internals while `body` is executing.
_Temporary_ memoization is important because:
* one does want to reload clj-kondo config if the user changes it, without needing a JVM restart;
* one doesn't want that to imply a performance hit in terms of repeatedly reading clj-kondo config files."
{:style/indent 0}
[& body]
`(with-memoized-libspec-allowlist*
(fn []
~@body)))
12 changes: 7 additions & 5 deletions src/refactor_nrepl/ns/prune_dependencies.clj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
(ns refactor-nrepl.ns.prune-dependencies
(:require
[cider.nrepl.middleware.info :as info]
[refactor-nrepl.config :as config]
[refactor-nrepl.core :as core]
[refactor-nrepl.find.symbols-in-file :as symbols-in-file]
[refactor-nrepl.ns.libspec-allowlist :as libspec-allowlist]
[refactor-nrepl.util :as util]))

(defn- lookup-symbol-ns
Expand Down Expand Up @@ -108,11 +108,13 @@
;; Some namespaces, e.g. those containing only protocol extensions,
;; are side-effecting at load but might look unused and otherwise be
;; pruned.
(defn- libspec-should-never-be-pruned? [libspec]
(defn libspec-should-never-be-pruned?
"Should `libspec` never be pruned away by the `clean-ns` op?"
[libspec]
(let [ns-name (str (:ns libspec))]
(some (fn [^String pattern]
(re-find (re-pattern pattern) ns-name))
(:libspec-whitelist config/*config*))))
(boolean (some (fn [^String pattern]
(-> pattern re-pattern (re-find ns-name)))
(libspec-allowlist/libspec-allowlist)))))

(defn- prune-libspec [symbols-in-file current-ns libspec]
(if (libspec-should-never-be-pruned? libspec)
Expand Down
32 changes: 32 additions & 0 deletions test/refactor_nrepl/ns/libspec_allowlist_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
(ns refactor-nrepl.ns.libspec-allowlist-test
(:require
[clojure.test :refer [are deftest is testing]]
[refactor-nrepl.ns.libspec-allowlist :as sut]
[refactor-nrepl.ns.prune-dependencies :as prune-dependencies]))

(deftest libspec-allowlist
(testing "Takes into account refactor-nrepls own config, and .clj-kondo/config files alike,
merging their results"
(is (= [;; From refactor-nrepl's default config:
"^cljsjs"
;; from our .clj-kondo file - symbols become quoted patterns:
"^\\Qsample.unused.namespace\\E$"
;; from our .clj-kondo file - strings have 'regex' semantics so are kept as-is:
"more.unused.namespaces*"]

(sut/libspec-allowlist)))

(is (every? string? (sut/libspec-allowlist))
"Items coming from different sources all have the same class,
ensuring they will be treated homogeneously by refactor-nrepl")

(testing "`libspec-should-never-be-pruned?` is integrated with clj-kondo logic,
effecively parsing its config into well-formed regexes"
(are [input expected] (= expected
(prune-dependencies/libspec-should-never-be-pruned? {:ns input}))
'sample.unused.namespace true
'Asample.unused.namespace false
'sample.unused.namespaceB false
'more.unused.namespaces true
'more.unused.namespacessss true
'more.unused.namespac false))))

0 comments on commit fb975c6

Please sign in to comment.