clj-kondo

borkdude 2024-08-01T09:52:18.508169Z

In the next clj-kondo version:

3
🎉 3
borkdude 2024-08-01T10:02:52.066059Z

Also a nice addition for the analysis (lsp): @inc wasn't previously recognized as a call to clojure.core/deref, now it is cc @ericdallo

1
🎉 1
ericdallo 2024-08-01T14:12:47.511529Z

cool! 👏

borkdude 2024-08-01T11:35:27.405239Z

https://clojurians.slack.com/archives/C06MAR553/p1722512056835909

🙌 1
✅ 1
Thierry 2024-08-05T12:27:19.110959Z

Thanks for the update! Came back from vacation to see linting took 4652ms, errors: 972, warnings: 7 haha 🤭 Using mount.lite with @ to deref the defstates it creates.

Thierry 2024-08-05T12:57:20.810239Z

<@U04V15CAJ> is there an exclude option for _`:type-mismatch` ? I tried, but doesn't work. `<http://mount.li|mount.li>_te/defstate` is linted as `_clojure.core/_def` but is of type `mount.lite.State` . State is a record of protocol IState, this record also contains IDeref. You can deref it to retrieve the contents.

Thierry 2024-08-05T12:59:29.299719Z

Example: _(*deref* db/_datasource_)_ / @db/datasource returns: _{:datasource #_object _[_com.zaxxer.hikari.HikariDataSource 0x30975b87 "HikariDataSource (HikariPool-1)"_]}_ This gets flagged by clj-kondo with: Expected: deref, received: map.clj-kondo(type-mismatch)

borkdude 2024-08-05T13:37:37.004799Z

can you make a small repro and file an issue?

borkdude 2024-08-05T13:43:48.336309Z

yes, you can override type mismatch:

{:linters {:type-mismatch {:namespaces {'clojure.core {'deref {:arities {1 {:args [:any]}}}}}}}}
from the top of my head

Thierry 2024-08-05T13:44:16.065389Z

Thanks, I will try and will make an issue with repro for you

borkdude 2024-08-05T13:47:06.539429Z

I think the issue might have arisen from the hooks which make clj-kondo think defstate returns a map, possibly: https://github.com/aroemers/mount-lite/blob/2.x/resources/clj-kondo.exports/functionalbytes/mount-lite/hooks/lite.clj

Thierry 2024-08-05T13:48:05.381839Z

In some cases it indeed can return a map

borkdude 2024-08-05T13:49:16.734019Z

The point isn't what happens in reality, but what clj-kondo thinks is happening, due to those hooks

borkdude 2024-08-05T13:51:02.469659Z

you can also try to override the type of defstate:

{:linters {:type-mismatch {:namespaces {'mount.lite {'defstate {:arities {:varargs {:ret :any}}}}}}}}

borkdude 2024-08-05T13:51:25.986109Z

if that works, perhaps it's best to move that to mount.lite

borkdude 2024-08-05T14:03:30.943279Z

@thierry572 you can try the version from my PR here: https://github.com/aroemers/mount-lite/pull/31

Thierry 2024-08-05T14:06:57.401119Z

will do, you are so fast. I was still figuring out how to create a repro

Thierry 2024-08-05T14:07:31.527769Z

I tried both linter options, neither work

borkdude 2024-08-05T14:08:24.378339Z

actually this is a better solution: https://github.com/aroemers/mount-lite/pull/31/commits/a1520a46c1da6195bc37a9e5b2682ee977f5dd66

💯 1
Thierry 2024-08-05T14:10:32.779059Z

linting took 5893ms, errors: 0, warnings: 0

Thierry 2024-08-05T14:10:38.086029Z

Thanks, that worked like a charm

borkdude 2024-08-05T14:11:05.915329Z

👍

borkdude 2024-08-05T14:11:58.062659Z

Perhaps you can make a comment in that PR to say that it worked for you

✅ 1
Thierry 2024-08-05T14:12:27.378409Z

I was just finishing typing exactly that

Thierry 2024-08-05T14:12:28.603209Z

🙂

Thierry 2024-08-05T14:14:54.224139Z

Maybe @arnout can merge the PR and do a release?

Thierry 2024-08-05T14:33:22.907219Z

Had to make a quick override hook to fix the default hook resetting

borkdude 2024-08-05T14:34:10.069779Z

yeah you could do that as well for now

Eric Dvorsak 2025-03-24T18:19:04.118399Z

There's a similar issue with mount

Eric Dvorsak 2025-03-24T19:32:22.064579Z

mount auto imports this hook:

