diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f4ba57d..96715f985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Malli is in well matured [alpha](README.md#alpha). * Fix ClojureScript [arithmetic warning](https://github.com/metosin/malli/issues/1093) * Distribute `:merge` over `:multi` [#1086](https://github.com/metosin/malli/pull/1086), see [documentation](README.md#distributive-schemas) * allow `m/-proxy-schema` child to be a `delay` +* add `::m/walk-inherit-entry-props` to `-walk` for unwrapping `::val` nodes and inheriting their props after walking * Fix `malli.dev.pretty` throws when explaining errors in nested maps [#1094](https://github.com/metosin/malli/issues/1096) ## 0.16.3 (2024-08-05) diff --git a/docs/tips.md b/docs/tips.md index ec28167c9..5154573d9 100644 --- a/docs/tips.md +++ b/docs/tips.md @@ -252,20 +252,14 @@ Example 2: if `:cost` is missing, try to calculate it from `:price` and `:qty`: ## Walking Schema and Entry Properties -1. walk entries on the way in -2. unwalk entries on the way out - ```clojure -(defn walk-properties [schema f] +(defn walk-properties [?schema f & args] (m/walk - schema + ?schema (fn [s _ c _] - (m/into-schema - (m/-parent s) - (f (m/-properties s)) - (cond->> c (m/entries s) (map (fn [[k p s]] [k (f p) (first (m/children s))]))) - (m/options s))) - {::m/walk-entry-vals true})) + (apply m/-update-properties (m/-set-children s c) f args)) + {::m/walk-inherit-entry-props true + ::m/walk-entry-vals true})) ``` Stripping all swagger-keys: diff --git a/src/malli/core.cljc b/src/malli/core.cljc index 05f2fc63c..ecf15db27 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -35,7 +35,7 @@ (-transformer [this transformer method options] "returns a function to transform the value for the given schema and method. Can also return nil instead of `identity` so that more no-op transforms can be elided.") - (-walk [this walker path options] "walks the schema and it's children, ::m/walk-entry-vals, ::m/walk-refs, ::m/walk-schema-refs options effect how walking is done.") + (-walk [this walker path options] "walks the schema and it's children, ::m/walk-entry-vals, ::m/walk-refs, ::m/walk-schema-refs, ::m/walk-inherit-entry-props options effect how walking is done.") (-properties [this] "returns original schema properties") (-options [this] "returns original options") (-children [this] "returns schema children") @@ -338,8 +338,15 @@ (defn -inner-indexed [walker path children options] (-vmap (fn [[i c]] (-inner walker c (conj path i) options)) (map-indexed vector children))) -(defn -inner-entries [walker path entries options] - (-vmap (fn [[k s]] [k (-properties s) (-inner walker s (conj path k) options)]) entries)) +(defn -inner-entries [walker path entries {::keys [walk-inherit-entry-props] :as options}] + (-vmap (fn [[k s]] + (let [s' (-inner walker s (conj path k) options)] + (if (and walk-inherit-entry-props + (schema? s') + (= ::val (type s'))) + [k (-properties s') (-deref s')] + [k (-properties s) s']))) + entries)) (defn -walk-entries [schema walker path options] (when (-accept walker schema path options) diff --git a/test/malli/util_test.cljc b/test/malli/util_test.cljc index e0a8c7522..fb91adf75 100644 --- a/test/malli/util_test.cljc +++ b/test/malli/util_test.cljc @@ -1044,3 +1044,38 @@ {} {:registry (merge (mu/schemas) (m/default-schemas))} (mt/default-value-transformer {::mt/add-optional-keys true}))))) + +;; not quite ready. does not walk inside registries and pointers expand +;; when printing their properties. +(defn walk-properties [?schema f & args] + (m/walk + ?schema + (fn [s _ c _] + (apply m/-update-properties (m/-set-children s c) f args)) + {::m/walk-inherit-entry-props true + ::m/walk-entry-vals true})) + +(defn remove-swagger-keys [p] + (not-empty + (reduce-kv + (fn [acc k _] + (cond-> acc (some #{:swagger} [k (-> k namespace keyword)]) (dissoc k))) + p p))) + +(deftest walk-properties-test + (is (= [:map {:title "Organisation name"} [:ref :string] [:kikka :string]] + (m/form + (walk-properties + [:map {:title "Organisation name"} + [:ref {:swagger/description "Reference to the organisation" + :swagger/example "Acme floor polish, Houston TX"} :string] + [:kikka [:string {:swagger {:title "kukka"}}]]] + remove-swagger-keys)))) + (is (= [:map {:foo 1} [:a {:foo 1} [:int {:foo 1}]]] + (m/form (walk-properties [:map [:a :int]] assoc :foo 1)))) + (is (= [:map [:a :int]] + (m/form (walk-properties [:map {:foo 1} [:a {:foo 1} [:int {:foo 1}]]] dissoc :foo)))) + (is (= [:map {:foo 1 :registry {:foo :int}} [:a {:foo 1} [:int {:foo 1}]]] + (m/form (walk-properties [:map {:registry {:foo :int}} [:a :int]] assoc :foo 1)))) + (is (= [:map {:registry {:foo :int}} [:a :int]] + (m/form (walk-properties [:map {:foo 1 :registry {:foo :int}} [:a {:foo 1} [:int {:foo 1}]]] dissoc :foo)))))