Fork me on GitHub
#clj-kondo
<
2021-03-04
>
ericdallo12:03:09

Can I have a hook in my ~/.clj-kondo dir? I'd like to create a hook for a common macro used on hundred of clojure projects

borkdude12:03:45

yes, you can

nice 1
thanks 1
borkdude13:03:00

It might even better to check the hook code into those projects or into the libraries for which the hook code is written for, so your co-workers can re-use them too

ericdallo13:03:30

Yes, we already have a common config for clj-kondo 🙂 my idea is add a hook there as well

ericdallo13:03:36

Is there a example of a hook that defines a var-definition? I have a macro that behaves similar to defn with some minor differences, How can I tell to the clj-kondo in the hook that the first arg is the var-definition name ?

borkdude13:03:33

@ericdallo Write a hook that expands into a clojure.core/defn or clojure.core/def node

ericdallo13:03:51

Oh got it, I'll give a try

borkdude13:03:25

It's basically a macro-expansion with rewrite-clj nodes

borkdude13:03:37

And then you return that node using {:node your-new-node}

ericdallo13:03:37

It worked, thanks! 🙂

ericdallo13:03:31

BTW, I needed to manually add the with-meta to the analysis correctly work

borkdude13:03:07

@ericdallo That is expected and documented. Maybe for your custom defn you also could have used {:lint-as {... clj-kondo.lint-as/def-catch-all}}

ericdallo13:03:44

I was using that :lint-as for months, but now I want to fix some things from that macro

borkdude13:03:09

We could maybe change the behavior of newly created nodes automatically taking over the position of the outer original node, but that might also confuse people when there is a linting warning on the wrong position

ericdallo13:03:46

it's a integration test macro:

(defflow my-integration-test

  [a (my-func)]
  (some-flow)
  [b (other-func)]
  (other-flow))

borkdude13:03:43

you can add your hook to this library

borkdude13:03:55

when you lint your classpath, then clj-kondo will recognize it

borkdude13:03:06

as in: copy it to your config dir

borkdude13:03:14

you will still have to opt in to the config yourself

ericdallo13:03:56

oh, really cool! So I'd just need to add to my config the :hooks map, but not the hooks folder with the hooks since it'd be present on the lib, right?

ericdallo13:03:29

oh, it's like magic! really cool

borkdude13:03:03

yes, and when you have a new version of your library, the hook code is updated as well

ericdallo13:03:03

really amazing indeed, could I open a PR for https://github.com/clj-kondo/config/tree/master/resources/clj-kondo.exports/clj-kondo adding that state-flow macro later?

borkdude13:03:24

yeah you could do that, but you could also just add it to state-flow itself

ericdallo13:03:59

Yes, I'll certainly add to the state-flow, so maybe we don't need to add to the clj-kondo/config so?

borkdude13:03:25

yeah, clj-kondo/config is only for hooks that are contributed without being it part of the libraries themselves

👍 1
ericdallo15:03:01

FTR this is the final hook

ericdallo15:03:06

(defn ^:private defflow-bindings [nodes]
  (->> nodes
       (filter api/vector-node?)
       (map (fn [node]
              (let [[sym val] (:children node)]
                [sym val])))
       flatten
       vec))

(defn ^:private defflow-flows [nodes]
  (filter (complement api/vector-node?) nodes))

