Skip to content

Commit 4c4a897

Browse files
authored
Fix clj-kondo hooks, include them in jar (#30)
* Include clj-kondo hooks in jar * Fix clj-kondo hook for multiple arities Also add tests around the hook
1 parent c0843b3 commit 4c4a897

File tree

7 files changed

+202
-29
lines changed

7 files changed

+202
-29
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@ resources/public/workspaces
5959
!.idea/runConfigurations
6060
pom.xml.releaseBackup
6161
release.properties
62+
/.clj-kondo/*/

deps.edn

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
:deps {expound/expound {:mvn/version "0.8.7"}
55
org.clojure/core.async {:mvn/version "1.3.618"}}
66

7-
:aliases {:test {:extra-paths ["src/test"]
7+
:aliases {:test {:extra-paths ["src/test" "src/test-clj-kondo"]
88
:extra-deps {org.clojure/test.check {:mvn/version "1.1.0"}
9-
fulcrologic/fulcro-spec {:mvn/version "3.1.9"}}}
9+
fulcrologic/fulcro-spec {:mvn/version "3.1.9"}
10+
clj-kondo/clj-kondo {:mvn/version "2022.01.15"}}}
1011

1112
:clj-tests {:extra-paths ["src/test"]
1213
:main-opts ["-m" "kaocha.runner"]
@@ -18,4 +19,3 @@
1819
org.clojure/tools.nrepl {:mvn/version "0.2.13"}
1920
binaryage/devtools {:mvn/version "1.0.0"}
2021
org.clojure/tools.namespace {:mvn/version "1.0.0"}}}}}
21-

pom.xml

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
<resource>
3737
<directory>src/main</directory>
3838
</resource>
39+
<resource>
40+
<directory>src/clj-kondo</directory>
41+
</resource>
3942
</resources>
4043
<plugins>
4144
<plugin>

src/clj-kondo/clj-kondo.exports/com.fulcrologic/guardrails/com/fulcrologic/guardrails/clj_kondo_hooks.clj

+33-20
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,17 @@
33

44
(def =>? #{'=> :ret})
55
(def |? #{'| :st})
6+
(def known-sym? #{'=> '| '<-})
67

7-
(defn >defn
8-
[{:keys [node]}]
9-
(let [args (rest (:children node))
10-
fn-name (first args)
11-
?docstring (when (string? (api/sexpr (second args)))
12-
(second args))
13-
args (if ?docstring
14-
(nnext args)
15-
(next args))
16-
argv (first args)
17-
gspec (second args)
18-
body (nnext args)
19-
new-node (api/list-node
20-
(list*
21-
(api/token-node 'defn)
22-
fn-name
23-
argv
24-
gspec
25-
body))]
8+
(defn args+gspec+body [nodes]
9+
(let [argv (first nodes)
10+
gspec (second nodes)
11+
body (nnext nodes)
12+
gspec' (->> gspec
13+
(:children)
14+
(filterv #(-> % :value known-sym? not))
15+
(api/vector-node))
16+
new-nodes (list* argv gspec' body)]
2617
;; gspec: [arg-specs* (| arg-preds+)? => ret-spec (| fn-preds+)? (<- generator-fn)?]
2718
(if (not= 1 (count (filter =>? (api/sexpr gspec))))
2819
(api/reg-finding! (merge (meta gspec)
@@ -58,4 +49,26 @@
5849
{:message (str "Guardrail spec does not match function signature. "
5950
"Too " (if too-many-specs? "many" "few") " specs.")
6051
:type :clj-kondo.fulcro.>defn/invalid-gspec})))))))
61-
{:node new-node}))
52+
new-nodes))
53+
54+
(defn >defn
55+
[{:keys [node]}]
56+
(let [args (rest (:children node))
57+
fn-name (first args)
58+
?docstring (when (some-> (second args) api/sexpr string?)
59+
(second args))
60+
args (if ?docstring
61+
(nnext args)
62+
(next args))
63+
post-docs (if (every? #(-> % api/sexpr list?) args)
64+
(mapv #(-> % :children args+gspec+body api/list-node) args)
65+
(args+gspec+body args))
66+
post-name (if ?docstring
67+
(list* ?docstring post-docs)
68+
post-docs)
69+
new-node (api/list-node
70+
(list*
71+
(api/token-node 'defn)
72+
fn-name
73+
post-name))]
74+
{:node new-node}))
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
{:hooks {:analyze-call {com.fulcrologic.guardrails.core/>defn com.fulcrologic.guardrails.clj-kondo-hooks/>defn
2-
com.fulcrologic.guardrails.core/>defn- com.fulcrologic.guardrails.clj-kondo-hooks/>defn}}
1+
{:hooks {:analyze-call {com.fulcrologic.guardrails.core/>defn
2+
com.fulcrologic.guardrails.clj-kondo-hooks/>defn
3+
com.fulcrologic.guardrails.core/>defn-
4+
com.fulcrologic.guardrails.clj-kondo-hooks/>defn}}
35
:linters {:clj-kondo.fulcro.>defn/invalid-gspec {:level :error}}
4-
:lint-as {com.fulcrologic.guardrails.core/>def clojure.core/def
5-
com.fulcrologic.guardrails.core/>defn clojure.core/defn
6-
com.fulcrologic.guardrails.core/>defn- clojure.core/defn-}}
6+
:lint-as {com.fulcrologic.guardrails.core/>def clojure.spec.alpha/def}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
(ns com.fulcrologic.guardrails.clj-kondo-hooks-test
2+
(:require
3+
[clj-kondo.core :as clj-kondo]
4+
[clojure.test :refer [deftest is]]))
5+
6+
(defn clj-kondo-findings [input-string]
7+
;; ensure latest hook is used
8+
(require '[clj-kondo.impl.hooks] :reload)
9+
(-> input-string
10+
(with-in-str
11+
(clj-kondo/run!
12+
{:lint ["-"]
13+
:cache false
14+
:config
15+
'{:hooks {:analyze-call
16+
{com.fulcrologic.guardrails.core/>defn
17+
com.fulcrologic.guardrails.clj-kondo-hooks/>defn
18+
com.fulcrologic.guardrails.core/>defn-
19+
com.fulcrologic.guardrails.clj-kondo-hooks/>defn}}
20+
:linters {:clj-kondo.fulcro.>defn/invalid-gspec {:level :error}}
21+
:lint-as {com.fulcrologic.guardrails.core/>def clojure.spec.alpha/def}}}))
22+
(:findings)))
23+
24+
(deftest >defn-hook-happy-path
25+
(is (= []
26+
(clj-kondo-findings
27+
"(ns foo
28+
(:require
29+
[com.fulcrologic.guardrails.core :refer [>defn]]
30+
[clojure.spec.alpha :as s]))
31+
32+
(>defn simples
33+
[a]
34+
[int? => int?]
35+
(if (> a 0)
36+
(* a (dec a))
37+
1))
38+
39+
(>defn one-list-arity
40+
([b]
41+
[int? => int?]
42+
(if (> b 0)
43+
(* b (dec b))
44+
1)))
45+
46+
(>defn docstring
47+
\"docstring\"
48+
[a]
49+
[int? => int?]
50+
(if (> a 0)
51+
(* a (dec a))
52+
1))
53+
54+
(>defn docstring-one-list-arity
55+
\"docstring\"
56+
([a]
57+
[int? => int?]
58+
(if (> a 0)
59+
(* a (dec a))
60+
1)))
61+
62+
(>defn test-function
63+
\"docstring\"
64+
([a]
65+
[int? => int?]
66+
(if (> a 0)
67+
(* a (test-function (dec a)))
68+
1))
69+
([a b]
70+
[int? int? => int?]
71+
(if (> a b)
72+
(recur a (inc b))
73+
(+ a b)))
74+
([a b c & d]
75+
[int? int? int? (s/* int?) => '=> int?]
76+
(if (seq d)
77+
(reduce + 0 d)
78+
(+ a b c))))
79+
"))))
80+
81+
(deftest >defn-hook-errors
82+
(is (= [{:col 3
83+
:end-col 27
84+
:end-row 8
85+
:filename "<stdin>"
86+
:level :error
87+
:message "Gspec requires exactly one `=>` or `:ret`"
88+
:row 8
89+
:type :clj-kondo.fulcro.>defn/invalid-gspec}
90+
{:col 4
91+
:end-col 10
92+
:end-row 15
93+
:filename "<stdin>"
94+
:level :error
95+
:message "Gspec requires exactly one `=>` or `:ret`"
96+
:row 15
97+
:type :clj-kondo.fulcro.>defn/invalid-gspec}
98+
{:col 4
99+
:end-col 28
100+
:end-row 23
101+
:filename "<stdin>"
102+
:level :error
103+
:message "Gspec requires exactly one `=>` or `:ret`"
104+
:row 23
105+
:type :clj-kondo.fulcro.>defn/invalid-gspec}
106+
{:col 10
107+
:end-col 22
108+
:end-row 23
109+
:filename "<stdin>"
110+
:level :error
111+
:message "Unresolved symbol: =wrong-sym=>"
112+
:row 23
113+
:type :unresolved-symbol}]
114+
(clj-kondo-findings
115+
"(ns foo
116+
(:require
117+
[com.fulcrologic.guardrails.core :refer [>defn]]
118+
[clojure.spec.alpha :as s]))
119+
120+
(>defn simples
121+
[a]
122+
[int? => int? :ret int?]
123+
(if (> a 0)
124+
(* a (dec a))
125+
1))
126+
127+
(>defn one-list-arity
128+
([b]
129+
[int?]
130+
(if (> b 0)
131+
(* b (dec b))
132+
1)))
133+
134+
(>defn test-function
135+
\"docstring\"
136+
([a]
137+
[int? =wrong-sym=> int?]
138+
(if (> a 0)
139+
(* a (test-function (dec a)))
140+
1))
141+
([a b]
142+
[int? int? => int?]
143+
(if (> a b)
144+
(recur a (inc b))
145+
(+ a b)))
146+
([a b c & d]
147+
[int? int? int? (s/* int?) => int?]
148+
(if (seq d)
149+
(reduce + 0 d)
150+
(+ a b c))))
151+
"))))

tests.edn

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
:ns-patterns ["-test$" "-spec$"]
44
:test-paths ["src/test"]
55
:skip-meta [:integration]
6-
:source-paths ["src/main"]}]
6+
:source-paths ["src/main"]}
7+
{:id :clj-kondo-hooks
8+
:ns-patterns ["-test$" "-spec$"]
9+
:test-paths ["src/test-clj-kondo"]
10+
:skip-meta [:integration]
11+
:source-paths ["src/clj-kondo"]}]
712
:reporter [fulcro-spec.reporters.terminal/fulcro-report]
813
:plugins []
914
:capture-output? false

0 commit comments

Comments
 (0)