Fork me on GitHub
#clj-kondo
<
2023-11-14
>
ingesol09:11:13

Hi! Would it make sense to have a linter to warn about direct calls to the host environment, like js/window , java.lang.String ? It would be useful for codebases that need to be cross compatible (Node, JVM, browser)

borkdude09:11:49

is this just an idea or something you're experiencing as a problem? In my experience when writing a .cljc file you usually get sufficient warnings if you're trying to do a JVM thing in an un-reader-conditionalized part of the code

ingesol15:11:16

Thanks for the shift in perspective! It’s more of an idea I think. We have a huge CLJS-based app, and would like to test and run parts of it on nodejs. Converting everything to CLJC is probably not happening, but would be the sensible thing to do if we wanted it cross platform

tragiclifestories13:11:54

Hi! I'm wondering if somebody can help me with implementing an :analyze-call hook - basically I want it to take the second and after arguments of the macro invocation and produce (-> nil arg2 arg3) etc. 🧵

tragiclifestories14:11:25

What I have is:

(ns hooks.spec-generate
  (:require [clj-kondo.hooks-api :as api]))

(defn generate-> [{:keys [node]}]
  (let [[_ & body] (rest (:children node))
        new-node (api/list-node
                  (list*
                   (api/token-node '->)
                   nil
                   (if body
                     body
                     (api/list-node
                      (api/keyword-node :default)))))]
    {:node new-node}))

tragiclifestories14:11:44

But when the call site has, eg:

(generate-> :first-arg (assoc :foo :bar))
I still get linting errors for arity and keywords not being the right type for the first argument to assoc

tragiclifestories14:11:03

so I feel like I'm Doing It Wrong:tm: but can't work out why

tragiclifestories14:11:08

config.edn (extract):

{:hooks
 {:analyze-call {finops.spec/generate-> hooks.spec-generate/generate->}}}

imre14:11:49

This might be easier with a macroexpand hook

borkdude14:11:12

This looks wrong:

(api/token-node '->)
                   nil

borkdude14:11:27

You should probably write:

(api/token-node 'clojure.core/->)
(api/token-node nil)

borkdude14:11:57

and (api/list-node ..) should be called with a list-like thing, not with a single node

borkdude14:11:21

if you call clj-kondo on the command line with --debug it will tell you that latter error

borkdude14:11:44

probably also the other error for nil not being a node

tragiclifestories14:11:54

Yeah, all that fixed it. I think I understand the hooks API a little better now, thanks!

Noah Bogart16:11:16

would it be possible to return plain clojure data from a hook and have the analyzer convert it to the appropriate nodes as necessary?

Noah Bogart16:11:52

as one who writes a lot of hooks lol, I wonder what's gained by having to manually write api/token-node and api/list-node etc. is there something special about those that a postwalk couldn't do?

Noah Bogart16:11:18

or if you don't want to enable it for everyone, maybe there could be a helper function to do it that hook authors can use themselves

borkdude16:11:57

This is what the :macroexpand hook does?

Noah Bogart16:11:49

is that the only difference? for some reason, I thought :macroexpand did other stuff too

borkdude16:11:29

the differences are described in the docs, but in short, macroexpand is less powerful

borkdude16:11:58

since you don't have precise control over locations: numbers, etc cannot carry metadata

borkdude16:11:50

but for def-whatever like macros it's often enough

Noah Bogart16:11:45

can you call reg-finding! in them? does it work the same otherwise?

borkdude16:11:38

yes, you can

👀 1
Noah Bogart16:11:49

hell yeah, okay

Noah Bogart16:11:29

the docs made it seem like it was more magical and couldn't do all the same stuff as :analyze-call

borkdude16:11:10

maybe you read magic into it?

borkdude16:11:44

it's not magic, but it's less accurate because of loss of data while translating to s-expressions and back

borkdude16:11:10

also there is currently a problem with namespaced keywords like ::foo/bar - those aren't properly converted back and forth

borkdude16:11:21

not many people have noticed that though

Noah Bogart16:11:06

right. i think the lack of examples and the short docs made me think it was fundamentally different from :analyze-call. the analyze-call docs are long and have lots of examples, and the macroexpand docs don't say "this is analyze-call but with coercion".

Noah Bogart16:11:58

maybe i'll write up an example that calls api/reg-finding! to demonstrate that it all works the same as :analyze-call except for the returned type

borkdude17:11:04

that would be nice :)

borkdude17:11:16

macroexpand didn't exist at first when those docs got written

👍 1
Noah Bogart18:11:17

i did some looking through the hooks code and it turns out you have api/coerce in there already, so that's exactly what i was looking for lol. from

(let [defn-block (api/list-node (list* (api/token-node 'defn-)
                                           job-name
                                           (api/vector-node [fn-arg])
                                           body))
          node (api/list-node [(api/token-node 'do) defn-block job-name])]
      {:node node})))
to
(let [node (api/coerce `(do (defn- ~job-name [~fn-arg] ~@body)
                                ~job-name))]
      {:node node})))

Noah Bogart19:11:45

once again, you've outdone yourself and have made my development life easier. thank you!

mkvlr17:11:58

could clj-kondo implement a cyclic dep linter? This is one of the things where I currently restart my process which is annoying and slow. Maybe I should also into a better way to repl debug this.

❤️ 1
borkdude18:11:56

I think clojure-lsp is in a better place to do this than clj-kondo since clojure-lsp runs as a server and scans your entire project. It is possible to use the existing data as shown here: https://github.com/clj-kondo/clj-kondo/blob/12342316a4eecf1c543f1f1dbfd283b6cc68dc68/analysis/README.md?plain=1#L454

Derek22:11:54

Was there a change in behavior between 2023.09.07 and 2023.10.20 related to incorrect lint-as rules?

Derek22:11:02

A macro that should have been linted as clojure.core/fn was linted as clj-kondo.lint-as/def-catch-all incorrectly

Derek22:11:49

With 2023.09.07 it runs, but in 2023.10.20 it fails to parse and throws an NPE

Derek22:11:57

I'm carving out a small repro

borkdude22:11:59

This bug was already reported and fixed on master.

Derek22:11:20

Thank you

Derek22:11:00

We're fixing our lint-as config

👍 1