clj-kondo

https://github.com/clj-kondo/clj-kondo
ikitommi 2021-03-06T12:39:50.182100Z

given a defn in some namespace, e.g. clojure.core/map-indexed, is there a way to programmatically infer the arity information? using clj-kondo? using tools.analyzer? something else?

ikitommi 2021-03-06T12:41:02.182800Z

also, getting the argument names would be great.

borkdude 2021-03-06T12:41:33.183Z

@ikitommi you can do this using the analysis output:

$ clj-kondo --config '{:output {:analysis true :format :edn}}' --lint - <<< "(defn foo ([x y] x) ([x y & zs] zs))" | jet --query ':analysis :var-definitions' | puget
[{:col 1,
  :end-col 37,
  :end-row 1,
  :filename "<stdin>",
  :fixed-arities #{2},
  :name foo,
  :name-col 7,
  :name-end-col 10,
  :name-end-row 1,
  :name-row 1,
  :ns user,
  :row 1,
  :varargs-min-arity 2}]

borkdude 2021-03-06T12:42:18.183400Z

With argument names:

$ clj-kondo --config '{:output {:analysis {:arglists true} :format :edn}}' --lint - <<< "(defn foo ([x y] x) ([x y & zs] zs))" | jet --query ':analysis :var-definitions' | puget
[{:arglist-strs ["[x y]" "[x y & zs]"],
  :col 1,
  :end-col 37,
  :end-row 1,
  :filename "<stdin>",
  :fixed-arities #{2},
  :name foo,
  :name-col 7,
  :name-end-col 10,
  :name-end-row 1,
  :name-row 1,
  :ns user,
  :row 1,
  :varargs-min-arity 2}]

ikitommi 2021-03-06T12:43:16.184200Z

great. would you have a clojure code snippet for thatt, e.g. not using via the whole app?

ikitommi 2021-03-06T12:44:06.185700Z

there btw a lot of code in clj-kondo, reading it now.

borkdude 2021-03-06T12:44:08.185800Z

you can get this using (with-in-str expr (clj-kondo.core/run! {:lint ["-"] :config {:output {:analysis true}}}))

borkdude 2021-03-06T12:44:41.186100Z

More docs here: https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md

ikitommi 2021-03-06T12:47:42.187500Z

ok, given that I woud like to run this in a repl, I guess source would be a way to get the expr? I’m getting “Source no found” a lot from that.

borkdude 2021-03-06T12:48:17.188200Z

What is your flow?

ikitommi 2021-03-06T12:48:19.188300Z

use case: list vars or read all defn vars in a ns and collect the arities from those.

ikitommi 2021-03-06T12:48:48.189Z

(extract-arities *ns*) kinda helper.

borkdude 2021-03-06T12:49:17.189500Z

I would start with the source from that entire ns

borkdude 2021-03-06T12:49:27.189700Z

just put the entire file through clj-kondo

ikitommi 2021-03-06T12:50:26.190500Z

what would be a robust way to get the whole source?

borkdude 2021-03-06T12:51:13.191Z

from the REPL? (slurp (io/resource "your_org/your_ns.clj")) probably

borkdude 2021-03-06T12:53:01.191300Z

user=&gt; (require '[<http://clojure.java.io|clojure.java.io> :as io])
nil
user=&gt; (slurp (io/resource "hello_world/main.clj"))
"(ns hello-world.main\n  (:require [clojure.edn :as edn])\n  (:gen-class))\n\n(defn -main [&amp; args]\n  (time (println \"Hello world!\"))\n  (prn (eval (edn/read-string (first args)))))\n"

ikitommi 2021-03-06T12:57:14.191800Z

from repl spin out of malli:

(io/resource "clojure/core.clj")
; =&gt; #object[java.net.URL]

(io/resource "malli/core.clj")
; =&gt; nil 

borkdude 2021-03-06T12:58:11.192Z

.cljc?

ikitommi 2021-03-06T12:58:26.192400Z

:face_palm:

ikitommi 2021-03-06T12:58:29.192600Z

thanks! 🙂

lread 2021-03-06T13:04:29.196200Z

The .cljc thing comes up from time to time. I wonder showing the platform with the error in some way might help. Maybe not so interesting if error applies to all platforms, but interesting if it only applies to a subset of platforms.

borkdude 2021-03-06T13:06:00.196800Z

He was trying to read a file with a .cljc extension, but used the .clj extension, this wasn't related to a linting warning

borkdude 2021-03-06T13:06:25.197300Z

But your idea could be useful

lread 2021-03-06T13:07:32.198700Z

Ah did not read carefully, just saw .cljc 🙂, but yeah, I was talking about linting and think it might reduce confusion.

lread 2021-03-06T13:39:03.199300Z

Is it worth me writing up an issue?

borkdude 2021-03-06T13:41:56.199700Z

Yes, with examples of the output you'd want to see

borkdude 2021-03-06T13:42:09.199900Z

Please

borkdude 2021-03-06T13:42:10.200100Z

:)

