Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -walk option to inherit ::val properties #1091

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 5 additions & 11 deletions docs/tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
13 changes: 10 additions & 3 deletions src/malli/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down
35 changes: 35 additions & 0 deletions test/malli/util_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))