From d1afbdaa36c48a908d322a4f41108d1ee08b8890 Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Thu, 15 Aug 2024 20:13:29 -0500 Subject: [PATCH] surrounding --- src/malli/core.cljc | 7 +-- src/malli/dev.clj | 109 +++++++++++++++++++++++++++++++++++--- src/malli/dev/pretty.cljc | 12 ++++- 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/src/malli/core.cljc b/src/malli/core.cljc index f8818b8bb..ec3990a88 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -149,7 +149,8 @@ (defn -fail! ([type] (-fail! type nil)) - ([type data] (throw (-exception type data)))) + ([type data] (throw (-exception type data))) + ([type data options] (throw (-exception type data)))) (defn -safe-pred [f] #(try (boolean (f %)) (catch #?(:clj Exception, :cljs js/Error) _ false))) @@ -267,14 +268,14 @@ (when-some [p (some-> registry (mr/-schema (c/type ?schema)))] (when (schema? ?schema) (when (= p (-parent ?schema)) - (-fail! ::infinitely-expanding-schema {:schema ?schema}))) + (-fail! ::infinitely-expanding-schema {:schema ?schema} options))) (-into-schema p nil [?schema] options))))) (defn- -lookup! [?schema ?form f rec options] (or (and f (f ?schema) ?schema) (if-let [?schema (-lookup ?schema options)] (cond-> ?schema rec (recur ?form f rec options)) - (-fail! ::invalid-schema {:schema ?schema, :form ?form})))) + (-fail! ::invalid-schema {:schema ?schema, :form ?form} options)))) (defn -properties-and-options [properties options f] (if-let [r (:registry properties)] diff --git a/src/malli/dev.clj b/src/malli/dev.clj index 557610b64..15ab022b3 100644 --- a/src/malli/dev.clj +++ b/src/malli/dev.clj @@ -8,20 +8,113 @@ ([text] (-log! text (pretty/-printer))) ([text printer] (pretty/-log! text printer))) +(def ^:private ^:dynamic *forms* nil) + (defn -capture-fail! ([] (-capture-fail! nil)) ([{:keys [report] :or {report (pretty/reporter)}}] (alter-var-root #'m/-fail! - (fn [f] (-> (fn -fail! - ([type] (-fail! type nil)) - ([type data] (let [e (m/-exception type data)] - (report type data) - (throw e)))) - (with-meta {::original f})))))) + (fn [f] + (-> (fn -fail! + ([type] (-fail! type nil)) + ([type data] (let [e (m/-exception type data)] + (report type data) + (throw e))) + ([type data options] + (let [data (assoc data ::forms (some-> *forms* deref)) + e (m/-exception type data)] + (report type data) + (throw e)))) + (with-meta {::original (::original (meta f) f)})))))) (defn -uncapture-fail! [] - (alter-var-root #'m/-fail! (fn [f] (-> f meta ::original (or f))))) + (alter-var-root #'m/-fail! (fn [f] (::original (meta f) f)))) + +(def ^:dynamic *level* nil) + +(defn- ensure-forms [f] + (binding [*forms* (or *forms* (atom [])) + *level* (or (some-> *level* inc) 0)] + (f *forms* *level*))) + +(defn -capture-schema-ctors! [] + (alter-var-root #'m/schema + (fn [f] + (let [f (::original (meta f) f)] + (fn this + ([?schema] (this ?schema nil)) + ([?schema options] + (ensure-forms + (fn [forms level] + (swap! forms conj {:level level :form ?schema}) + (f ?schema options)))))))) + (alter-var-root #'m/into-schema + (fn [f] + (let [f (::original (meta f) f)] + (fn this + ([type properties children] (this type properties children nil)) + ([type properties children options] + (ensure-forms + (fn [forms level] + (swap! forms conj {:level level :form [type properties children]}) + (f type properties children options)))))))) + (alter-var-root #'m/-lookup! + (fn [-lookup!] + (let [-lookup! (::original (meta -lookup!) -lookup!)] + (fn [?schema ?form f rec options] + (ensure-forms + (fn [forms level] + (swap! forms conj {:level level :form ?schema}) + (-lookup! ?schema ?form f rec options))))))) + (alter-var-root #'m/-lookup + (fn [f] + (let [f (::original (meta f) f)] + (fn [?schema options] + (ensure-forms + (fn [forms level] + (swap! forms conj {:level level :form ?schema}) + (f ?schema options)))))))) + +(defn -uncapture-schema-ctors! [] + (alter-var-root #'m/-lookup (fn [f] (::original (meta f) f))) + (alter-var-root #'m/-lookup! (fn [f] (::original (meta f) f))) + (alter-var-root #'m/into-schema (fn [f] (::original (meta f) f))) + (alter-var-root #'m/schema (fn [f] (::original (meta f) f)))) + +(comment + (-capture-fail!) + (-capture-schema-ctors!) + (m/schema [:map [:a [:tuple nil nil]]]) +;; -- Schema Creation Error ---------------------------------------- Thread:1583 -- +;; +;; Invalid Schema +;; +;; nil +;; +;; Surrounding Syntax +;; +;; [:map [:a [:tuple nil nil]]] +;; :map +;; :map +;; [#IntoSchema{:type :map} nil [[:a [:tuple nil nil]]]] +;; #IntoSchema{:type :map} +;; [:tuple nil nil] +;; :tuple +;; :tuple +;; [#IntoSchema{:type :tuple} nil [nil]] +;; #IntoSchema{:type :tuple} +;; nil +;; nil +;; nil +;; +;; More information +;; +;; https://cljdoc.org/d/metosin/malli/CURRENT +;; +;; -------------------------------------------------------------------------------- + + ) ;; ;; Public API @@ -33,6 +126,7 @@ (remove-watch @#'m/-function-schemas* ::watch) (->> (mi/unstrument!) (count) (format "unstrumented %d function vars") (-log!)) (clj-kondo/save! {}) + (-uncapture-schema-ctors!) (-uncapture-fail!) (-log! "dev-mode stopped")) @@ -45,6 +139,7 @@ ([options] (with-out-str (stop!)) (-capture-fail! options) + (-capture-schema-ctors!) (mi/collect! {:ns (all-ns)}) (let [watch (bound-fn [_ _ old new] (->> (for [[n d] (:clj new) diff --git a/src/malli/dev/pretty.cljc b/src/malli/dev/pretty.cljc index 1c54fbd80..c423f5f43 100644 --- a/src/malli/dev/pretty.cljc +++ b/src/malli/dev/pretty.cljc @@ -92,17 +92,25 @@ (v/-block "Function Schema" (v/-visit schema printer) printer) :break :break (v/-block "More information" (v/-link "https://cljdoc.org/d/metosin/malli/CURRENT/doc/function-schemas" printer) printer)]}) -(defmethod v/-format ::m/invalid-ref [_ {:keys [ref]} printer] +(defmethod v/-format ::m/invalid-ref [_ {:malli.dev/keys [forms] :keys [ref]} printer] {:body [:group (v/-block "Invalid Reference" (v/-visit [:ref ref] printer) printer) :break :break (v/-block "Reason" (-ref-text printer) printer) :break :break (v/-block "More information" (v/-link "https://cljdoc.org/d/metosin/malli/CURRENT" printer) printer)]}) -(defmethod v/-format ::m/invalid-schema [_ {:keys [schema form]} printer] +(defmethod v/-format ::m/invalid-schema [_ {:malli.dev/keys [forms] :keys [schema form]} printer] (let [proposals (seq (me/-most-similar-to #{schema} schema (set (keys (mr/schemas m/default-registry)))))] {:title "Schema Creation Error" :body [:group (v/-block "Invalid Schema" (v/-visit form printer) printer) :break :break + (when forms + [:group + (v/-block "Surrounding Syntax" + (interpose :break (map (fn [{:keys [form level]}] + [:align level (v/-text (pr-str form) printer)]) + forms)) + printer) + :break :break]) (when proposals [:group (v/-block "Did you mean" (->> (for [proposal proposals] (v/-visit proposal printer)) (interpose :break)) printer) :break :break])