Fairly new to Malli (and Clojure in general), this question might be a bit silly. I have a walker that relaxes certain schema terms to strings (for use in a structured extraction pipeline) - I have some custom types based on malli.experimental.time but the walker seems to panic when it encounters an :iso-duration (defined as either a Period or a Duration). I can't figure out what's causing the infinitely-expanding-schema error. Any help would be much appreciated - code/nREPL outputs below.
clj꞉cpdl.types.registry꞉> (try (generate-loose-registry basic-additions)
(catch Exception e
(clojure.pprint/pprint (ex-data e))))
; #IntoSchema {:type :time/duration}
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:source]
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:target]
; #IntoSchema {:type :time/duration}
; #IntoSchema {:type :time/duration}
; #IntoSchema {:type :time/duration}
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:relative 1 :anchor 1]
; 🔍 DIAGNOSTIC [depth 3 ] type: :or | path: [:relative 1 :anchor] | children count: 2 | children: [:and :string] | props: {}
; 🔍 DIAGNOSTIC [depth 3 ] type: :or | path: [:relative 1 :offset] | children count: 2 | children: [:malli.core/schema :malli.core/schema] | props: {}
; ❌ Error loosening type: :cpdl/schedule
; {:type :malli.core/infinitely-expanding-schema,
; :message :malli.core/infinitely-expanding-schema,
; :data {:schema [:or :time/duration :time/period]}}
nil
Custom type definitions:
(def iso-duration-schema
(m/schema [:or :time/duration :time/period] {:registry (merge (m/default-schemas) (met/schemas))}))
(def iso-partial-schema
(m/schema
[:and
[:string {:description "ISO 8601 string with variable precision (YYYY to full instance)"}]
[:fn {:error/message "Must be a valid ISO 8601 truncated date string"}
iso-partial?]]))
(def registry
{:uuid-v7 uuid-v7-schema
:iso-duration iso-duration-schema
:iso-partial iso-partial-schema})
(defn merge-with-base
([] (merge-with-base (m/default-schemas)))
([base-registry]
(merge base-registry (mu/schemas) (met/schemas) registry)))
Schema walker for reference:
(defn loose-walker [schema path children options]
(let [t (m/type schema)
props (m/properties schema)
loose-registry (:loose-registry options)
base-registry (:base-registry options)]
...
(cond
...
;; Relax primitives
(or (uuid-types t) (#{:inst :keyword :iso-partial :iso-duration :time/instant :time/duration :time/period} t))
(do
(println " ✏️ Relaxing primitive:" t "to :string at path:" path)
[:string (-> props
(assoc :loose/changed? true)
;;(update :description #(str (or % "") " (Relaxed from " t ")"))
)])
...
;; Bubble changes in composites/collections
(#{:merge :union :multi :maybe :ornil :vector :sequential :set :tuple :or} t)
(let [changed? (bubble-changed? t children)
new-props (cond-> props changed? (assoc :loose/changed? true))]
(into [t new-props] children))
...
:else
(into [t props] children))))
EDIT: Unwrapping the m/schema call doesn't fix the error but returns an invalid-schema error at the same place 😞
clj꞉cpdl.types.registry꞉> (try (generate-loose-registry basic-additions)
(catch Exception e
(clojure.pprint/pprint (ex-data e))))
; #IntoSchema {:type :time/duration}
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:source]
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:target]
; #IntoSchema {:type :time/duration}
; #IntoSchema {:type :time/duration}
; #IntoSchema {:type :time/duration}
; ✏️ Relaxing primitive: :uuid-v7 to :string at path: [:relative 1 :anchor 1]
; 🔍 DIAGNOSTIC [depth 3 ] type: :or | path: [:relative 1 :anchor] | children count: 2 | children: [:and :string] | props: {}
; 🔍 DIAGNOSTIC [depth 3 ] type: :or | path: [:relative 1 :offset] | children count: 2 | children: [:malli.core/schema :malli.core/schema] | props: {}
; ❌ Error loosening type: :cpdl/schedule
; {:type :malli.core/invalid-schema,
; :message :malli.core/invalid-schema,
; :data
; {:schema [:or :time/duration :time/period], :form [:iso-duration]}}
nil
EDIT 2: Never mind, found the error (it was because I wrapped a keyword in a bracket pair in some of the type definitions where the custom type was called)