This is either a question of a feature request, depending on whether or not it's already available. Based on what I've read from the docs, this hasn't been mentioned.
Use case
I'm working with ClojureScript, where my map values which are keyword are often turned into strings against my will. In hopes of fighting this problem, I've been trying out spec-tools. He's an example of the conforming I'm doing:
user=> (require '[cljs.spec.alpha :as s]
'[spec-tools.core :as st]
'[spec-tools.spec :as sts])
user=> (s/def ::foo (s/keys :req [::bar ::spam]))
:user/foo
user=> (s/def ::bar (s/and sts/keyword? #{::meow}))
:user/bar
user=> (s/def ::spam sts/string?)
:user/spam
user=> (st/conform ::foo {::bar "user/meow" ::spam "user/meow"} st/string-conforming)
{:user/bar :user/meow :user/spam "user/meow"}
Desired functionality
As shown above, this conforming is sweeet. Unfortunately, it also does the normal conforming stuff, like turning s/or
and s/alt
into their named pairs. Here's an example, based on the same REPL session above.
user=> (s/def ::spam (s/or :string sts/string? :integer sts/integer?))
:user/spam
user=> (st/conform ::foo {::bar "user/meow" ::spam "user/meow"} st/string-conforming)
{:user/bar :user/meow :user/spam [:string "user/meow"]}
As soon as ::spam
has an alternative, the value I get back is less than ideal.
Short-term work-around
For now, I've been subsequently unforming my conform, which adds the keywords in the right spot, but removes the named pairs. As you can imagine, for performance, efficiency, and cleanliness, this isn't ideal. Here's an example, again, based on the above session:
user=> (s/unform ::foo (st/conform ::foo {::bar "user/meow" ::spam "user/meow"} st/string-conforming))
{:user/bar :user/meow :user/spam "user/meow"}
Long-term solution
As this is a common problem in both ClojureScript and Clojure code working with JSON and other formats which don't support EDN keywords, a cleaner solution would be preferred. I'd be happy to discuss more.
Thanks!