i'm writing a complex hook for #splint's patterns, and i need to postwalk the clj-kondo nodes. has anyone written a postwalk for clj-kondo nodes?
Are you writing a hook for a macro in splint or ..?
yes
maybe it's easier to use :macroexpand hook so you can use normal postwalk? it's not as accurate but a lot easier
well, i don't want to macroexpand, i want to call api/reg-finding! for mistakes
the macroexpansion would be......... very big
I see. do you have an example perhaps, so I can better understand your use case?
sure
(defrule performance/into-transducer
"..."
{:pattern '(into [] ((? trans transducers) ?f ?coll))
...}and what is an example of a finding you want to catch?
:pattern doesn't need to be quoted but i do quote it because that stops clj-kondo for yelling. i'd like to lint it.
one sec while i write an example
since it's a macro you can also do the check in your macro :)
but why do you need postwalk for this?
oh i do, i throw lots of errors, but i use clj-kondo and want the faster linting as well
yes understood, why not both
the :pattern is like a sexpr regex, where it matches literal forms in the given shape, except for symbols that start with ? (like ?coll), or lists that start with ? (like (? trans transducers)). the symbols are just captures which are stored in a context map, but the lists have special rules about them
(? trans transducers) binds x to ?trans if it matches the predicate (transducers x) , so it requires transducers to exist.
ok, so it's more than just the quote, right
that you want to lint
right, i need to walk the form and find the lists that start with ? (or other special forms i won't get into), and then check if they're broken in some way lol
What I meant with the :macroexpand hook is that this may be way easier to implement. :macroexpand isn't just about macroexpansion, you can still return nil and call findings/reg-finding!
but you get to operate on normal s-expressions
and it all carries metadata?
in sofar possible. numbers can't carry metadata but symbols will
(defn walk
[inner outer form]
(cond
(:children form) (outer (assoc form :children (mapv inner (:children form))))
:else (outer form)))
(defn postwalk
[f form]
(walk #(postwalk f %) f form))
did what i need it to do lolmuch simpler than clojure.walk's impl
nice :)
I think this might mess up some nodes that don't have a :tag keyword on them but implement the protocol in a different way
but I'm not sure about that
good to know
i'm merely using this as a way to step through the whole thing, i return the original object each time
ah then it's ok for sure
(postwalk (fn [obj] (...) obj) node)
i have a bunch of s/def specs for a macro i have, which validates things like "is this a number?" and "either pattern OR patterns but not both". is it possible to get clj-kondo to use the specs to check my macro without writing a hook?
unfortunately not since specs usually aren't very static in nature