Fork me on GitHub
#clj-kondo
<
2022-01-13
>
Michael Gardner04:01:25

I'm writing a simple CLI tool that uses clj-kondo's analysis output. Working with clj-kondo has been very pleasant!

Michael Gardner04:01:19

I'm trying to make things fast now, and I noticed that it doesn't seem any faster to run the analysis the second time, even though a cache is created in .clj-kondo . Is this expected? How can I verify what clj-kondo is doing with the cache? I tried setting :debug true but didn't see any extra output at all, so I'm probably holding it wrong

borkdude08:01:26

The analysis output itself isn't cached. The cache is used to look up info about other namespaces for linting: it's only used for functionality used by clj-kondo itself. If you want to do this as a user you should implement your own cache.

👍 1
borkdude12:01:40

Going to add some linting for .clj-kondo/config.edn. Any suggestions for common mistakes?

borkdude12:01:37

The first one I've added is:

dharrigan14:01:11

It's been pretty good so far, the one that caught me out recently was having a top-level key nested under another top-level key.

dharrigan14:01:25

(as you know 🙂 )

borkdude15:01:22

clj-kondo 2022.01.13: a linter for Clojure code that sparks joy clj-kondo • Add linter `:conflicting-fn-arity`: warn when an arity occurs more than once in a function that overloads on arity. https://github.com/clj-kondo/clj-kondo/issues/1136 (https://github.com/mknoszlig) • Add linter `:clj-kondo-config` which provides linting for `.clj-kondo/config.edn`. https://github.com/clj-kondo/clj-kondo/issues/1527 • Relax `:reduce-without-init` for functions known to be safe https://github.com/clj-kondo/clj-kondo/issues/1519 • Symbol arg to `fdef` can be arbitrary namespace https://github.com/clj-kondo/clj-kondo/issues/1532 • Improve potemkin generated var-definition analysis https://github.com/clj-kondo/clj-kondo/issues/1521 (https://github.com/ericdallo) • Stabilize cache version independent from kondo version https://github.com/clj-kondo/clj-kondo/issues/1520. This allows you to re-use the cache over multiple kondo versions. • :output {:progress true} should print to stderr https://github.com/clj-kondo/clj-kondo/issues/1523 • Only print informative messages when `--debug` is enabled. https://github.com/clj-kondo/clj-kondo/issues/1514 • Add Sublime Text instructions https://github.com/clj-kondo/clj-kondo/issues/827 (https://github.com/KyleErhabor) • Fix end location in anonyous function body https://github.com/clj-kondo/clj-kondo/issues/1533 • Bump datalog-parser to 0.1.9: allows symbol constants in datalog expression

❤️ 1
imre19:01:01

:simple-libspec false is right after the map it's supposed to be in

imre19:01:32

I'm guessing the new config linter would catch a similar one

borkdude19:01:35

I don't even know what this does. How do you know where it's supposed to go? ;)

imre19:01:28

Checked the impl of the linter whose config is just before it

imre19:01:51

And its indentation implies it should be in the map

borkdude19:01:01

ah I see it now yes, thanks

borkdude19:01:43

the linter doesn't catch this yet, but can be made so

imre19:01:50

I guess it would have caught it as an unknown linter. As of the linked commit, the key is in a position where a linter name should be

borkdude19:01:00

let's test it out :)

borkdude19:01:30

It doesn't catch that specific one since the expected names are derived from this config 😂

imre19:01:07

Quite the edge case 😁

dharrigan15:01:58

First release of the year, if I'm not mistaken! Here's to many more! 🙂

Ben Sless17:01:24

Is there a ticket for #meander support?

borkdude17:01:35

@ben.sless No, but the first reaction will be: do it as a configuration macro/hook and share it via clj-kondo.exports in the library

borkdude17:01:05

I can help with that if you want

Ben Sless17:01:15

It's incredibly complicated with a ton of syntax and binding forms, wouldn't really know where to start

borkdude17:01:42

Let's just start with an example

Ben Sless17:01:55

(m/rewrite {:a 'a :b nil :c 3}

  {:a ?a :b ?b :c ?c}
  {:a ?a
   & ~[(if ?b [:b ?b])
       (if ?c [:c ?c])]})
(rewrite expr & pairs)

Ben Sless17:01:23

left and right pairs are handled differently, lhs introduce bindings, rhs use bindings

borkdude17:01:26

what does the tilde mean in this context?

borkdude17:01:39

yeah, this can all be done using hooks, I'm convinced :)

borkdude17:01:17

it's pretty similar to core.match

Ben Sless17:01:58

core.match on steroids and mutagenic agents 🙂

borkdude17:01:30

I'll take a stab at this and you can take it further if you want.

Ben Sless17:01:07

Appreciate it. If it helps, this is what this would expand to:

(let*
  [R__15723
   (let*
     [TARGET__15718 {:a 'a, :b nil, :c 3}]
     (let*
       [T__15721
        (. TARGET__15718 valAt :c)
        T__15720
        (. TARGET__15718 valAt :b)
        T__15719
        (. TARGET__15718 valAt :a)]
       (let*
         [?a T__15719]
         (let*
           [?b T__15720]
           (let*
             [?c T__15721]
             (let*
               [form__12952__auto__ {:a ?a}]
               (merge
                 (into {} cat [[(if ?b [:b ?b]) (if ?c [:c ?c])]])
                 form__12952__auto__)))))))]
  (if (meander.match.runtime.epsilon/fail? R__15723) nil R__15723))

Ben Sless17:01:06

If there was no unquote, the code inside the vector would be quoted as symbols

borkdude17:01:41

.clj-kondo/meander/epsilon.clj:

(ns meander.epsilon
  (:require [clojure.string :as str]
            [clojure.walk :as walk]))

(defn collect-vars [expr]
  (let [vars (volatile! [])]
    (walk/postwalk (fn [x]
                     (when (and (symbol? x)
                                (str/starts-with? (str x) "?"))
                       (vswap! vars conj x))
                     x)
                   expr)
    @vars))

(defmacro rewrite [expr & exprs]
  (let [ret `(do ~expr
                 ~@(map (fn [[lhs rhs]]
                          `(fn ~(collect-vars lhs)
                             ~rhs))
                        (partition 2 exprs)))]
    ;; (prn ret)
    ret))

borkdude17:01:56

.clj-kondo/config.edn:

{:hooks {:macroexpand {meander.epsilon/rewrite meander.epsilon/rewrite}}}

borkdude17:01:58

this should be enough to get you started. once you have complete support, you can rewrite it into a :analyze-call hook, which would take care of better locations

Ben Sless17:01:42

Thanks, I'll try rolling with it and see how it goes

borkdude17:01:47

The idea is: just expand into something which makes syntactically sense, but it doesn't really have to make sense in terms of what the library exactly does