clj-kondo

https://github.com/clj-kondo/clj-kondo
ericdallo 2021-03-04T12:57:09.113600Z

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

borkdude 2021-03-04T12:57:45.113900Z

yes, you can

1
1
borkdude 2021-03-04T13:02:00.114800Z

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

ericdallo 2021-03-04T13:05:30.115400Z

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

ericdallo 2021-03-04T13:25:36.116700Z

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 ?

borkdude 2021-03-04T13:26:33.117700Z

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

ericdallo 2021-03-04T13:27:51.117900Z

Oh got it, I'll give a try

borkdude 2021-03-04T13:28:25.118200Z

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

borkdude 2021-03-04T13:28:37.118500Z

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

ericdallo 2021-03-04T13:38:37.118700Z

It worked, thanks! 🙂

ericdallo 2021-03-04T13:39:31.119400Z

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

borkdude 2021-03-04T13:40:07.120200Z

@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}}

ericdallo 2021-03-04T13:40:44.120900Z

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

borkdude 2021-03-04T13:41:09.121800Z

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

ericdallo 2021-03-04T13:41:46.122800Z

it's a integration test macro:

(defflow my-integration-test

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

borkdude 2021-03-04T13:42:22.123100Z

cool

borkdude 2021-03-04T13:42:43.123500Z

you can add your hook to this library

borkdude 2021-03-04T13:42:55.123800Z

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

borkdude 2021-03-04T13:43:06.124400Z

as in: copy it to your config dir

borkdude 2021-03-04T13:43:14.124800Z

you will still have to opt in to the config yourself

ericdallo 2021-03-04T13:43:56.125600Z

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?

ericdallo 2021-03-04T13:44:29.126400Z

oh, it's like magic! really cool

borkdude 2021-03-04T13:46:03.126900Z

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

ericdallo 2021-03-04T13:47:03.127900Z

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?

borkdude 2021-03-04T13:47:24.128300Z

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

ericdallo 2021-03-04T13:47:59.129Z

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

borkdude 2021-03-04T13:48:25.129600Z

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

👍 1
ericdallo 2021-03-04T15:58:01.130200Z

FTR this is the final hook

ericdallo 2021-03-04T15:58:06.130300Z

(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}))

ericdallo 2021-03-04T15:58:50.130500Z

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)))

borkdude 2021-03-04T16:00:22.130800Z

you can probably combine map + flatten into mapcat

borkdude 2021-03-04T16:00:56.131Z

looking good, don't forget to remove the prn

❤️ 1
ericdallo 2021-03-04T16:01:46.131200Z

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

borkdude 2021-03-04T16:02:32.131500Z

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

borkdude 2021-03-04T16:02:54.131700Z

if clojure.test has not been required yet

ericdallo 2021-03-04T16:03:03.131900Z

oh, I see, let me try

ericdallo 2021-03-04T16:19:46.132100Z

Not sure if I did correctly the export config

ericdallo 2021-03-04T16:19:53.132300Z

does that looks correct for you? https://github.com/nubank/state-flow/pull/149

borkdude 2021-03-04T16:26:54.132500Z

lemme check

borkdude 2021-03-04T16:28:12.132700Z

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

borkdude 2021-03-04T16:29:05.133100Z

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

ericdallo 2021-03-04T16:29:19.133300Z

got it, let me change it

ericdallo 2021-03-04T16:33:35.133500Z

Done, still looks odd to me the path:

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

borkdude 2021-03-04T16:33:48.133700Z

yeah, that's right :)

ericdallo 2021-03-04T16:34:03.133900Z

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

borkdude 2021-03-04T16:34:27.134100Z

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

ericdallo 2021-03-04T16:37:13.134300Z

so it seems correct to me

ericdallo 2021-03-04T16:37:31.134500Z

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

borkdude 2021-03-04T16:37:49.134700Z

yes

ericdallo 2021-03-04T16:47:59.134900Z

Hum, it didn't work

ericdallo 2021-03-04T16:48:34.135100Z

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}}}

ericdallo 2021-03-04T16:48:40.135300Z

but it didn't work as well

borkdude 2021-03-04T16:49:38.135500Z

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

ericdallo 2021-03-04T16:49:52.135700Z

Yes that's what I thought

ericdallo 2021-03-04T16:50:03.135900Z

so maybe the folders hierarchy in the lib are not right

borkdude 2021-03-04T16:50:06.136100Z

Read the part about how to opt in: https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#exporting-and-importing-configuration

ericdallo 2021-03-04T16:53:17.136500Z

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

borkdude 2021-03-04T16:53:59.136700Z

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

ericdallo 2021-03-04T16:54:39.136900Z

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

borkdude 2021-03-04T16:55:44.137100Z

in the project where you imported it

borkdude 2021-03-04T16:55:50.137300Z

or did you import it in your home dir?

borkdude 2021-03-04T16:56:01.137500Z

just tell me where you see the copied files

ericdallo 2021-03-04T16:57:25.137700Z

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

borkdude 2021-03-04T16:58:03.137900Z

You should read the last part of https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#exporting-and-importing-configuration better

borkdude 2021-03-04T16:58:45.138100Z

Where is the copied file (if at all)

borkdude 2021-03-04T16:58:50.138300Z

Just give me the full path

ericdallo 2021-03-04T16:59:48.138500Z

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

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

ericdallo 2021-03-04T17:00:28.138700Z

I don't see any Copied config to message anywhere

ericdallo 2021-03-04T17:00:56.138900Z

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.

borkdude 2021-03-04T17:01:32.139100Z

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

ericdallo 2021-03-04T17:14:18.139400Z

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 🙂

borkdude 2021-03-04T17:15:19.139600Z

glad you found it ;)

🎉 1
devn 2021-03-04T18:02:15.140400Z

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…

borkdude 2021-03-04T18:55:58.141600Z

@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.

borkdude 2021-03-04T18:56:28.142Z

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

devn 2021-03-04T20:56:41.142900Z

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

borkdude 2021-03-04T21:00:12.143200Z

it can continue to do so, the information is there

borkdude 2021-03-04T21:00:23.143400Z

you get this with the lens-mode now

borkdude 2021-03-04T21:00:53.143600Z

^ @ericdallo

ericdallo 2021-03-04T21:02:26.144300Z

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

ericdallo 2021-03-04T21:02:40.144700Z

like for api usages and etc

borkdude 2021-03-04T21:03:24.145100Z

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

ericdallo 2021-03-04T21:03:48.145600Z

yes, a config would work

borkdude 2021-03-04T21:03:52.145800Z

@devn

ericdallo 2021-03-04T21:05:03.146500Z

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

borkdude 2021-03-04T21:08:31.146800Z

The default should probably be: disabled

borkdude 2021-03-04T21:09:11.147400Z

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

borkdude 2021-03-04T21:09:44.147700Z

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

borkdude 2021-03-04T21:09:53.147900Z

(which for me personally is enough)

devn 2021-03-04T21:16:05.148800Z

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.

devn 2021-03-04T21:17:37.149800Z

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”).

devn 2021-03-04T21:18:25.150500Z

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

borkdude 2021-03-04T21:19:02.151300Z

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

ericdallo 2021-03-04T21:19:54.152200Z

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

borkdude 2021-03-04T21:20:11.152800Z

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

borkdude 2021-03-04T21:20:19.153200Z

some different color maybe?

borkdude 2021-03-04T21:20:26.153700Z

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

👍 3
richiardiandrea 2021-03-04T22:08:54.155200Z

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

borkdude 2021-03-04T22:13:00.156Z

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