kondo newb here: how hard would it be to make a linter that searched for over eagerness / redundant mapv's, e.g. (into coll (mapv ...)
?
welcome ghadi! not sure, needs some thought
@ghadi clj-kondo already has some type checking related stuff, so we can check for vector instead of seq as the second arg of into and do something with that
e.g. now it has:
$ clj-kondo --lint - <<< '(into [] :foo)'
<stdin>:1:10: error: Expected: seqable collection, received: keyword.
basically I'm looking for ->>
threads where there is a mapv not as the terminal operation
is this a one time analysis or something for general usage?
general
obviously it can't be perfect, but I think an analysis of the symbols would be Good Enoughâ„¢, no need for static analysis
ok, feel free to post an issue for this: https://github.com/borkdude/clj-kondo/issues there's also one potentially related issue: https://github.com/borkdude/clj-kondo/issues/323 someone wrote a hook as a solution for that: https://github.com/borkdude/clj-kondo/issues/323#issuecomment-691247062
so I expect that this can also be written as a hook maybe
as a first form of experimentation
(hook docs: https://github.com/borkdude/clj-kondo/blob/master/doc/hooks.md)
borkdude@MBP2019 /tmp $ cat .clj-kondo/config.edn
{:hooks {:analyze-call {clojure.core/into strict/into-check}}
:linters {:into-strict {:level :warning}}}
borkdude@MBP2019 /tmp $ cat .clj-kondo/strict.clj
(ns strict
(:require [clj-kondo.hooks-api :as api]))
(defn into-check [{:keys [:node]}]
(let [forms (rest (:children node))]
(when (= 2 (count forms)) ;; only check 2-arity for now
(let [from (last forms)
sexpr (api/sexpr from)]
(when (seq? sexpr)
(when (= 'mapv (first sexpr))
(let [loc (meta from)]
(api/reg-finding! (merge {:type :into-strict
:message "Avoid strictness in from"}
loc)))))))))
borkdude@MBP2019 /tmp $ clj-kondo --lint - <<< '(into [] (mapv inc [1 2 3]))'
<stdin>:1:10: warning: Avoid strictness in from
linting took 12ms, errors: 0, warnings: 1
neat hook API
cool! that gives me a starting point
does clj-kondo support spec regexes?
interesting point. that's a consideration for the future. I'm considering adding it to babashka and also to clj-kondo (both use sci for interpreting Clojure in the native binary). but there is the issue of alpha-ness: https://github.com/borkdude/babashka/issues/558
Hold on
@ghadi I made a hacked version of spartan.spec which runs with the current clj-kondo:
https://gist.github.com/borkdude/85ad5edd88a1877ad2802a0d49ef6c3c
so if you save that as spec.clj
into .clj-kondo
, then this works in the hook:
(s/def ::foo (s/cat :x int? :y string?))
(prn (s/conform ::foo [1 "foo"]))
$ clj-kondo --lint - <<< '(into [] (mapv inc [1 2 3]))'
{:x 1, :y "foo"}
<stdin>:1:10: warning: Avoid strictness in from
linting took 66ms, errors: 0, warnings: 1
Note that this is a hack but it might work for youalso (require '[spec :as s])
but don't expect spec to be present in clj-kondo releases soon since it's not clear to wait for spec2, etc.
what are the things in clojure.spec that sci can't handle?
(assuming it's sci)
@ghadi it is. at the time I wrote the spartan.spec port of spec, sci didn't support protocols yet, so I changed it all to just maps. but I'm pretty sure spec 1 and 2 can be made GraalVM compatible and hooked into the sci bindings of clj-kondo and babashka, so the spec functions themselves run at native speed instead of from interpreted code
if you now try to run clojure spec from source with bb, you'll get this:
$ bb -cp $(clojure -Spath) -e "(require '[clojure.spec.alpha])"
...
128: (symbol (clojure.lang.Compiler/demunge f-ns) (clojure.lang.Compiler/demunge f-n)))))
^--- Could not resolve symbol: clojure.lang.Compiler/demunge
This is because bb doesn't have the clojure.lang.Compiler
class in its sci bindingsand I'm pretty sure there's a few of these issues left when you work around that. The way forward for me would be to not run it from source but bind it natively. Spartan.spec is a stub meanwhile