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?
also, getting the argument names would be great.
@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}]
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}]
great. would you have a clojure code snippet for thatt, e.g. not using via the whole app?
there btw a lot of code in clj-kondo, reading it now.
you can get this using (with-in-str expr (clj-kondo.core/run! {:lint ["-"] :config {:output {:analysis true}}}))
More docs here: https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md
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.
What is your flow?
use case: list vars or read all defn vars in a ns and collect the arities from those.
(extract-arities *ns*)
kinda helper.
I would start with the source from that entire ns
just put the entire file through clj-kondo
what would be a robust way to get the whole source?
from the REPL? (slurp (io/resource "your_org/your_ns.clj"))
probably
user=> (require '[<http://clojure.java.io|clojure.java.io> :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"
from repl spin out of malli:
(io/resource "clojure/core.clj")
; => #object[java.net.URL]
(io/resource "malli/core.clj")
; => nil
.cljc?
:face_palm:
thanks! 🙂
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.
He was trying to read a file with a .cljc extension, but used the .clj extension, this wasn't related to a linting warning
But your idea could be useful
Ah did not read carefully, just saw .cljc 🙂, but yeah, I was talking about linting and think it might reduce confusion.
Is it worth me writing up an issue?
Yes, with examples of the output you'd want to see
Please
:)
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.
@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.
Cool, will give it a shot!
E.g. it's common to call undocumented vars within your own project, how will you avoid false positives? Using a config?
Thinking of it, maybe it's ok if that var is called from http://your.org but not from http://someone-elses.org namespace
or something like that
Ya, you’d exclude your own nses.
Ok, here’s 1 of 2: https://github.com/clj-kondo/clj-kondo/issues/1196
@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]
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)
Oh… I did not realize there was not a separate format available for editors. They just parse the terminal output from clj-kondo?
Ah I see, there are options.
So, at the terminal, I don’t think (?) I really need the linter-key but that can be suppressed if I understand you.
@lee They either parse the terminal output or use something like JSON
or in the case of Clojure LSP they just get EDN in the same process
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
And whatever format makes sense is whatever format is most convenient to the editor env I suppose.
The current format is a pretty standard format which vim and emacs get out of the box, so we better not mess with that
gotcha
but adding things at the end works
cool!
I think your suffix idea makes sense.
If the linter issue was for both clj and cljs would both languages be shown?
hmm, good point...
well no, because you actually currently get only one warning because there is a distinct
call somewhere
I think if we would add the language you would get two different warnings
this is just how .cljc is processed: it's linted twice, once for each language
yeah, maybe not as terse, but certainly tells the user what they need to know.