Fork me on GitHub

first time I try to play around with rewrite-clj


I'm just trying to do something like this (simplifying a bit) from (log/error exc "Message") to (log/error "message" {} exc) So from my understanding I have to use z/subedit to avoid replacing the whole content of the file.


but I'm not getting how to actually do the inner transformations, I got something semi-working extracting the inner sexprs with various z/right calls, and putting them back with format, but I guess that's not really the right way


any suggestions about how to do that more properly maybe?


Hi @andrea.crotti! Welcome to rewrite-clj! There is no one right answer, but I seem to find myself reaching for the rewrite-clj walk functions when making a change like this. First let’s do some requiring, setup a string that includes your sample code, and print it out for later comparison:

(require '[clojure.string :as string]
         '[ :as z]
         '[rewrite-clj.node :as n])

(def s ";; my source sample\n(+ 1 2 3)\n\n(log/error exc \"Message\")\n\n(dingo dango bango)")
(println s)
Gives us:
;; my source sample
(+ 1 2 3)

(log/error exc "Message")

(dingo dango bango)
Now let’s see how we can use the zipper to update the sample code:
(-> (z/of-string s)
    z/up ;; because we want to walk the whole zipper - not just the first non-whitespace node
    (z/postwalk (fn visit? [zloc]
                  (and (z/list? zloc)
                       (= "log/error" (-> zloc z/down z/string))))
                (fn visit [zloc]
                  ;; the exception is the first arg, lets save its node
                  (let [ex-node (-> zloc z/down z/right z/node)]
                    (-> zloc
                        ;; append an empty map as the last arg
                        (z/append-child (n/map-node []))
                        ;; now append the exception arg as the last arg (after the empty map)
                        (z/append-child ex-node)
                        ;; move to the old exception arg...
                        ;; ... and remove it
                        ;; did you really want to lowercase your message? We can do that.
                        ;; move to the message...
                        ;; ... and lowercase it
                        (z/edit string/lower-case)
                        ;; move back up to maintain our incoming zloc position in the zipper
Gives us:
;; my source sample
(+ 1 2 3)

(log/error "message" {} exc)

(dingo dango bango)
Whatcha think? Is all that pretty clear and easy to understand? If not, just ask.

Noah Bogart17:08:43

Damn, I’m not the one asking but this is the most clear example I’ve seen. Love it


Thanks @nbtheduke, glad you liked it!


Ah nice thanks I'll try tomorrow


It's amazing that we can use this with babashka btw


Yeah that bb integration is super sweet, I love that too.


I also have to check if we are using or the other namespace we are switching to


I wonder if it's worth using a regexp for that instead, or just try to use rewrite-clj for everyting


I find that sometimes rewrite-clj can be overkill when a simple regex will do.


@andrea.crotti do you mean you want to know what the log alias is referring to?


you can also use clj-kondo analysis for this, it gives you the same locations as rewrite-clj uses (because clj-kondo uses rewrite-clj, it plays quite nice with it)


examples of that are carve (which you are familiar with) and e.g. this script for turning double-colon'd keywords into normal ones:


you can actually use clj-kondo analysis and then skip straight to the locations that are relevant, without matching literally on "log/error"


ah cool yes I can try that

lread21:08:47 has been released • I don’t think these will have affected many folks - but want to get fixes out into the wild: ◦ zipper now works correctly when using both :auto-resolve and :track-position? options ◦ a Cons now coerces to a list node (thanks @borkdude!) • and thanks to @vemv rewrite-clj sources are now also linted with Eastwood

🍻 8