diff --git a/modules/reitit-core/src/reitit/coercion.cljc b/modules/reitit-core/src/reitit/coercion.cljc index 8dd08d83..bc3dc6ca 100644 --- a/modules/reitit-core/src/reitit/coercion.cljc +++ b/modules/reitit-core/src/reitit/coercion.cljc @@ -1,5 +1,5 @@ (ns reitit.coercion - (:require [clojure.walk :as walk] + (:require [#?(:clj reitit.walk :cljs clojure.walk) :as walk] [reitit.impl :as impl]) #?(:clj (:import (java.io Writer)))) diff --git a/modules/reitit-core/src/reitit/walk.clj b/modules/reitit-core/src/reitit/walk.clj new file mode 100644 index 00000000..8e6a59ea --- /dev/null +++ b/modules/reitit-core/src/reitit/walk.clj @@ -0,0 +1,50 @@ +(ns ^:no-doc reitit.walk) + +(defprotocol IKeywordize + (-keywordize [coll])) + +(defn keywordize-keys [m] (-keywordize m)) + +(defn- keywordize-kv + [m k v] + (assoc! m (if (string? k) (keyword k) (-keywordize k)) (-keywordize v))) + +(defn- -keywordize-map + [m] + (persistent! (reduce-kv keywordize-kv (transient (empty m)) m))) + +(def ^:private keywordize-xf (map keywordize-keys)) + +(defn- -keywordize-default + [coll] + (into (empty coll) keywordize-xf coll)) + +(doseq [type [clojure.lang.PersistentHashSet + clojure.lang.PersistentVector + clojure.lang.PersistentQueue + clojure.lang.PersistentStructMap + clojure.lang.PersistentTreeSet]] + (extend type IKeywordize {:-keywordize -keywordize-default})) + +(doseq [type [clojure.lang.PersistentArrayMap + clojure.lang.PersistentHashMap + clojure.lang.PersistentTreeMap]] + (extend type IKeywordize {:-keywordize -keywordize-map})) + +(extend-protocol IKeywordize + Object + (-keywordize [x] x) + nil + (-keywordize [_] nil) + clojure.lang.MapEntry + (-keywordize [e] (clojure.lang.MapEntry/create + (-keywordize (.key e)) + (-keywordize (.val e)))) + clojure.lang.ISeq + (-keywordize [coll] (map -keywordize coll)) + clojure.lang.PersistentList + (-keywordize [coll] (apply list (map -keywordize coll))) + clojure.lang.PersistentList$EmptyList + (-keywordize [x] x) + clojure.lang.IRecord + (-keywordize [r] (reduce (fn [r x] (conj r (-keywordize x))) r r))) diff --git a/test/clj/reitit/walk_test.clj b/test/clj/reitit/walk_test.clj new file mode 100644 index 00000000..2b5c42fd --- /dev/null +++ b/test/clj/reitit/walk_test.clj @@ -0,0 +1,13 @@ +(ns reitit.walk-test + (:require + [clojure.test.check.clojure-test :refer [defspec]] + [clojure.test.check.properties :as prop] + [clojure.test.check.generators :as gen] + [clojure.walk :as walk] + [reitit.walk :as sut])) + +(defspec keywordize=walk-keywordize + 10000 + (prop/for-all [v gen/any-equatable] + (= (sut/keywordize-keys v) + (walk/keywordize-keys v))))