Fork me on GitHub
#clj-kondo
<
2021-03-06
>
ikitommi12:03:50

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?

ikitommi12:03:02

also, getting the argument names would be great.

borkdude12:03:33

@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}]

borkdude12:03:18

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}]

ikitommi12:03:16

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

ikitommi12:03:06

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

borkdude12:03:08

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

ikitommi12:03:42

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.

borkdude12:03:17

What is your flow?

ikitommi12:03:19

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

ikitommi12:03:48

(extract-arities *ns*) kinda helper.

borkdude12:03:17

I would start with the source from that entire ns

borkdude12:03:27

just put the entire file through clj-kondo

ikitommi12:03:26

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

borkdude12:03:13

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

borkdude12:03:01

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

ikitommi12:03:14

from repl spin out of malli:

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

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

ikitommi12:03:26

:face_palm:

ikitommi12:03:29

thanks! 🙂

lread13:03:29

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.

borkdude13:03:00

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

borkdude13:03:25

But your idea could be useful

lread13:03:32

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

lread13:03:03

Is it worth me writing up an issue?

borkdude13:03:56

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

lread13:03:12

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.

borkdude13:03:58

@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.

lread13:03:23

Cool, will give it a shot!

borkdude13:03:41

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

borkdude13:03:32

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

borkdude13:03:42

or something like that

lread13:03:26

Ya, you’d exclude your own nses.

borkdude21:03:54

@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]

borkdude21:03:09

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)

lread21:03:42

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

lread21:03:48

Ah I see, there are options.

lread21:03:14

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

borkdude21:03:21

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

borkdude21:03:37

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

borkdude21:03:15

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

lread21:03:19

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

borkdude21:03:49

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

borkdude21:03:58

but adding things at the end works

lread21:03:55

I think your suffix idea makes sense.

lread21:03:43

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

borkdude21:03:51

hmm, good point...

borkdude21:03:27

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

borkdude21:03:55

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

borkdude21:03:22

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

lread21:03:06

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