mirror of
https://github.com/penpot/penpot.git
synced 2025-08-04 09:08:58 +02:00
♻️ Add spec ns on shared code (and adapt frontend code to use it).
This commit is contained in:
parent
9a184d1c7a
commit
6957a49752
20 changed files with 297 additions and 238 deletions
33
common/uxbox/common/exceptions.cljc
Normal file
33
common/uxbox/common/exceptions.cljc
Normal file
|
@ -0,0 +1,33 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.common.exceptions
|
||||
"A helpers for work with exceptions."
|
||||
(:require [clojure.spec.alpha :as s]))
|
||||
|
||||
(s/def ::type keyword?)
|
||||
(s/def ::code keyword?)
|
||||
(s/def ::mesage string?)
|
||||
(s/def ::hint string?)
|
||||
(s/def ::cause #?(:clj #(instance? Throwable %)
|
||||
:cljs #(instance? js/Error %)))
|
||||
(s/def ::error-params
|
||||
(s/keys :req-un [::type]
|
||||
:opt-un [::code
|
||||
::hint
|
||||
::mesage
|
||||
::cause]))
|
||||
|
||||
(defn error
|
||||
[& {:keys [type code message hint cause] :as params}]
|
||||
(s/assert ::error-params params)
|
||||
(let [message (or message hint "")
|
||||
payload (dissoc params :cause :message)]
|
||||
(ex-info message payload cause)))
|
||||
|
||||
(defmacro raise
|
||||
[& args]
|
||||
`(throw (error ~@args)))
|
|
@ -1,6 +1,7 @@
|
|||
(ns uxbox.common.pages
|
||||
"A common (clj/cljs) functions and specs for pages."
|
||||
(:require
|
||||
[uxbox.common.spec :as us]
|
||||
[clojure.spec.alpha :as s]
|
||||
[uxbox.common.data :as d]))
|
||||
|
||||
|
@ -136,10 +137,6 @@
|
|||
|
||||
;; --- Changes Processing Impl
|
||||
|
||||
(defn change
|
||||
[data]
|
||||
(s/assert ::change data))
|
||||
|
||||
(declare process-change)
|
||||
(declare process-mod-shape)
|
||||
(declare process-mod-opts)
|
||||
|
@ -151,7 +148,7 @@
|
|||
|
||||
(defn process-changes
|
||||
[data items]
|
||||
(->> (s/assert ::changes items)
|
||||
(->> (us/assert ::changes items)
|
||||
(reduce process-change data)))
|
||||
|
||||
(defn- process-change
|
||||
|
|
133
common/uxbox/common/spec.cljc
Normal file
133
common/uxbox/common/spec.cljc
Normal file
|
@ -0,0 +1,133 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.common.spec
|
||||
"Data manipulation and query helper functions."
|
||||
(:refer-clojure :exclude [assert])
|
||||
#?(:cljs (:require-macros [uxbox.common.spec :refer [assert]]))
|
||||
(:require
|
||||
#?(:clj [datoteka.core :as fs])
|
||||
#?(:clj [clojure.spec.alpha :as s]
|
||||
:cljs [cljs.spec.alpha :as s])
|
||||
[expound.alpha :as expound]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(s/check-asserts true)
|
||||
|
||||
;; --- Constants
|
||||
|
||||
(def email-rx
|
||||
#"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
||||
|
||||
(def uuid-rx
|
||||
#"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
|
||||
|
||||
;; --- Conformers
|
||||
|
||||
(defn- uuid-conformer
|
||||
[v]
|
||||
(if (uuid? v)
|
||||
v
|
||||
(if (string? v)
|
||||
(if (re-matches uuid-rx v)
|
||||
#?(:cljs (uuid v)
|
||||
:clj (java.util.UUID/fromString v))
|
||||
|
||||
(if (str/empty? v) nil ::s/invalid))
|
||||
::s/invalid)))
|
||||
|
||||
(defn boolean-conformer
|
||||
[v]
|
||||
(if (boolean? v)
|
||||
v
|
||||
(if (string? v)
|
||||
(if (re-matches #"^(?:t|true|false|f|0|1)$" v)
|
||||
(contains? #{"t" "true" "1"} v)
|
||||
::s/invalid)
|
||||
::s/invalid)))
|
||||
|
||||
(defn boolean-unformer
|
||||
[v]
|
||||
(if v "true" "false"))
|
||||
|
||||
(defn- number-conformer
|
||||
[v]
|
||||
(cond
|
||||
(number? v) v
|
||||
(str/numeric? v)
|
||||
#?(:clj (Double/parseDouble v)
|
||||
:cljs (js/parseFloat v))
|
||||
:else ::s/invalid))
|
||||
|
||||
(defn- integer-conformer
|
||||
[v]
|
||||
(cond
|
||||
(integer? v) v
|
||||
(string? v)
|
||||
(if (re-matches #"^[-+]?\d+$" v)
|
||||
#?(:clj (Long/parseLong v)
|
||||
:cljs (js/parseInt v 10))
|
||||
::s/invalid)
|
||||
:else ::s/invalid))
|
||||
|
||||
(defn- color-conformer
|
||||
[v]
|
||||
(if (and (string? v) (re-matches #"^#[0-9A-Fa-f]{6}$" v))
|
||||
v
|
||||
::s/invalid))
|
||||
|
||||
(defn- email-conformer
|
||||
[v]
|
||||
(if (and (string? v) (re-matches email-rx v))
|
||||
v
|
||||
::s/invalid))
|
||||
|
||||
#?(:clj
|
||||
(defn path-conformer
|
||||
[v]
|
||||
(cond
|
||||
(string? v) (fs/path v)
|
||||
(fs/path? v) v
|
||||
:else ::s/invalid)))
|
||||
|
||||
|
||||
;; --- Default Specs
|
||||
|
||||
(s/def ::inst inst?)
|
||||
(s/def ::email (s/conformer email-conformer str))
|
||||
(s/def ::color (s/conformer color-conformer str))
|
||||
(s/def ::uuid (s/conformer uuid-conformer str))
|
||||
(s/def ::boolean (s/conformer boolean-conformer boolean-unformer))
|
||||
(s/def ::number (s/conformer number-conformer str))
|
||||
(s/def ::integer (s/conformer integer-conformer str))
|
||||
(s/def ::not-empty-string (s/and string? #(not (str/empty? %))))
|
||||
#?(:clj (s/def ::path (s/conformer path-conformer str)))
|
||||
|
||||
;; --- Macros
|
||||
|
||||
(defn assert*
|
||||
[spec x]
|
||||
(s/assert* spec x))
|
||||
|
||||
#?(:clj
|
||||
(defmacro assert
|
||||
"Always active assertion macro (does not obey to :elide-asserts)"
|
||||
[spec x]
|
||||
`(assert* ~spec ~x)))
|
||||
|
||||
;; --- Public Api
|
||||
|
||||
(defn conform
|
||||
[spec data]
|
||||
(let [result (s/conform spec data)]
|
||||
(when (= result ::s/invalid)
|
||||
(throw (ex/error :type :validation
|
||||
:code :spec-validation
|
||||
:explain (with-out-str
|
||||
(expound/printer data))
|
||||
:data (::s/problems data))))
|
||||
result))
|
Loading…
Add table
Add a link
Reference in a new issue