mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 09:11:42 +02:00
♻️ Improve the asserts framework
This commit is contained in:
parent
c02e8ff883
commit
98190ed92d
2 changed files with 88 additions and 61 deletions
|
@ -5,7 +5,7 @@
|
||||||
;; Copyright (c) UXBOX Labs SL
|
;; Copyright (c) UXBOX Labs SL
|
||||||
|
|
||||||
(ns app.common.spec
|
(ns app.common.spec
|
||||||
"Data manipulation and query helper functions."
|
"Data validation & assertion helpers."
|
||||||
(:refer-clojure :exclude [assert bytes?])
|
(:refer-clojure :exclude [assert bytes?])
|
||||||
#?(:cljs (:require-macros [app.common.spec :refer [assert]]))
|
#?(:cljs (:require-macros [app.common.spec :refer [assert]]))
|
||||||
(:require
|
(:require
|
||||||
|
@ -31,8 +31,6 @@
|
||||||
(def max-safe-int (int 1e6))
|
(def max-safe-int (int 1e6))
|
||||||
(def min-safe-int (int -1e6))
|
(def min-safe-int (int -1e6))
|
||||||
|
|
||||||
(def valid? s/valid?)
|
|
||||||
|
|
||||||
;; --- Conformers
|
;; --- Conformers
|
||||||
|
|
||||||
(defn uuid-conformer
|
(defn uuid-conformer
|
||||||
|
@ -220,73 +218,102 @@
|
||||||
(fn [s]
|
(fn [s]
|
||||||
(str/join "," s))))
|
(str/join "," s))))
|
||||||
|
|
||||||
;; --- Macros
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; MACROS
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn spec-assert*
|
(defn explain-data
|
||||||
[spec val hint ctx]
|
[spec value]
|
||||||
(if (s/valid? spec val)
|
(s/explain-data spec value))
|
||||||
val
|
|
||||||
(let [data (s/explain-data spec val)]
|
|
||||||
(ex/raise :type :assertion
|
|
||||||
:code :spec-validation
|
|
||||||
:hint hint
|
|
||||||
::ex/data (merge ctx data)))))
|
|
||||||
|
|
||||||
(defmacro assert
|
(defn valid?
|
||||||
"Development only assertion macro."
|
[spec value]
|
||||||
[spec x]
|
(s/valid? spec value))
|
||||||
(when *assert*
|
|
||||||
(let [nsdata (:ns &env)
|
|
||||||
context (if nsdata
|
|
||||||
{:ns (str (:name nsdata))
|
|
||||||
:name (pr-str spec)
|
|
||||||
:line (:line &env)
|
|
||||||
:file (:file (:meta nsdata))}
|
|
||||||
(let [mdata (meta &form)]
|
|
||||||
{:ns (str (ns-name *ns*))
|
|
||||||
:name (pr-str spec)
|
|
||||||
:line (:line mdata)}))
|
|
||||||
message (str "spec assert: '" (pr-str spec) "'")]
|
|
||||||
`(spec-assert* ~spec ~x ~message ~context))))
|
|
||||||
|
|
||||||
(defmacro verify
|
(defmacro assert-expr*
|
||||||
"Always active assertion macro (does not obey to :elide-asserts)"
|
"Auxiliar macro for expression assertion."
|
||||||
[spec x]
|
[expr hint]
|
||||||
(let [nsdata (:ns &env)
|
`(when-not ~expr
|
||||||
context (when nsdata
|
(ex/raise :type :assertion
|
||||||
|
:code :expr-validation
|
||||||
|
:hint ~hint)))
|
||||||
|
|
||||||
|
(defmacro assert-spec*
|
||||||
|
"Auxiliar macro for spec assertion."
|
||||||
|
[spec value hint]
|
||||||
|
(let [context (if-let [nsdata (:ns &env)]
|
||||||
{:ns (str (:name nsdata))
|
{:ns (str (:name nsdata))
|
||||||
:name (pr-str spec)
|
:name (pr-str spec)
|
||||||
:line (:line &env)
|
:line (:line &env)
|
||||||
:file (:file (:meta nsdata))})
|
:file (:file (:meta nsdata))}
|
||||||
message (str "spec verify: '" (pr-str spec) "'")]
|
{:ns (str (ns-name *ns*))
|
||||||
`(spec-assert* ~spec ~x ~message ~context)))
|
:name (pr-str spec)
|
||||||
|
:line (:line (meta &form))})
|
||||||
|
hint (or hint (str "spec assert: " (pr-str spec)))]
|
||||||
|
|
||||||
|
`(if (valid? ~spec ~value)
|
||||||
|
~value
|
||||||
|
(let [data# (explain-data ~spec ~value)]
|
||||||
|
(ex/raise :type :assertion
|
||||||
|
:code :spec-validation
|
||||||
|
:hint ~hint
|
||||||
|
::ex/data (merge ~context data#))))))
|
||||||
|
|
||||||
|
(defmacro assert
|
||||||
|
"Is a spec specific assertion macro that only evaluates if *assert*
|
||||||
|
is true. DEPRECATED: it should be replaced by the new, general
|
||||||
|
purpose assert! macro."
|
||||||
|
[spec value]
|
||||||
|
(when *assert*
|
||||||
|
`(assert-spec* ~spec ~value nil)))
|
||||||
|
|
||||||
|
(defmacro verify
|
||||||
|
"Is a spec specific assertion macro that evaluates always,
|
||||||
|
independently of *assert* value. DEPRECATED: should be replaced by
|
||||||
|
the new, general purpose `verify!` macro."
|
||||||
|
[spec value]
|
||||||
|
`(assert-spec* ~spec ~value nil))
|
||||||
|
|
||||||
(defmacro assert!
|
(defmacro assert!
|
||||||
"General purpose assertion macro."
|
"General purpose assertion macro."
|
||||||
[& {:keys [expr spec always? hint val]}]
|
[& params]
|
||||||
(cond
|
;; If we only receive two arguments, this means we use the simplified form
|
||||||
(some? spec)
|
(let [pcnt (count params)]
|
||||||
(let [context (if-let [nsdata (:ns &env)]
|
(cond
|
||||||
{:ns (str (:name nsdata))
|
;; When we have a single argument, this means a simplified form
|
||||||
:name (pr-str spec)
|
;; of expr assertion
|
||||||
:line (:line &env)
|
(= 1 pcnt)
|
||||||
:file (:file (:meta nsdata))}
|
(let [expr (first params)
|
||||||
{:ns (str (ns-name *ns*))
|
hint (str "expr assert failed:" (pr-str expr))]
|
||||||
:name (pr-str spec)
|
(when *assert*
|
||||||
:line (:line (meta &form))})
|
`(assert-expr* ~expr ~hint)))
|
||||||
message (or hint (str "spec assert: " (pr-str spec)))]
|
|
||||||
(when (or always? *assert*)
|
|
||||||
`(spec-assert* ~spec ~val ~message ~context)))
|
|
||||||
|
|
||||||
(some? expr)
|
;; If we have two arguments, this can be spec or expr
|
||||||
(let [message (or hint (str "expr assert: " (pr-str expr)))]
|
;; assertion. The spec assertion is determined if the first
|
||||||
(when (or always? *assert*)
|
;; argument is a qualified keyword.
|
||||||
`(when-not ~expr
|
(= 2 pcnt)
|
||||||
(ex/raise :type :assertion
|
(let [[spec-or-expr value-or-msg] params]
|
||||||
:code :expr-validation
|
(if (qualified-keyword? spec-or-expr)
|
||||||
:hint ~message))))
|
`(assert-spec* ~spec-or-expr ~value-or-msg nil)
|
||||||
|
`(assert-expr* ~spec-or-expr ~value-or-msg)))
|
||||||
|
|
||||||
:else nil))
|
(= 3 pcnt)
|
||||||
|
(let [[spec value hint] params]
|
||||||
|
`(assert-spec* ~spec ~value ~hint))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(let [{:keys [spec expr hint always? val]} params]
|
||||||
|
(when (or always? *assert*)
|
||||||
|
(if spec
|
||||||
|
`(assert-spec* ~spec ~val ~hint)
|
||||||
|
`(assert-expr* ~expr ~hint)))))))
|
||||||
|
|
||||||
|
(defmacro verify!
|
||||||
|
"A variant of `assert!` macro that evaluates always, independently
|
||||||
|
of the *assert* value."
|
||||||
|
[& params]
|
||||||
|
(binding [*assert* true]
|
||||||
|
`(assert! ~@params)))
|
||||||
|
|
||||||
;; --- Public Api
|
;; --- Public Api
|
||||||
|
|
||||||
|
|
|
@ -111,11 +111,11 @@
|
||||||
;; --- Helper Functions
|
;; --- Helper Functions
|
||||||
|
|
||||||
(defn ^boolean check-browser? [candidate]
|
(defn ^boolean check-browser? [candidate]
|
||||||
(us/verify ::browser candidate)
|
(us/verify! ::browser candidate)
|
||||||
(= candidate @browser))
|
(= candidate @browser))
|
||||||
|
|
||||||
(defn ^boolean check-platform? [candidate]
|
(defn ^boolean check-platform? [candidate]
|
||||||
(us/verify ::platform candidate)
|
(us/verify! ::platform candidate)
|
||||||
(= candidate @platform))
|
(= candidate @platform))
|
||||||
|
|
||||||
(defn resolve-profile-photo-url
|
(defn resolve-profile-photo-url
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue