clj-kondo 2025-06-14

I'm trying to write a hook for a macro I wrote that is "function like". I'm not succeeding ๐Ÿ˜… Details in ๐Ÿงต

I figured out how to reproduce it at least! If the macro is defined in a cljc file, it stops working consistently for me: https://github.com/cjohansen/kondo-macro-woe

what if you add to this:

(:require-macros [mylib.core])
:refer [defthing]?

I thought that is how it works normally in CLJS

and then wrap the macro in a :clj reader conditional

to avoid adding a macro like thing at runtime in CLJS

I'm not an expert in this, but I do have :require-macros in mylib.core, and this all compiles and runs as expected.

can you try it though?

I think this is what clj-kondo might expect

To put that in the test namespace?

no in the macro namespace

(ns mylib.core
  #?(:cljs (:require-macros [mylib.core :refer [defthing]])))

ah, add refer

Still fails

ok, I'm afk most of today, I'll take a look when I can

Sure, no hurry

What's interesting to me is that it even fails usage/linting in a clj file. It seems to be related to the macro coming from a cljc file. If I rename the core file to core.clj, test.clj lints as expected.

yeah it might be a cljc + inline config related bug

I have a macro in src/myproject/api.clj that, in use, looks like this:

(defthing some-name [args]
  ,,,)
I want clj-kondo to recognize this as defining a var some-name in the current namespace, and to evaluate the body with the argument bindings available. There is src/no.cjohansen/myproject/config.edn with:
{:linters {:myproject/api {:level :warning}}
 :hooks {:analyze-call {myproject.api/defthing myproject.defs/defthing}}}
There is also src/no.cjohansen/myproject/defs.clj with:
(ns nexus.defs
    (:require [clj-kondo.hooks-api :as api]))

(defn- extract-docstr
       [[docstr? & forms :as remaining-forms]]
       (if (api/string-node? docstr?)
           [docstr? forms]
         [(api/string-node "no docs") remaining-forms]))

(defn defthing [{:keys [node]}]
  (let [[fname & forms] (rest (:children node))
        [docstr [attr-map & body]] (extract-docstr forms)]
    {:node
    (api/list-node
     (list*
      (api/token-node 'defn)
      fname
      docstr
      attr-map
      body))}))
I then have this test code:
(require '[clj-kondo.core :as clj-kondo])

(defn get-findings [code]
  (:findings
   (with-in-str
     (str
      '(require '[myproject.api :as myp])
      code)
     (clj-kondo.core/run! {:lint ["-"]}))))

(def code
  '(myp/defthing doit [a b]
     ))

(get-findings code)
And it returns all the warnings - unused binding doit etc. What am I missing? I copied everything from replicant, where things are working ๐Ÿค”

is the syntax the same as clojure.core/defn?

you could just do this:

{:lint-as {your.macro-ns/macro clojure.core/defn}}

Can I put that as meta data on the macro itself? This is for a library.

yeah, in your lib:

(defmacro defthing
  {:clj-kondo/lint-as 'clojure.core/defn}
  [...] ...)

(let me double check if that is correct)

That seems way easier. Wondering why I've opted for this complicated solution in Replicant ๐Ÿ˜…

Perhaps there are subtle syntax changes between your macro and defn

else why would you first extract docstring etc and then pass it on to defn

you might as well could pass the whole body to clojure.core/defn straightaway

I couldn't tell you - I don't remember why I wrote it the way I did ๐Ÿ˜„

if your test suite lints correctly using this config, I'd say you should be fine ;)

you do need to lint the macro ns first before the config takes effect

but in a normal clj-kondo workflow you first lint your dependencies, which is where this configuration is detected

I mainly use clj-kondo via lsp, not sure what it does

via lsp that's the same

it automatically does it

So now I have it partially working. Code evaluates, and go-to definition works, but lsp is still throwing squigglies ๐Ÿค”

can you restart the lsp server to double check and then make a screenshot?

Squigglies are unresolved symbols

could it be that you have another clj-kondo thing running in your emacs, e.g. flycheck-clj-kondo with an old clj-kondo version?

best to try it on the command line and see what it spits out

along with clj-kondo --version

clj-kondo --version clj-kondo v2025.01.16 Ancient, by your tempo, I would assume ๐Ÿ˜…

that sounds ok, do you see the same on the command line, warnings?

Yeah, same warnings

Same with 2025.06.05

do you have a .clj-kondo directory in the root of your project?

would you mind makeing a github repro of this that I could clone locally? I'll take a look either tomorrow or monday

do you perhaps still have the old hook activated?

Or not really, I made a new macro to test now

I'm trying it in a fresh repo, that'll answer it

I'm trying in a scratch buffer. Before:

Well, that didn't work ๐Ÿ˜‚

yeah, I also got it working in a blank project

I'll try to clean up my other project a little then

WTF. I cleared out both .clj-kondo, .lsp and src/no.cjohansen and it's still failing ๐Ÿคฏ

you could also zip your project and give it to me, so I can see it happening here perhaps

if it's open source

It's about to be ๐Ÿ™‚

Thanks for your kind support! I will have one more look at this with a fresh eye tomorrow, and if I still can't figure it out I'll take you up on your offer and send you the code ๐Ÿ˜Š

sure, I'm going to ๐Ÿ’ค now too!

if all else fails you could always not use the inline config but a {:lint-as {...}} thing in a config file

The inline config seems to me to be the ideal solution. And it worked in a fresh directory, so I must be doing something stupid.

you can check your .clj-kondo directory for inline configs

either directly in it or inside imports (not sure)

there are some in imports, but not for the afflicted namespace

there should be, else it's not going to work

$ ls .clj-kondo/inline-configs
scratch.clj

$ cat .clj-kondo/inline-configs/scratch.clj/config.edn
{:lint-as #:scratch{my-defn clojure.core/defn}}%

something like that should appear but for your macro file

afk now

๐Ÿ’ค 1

Thanks for the help so far! Sleep well ๐Ÿ™‚

Sorry, I forgot all about this due to other stuff coming up. Would you mind filing a github issue and meanwhile probably it's best to use a config file rather than an inline config

until I find out what's the issue

No worries ๐Ÿ™‚ I'll file an issue, but the good news is that I've ditched the idea of this specific macro ๐Ÿ˜„