I’m trying to use rewrite-clj to manipulate datastructures that include ::
’ed keys, and I’m seeing a lot of :?_current-ns_?
. I thought I could use
(n/sexpr v
{:auto-resolve (fn [alias]
(prn "calling autoresolve")
(get {:current *ns*}
alias
(symbol (str alias "-unresolved"))))})
to do replace it with something else, but it seems like the :auto-resolve
fn is never called.Actually, I could just do
(n/sexpr v
{:auto-resolve (partial identity *ns*)})
, I guess.you are never seeing the prns?
never
I know that *ns*
is not supported anymore ( 😞 ), but I don’t understand why the fn isn’t called.
(and for resolving the ns dynamically, I guess I’ll have to travel the ns
form and find the right symbol myself… and carry that down to the place where I need it.)
user=> (require '[rewrite-clj.node :as n])
nil
user=> (require '[rewrite-clj.parser :as p])
nil
user=> (p/parse-string "::foo")
<token: ::foo>
user=> (n/sexpr (p/parse-string "::foo"))
:?_current-ns_?/foo
user=> (n/sexpr (p/parse-string "::foo") {:auto-resolve (fn [m] (prn m))})
:current
:foo
user=> (n/sexpr (p/parse-string "{:a ::foo}") {:auto-resolve (fn [m] (prn m))})
:current
{:a :foo}
@reefersleep, carrying on from @borkdude’s example but also using *ns*
:
> clj
Clojure 1.10.3
user=> (require '[rewrite-clj.node :as n])
nil
user=> (require '[rewrite-clj.parser :as p])
nil
user=> (def my-node (p/parse-string "::foo"))
#'user/my-node
user=> (n/sexpr my-node {:auto-resolve (fn [x] (ns-name *ns*))})
:user/foo
But maybe binding *ns*
to what you really want it to be will be the challenge? Dunno.
Also can’t remember if you are using zip API. If so you can provide :auto-resolve
at zipper creation time and it will be used automatically for any zipper operations that auto-resolve.
Depending on your use case, you’ll also want to look at auto-resolve fn argument. As @borkdude illustrated, it will be :current
for current namespace auto-resolves ::foo
, and the ns alias for namespace alias auto-resolves ::my-ns-alias/foo
@lee your example works as expected. Don’t know why my code does not!
I’m a dumb. I was referring to the wrong value, I think. Let me investigate.
If so, I’m really sorry for wasting your time!
Not a problem at all, we’ve all been there!
Actually I sometimes live there! :simple_smile:
When ya do figure it out, let us know what it was. It might help us to improve the docs or the library.
It was nothing to do with rewrite-clj
, I should have simplified my code example and/or more thoroughly inspected the values I was manipulating. The code had gotten a bit unwieldy, I guess 🙂 (And maybe I’m suffering from baby-related sleep deprivation issues 😉 )
Well, whatever the reason, glad you are back on track!
Thanks!
The next challenge, as you said, is to get the correct ns.
For (ns-name *ns*)
, I’m getting the ns I’m calling from, not the ns I’m navigating with rewrite-clj
.
(As stated in the docs, in some way)
Yeah, rewrite-clj doesn’t look at or modify *ns*
.
Is there a plan to provide the current ns in some other way?
Of the file you are parsing?
Or does rewrite-clj
just avoid doing it because it’s not really a compiler? 🙂
yes
I mean, I get that *ns*
can be dynamically changed throughout a file, so it’s not straightforward
plus it requires the full scope of the read/compiled file, and I guess that’s not really the mission of rewrite-clj
.
I was considering parsing out namespace info in earlier designs of rewrite-clj v1. Thankfully @borkdude talked me out of it. I documented the https://github.com/clj-commons/rewrite-clj/blob/main/doc/design/namespaced-elements.adoc#sexpr-rabbit-hole.
Yeah, even if rewrite-clj did parse out this info (which it doesn’t and we don’t have plans for it to do so), it would not change or read *ns*
.
Wonderful notes, great investment!
Thanks, I write things down because I am rather forgetful!
It would not be difficult to get parsing of the current ns out of a source file correct most of the time. But most of the time isn’t good enough for rewrite-clj.
I try to do the same, but I tend to forget that I have the notes or where they are 😅
Well chalk it up to sleep deprevation!
That said, I think cljfmt, which uses rewrite-clj does parse out ns info. You might want to look there for inspiration, if you are trying to do something similar.
> most of the time isn’t good enough for rewrite-clj I totally get that. You’d be making promises you couldn’t keep. I guess I’ll try reading the ns form; I think we make very few ns gymnastics in our code base, but I might be surprised.
Thanks, I’ll have a look!
If you are just looking for the current ns and not ns aliases, you’ll likely not have a terrible slog.
That I am, and I’m thinking the same. I’ve read before that the ns
form is terribly dynamic, but I don’t think we make particular use of that dynamism. (let [namespaze (-> zloc z/down z/right)]
will probably work most of the time.
There’s also https://github.com/clj-kondo/clj-kondo/tree/master/analysis, if you want to look at that route.
I might go for that in the next iteration. For now, cljfmt
’s solution looks like what I had imagined doing 🙂
Not to sway you at all, but I just used https://github.com/lread/test-doc-blocks/blob/b2f43e25191ff0ca4609bb78fac60b89c2a5bf07/src/lread/test_doc_blocks/impl/doc_parse.clj#L287. Super duper easy to use. So that option is there too.
Consider me unintentionally swayed 🙂
Ha! Do what works for you, all just ideas.
Looks easy enough!
I’m just reluctant to add more deps. This project has way too many already. But what I’m doing should really be refactored into its own project anyway, eventually.
Yeah, like you did, that seems fine!
(defn get-namespace [^java.io.File file]
(-> (clj-kondo/run! {:lint [(.getPath file)]
:config {:output {:analysis true}}})
:analysis
:namespace-definitions
first
:name))
@reefersleep you can even compare the locations of var definitions reported by clj-kondo against your rewrite-clj node
and their namespaces
That’s pretty cool, so you can get the exact ns for each node? Wow.
@reefersleep it seems you were interested in keywords though right?
you can get those too in the analysis with an extra option
Which one? @borkdude
:keywords true
https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md
Beautiful.
Trying to figure out how to match that with the rewrite-clj
node, I’m expecting the node API to hold the row and col somewhere, just haven’t found it yet
Ah. :track-position true
If you aren’t needing to keep track of changes to position you can opt out of :track-position
and use https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.0.591-alpha/doc/user-guide#nodes
@borkdude’s https://github.com/borkdude/carve might be a good clj-kondo/rewrite-clj example for you
ahhh nice
@reefersleep yeah, just call meta
on the node
This is what sold me to rewrite-clj initially: I needed location info of every possible thing in clojure code for clj-kondo
🙂
Damn. Wrote the code blind, and it worked the first time around.
Lovely! Fetched the row and col of each keyword node and composed the namespaced keyword from clj-kondo’s analysis.
Thanks for your interest and sharing your journey!