rewrite-clj 2021-09-23

so the use case I’ve got for rewrite-edn is that I want to update a config file while preserving formatting, and config uses aero and integrant which use reader tags

I’m guessing that #ig/ref :bar ending up as (read-string "#ig/ref :bar") is meant for it to get evaluated in the environment

but in my case I really just need to leave it as is, so I’m thinking the best approach might be to have a function to serialize to string and handle this case there

Hi @yogthos. This is an interesting issue.

$ bb -e '(rewrite-clj.node/sexpr (rewrite-clj.parser/parse-string "#foo {:a 1}"))'
(read-string "#foo {:a 1}")
It seems rewrite-clj behaves like this and it just manifests in rewrite-edn as well. Perhaps the stringification of the node isn't very accurate

whereas:

$ bb -e '(str (rewrite-clj.parser/parse-string "#foo {:a 1}"))'
"#foo {:a 1}"

hmm yeah I think there should probably be an extra step during stringification

I meant sexprification instead of stringification

the str-ion seems accurate enough

The issue here might be that there is no way to make this into a s-expr without making up some kind of thing

Ya I noticed that rewrite-clj’s sexpr will sometimes return (read-string...) https://github.com/clj-commons/rewrite-clj/blob/main/doc/01-user-guide.adoc#reader-macro-chars…

because the reader normally turns this into a s-expr but for this you need to actually execute the reader tag function

should rewrite-clj be able to get an :readers option which will actually execute the function?

would it be possible to add metadata in rewrite-clj to disambiguate?

and yeah passing :readers explicitly could work as well

like this for example:

$ bb -e '(rewrite-clj.node/sexpr (rewrite-clj.parser/parse-string "#foo {:a 1}") {:readers {(quote foo) identity}})'
(read-string "#foo {:a 1}")

(parse-string "#js [1 2 3]" {:readers {'js (fn [v] (list 'js v))}})
(js [1 2 3])

(this is from edamame)

being able to pass a fn (and not only a map) also gives more flexibility

So, being a bit slow simple_smile, I’m not sure I understand yet. Are we talking about this?: code as text -> rewrite-clj node -> clojure form -> rewrite-clj node -> code as text?

Sexpr in rewrite-clj is… nuanced… can work… but there are real limitations. Is it possible to work from rewrite-clj nodes only, or is using rewrite-clj’s sexpr necessary for this use case?

in my use case I don't need to use sexpr as I just need to roundtrip text to text

so yeah looks like I can just skip that step and everything works as intended, e.g:

(let [zloc (-> (slurp "system.edn") (rewrite-edn/parse-string))
     child (rewrite-edn/parse-string "{:label "ig/ref", :value ":system/env"}")]
    (str (rewrite-edn/assoc-in zloc [:router/core] child)))

not sure if the current sexpr behavior is desirable or not, but I think just documenting this would be enough for now

Yeah it is kinda sorta documented under sexpr nuances in the user guide.