lread 2021-03-06T13:44:12.202300Z

Happy to! Also we might have lost the thread of another idea I raised... about a linter warning when a var marked with no-doc meta is called. Can raise an issue for that as well if there is any interest.

borkdude 2021-03-06T13:44:58.203Z

@lee Happy to see an issue on that, but I don't have any ideas on this myself, so if you can be very explicit about how that is supposed to work, please do.

lread 2021-03-06T13:45:23.203700Z

Cool, will give it a shot!

borkdude 2021-03-06T13:45:41.204100Z

E.g. it's common to call undocumented vars within your own project, how will you avoid false positives? Using a config?

borkdude 2021-03-06T13:46:32.204800Z

Thinking of it, maybe it's ok if that var is called from http://your.org but not from http://someone-elses.org namespace

borkdude 2021-03-06T13:46:42.205Z

or something like that

lread 2021-03-06T13:48:26.205700Z

Ya, you’d exclude your own nses.

lread 2021-03-06T20:20:03.206200Z

Ok, here’s 1 of 2: https://github.com/clj-kondo/clj-kondo/issues/1196

borkdude 2021-03-06T21:06:54.208700Z

@lee Generalizing this idea, I think we could make it configurable to see more info behind the message in brackets. E.g. {:suffix {:language true, :linter-key true} and then you will see for e.g.:

#?(:cljs x :clj y)
1:6: Unresolved symbol: x [cljs, :unresolved-symbol]
1:10: Unresolved symbol: y [clj, :unresolved-symbol]

borkdude 2021-03-06T21:08:09.209800Z

I think clojure-lsp already shows the linter key in the "suffix" but this could be pluggable. Maybe using a sequential to indicate the order: {:output {:suffix [:language :linter-key]}} (so you will first get the language and then the linter key)

lread 2021-03-06T21:33:39.210600Z

2 of 2: https://github.com/clj-kondo/clj-kondo/issues/1197

lread 2021-03-06T21:36:42.212300Z

Oh… I did not realize there was not a separate format available for editors. They just parse the terminal output from clj-kondo?

lread 2021-03-06T21:38:48.212600Z

Ah I see, there are options.

lread 2021-03-06T21:40:14.213700Z

So, at the terminal, I don’t think (?) I really need the linter-key but that can be suppressed if I understand you.

borkdude 2021-03-06T21:40:21.213900Z

@lee They either parse the terminal output or use something like JSON

borkdude 2021-03-06T21:40:37.214300Z

or in the case of Clojure LSP they just get EDN in the same process

borkdude 2021-03-06T21:41:15.215400Z

well, my idea was to make this optional, so you can configure it how you like and if you don't do anything it stays like it is now

lread 2021-03-06T21:41:19.215500Z

And whatever format makes sense is whatever format is most convenient to the editor env I suppose.

borkdude 2021-03-06T21:41:49.216100Z

The current format is a pretty standard format which vim and emacs get out of the box, so we better not mess with that

lread 2021-03-06T21:41:57.216400Z

gotcha

borkdude 2021-03-06T21:41:58.216500Z

but adding things at the end works

lread 2021-03-06T21:42:41.216800Z

cool!

lread 2021-03-06T21:44:55.217800Z

I think your suffix idea makes sense.

lread 2021-03-06T21:45:43.218500Z

If the linter issue was for both clj and cljs would both languages be shown?

borkdude 2021-03-06T21:46:51.218700Z

hmm, good point...

borkdude 2021-03-06T21:47:27.219300Z

well no, because you actually currently get only one warning because there is a distinct call somewhere

borkdude 2021-03-06T21:47:55.219800Z

I think if we would add the language you would get two different warnings

borkdude 2021-03-06T21:48:22.220500Z

this is just how .cljc is processed: it's linted twice, once for each language

lread 2021-03-06T21:49:06.221200Z

yeah, maybe not as terse, but certainly tells the user what they need to know.