(defn defstate [{:keys [node]}]
  (let [[n & args] (next (:children node))
        [docs args] (if (string? (api/sexpr (first args)))
                      [(first args) (next args)]
                      [nil args])
        m (when-let [m (first (:meta n))]
            (api/sexpr m))
        m (if (map? m) m {})
        ks (cond-> (take 1 args)
                   (> (count args) 2) (conj (nth args 2)))
        invalid-key (first (remove (comp (partial contains? #{:start :stop}) api/sexpr) ks))]
    (cond
      invalid-key
      (api/reg-finding!
        {:message (str "lifecycle functions can only contain `:start` and `:stop`. illegal function found: " (api/sexpr invalid-key))
         :type    :mount/defstate
         :row     (:row (meta invalid-key))
         :col     (:col (meta invalid-key))})
      (not (contains? (set (map api/sexpr ks)) :start))
      (throw (ex-info "lifecycle functions must include `:start`" {}))
      ((complement contains?) #{2 4} (count args))
      (throw (ex-info "lifecycle functions must consist of no more than 2 pair forms: `:start` and `:stop`" {}))
      (and (contains? m :on-reload) (not (contains? #{:noop :stop} (:on-reload m))))
      (api/reg-finding!
        {:message "metadata `:on-reload` key can only have value of `noop` or `stop`"
         :type    :mount/defstate
         :row     (:row (meta n))
         :col     (:col (meta n))})
      :else
      {:node (api/list-node
              (cond-> [(api/token-node 'def) n]
                docs (conj docs)
                true (conj (api/list-node
                            [(api/token-node 'atom)
                             (api/list-node
                              (list*
                               (api/token-node 'do)
                               args))]))))})))
I then get 134:31: error: Expected: map, received: atom I suspect it's because the hook is transforming defstate to a def that contains an atom with:
`(api/token-node 'atom)
the linting error appears in a function defined with malli.experimental/defn:
(mx/defn my-function :- :boolean
  [a-state :- [:map]]
  ...)
it expects a map and the state is a map so it works, but since it looks like an atom from the hook I get a linting error. Not sure how to fix it it's actually completely different from this mount-lite issue

Eric Dvorsak 2025-03-24T19:38:13.995429Z

actually it looks like the hook isn't called on that particular case so it might not even be how clj-kondo decides a-state is an atom and not a map here

Eric Dvorsak 2025-03-24T19:42:01.357439Z

nevermind I had already fixed it I just had to delete clj-kondo cache. I had a bad lint-as config mount.core/defstate clojure.core/def

Eric Dvorsak 2025-03-24T20:22:31.633409Z

damn was just a fluke the error is still there with linter

:linters {:type-mismatch {:namespaces {'mount.core {'defstate {:arities {:varargs {:ret :any}}}}}}

borkdude 2025-03-24T20:56:51.702909Z

try mount.core/defstate clj-kondo.lint-as/def-catch-all

borkdude 2025-03-24T20:57:07.062819Z

this suppresses all other warnings but still recognizes the var name

borkdude 2025-03-24T20:57:19.627229Z

unless you want more linting of course

Eric Dvorsak 2025-03-24T20:57:50.447639Z

will it completely ignore the defstate hook which provides some nice errors when you screw up the macro usage?

borkdude 2025-03-24T20:58:56.572039Z

ah sorry, I didn't completely read this thread, premature answer

borkdude 2025-03-24T20:59:32.426599Z

so it's not an issue with mount?

borkdude 2025-03-24T20:59:51.654809Z

sorry, it's getting late, I'll try to look again tomorrow if you can clarify the issue

Eric Dvorsak 2025-03-24T20:59:59.991679Z

it's kindof an issue at the intersection of kondo, malli and mount

Eric Dvorsak 2025-03-24T21:00:56.363929Z

lint-as def-catch-all does stop the error

borkdude 2025-03-24T21:02:13.673949Z

yeah sorry it's a type system issue. but I don't have knowledge about mount. perhaps you can start a new thread with a clear description of the problem instead of re-using this thread. it will also help if you have a ready-to-go github repo to reproduce the problem. I'll have a look tomorrow

Eric Dvorsak 2025-03-24T21:04:09.353699Z

here is a mini-repro:

(:require '[mount.core :refer [args defstate]]
          '[malli.experimental :as mx])

(defstate tconfig
  :start
  {:hello :world})

(mx/defn is-dry-run? :- :boolean
  [config :- [:map] dry-run? :- [:maybe :boolean]]
  (if (nil? dry-run?)
    (get-in config [:firebase/config :dry-run?] true)
    dry-run?))

(is-dry-run? tconfig true)

Eric Dvorsak 2025-03-24T21:04:38.664119Z

will do a mini repro

Eric Dvorsak 2025-03-24T22:26:27.129309Z

I was not able to reproduce, and after running

clj-kondo --lint "$(clojure -Spath)" --copy-configs --skip-lint
to update the imports in my OG project I noticed this change:
modified   .clj-kondo/mount/mount/hooks/defstate.clj
@@ -34,8 +34,6 @@
               (cond-> [(api/token-node 'def) n]
                 docs (conj docs)
                 true (conj (api/list-node
-                            [(api/token-node 'atom)
-                             (api/list-node
-                              (list*
-                               (api/token-node 'do)
-                               args))]))))})))
+                            (list*
+                             (api/token-node 'do)
+                             args)))))})))
and now I don't have the error anymore

borkdude 2025-03-24T22:30:18.935639Z

cool. probably the config got updated then, problem solved :) looks like it got updated recently: https://github.com/tolitius/mount/commits/master/

imre 2024-08-01T11:44:40.676579Z

Linter idea: ability to put minimum version of clj-kondo into config and fail when checked by an older version of clj-kondo. Perhaps add as part of the clj-kondo config linter?

❤️ 3
borkdude 2024-08-01T11:45:34.626399Z

yeah, good idea. issue welcome

imre 2024-08-01T11:45:50.806809Z

sure gimme a few mins

borkdude 2024-08-01T11:53:31.259559Z

there's a similar mechanism in babashka for the version comparison etc, probably that code can be borrowed/copy-pasted

borkdude 2024-08-01T11:53:50.739519Z

in bb it's called :min-bb-version in bb.edn

imre 2024-08-01T11:57:05.802899Z

yep, that's where the idea came from

imre 2024-08-01T11:57:33.478239Z

I added a bit about detecting outdated bin from the linter names in the config

imre 2024-08-01T11:58:11.403079Z

oh that's actually covered by the current linter

imre 2024-08-01T11:58:41.177709Z

I wonder if that only works on the very file or the aggregate?

Stig Brautaset 2024-08-01T12:38:13.653809Z

This would be very welcome. I was confused why a check was failing in CI when it passed locally, and it turned out to be exactly this: CI version of clj-kondo was older than my local one.

imre 2024-08-01T12:38:46.412069Z

give it a 👍🏼 so 🙂

👍 1