Fork me on GitHub
#clj-kondo
<
2023-04-15
>
rschmukler21:04:06

Is there any way to have a hook treat a namespace as required? I am working on writing a hook for a macro that expands into a call to clojure.core.match/match - I would like the expansion to be linted by clj-kondo - The consuming namespaces don't require clojure.core.match directly (instead the macroexpansion resolves it) causing clj-kondo to hit an :unresolved-namespace error. If the consuming namespace requires clojure.core.match everything works correctly.

borkdude21:04:50

Hmm yes. this issue has come up a few times now. What you can do is this:

:config-in-call {your-ns/your-macro {:unresolved-namespace {:exclude [clojure.core.match]}}}

rschmukler21:04:54

Nice, thank you! Is there any way to apply this to metadata on the node returned from the hook instead? (ie. similar to how you can add metadata for :clj-kondo/ignore)

borkdude21:04:04

currently not yet, but you can do this in your macro:

(defmacro my-macro
  {:clj-kondo/config '{:linters {:unresolved-namespace ...}}}
  [ ])
after linting that macro, the config applies to calls to that macro this should work in clj-kondo from a month ago

rschmukler21:04:41

Hmmm, the :config-in-call doesn't seem to be working. I will try the annotation on the macro directly. Wondering if it's because of an interaction between :analyze-call and :config-in-call

rschmukler21:04:02

The metadata annotation did work correctly, but it's worth noting that because the require didn't happen, the analysis for clojure.core.match did not get applied (eg. a warning on an unused variable) - nevermind, looks to be working

borkdude21:04:20

the annotation on the macro has the same effect as config-in-call so maybe you just made a mistake in config-in-call

borkdude22:04:01

if you look in .clj-kondo/_inlined-configs or so you will see what config it expanded to

rschmukler22:04:46

Checking the .clj-kondo/_inlined-configs - should that be a file? Trying to access it but doesn't look to exist

borkdude22:04:18

it's a directory with an edn file inside of it

borkdude22:04:30

which contains the metadata you added to the macro in an expanded form

borkdude22:04:46

I think the dir may just be called _inlined or so

rschmukler22:04:10

The config-in-call was me copy pasting:

:config-in-call {your-ns/your-macro {:unresolved-namespace {:exclude [clojure.core.match]}}}
Needed to be
:config-in-call {your-ns/your-macro {:linters {:unresolved-namespace {:exclude [clojure.core.match]}}}}

rschmukler22:04:32

The metadata / config-in-call works 🙂 Thank you a ton for the help

borkdude22:04:48

cool, so clojure.core.match analysis also works appropriately?

rschmukler22:04:54

It does indeed 🙂

rschmukler22:04:07

(defmacro when-match
  "Similar to `when-let` but uses match patterns for binding."
  {:clj-kondo/config '{:linters {:unresolved-namespace {:exclude [clojure.core.match]}}}}
  [bindings & body]
  (let [[pattern expr] bindings]
    `(match ~expr
       ~pattern (do ~@body)
       _# nil)))

rschmukler22:04:52

Just a simple little thing, but pretty useful. Extra useful w/ clj-kondo linting 🥳 - Thank you again for the help and everything you do for the clojure community 🙏

❤️ 2
borkdude22:04:05

Glad to help!

rschmukler22:04:57

Ahhh! The clojure.core.match analysis actually doesn't work 😞 I had a lingering require

rschmukler22:04:02

(So it's giving unresolved variable warnings as written). Any way to tricking into resolving the symbol?

borkdude22:04:06

ah, that's a shame. I think we should fix this in clj-kondo, to treat an excluded namespace as if it were already required. can you post an issue about that?

rschmukler22:04:21

Yep, will do!

borkdude22:04:29

I don't think there's a good workaround for it now, unless maybe you generate

(do (require 'clojure.core.match) (when-let ...))
not sure if that's going to work, I don't think it will

borkdude22:04:30

no, that won't work

borkdude22:04:21

let's just implement the exclude fix

rschmukler22:04:15

Unfortunately it doesn't work unless the macro is called in the root of the namespace (ie. it won't work on code inside a defn)

borkdude22:04:57

yeah, I expected that