clj-kondo

https://github.com/clj-kondo/clj-kondo
practicalli-john 2020-12-17T12:23:47.161400Z

Is clj-kondo able to pick up files with - in the name rather than _ ? So if I had test/practicalli/lintme-test.clj instead of test/practicalli/lintme_test.clj I would get a warning.

borkdude 2020-12-17T12:24:29.161600Z

clj-kondo will lint any file you throw at it

practicalli-john 2020-12-17T12:25:03.162300Z

but it does not tell me I should have used an underscore. I assume this is out of scope

borkdude 2020-12-17T12:25:06.162500Z

Maybe you're asking about this? https://github.com/borkdude/clj-kondo/issues/842

❤️ 1
borkdude 2020-12-17T12:25:45.163Z

Still waiting for @pez's PR ;)

borkdude 2020-12-17T12:26:19.163800Z

Feel free to "upvote" the issue with a thumbs up

👍 1
borkdude 2020-12-17T12:26:28.164100Z

(this is Github's silly way to prioritize issues)

pez 2020-12-17T13:31:00.165Z

Haha, never heard the “Yes, fits this project” signal. 😃

pez 2020-12-17T13:31:43.165600Z

Not that you didn’t send it. It was just lost somewhere in transit. Haha.

orestis 2020-12-17T13:53:10.166100Z

So I’ve put better-cond in my codebase… and clj-kondo can’t read it (obviously). I started implementing a hook for it but it’s tricky. @borkdude I remember you used it as an example but I’m quite lost since the discussions were using a different syntax.

borkdude 2020-12-17T13:55:09.166500Z

@orestis I have a test hook for better-cond: https://github.com/borkdude/clj-kondo/blob/master/corpus/.clj-kondo/hooks/better_cond.clj

borkdude 2020-12-17T13:55:28.167200Z

which I used to test-drive the hook functionality. But I'm not sure how complete it is

borkdude 2020-12-17T13:55:40.167400Z

Feel free to add it to https://github.com/clj-kondo/config

orestis 2020-12-17T14:10:25.168100Z

It’s not complete, but it’s a good starting point. I’ll bother you with some things if I don’t manage to finish it 🙂

👍 1
orestis 2020-12-17T15:30:30.169100Z

Do you have a way to easily debug the various expressions? I’m trying to call api/sexpr but it seems to only work on the top level and I’d like to avoid writing the recursive version 😛

borkdude 2020-12-17T15:31:16.169500Z

@orestis Just call prn or println on the node

orestis 2020-12-17T15:34:00.169700Z

I get [<token: do> <list: (whena(dob))>] (no spacing)

orestis 2020-12-17T15:34:30.170400Z

which I think means:

(do (when a (do b))) 
but I’m not sure

borkdude 2020-12-17T15:34:31.170500Z

this is usually a sign that you garbled something

orestis 2020-12-17T15:34:40.170700Z

ah good to know 🙂

borkdude 2020-12-17T15:35:00.171Z

it seems you have a vector of nodes and not a node object itself

orestis 2020-12-17T15:35:42.171900Z

Isn’t that common though? When you are taking the children of a node and want to do stuff?

borkdude 2020-12-17T15:35:42.172Z

this happens to me too, just keep printing and iterating ;)

borkdude 2020-12-17T15:36:15.172600Z

yes, but you should put the children back into some node: (api/vector-node children) and not [children] in order for it to be a valid node

orestis 2020-12-17T15:38:17.173600Z

Ah right, I was trying to figure out if it should be a vector-node or a list-node or what?

orestis 2020-12-17T16:10:38.173900Z

I’m getting the hang of this:

(defn process-pairs [pairs]
  (loop [[[lhs rhs :as pair] & pairs] pairs
         new-body [(api/token-node 'do)]]
    (if pair
      (let [lhs-sexpr (api/sexpr lhs)]
        (clojure.core/cond
          ;; single trailing element, flush the body
          (= 1 (count pair))
          (api/list-node (conj new-body lhs))

          ;; when node, recurse
          (#{:when 'when} lhs-sexpr)
          (api/list-node 
            (conj new-body (api/list-node
                             [(api/token-node 'when)
                              rhs
                              (process-pairs pairs)])))

          ;; let-like nodes
          (#{:let :when-let :when-some
             'let 'when-let 'when-some} lhs-sexpr)
          (api/list-node (conj new-body 
                               (api/list-node 
                                 [(api/token-node 'let)
                                  rhs 
                                  (process-pairs pairs)])))

          ;; normal conditions, just add them to the body
          :else
          (recur pairs
                 (conj new-body lhs rhs))))
      ;; no trailing element, flush the body
      (api/list-node new-body))))

(def cond
  (fn [{:keys [node]}]
    (let [expr (let [args (rest (:children node))
                     pairs (partition-all 2 args)]
                 (process-pairs pairs))]
      ;(println "COND" {:node (api/sexpr expr)})
      {:node (with-meta expr
               (meta node))})))

orestis 2020-12-17T16:12:30.175300Z

This deals with most cases — but not the “early bailing” ones (e.g. when-let) because the type-checking continues…

borkdude 2020-12-17T16:13:09.175800Z

I bet better-cond would come in handy here ;)

orestis 2020-12-17T16:13:10.175900Z

(b/cond
  :when-let [b nil]
  (+ 1 b))

orestis 2020-12-17T16:13:41.176700Z

In reality, (+ 1 b) is never evaluated because b is nil, but clj-kondo flags: expected number, got nil

borkdude 2020-12-17T16:13:42.176800Z

ah, that gives a false positive?

borkdude 2020-12-17T16:14:19.177700Z

who uses nil in when-let though?

borkdude 2020-12-17T16:14:28.178100Z

that's not a realistic use case

orestis 2020-12-17T16:14:32.178200Z

It’s not too bad in practice since you never use explicit nils but doing the full thing would probably mean just lifting the implementation 1-1

orestis 2020-12-17T16:14:48.178600Z

Gotta run 🙂 I’ll continnue this tomorrow.

borkdude 2020-12-17T16:14:52.178800Z

:thumbsup:

Oliver George 2020-12-17T23:41:09.180300Z

Idle thought: do you imagine clj-kondo might grow to include a --autofix flag to make the obvious corrections (e.g. remove redundant lets, remove unused bindings, convert if to when...)