Fork me on GitHub

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?


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: there's also one potentially related issue: someone wrote a hook as a solution for that:


so I expect that this can also be written as a hook maybe


as a first form of experimentation



[email protected] /tmp $ cat .clj-kondo/config.edn
{:hooks {:analyze-call {clojure.core/into strict/into-check}}
 :linters {:into-strict {:level :warning}}}
[email protected] /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"}
[email protected] /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:


@ghadi I made a hacked version of spartan.spec which runs with the current clj-kondo: 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 you


also (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 bindings


and 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