|
1 | 1 | (ns refactor-nrepl.ns.ns-parser
|
2 |
| - (:require [clojure.java.io :as io] |
3 |
| - [instaparse.core :refer [parse parser]] |
4 |
| - [refactor-nrepl.ns.helpers :refer [get-ns-component]])) |
| 2 | + "Extracts a list of imports or libspecs from an ns form. A libspec |
| 3 | + looks like this: |
5 | 4 |
|
6 |
| -(defn- parse-form |
7 |
| - "Form is either (:import..) (:use ..) or (:require ..)" |
8 |
| - [form] |
9 |
| - (let [ns-parser (parser |
10 |
| - (io/resource "refactor_nrepl/ns/require-or-use-or-import.bnf") |
11 |
| - :auto-whitespace :comma)] |
12 |
| - (parse ns-parser (str form)))) |
| 5 | + {:ns ns-name |
| 6 | + :as alias |
| 7 | + :refer [referred symbols here] ;; or :all |
| 8 | + :rename {:rename :spec} |
| 9 | + :only [only these symbols]}" |
| 10 | + (:require [refactor-nrepl.ns.helpers :refer [get-ns-component prefix-form?]])) |
13 | 11 |
|
14 |
| -(defn- add-prefix-to-libspec |
15 |
| - [prefix libspec] |
16 |
| - (if (sequential? libspec) |
17 |
| - (let [suffix (second libspec)] |
18 |
| - (assoc libspec 0 :libspec-with-opts |
19 |
| - 1 (str prefix "." suffix))) |
20 |
| - (str prefix "." libspec))) |
21 |
| - |
22 |
| -(defn- use-to-refer-all |
| 12 | +(defn- process-libspec |
23 | 13 | [libspec]
|
24 |
| - (if (nil? (:refer libspec)) |
25 |
| - (update-in libspec [:refer] (constantly :all)) |
26 |
| - libspec)) |
27 |
| - |
28 |
| -(defmulti parse-libspec first) |
29 |
| - |
30 |
| -(defn- extract-referred [libspec] |
31 |
| - (let [refer (some->> libspec (drop-while #(not= % ":refer")) second)] |
32 |
| - (if (sequential? refer) |
33 |
| - (map symbol (rest refer)) |
34 |
| - (when refer |
35 |
| - :all)))) |
36 |
| - |
37 |
| -(defn- extract-rename-spec [libspec] |
38 |
| - (some->> libspec |
39 |
| - (drop-while #(not= % ":rename")) |
40 |
| - second |
41 |
| - rest |
42 |
| - (map symbol) |
43 |
| - (apply hash-map))) |
44 |
| - |
45 |
| -(defmethod parse-libspec :libspec-with-opts |
46 |
| - [[_ ns & libspec]] |
47 |
| - {:ns (symbol ns) |
48 |
| - :as (some->> libspec (drop-while #(not= % ":as")) second symbol) |
49 |
| - :refer (extract-referred libspec) |
50 |
| - :rename (extract-rename-spec libspec) |
51 |
| - :only (some->> libspec (drop-while #(not= % ":only")) second rest) |
52 |
| - :flags (some->> libspec (filter #{":reload" ":reload-all" ":verbose"}))}) |
53 |
| - |
54 |
| -(defmethod parse-libspec :libspec-no-opts |
55 |
| - [[_ ns]] |
56 |
| - {:ns (symbol ns)}) |
57 |
| - |
58 |
| -(defmethod parse-libspec :prefix-libspec |
59 |
| - [[_ prefix & libspecs]] |
60 |
| - (->> libspecs |
61 |
| - (map (partial add-prefix-to-libspec prefix)) |
62 |
| - (map parse-libspec))) |
63 |
| - |
64 |
| -(defn- extract-libspecs |
65 |
| - [form] |
66 |
| - (flatten |
67 |
| - (let [parse-tree (rest (second (parse-form form)))] |
68 |
| - (for [libspec parse-tree] |
69 |
| - (parse-libspec libspec))))) |
70 |
| - |
71 |
| -(defmulti parse-import first) |
72 |
| - |
73 |
| -(defmethod parse-import :class |
74 |
| - [import] |
75 |
| - (second import)) |
76 |
| - |
77 |
| -(defn- add-package-prefix-to-class |
78 |
| - [prefix [_ class-name :as class]] |
79 |
| - (assoc class 1 (str prefix "." class-name))) |
80 |
| - |
81 |
| -(defmethod parse-import :classes-with-prefix |
82 |
| - [[_ prefix & classes]] |
83 |
| - (->> classes |
84 |
| - (map (partial add-package-prefix-to-class prefix)) |
85 |
| - (map parse-import))) |
86 |
| - |
87 |
| -(defn- extract-imports |
88 |
| - [form] |
89 |
| - (let [parse-tree (rest (second (parse-form form)))] |
90 |
| - (for [import parse-tree] |
91 |
| - (parse-import import)))) |
92 |
| - |
93 |
| -(defn- extract-used [use-form] |
94 |
| - (some->> use-form |
95 |
| - extract-libspecs |
96 |
| - (map use-to-refer-all))) |
97 |
| - |
98 |
| -(defn- extract-requires [require-form] |
99 |
| - (some-> require-form |
100 |
| - extract-libspecs)) |
| 14 | + (if (vector? libspec) |
| 15 | + (let [[ns & specs] libspec |
| 16 | + extract-spec (fn [spec](->> specs (drop-while #(not= % spec)) second))] |
| 17 | + (into {:ns ns} (map vec (partition 2 specs)))) |
| 18 | + {:ns (symbol libspec)})) |
| 19 | + |
| 20 | +(defn- expand-prefix-specs |
| 21 | + "Eliminate prefix vectors." |
| 22 | + [libspecs] |
| 23 | + (let [add-prefix (fn add-prefix [prefix libspec] |
| 24 | + (if (vector? libspec) |
| 25 | + (apply vector |
| 26 | + (str prefix "." (first libspec)) |
| 27 | + (rest libspec)) |
| 28 | + (str prefix "." libspec))) |
| 29 | + normalize-libspec-vector (fn [libspec] |
| 30 | + (if (prefix-form? libspec) |
| 31 | + (let [prefix (first libspec)] |
| 32 | + (map (partial add-prefix prefix) |
| 33 | + (rest libspec))) |
| 34 | + [libspec]))] |
| 35 | + (mapcat normalize-libspec-vector libspecs))) |
| 36 | + |
| 37 | +(defn- use-to-refer-all [use-specs] |
| 38 | + (map (fn [use-spec] (if (vector? use-spec) |
| 39 | + (if (prefix-form? use-spec) |
| 40 | + [(first use-spec) (map #(conj % :refer :all))] |
| 41 | + (conj use-spec :refer :all)) |
| 42 | + [use-spec :refer :all])) |
| 43 | + use-specs)) |
101 | 44 |
|
102 | 45 | (defn get-libspecs [ns-form]
|
103 |
| - (concat |
104 |
| - (extract-used (get-ns-component ns-form :use)) |
105 |
| - (extract-requires (get-ns-component ns-form :require)))) |
| 46 | + (->> (get-ns-component ns-form :use) |
| 47 | + rest ; drop :use keyword |
| 48 | + use-to-refer-all |
| 49 | + (into (rest (get-ns-component ns-form :require))) |
| 50 | + expand-prefix-specs |
| 51 | + (map process-libspec) |
| 52 | + distinct)) |
106 | 53 |
|
107 | 54 | (defn get-imports [ns-form]
|
108 |
| - (some-> (get-ns-component ns-form :import) extract-imports |
109 |
| - flatten)) |
| 55 | + (let [expand-prefix-specs (fn [import-spec] |
| 56 | + (if (vector? import-spec) |
| 57 | + (let [package (first import-spec)] |
| 58 | + (map (fn [class-name] |
| 59 | + (str package "." class-name)) |
| 60 | + (rest import-spec))) |
| 61 | + import-spec))] |
| 62 | + (some->> (get-ns-component ns-form :import) |
| 63 | + rest ; drop :import |
| 64 | + (map expand-prefix-specs) |
| 65 | + flatten |
| 66 | + distinct))) |
0 commit comments