Skip to content

Commit

Permalink
Implement new middleware op: suggest-libspecs (#392)
Browse files Browse the repository at this point in the history
Closes #384
  • Loading branch information
vemv authored Jul 4, 2023
1 parent 1e2987e commit d916e2e
Show file tree
Hide file tree
Showing 19 changed files with 615 additions and 82 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

## 3.7.0

* Implement new middleware op: `suggest-libspecs`
* Supports a beta clj-refactor.el feature.

## 3.6.0

* [#387](https://github.com/clojure-emacs/refactor-nrepl/issues/387): extend clj-kondo `:unused-namespace` integration. Now namespace local configuration is also taken into account.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ deploy: check-env .inline-deps
jar: .inline-deps
lein with-profile -user,+$(VERSION),+plugin.mranderson/config jar

# Usage: PROJECT_VERSION=3.2.1 make install
# Usage: PROJECT_VERSION=3.7.0 make install
# PROJECT_VERSION is needed because it's not computed dynamically
install: check-install-env .inline-deps
lein with-profile -user,+$(VERSION),+plugin.mranderson/config install
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ 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.6.0"]
[cider/cider-nrepl "0.28.3"]]
:plugins [[refactor-nrepl "3.7.0"]
[cider/cider-nrepl "0.31.0"]]
```

### Embedded nREPL
Expand Down Expand Up @@ -365,7 +365,7 @@ When you want to release locally to the following:
And here's how to deploy to Clojars:

```bash
git tag -a v3.6.0 -m "3.6.0"
git tag -a v3.7.0 -m "3.7.0"
git push --tags
```

Expand All @@ -375,7 +375,7 @@ An extensive changelog is available [here](CHANGELOG.md).

## License

Copyright © 2013-2022 Benedek Fazekas, Magnar Sveen, Alex Baranosky, Lars Andersen, Bozhidar Batsov
Copyright © 2013-2023 Benedek Fazekas, Magnar Sveen, Alex Baranosky, Lars Andersen, Bozhidar Batsov

Distributed under the Eclipse Public License, the same as Clojure.

Expand Down
46 changes: 38 additions & 8 deletions src/refactor_nrepl/ns/libspecs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,38 @@
[refactor-nrepl.core :as core]
[refactor-nrepl.ns.ns-parser :as ns-parser]
[refactor-nrepl.ns.suggest-aliases :as suggest-aliases]
[refactor-nrepl.util :as util])
[refactor-nrepl.util :as util]
[refactor-nrepl.util.meta :as meta])
(:import
(java.io File)))

;; The structure here is {path {lang [timestamp value]}}
;; where lang is either :clj or :cljs
(def ^:private cache (atom {}))

(defn vec-distinct-into [x y]
(into []
(comp cat
(distinct))
[x y]))

(defn merge-libspecs-meta [a b]
(let [{:keys [used-from files]} (meta b)]
(cond-> a
(seq used-from) (vary-meta update :used-from vec-distinct-into used-from)
(seq files) (vary-meta update :files vec-distinct-into files))))

(defn- aliases [libspecs]
(->> libspecs
(map (juxt :as :ns))
(remove #(nil? (first %)))
distinct))
(meta/distinct merge-libspecs-meta
(into []
(comp (map (juxt :as :ns))
(filter first))
libspecs)))

(defn- aliases-by-frequencies [libspecs]
(let [grouped (->> libspecs
(mapcat aliases) ; => [[str clojure.string] ...]
(let [grouped (->> (into []
(mapcat aliases) ; => [[str clojure.string] ...]
libspecs)
(sort-by (comp str second))
(group-by first) ; => {str [[str clojure.string] [str clojure.string]] ...}
)]
Expand All @@ -37,13 +52,28 @@
(when (= ts (.lastModified f))
v)))

(defn add-used-from-meta [libspecs ^File f]
(let [extension (case (re-find #"\.clj[cs]?$" (-> f .getAbsolutePath))
".clj" [:clj] ;; these are expressed as vectors, so that `#'merge-libspecs-meta` can operate upon them
".cljs" [:cljs]
".cljc" [:cljc]
nil)]
(if-not extension
libspecs
(into []
(map (fn [libspec]
(cond-> libspec
(not (-> libspec :ns string?))
(update :ns vary-meta assoc :used-from extension))))
libspecs))))

