-
-
Notifications
You must be signed in to change notification settings - Fork 290
/
hooks_api.clj
181 lines (150 loc) · 5.39 KB
/
hooks_api.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
(ns clj-kondo.hooks-api
(:require
[clj-kondo.impl.cache :as cache]
[clj-kondo.impl.findings :as findings]
[clj-kondo.impl.metadata :as meta]
[clj-kondo.impl.namespace :as namespace]
[clj-kondo.impl.rewrite-clj.node :as node]
[clj-kondo.impl.rewrite-clj.parser :as parser]
[clj-kondo.impl.utils :as utils]
[clojure.pprint]
[sci.core :as sci])
(:refer-clojure :exclude [macroexpand resolve]))
(defn- mark-generate [node]
(assoc node :clj-kondo.impl/generated true))
(defn generated-node?
"Checks whether node was generated by other hook, or if the node was
written by user. Assumes that a node without location metadata was
generated."
[node]
(or (:clj-kondo.impl/generated node)
(let [m (meta node)]
(or (:clj-kondo.impl/generated m)
(not (:row m))))))
(defn parse-string [s]
(parser/parse-string s))
(defn keyword-node? [n]
(utils/keyword-node? n))
(def keyword-node
(comp mark-generate utils/keyword-node))
(defn string-node? [n]
(instance? clj_kondo.impl.rewrite_clj.node.string.StringNode n))
(def string-node
(comp mark-generate utils/string-node))
(defn token-node? [n]
(instance? clj_kondo.impl.rewrite_clj.node.token.TokenNode n))
(def token-node
(comp mark-generate utils/token-node))
(defn vector-node? [n]
(and (instance? clj_kondo.impl.rewrite_clj.node.seq.SeqNode n)
(identical? :vector (utils/tag n))))
(def vector-node (comp mark-generate utils/vector-node))
(def list-node? utils/list-node?)
(def list-node (comp mark-generate utils/list-node))
(defn map-node? [n]
(and (instance? clj_kondo.impl.rewrite_clj.node.seq.SeqNode n)
(identical? :map (utils/tag n))))
(def map-node (comp mark-generate utils/map-node))
(defn sexpr [expr]
(node/sexpr expr))
(defn tag [n]
(node/tag n))
(defn reg-finding! [m]
(let [ctx utils/*ctx*
filename (:filename ctx)]
(findings/reg-finding! ctx (assoc m :filename filename))))
(defn reg-keyword!
[k reg-by]
(utils/assoc-some k :reg reg-by))
(defn coerce [s-expr]
(node/coerce s-expr))
(defn- var-definitions
"Project cached analysis as a subset of public var-definitions."
[analysis]
(let [selected-keys [:ns :name
:fixed-arities :varargs-min-arity
:private :macro]]
(->> (dissoc analysis :filename :source)
(utils/map-vals #(select-keys % selected-keys)))))
(defn- ns-analysis*
"Adapt from-cache-1 to provide a uniform return format.
Unifies the format of cached information provided for each source
language."
[lang ns-sym]
(if (= lang :cljc)
(->> (dissoc
(cache/from-cache-1 (:cache-dir utils/*ctx*) :cljc ns-sym)
:filename
:source)
(utils/map-vals var-definitions))
(some->> (cache/from-cache-1 (:cache-dir utils/*ctx*) lang ns-sym)
var-definitions
(hash-map lang))))
(defn ns-analysis
"Return any cached analysis for the namespace identified by ns-sym.
Returns a map keyed by language keyword with values being maps of var
definitions keyed by defined symbol. The value for each symbol is a
subset of the values provide by the top level :analysis option."
([ns-sym] (ns-analysis ns-sym {}))
([ns-sym {:keys [lang]}]
(if lang
(ns-analysis* lang ns-sym)
(reduce
merge
{}
(map #(ns-analysis* % ns-sym) [:cljc :clj :cljs])))))
(def ^:dynamic *reload* false)
(defn walk
[inner outer form]
(cond
(instance? clj_kondo.impl.rewrite_clj.node.protocols.Node form)
(outer (update form :children #(mapv inner %)))
:else (outer form)))
(defn prewalk
[f form]
(walk (partial prewalk f) identity (f form)))
(defn annotate
{:no-doc true}
[node original-meta]
(let [!!last-meta (volatile! (assoc original-meta :derived-location true))]
(prewalk (fn [node]
(cond
(and (instance? clj_kondo.impl.rewrite_clj.node.seq.SeqNode node)
(identical? :list (utils/tag node)))
(if-let [m (meta node)]
(if-let [m (not-empty (select-keys m [:row :end-row :col :end-col]))]
(do (vreset! !!last-meta (assoc m :derived-location true))
(mark-generate node))
(-> (with-meta node
(merge @!!last-meta (meta node)))
mark-generate))
(->
(with-meta node
@!!last-meta)
mark-generate))
(instance? clj_kondo.impl.rewrite_clj.node.protocols.Node node)
(let [m (meta node)]
(if (:row m)
node
(-> (with-meta node
(merge @!!last-meta m))
mark-generate)))
:else node))
node)))
(defn macroexpand [macro node bindings]
(let [call (sexpr node)
args (rest call)
res (apply macro call bindings args)
coerced (coerce res)
annotated (annotate coerced (meta node))
lifted (meta/lift-meta-content2 utils/*ctx* annotated)]
;;
lifted))
(defn pprint [& args]
(binding [*out* @sci/out]
(apply clojure.pprint/pprint args)))
(defn resolve [{:keys [name call]}]
(let [ctx utils/*ctx*
ret (namespace/resolve-name ctx call (-> ctx :ns :name) name nil)]
(select-keys ret [:ns :name])))
;; ctx call? ns-name name-sym expr