2

My actual behavior is

(js->clj (clj->js [:a :b :c]) :keywordize-keys true)
=> ["a" "b" "c"]

Desired behavior

[:a :b :c]
Jp_
  • 5,973
  • 4
  • 25
  • 36

1 Answers1

2

I don't use ClojureScript, but it should be noted that :keywordize-keys isn't doing anything likely because vectors are keyed by index. The elements of the vector are the values, not the indices.

You could do something like

(->> [:a :b :c]
     (clj->js)
     (js->clj)
     (mapv keyword))

; Should print [:a :b :c]

Of course, this gets a little more complicated if the structure is nested, but it's the same general idea.


Since JSON doesn't recognize the concept of a "keyword" though, there's no simple way of converting between the two formats and maintaining what is a String and what is a Keyword. If you really need to differentiate, you could use Clojure's EDN format instead of JSON. This would only work though if you aren't doing excessive JavaScript interop. Any data exchanged with a plain JS library will involve the conflation of Keywords and Strings unless the library understands EDN formatting, or you do something unfortunate like attaching some kind of metadata to the object indicating what is a keyword and what isn't.

You could also just do away with the idea of keywords altogether and use Strings for everything internally. That would suck, but at least it would make the interop easier.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • Yes.. my structure is very nested, but I'm realising my problem is more general. When I convert to json I loose the information which values were keywords, so there isn't a way I can tell even in a map if I have a keyword that is not the key of the map. – Jp_ Nov 29 '18 at 03:15
  • @Jp_ I don't see how it could be handled any differently though. JSON doesn't include any concept of keywords, so that information is necessarily lost when converting a Clojure map to a JSON representation. You could try dealing with Clojure's EDN instead of JSON, unless you need to interop with JS. – Carcigenicate Nov 29 '18 at 03:18
  • I need to interop with JS, what I'm doing is dumping a re-frame db into firebase realtime database. I thought would be a simple operation, but I'm not seeing a way out of it. Maybe keeping the information of what values are keywords somehow when using clj->js. – Jp_ Nov 29 '18 at 03:29
  • 2
    @Jp_ Or just assume all converted map keys are strings. Keywords are nice to have, but they aren't necessary. If you're dealing with records or maps that for whatever reason are using keywords, you can easily create a function to convert the map into a JSON friendly format by using the `name` function. – Carcigenicate Nov 29 '18 at 03:34
  • This works perfectly. Now maybe I can edit the question, as what I wanted was actually a cummutative property with clj->js and js->clj, what in my case was not necessary as I can use only strings in map values. – Jp_ Nov 29 '18 at 23:02