clj-kondo

https://github.com/clj-kondo/clj-kondo
borkdude 2020-06-01T07:01:26.290Z

@didibus No, E.g. the weird-macro example is similar to jdbc’s with-connection while the clj-kondo macro just expands into constructs that are known but is much simpler

borkdude 2020-06-01T07:02:27.291800Z

One other point is that clj-kondo has to deal with partial information. So it doesn’t go looking for namespaces elsewhere and find that macro for you

dominicm 2020-06-01T16:48:31.292400Z

@borkdude have you tried core.match yet? I think that's the killer example for it.

borkdude 2020-06-01T16:49:45.292700Z

I haven't yet, but that's a good one

dominicm 2020-06-01T16:50:46.294100Z

@borkdude is it possible to mark a macro expansion as allowing unused variables? Consider an anaphoric macro like proxy(?) where this is bound, but possibly not used.

borkdude 2020-06-01T16:54:08.294800Z

@dominicm Do you ask this in relation to the new macroexpand feature or in general?

dominicm 2020-06-01T16:54:44.295400Z

The new macro expansion feature

borkdude 2020-06-01T16:55:20.296100Z

I remember fixing something for proxy-super (https://github.com/borkdude/clj-kondo/commit/0cf0f2933d277c7986620bf31a8caca31c0e68af) But if you're implementing a stand-in macro, then you can just emit this so it will be linted as used.

dominicm 2020-06-01T16:58:44.296700Z

Heh, that's true. Hmm. Might be an option then :)

snoe 2020-06-01T17:06:25.297600Z

@borkdude that new macroexpansion feature looks great! I left some example macros that I've run across that might be useful to evaluate

seancorfield 2020-06-01T17:10:25.298900Z

Catching up on this thread from yesterday/earlier... So the idea is that you provide, essentially, a dumbed-down version of arbitrary macros in the config so that clj-kondo is better able to parse code and issue correct warnings?

seancorfield 2020-06-01T17:11:38.300100Z

The example shows it as text that is passed to SCI to evaluate -- would it be better to provide a (quoted) form instead so that folks writing these things can get code assist/syntax checking on the alternative macro definitions?

seancorfield 2020-06-01T17:12:19.300900Z

(but, yeah, looks very interesting -- and certainly SCI has allowed Chlorine to do amazing stuff, in user-land, to extend the functionality so the overall approach is sound)

borkdude 2020-06-01T17:46:40.301200Z

@snoe Thanks!

borkdude 2020-06-01T17:47:31.302300Z

@seancorfield Yes, you provide dumbed down version to teach clj-kondo about the syntax. The reason the code is not quoted is that this is supposed to be part of your .clj-kondo/config.edn and in EDN you can't use arbitrary code (not even quotes).

borkdude 2020-06-01T17:47:46.302700Z

I'm still thinking about a way to refer to another file in that config.

borkdude 2020-06-01T17:49:45.303600Z

@snoe I've already done one for slingshot try+: https://github.com/borkdude/clj-kondo/blob/baf3ff5077101dec2063fdced7a3ddac5c3c40b6/corpus/macroexpand.clj#L23

borkdude 2020-06-01T17:50:39.305Z

I've been considering reader tags to refer to other files, but I want something that can work in both .edn files and as metadata. Reader tags can break people's code.

seancorfield 2020-06-01T17:50:46.305300Z

Ah, good point about EDN not being code-sufficient. What Chlorine did was to have the config be .cljs and treat the whole file as SCI-consumable.

seancorfield 2020-06-01T17:51:21.306200Z

(that's harder for kondo which traffics in (unquoted) symbols tho')

borkdude 2020-06-01T17:52:09.306800Z

That works, but I want the code for each macro to be readable separately, as to not eval all macro stuff if only some of it is needed for linting e.g. one file

borkdude 2020-06-01T17:54:07.308Z

right now I have this:

{:macroexpand {foo/bar "foo/bar.clj"}}
which looks in .clj-kondo/foo/bar.clj for the macro

1
borkdude 2020-06-01T18:37:04.308800Z

@snoe Did one more test. better-cond, only tested the :let construction:

(ns foo
  {:clj-kondo/config '{:macroexpand {better.cond/cond
                                     "
(defn process-pairs [pairs]
  (loop [[[lhs rhs :as pair] & pairs] pairs
         new-body ['cond]]
    (if pair
      (cond
        (= 1 (count pair)) (seq (conj new-body lhs))
        (not (keyword? lhs))
        (recur pairs
               (conj new-body lhs rhs))
        (= :let lhs)
        (seq (conj new-body :else (list 'let rhs
                                       (process-pairs pairs)))))
      (seq new-body))))

(def f
  (fn [{:keys [:sexpr]}]
    (let [expr (let [args (rest sexpr)
                     pairs (partition-all 2 args)]
                 (process-pairs pairs))]
      {:sexpr (with-meta expr
                (meta sexpr))})))"}}}
  (:require [better.cond :as b]))

(let [x 10]
  (b/cond
    (= x 1) true
    :let [y (inc x)]      ;; binding is recognized
    (= 11 y) (subs y 0))) ;; yay, type error because y is not a string

borkdude 2020-06-01T18:38:58.309500Z

I'm pretty sure more sophisticated things can be linted, as long as you're willing to provide the stand-in macro

borkdude 2020-06-01T18:41:34.309600Z

snoe 2020-06-01T18:43:30.311500Z

that's awesome stuff - I think my dsl approach worked for "regular" looking macros a bit better than the lint-as but this is clearer and more generally applicable.

borkdude 2020-06-01T18:47:22.311800Z

I'll add this to the unit tests 🙂