(defn- put-cached-ns-info! [^File f lang]
(binding [;; briefly memoize this function to avoid repeating its IO cost while `f` is being cached:
ns-parser/*read-ns-form-with-meta* (memoize core/read-ns-form-with-meta)]
(let [libspecs (ns-parser/get-libspecs-from-file lang f)
[_ namespace-name] (ns-parser/*read-ns-form-with-meta* lang f)
suggested-aliases (suggest-aliases/suggested-aliases namespace-name)
v {:libspecs libspecs
v {:libspecs (add-used-from-meta libspecs f)
:namespace-name namespace-name
:suggested-aliases suggested-aliases
:test-like-ns-name? (suggest-aliases/test-like-ns-name? namespace-name)}]
Expand Down
56 changes: 47 additions & 9 deletions src/refactor_nrepl/ns/ns_parser.clj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
(:require
[clojure.java.io :as io]
[clojure.set :as set]
[clojure.string :as string]
[refactor-nrepl.core :as core])
(:import
(java.io File)))
Expand All @@ -25,6 +26,39 @@
(into {:ns ns} (->> specs (partition 2) (map vec))))
{:ns (symbol libspec)}))

(defn ns-decl->resource-path [ns-decl extension]
(-> ns-decl
second
str
munge
(string/replace "." "/")
(str extension)))

(defn resource-path->filenames [resource-path]
(->> (-> (Thread/currentThread)
(.getContextClassLoader)
(.getResources resource-path))
(enumeration-seq)
(distinct)
(mapv str)))

(defn ns-sym->ns-filenames [ns-sym]
(let [base (-> ns-sym
str
(string/replace "-" "_")
(string/replace "." "/"))]
(not-empty (into []
(comp (keep (fn [extension]
(-> base (str extension) resource-path->filenames not-empty)))
cat)
[".clj" ".cljs" ".cljc"]))))

(defn add-file-meta [{ns-sym :ns :as m}]
{:pre [ns-sym]}
(let [files (ns-sym->ns-filenames ns-sym)]
(cond-> m
files (update :ns vary-meta assoc :files files))))

(defn- expand-prefix-specs
"Eliminate prefix lists."
[libspecs]
Expand Down Expand Up @@ -57,17 +91,20 @@
~@body))

(defn- extract-libspecs [ns-form]
(mapcat identity
(reduce into
[]
[(with-libspecs-from ns-form :require
(->> libspecs
expand-prefix-specs
(map libspec-vector->map)))
(into []
(comp (map libspec-vector->map)
(map add-file-meta))
(expand-prefix-specs libspecs)))

(with-libspecs-from ns-form :use
(->> libspecs
expand-prefix-specs
(map use-to-refer-all)
(map libspec-vector->map)))]))
(into []
(comp (map use-to-refer-all)
(map libspec-vector->map)
(map add-file-meta))
(expand-prefix-specs libspecs)))]))

(defn get-libspecs [ns-form]
(some->> ns-form
Expand Down Expand Up @@ -139,12 +176,13 @@
Dialect is either :clj or :cljs, the default is :clj."
([^File f]
(get-libspecs-from-file :clj f))

([dialect ^File f]
(some->> f
.getAbsolutePath
(*read-ns-form-with-meta* dialect)
((juxt get-libspecs get-required-macros))
(mapcat identity))))
(reduce into []))))

(defn aliases
"Return a map of namespace aliases given a seq of libspecs.
Expand Down
Loading

0 comments on commit d916e2e

Please sign in to comment.