In the next clj-kondo version:
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
cool! 👏
https://clojurians.slack.com/archives/C06MAR553/p1722512056835909
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.
<@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.
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)
can you make a small repro and file an issue?
yes, you can override type mismatch:
{:linters {:type-mismatch {:namespaces {'clojure.core {'deref {:arities {1 {:args [:any]}}}}}}}}
from the top of my headThanks, I will try and will make an issue with repro for you
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
In some cases it indeed can return a map
The point isn't what happens in reality, but what clj-kondo thinks is happening, due to those hooks
you can also try to override the type of defstate:
{:linters {:type-mismatch {:namespaces {'mount.lite {'defstate {:arities {:varargs {:ret :any}}}}}}}}
if that works, perhaps it's best to move that to mount.lite
@thierry572 you can try the version from my PR here: https://github.com/aroemers/mount-lite/pull/31
will do, you are so fast. I was still figuring out how to create a repro
I tried both linter options, neither work
actually this is a better solution: https://github.com/aroemers/mount-lite/pull/31/commits/a1520a46c1da6195bc37a9e5b2682ee977f5dd66
linting took 5893ms, errors: 0, warnings: 0
Thanks, that worked like a charm
👍
Perhaps you can make a comment in that PR to say that it worked for you
I was just finishing typing exactly that
🙂
Maybe @arnout can merge the PR and do a release?
Had to make a quick override hook to fix the default hook resetting
yeah you could do that as well for now
There's a similar issue with mount
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 issueactually 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
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
damn was just a fluke the error is still there with linter
:linters {:type-mismatch {:namespaces {'mount.core {'defstate {:arities {:varargs {:ret :any}}}}}}try mount.core/defstate clj-kondo.lint-as/def-catch-all
this suppresses all other warnings but still recognizes the var name
unless you want more linting of course
will it completely ignore the defstate hook which provides some nice errors when you screw up the macro usage?
ah sorry, I didn't completely read this thread, premature answer
so it's not an issue with mount?
sorry, it's getting late, I'll try to look again tomorrow if you can clarify the issue
it's kindof an issue at the intersection of kondo, malli and mount
lint-as def-catch-all does stop the error
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
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)will do a mini repro
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 anymorecool. probably the config got updated then, problem solved :) looks like it got updated recently: https://github.com/tolitius/mount/commits/master/
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?
yeah, good idea. issue welcome
sure gimme a few mins
there's a similar mechanism in babashka for the version comparison etc, probably that code can be borrowed/copy-pasted
in bb it's called :min-bb-version in bb.edn
yep, that's where the idea came from
I added a bit about detecting outdated bin from the linter names in the config
oh that's actually covered by the current linter
I wonder if that only works on the very file or the aggregate?
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.
give it a 👍🏼 so 🙂