Fork me on GitHub
#clj-kondo
<
2023-01-14
>
robert-stuttaford16:01:53

curious, a question about linting cljc where a binding is used in only one target... is this the lowest-friction way to deal with unused-binding if you want zero warnings?

#_{:clj-kondo/ignore [:unused-binding]} ;; for `props`
(defui action-link-button [{:keys [href title] :as props}]
  ($ :a {:href href
         #?@(:cljs [:on-click (with-prevent-link-events
                                (let [{{:keys [action-chan]} :action-queue
                                       :keys [action]} props]
                                  #(action! action-chan action)))])}
     title))

borkdude16:01:02

yes, or :as #?(:cljs props :clj _)

robert-stuttaford16:01:36

glad i asked, didn't think of that trick!

👍 2
dominicm16:01:51

I'm linting a macro that's intended for use with cljs. It expands to contain something like:

;; bar.clj
(ns foo.bar)

(defmacro baz
  []
  `(some.other.ns/bish))
Then to make it available, I do:
;; bar.cljs
(ns foo.bar
  (:require some.other.ns)
  (:require-macros [foo.bar :refer [baz]]))
But kondo is insistent that when I use the macro that I need to require some.other.ns.
;; app.cljs
(ns app
  (:require [foo.bar :refer [baz]]))

(baz)
Is there some way I can have my analysis hook indicate that some.other.ns will be loaded so it isn't a problem?

borkdude18:01:19

You can write (list 'some.other.ns/bish)

borkdude18:01:49

or ~'some-other-ns/bish

dominicm20:01:36

Won't that just quote the form, rather than indicate it's loaded?

borkdude20:01:58

Yes, isn't that exactly what you want?

dominicm20:01:19

The form needs to be expanded so it can be analyzed. Just not for this symbol referring to a namespace that isn't required.

dominicm20:01:06

I've missed the part where the form is sort of a fill in to get kondo to check that the code provided plays nicely in a threading macro with other code.

dominicm20:01:35

So I still want analyzed as if it works. But also, the require isn't missing, it's just done by the macro instead.

borkdude20:01:10

You want to generate (some-thing.foobar/whatever 1) regardless of what your namespace aliases are. Then it's better to use single quote as this is unrelated to your namespace state. Either: (list 'something.foobar/whatever 1) or

`(~'something.foo/whatever 1)
does that

borkdude20:01:17

or maybe I'm missing something. this is about macro usage?

borkdude20:01:26

can you maybe write a repro that I can inspect locally?

dominicm20:01:28

I think you're missing something

dominicm20:01:34

This is for my hook analysis

dominicm20:01:06

But in clojurescript, you have to refer to things by their full name from macros

borkdude20:01:19

maybe just require the namespace in the namespace where you're using the macro?

dominicm20:01:36

That leaks the abstraction though :)

dominicm20:01:00

That's a workaround, which is fine. But I'd like to drive through a solution

borkdude20:01:23

you can configure :unresolved-namespace :exclude [your.generated.namespace]

dominicm20:01:49

Can I do that just for a single nested form?

borkdude20:01:19

you can do that with a combination of :config-in-call for the macro maybe

borkdude20:01:03

:config-in-call {your.ns/macro {:linters {:unresolved-namespace {:exclude [some-thing.foobar]}}}

dominicm20:01:33

I'd prefer that the user was warned if they wrote the fully qualified namespace without requiring it.

dominicm20:01:46

I'd just like to ignore it in generated code

borkdude20:01:00

then maybe just not generate that namespace usage?

dominicm20:01:02

But I want kondo to analyze usage with it 😜 Eg, I want to generate (call.to.foo/bar ~@user-code) for kondo to lint that the user supplied list isn't longer than the args that bar can take, etc.

borkdude20:01:17

but if your macro generates that namespace usage, shouldn't the user at least require that namespace themselves? or is this never the case?

dominicm20:01:34

Never the case. The macro requires it for them.

borkdude20:01:52

how does a macro require namespaces for them?

dominicm20:01:14

It's required by the namespace the macro is defined in

borkdude20:01:02

but a macro runs in the JVM and generates CLJS code. the JVM cannot require CLJS code.

dominicm20:01:39

That's why the cljs namespace is there to do :require-macros. This is how cljs-compatible macros work.

borkdude20:01:30

But in that case the user already requires this macro namespace and the require should already be present? Can you give me a real example that I can run that demonstrates the problem?

dominicm20:01:11

But I'm generating a call to a third namespace, not the namespace the macro is defined in.

borkdude20:01:40

ok, and the cljs namespace is also loading that

dominicm20:01:43

I can put one together, but I'm pretty tired for tonight.

dominicm20:01:50

Yeah, exactly 🙂

borkdude20:01:22

so the :config-in-call + :unresolved-namespace + :exclude should work but instead of :exclude we should have something like :already-loaded for namespace that are safely assumed to be loaded

dominicm20:01:07

Exactly. OR, we could allow to mark the "generated" code which only has some of the analysis applied to it.

borkdude20:01:14

I think we could change the meaning of :exclude to mean: this isn't unresolved, but already loaded globally

borkdude20:01:28

that would be the smallest change to support your use case

borkdude20:01:21

and "globally" can be less global with a combination of :config-in-call

borkdude20:01:34

issue welcome