(defn defflow [{:keys [:node]}]
  (let [[name & flows] (rest (:children node))
        new-node (api/list-node
                  (list
                   (with-meta (api/token-node 'defn) (meta name))
                   (with-meta (api/token-node (api/sexpr name)) (meta name))
                   (api/vector-node [])
                   (api/list-node (list* (api/token-node 'let)
                                         (api/vector-node (defflow-bindings flows))
                                         (defflow-flows flows)))))]
    (prn (api/sexpr new-node))
    {:node new-node}))

ericdallo15:03:50

And a sample of usage:

(defflow my-flow
  [a (+ 1 2)]

  (flow "flow-1"
        (match? a
                1))

  [b (+ 1 2)]

  (flow "flow-2"
        (match? a
                b)))

borkdude16:03:22

you can probably combine map + flatten into mapcat

borkdude16:03:56

looking good, don't forget to remove the prn

❤️ 1
ericdallo16:03:46

thanks! I tried to change the defn to clojure.test/deftest but it seems to not work

borkdude16:03:32

you should probably generate (do (require 'clojure.test) (clojure.test/deftest ...)) in that case

borkdude16:03:54

if clojure.test has not been required yet

ericdallo16:03:03

oh, I see, let me try

ericdallo16:03:46

Not sure if I did correctly the export config

borkdude16:03:54

lemme check

borkdude16:03:12

@ericdallo I would use a multi-segment namespace like nubank.state-flow for the hook namespace

borkdude16:03:05

note that here clj-kondo is the org, because this hook is written on behalf of the clj-kondo org

ericdallo16:03:19

got it, let me change it

ericdallo16:03:35

Done, still looks odd to me the path:

resources/clj-kondo.exports/nubank/state-flow/nubank/state_flow.clj
is that right?

borkdude16:03:48

yeah, that's right :)

ericdallo16:03:03

Also I included a:

resources/clj-kondo.exports/nubank/state-flow/config.edn
not sure if this should be in the lib or manually set by user

borkdude16:03:27

only the parts that are relevant for the lib should be in there, including the hook config

ericdallo16:03:13

so it seems correct to me

ericdallo16:03:31

I'll try to generate a snapshot release local and test it

ericdallo16:03:59

Hum, it didn't work

ericdallo16:03:34

I tried to add to my home config:

{ :hooks         {:analyze-call {
                                state-flow.cljtest/defflow   nubank.state-flow/defflow
                                state-flow.core/flow         nubank.state-flow/flow}}}

ericdallo16:03:40

but it didn't work as well

borkdude16:03:38

You should not have to add this to your home config if you opt-in to your library config

ericdallo16:03:52

Yes that's what I thought

ericdallo16:03:03

so maybe the folders hierarchy in the lib are not right

ericdallo16:03:17

I already did it, I tried adding a :config-paths ["nubank/state-flow"] but didn't work 😕

borkdude16:03:59

is this dir present in your .clj-kondo dir?

ericdallo16:03:39

you mean the one in the lib or on my home?

borkdude16:03:44

in the project where you imported it

borkdude16:03:50

or did you import it in your home dir?

borkdude16:03:01

just tell me where you see the copied files

ericdallo16:03:25

So, that's what I did: • generated a local release in this branch: https://github.com/nubank/state-flow/pull/149/files • Changed a local project to usethe local release • when I start lsp on the file it does not handle the macro, it was handling when the hook was on my home dir before I move it to the lib

borkdude16:03:45

Where is the copied file (if at all)

borkdude16:03:50

Just give me the full path

ericdallo16:03:48

sorry, that last part is not clear to me, should I add that

{:config-paths ["nubank/state-flow"]}
in the lib config.edn?

ericdallo17:03:28

I don't see any Copied config to message anywhere

ericdallo17:03:56

oh found a log message on clojure-lsp:

WARNING: error while trying to read hook for integration.aux.init/defflow: Could not find namespace: nubank.state-flow.

borkdude17:03:32

Just try to walk through the docs step by step for the clj-kondo config project example, it should explain itself

ericdallo17:03:18

It works now, I renamed only the hook file not the ns inside it :man-facepalming: Thanks for the help and sorry for bother you 🙂

borkdude17:03:19

glad you found it ;)

🎉 1
devn18:03:15

is there any way to show globally unused publics in linting output? I think the answer is no, but I could swear there was a point in time where this was possible…

borkdude18:03:58

@devn This isn't supported out of the box, but you can do this using analysis output: https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md#unused-vars Private unused vars are reported though.

borkdude18:03:28

There is also https://github.com/borkdude/carve to do this for you

devn20:03:41

nice. i was mostly asking because in older versions of clojure-lsp, it’d highlight public global unused vars, and that was very handy for knocking out dead code

borkdude21:03:12

it can continue to do so, the information is there

borkdude21:03:23

you get this with the lens-mode now

ericdallo21:03:26

yes, we could do the same logic from lenses indeed, just don't know if we should always present that as a warning

ericdallo21:03:40

like for api usages and etc

borkdude21:03:24

maybe that can be a config, but IMO lens-mode is sufficient

ericdallo21:03:48

yes, a config would work

ericdallo21:03:03

Actually, a flag for that looks good, I just wonder the default

borkdude21:03:31

The default should probably be: disabled

borkdude21:03:11

it could just be an "info" diagnostic as well, the level could maybe be similarly set as how clj-kondo does it

borkdude21:03:44

I think I would turn it on sometimes, but not all the time, similar to lens-mode

borkdude21:03:53

(which for me personally is enough)

devn21:03:05

yeah, i can use the lens (and I have been), but the highlight was nice IMO. I’m actually a bit surprised y’all think the default should be disabled.

devn21:03:37

When I think about it, I’m not sure why you’d have an unused public fn that is part of an API that doesn’t have a matching test (even if the level of test is as simple as “it exists”).

devn21:03:25

but I mean, if it’s configurable, no sweat either way

borkdude21:03:02

highlight as in: not a warning like clj-kondo but something more subtle?

ericdallo21:03:54

Yeah, I think the same, I think I'll add something like :public-vars-lint-level :info

borkdude21:03:11

we could do a highlight the same as when you are on a local?

borkdude21:03:19

some different color maybe?

borkdude21:03:26

not sure how this is done. Maybe take it to #lsp?

👍 3
richiardiandrea22:03:54

Detect unreachable specs - has this idea already been proposed / implemented? https://stackoverflow.com/questions/45819346/how-to-check-the-resolvability-of-clojure-specs

borkdude22:03:00

unreachable as in unused or unresolvable as undefined - two different things ?

richiardiandrea01:03:01

ah good point, I would was thinking more of used but undefined like a (s/keys :req-un [::where]) that does not have corresponding (s/def ::where map?)