mirror of
https://github.com/penpot/penpot.git
synced 2025-01-21 06:02:32 -05:00
Merge branch 'token-studio-develop' into token-sets-ui
This commit is contained in:
commit
1a3184d327
14 changed files with 335 additions and 258 deletions
|
@ -47,10 +47,12 @@
|
|||
:string
|
||||
:typography})
|
||||
|
||||
(def token-name-ref :string)
|
||||
|
||||
(sm/register! ::token
|
||||
[:map {:title "Token"}
|
||||
[:id ::sm/uuid]
|
||||
[:name :string]
|
||||
[:name token-name-ref]
|
||||
[:type [::sm/one-of token-types]]
|
||||
[:value :any]
|
||||
[:description {:optional true} :string]
|
||||
|
@ -58,48 +60,48 @@
|
|||
|
||||
(sm/register! ::border-radius
|
||||
[:map
|
||||
[:rx {:optional true} ::sm/uuid]
|
||||
[:ry {:optional true} ::sm/uuid]
|
||||
[:r1 {:optional true} ::sm/uuid]
|
||||
[:r2 {:optional true} ::sm/uuid]
|
||||
[:r3 {:optional true} ::sm/uuid]
|
||||
[:r4 {:optional true} ::sm/uuid]])
|
||||
[:rx {:optional true} token-name-ref]
|
||||
[:ry {:optional true} token-name-ref]
|
||||
[:r1 {:optional true} token-name-ref]
|
||||
[:r2 {:optional true} token-name-ref]
|
||||
[:r3 {:optional true} token-name-ref]
|
||||
[:r4 {:optional true} token-name-ref]])
|
||||
|
||||
(def border-radius-keys (schema-keys ::border-radius))
|
||||
|
||||
(sm/register! ::stroke-width
|
||||
[:map
|
||||
[:stroke-width {:optional true} ::sm/uuid]])
|
||||
[:stroke-width {:optional true} token-name-ref]])
|
||||
|
||||
(def stroke-width-keys (schema-keys ::stroke-width))
|
||||
|
||||
(sm/register! ::sizing
|
||||
[:map
|
||||
[:width {:optional true} ::sm/uuid]
|
||||
[:height {:optional true} ::sm/uuid]
|
||||
[:layout-item-min-w {:optional true} ::sm/uuid]
|
||||
[:layout-item-max-w {:optional true} ::sm/uuid]
|
||||
[:layout-item-min-h {:optional true} ::sm/uuid]
|
||||
[:layout-item-max-h {:optional true} ::sm/uuid]])
|
||||
[:width {:optional true} token-name-ref]
|
||||
[:height {:optional true} token-name-ref]
|
||||
[:layout-item-min-w {:optional true} token-name-ref]
|
||||
[:layout-item-max-w {:optional true} token-name-ref]
|
||||
[:layout-item-min-h {:optional true} token-name-ref]
|
||||
[:layout-item-max-h {:optional true} token-name-ref]])
|
||||
|
||||
(def sizing-keys (schema-keys ::sizing))
|
||||
|
||||
(sm/register! ::opacity
|
||||
[:map
|
||||
[:opacity {:optional true} ::sm/uuid]])
|
||||
[:opacity {:optional true} token-name-ref]])
|
||||
|
||||
(def opacity-keys (schema-keys ::opacity))
|
||||
|
||||
(sm/register! ::spacing
|
||||
[:map
|
||||
[:row-gap {:optional true} ::sm/uuid]
|
||||
[:column-gap {:optional true} ::sm/uuid]
|
||||
[:p1 {:optional true} ::sm/uuid]
|
||||
[:p2 {:optional true} ::sm/uuid]
|
||||
[:p3 {:optional true} ::sm/uuid]
|
||||
[:p4 {:optional true} ::sm/uuid]
|
||||
[:x {:optional true} ::sm/uuid]
|
||||
[:y {:optional true} ::sm/uuid]])
|
||||
[:row-gap {:optional true} token-name-ref]
|
||||
[:column-gap {:optional true} token-name-ref]
|
||||
[:p1 {:optional true} token-name-ref]
|
||||
[:p2 {:optional true} token-name-ref]
|
||||
[:p3 {:optional true} token-name-ref]
|
||||
[:p4 {:optional true} token-name-ref]
|
||||
[:x {:optional true} token-name-ref]
|
||||
[:y {:optional true} token-name-ref]])
|
||||
|
||||
(def spacing-keys (schema-keys ::spacing))
|
||||
|
||||
|
@ -113,7 +115,7 @@
|
|||
|
||||
(sm/register! ::rotation
|
||||
[:map
|
||||
[:rotation {:optional true} ::sm/uuid]])
|
||||
[:rotation {:optional true} token-name-ref]])
|
||||
|
||||
(def rotation-keys (schema-keys ::rotation))
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.workspace.tokens.common :refer [workspace-shapes]]
|
||||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[beicon.v2.core :as rx]
|
||||
[clojure.data :as data]
|
||||
[cuerdas.core :as str]
|
||||
|
@ -55,22 +56,22 @@
|
|||
(first))]
|
||||
shape))
|
||||
|
||||
(defn token-from-attributes [token-id attributes]
|
||||
(->> (map (fn [attr] [attr token-id]) attributes)
|
||||
(defn token-from-attributes [token attributes]
|
||||
(->> (map (fn [attr] [attr (wtt/token-identifier token)]) attributes)
|
||||
(into {})))
|
||||
|
||||
(defn unapply-token-id [shape attributes]
|
||||
(update shape :applied-tokens d/without-keys attributes))
|
||||
|
||||
(defn apply-token-id-to-attributes [{:keys [shape token-id attributes]}]
|
||||
(let [token (token-from-attributes token-id attributes)]
|
||||
(defn apply-token-to-attributes [{:keys [shape token attributes]}]
|
||||
(let [token (token-from-attributes token attributes)]
|
||||
(toggle-or-apply-token shape token)))
|
||||
|
||||
(defn apply-token-to-shape
|
||||
[{:keys [shape token attributes] :as _props}]
|
||||
(let [applied-tokens (apply-token-id-to-attributes {:shape shape
|
||||
:token-id (:id token)
|
||||
:attributes attributes})]
|
||||
(let [applied-tokens (apply-token-to-attributes {:shape shape
|
||||
:token token
|
||||
:attributes attributes})]
|
||||
(update shape :applied-tokens #(merge % applied-tokens))))
|
||||
|
||||
(defn maybe-apply-token-to-shape
|
||||
|
@ -80,17 +81,6 @@
|
|||
(apply-token-to-shape props)
|
||||
shape))
|
||||
|
||||
(defn update-token-from-attributes
|
||||
[{:keys [token-id shape-id attributes]}]
|
||||
(ptk/reify ::update-token-from-attributes
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [shape (get-shape-from-state shape-id state)
|
||||
applied-tokens (apply-token-id-to-attributes {:shape shape
|
||||
:token-id token-id
|
||||
:attributes attributes})]
|
||||
(rx/of (update-shape shape-id {:applied-tokens applied-tokens}))))))
|
||||
|
||||
(defn get-token-data-from-token-id
|
||||
[id]
|
||||
(let [workspace-data (deref refs/workspace-data)]
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.tokens.core :as wtc]
|
||||
[app.main.ui.workspace.tokens.editable-select :refer [editable-select]]
|
||||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[app.main.ui.workspace.tokens.changes :as wtch]
|
||||
[app.main.ui.workspace.tokens.token-types :as wtty]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
@ -985,18 +987,25 @@
|
|||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [type prop value]
|
||||
(let [token-value (wtc/maybe-resolve-token-value value)
|
||||
val (or token-value (mth/finite value 0))]
|
||||
(let [token-identifier (wtt/token-identifier value)
|
||||
val (or token-identifier (mth/finite value 0))
|
||||
on-update-shape wtch/update-layout-padding]
|
||||
(cond
|
||||
(and (= type :simple) (= prop :p1))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}
|
||||
:applied-tokens {:padding-p1 (if token-value (:id value) nil)
|
||||
:padding-p3 (if token-value (:id value) nil)}}))
|
||||
(if token-identifier
|
||||
(st/emit! (wtch/apply-token {:shape-ids ids
|
||||
:attributes #{:p1 :p3}
|
||||
:token value
|
||||
:on-update-shape on-update-shape}))
|
||||
(st/emit! (on-update-shape value ids #{:p1 :p3})))
|
||||
|
||||
(and (= type :simple) (= prop :p2))
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}
|
||||
:applied-tokens {:padding-p2 (if token-value (:id value) nil)
|
||||
:padding-p4 (if token-value (:id value) nil)}}))
|
||||
(if token-identifier
|
||||
(st/emit! (wtch/apply-token {:shape-ids ids
|
||||
:attributes #{:p2 :p4}
|
||||
:token value
|
||||
:on-update-shape on-update-shape}))
|
||||
(st/emit! (on-update-shape value ids #{:p2 :p4})))
|
||||
|
||||
(some? prop)
|
||||
(st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))))
|
||||
|
|
|
@ -300,7 +300,7 @@
|
|||
(update-fn shape)
|
||||
shape))
|
||||
{:reg-objects? true
|
||||
:attrs [:rx :ry :r1 :r2 :r3 :r4]})))
|
||||
:attrs [:rx :ry :r1 :r2 :r3 :r4 :applied-tokens]})))
|
||||
|
||||
on-switch-to-radius-1
|
||||
(mf/use-fn
|
||||
|
|
|
@ -34,11 +34,10 @@
|
|||
(watch [_ state _]
|
||||
(->> (rx/from (sd/resolve-tokens+ (get-in state [:workspace-data :tokens])))
|
||||
(rx/mapcat
|
||||
(fn [sd-tokens]
|
||||
(fn [resolved-tokens]
|
||||
(let [undo-id (js/Symbol)
|
||||
resolved-value (-> (get sd-tokens (:id token))
|
||||
(wtt/resolve-token-value))
|
||||
tokenized-attributes (wtt/attributes-map attributes (:id token))]
|
||||
resolved-value (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value])
|
||||
tokenized-attributes (wtt/attributes-map attributes token)]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwsh/update-shapes shape-ids (fn [shape]
|
||||
|
@ -58,7 +57,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of
|
||||
(let [remove-token #(when % (wtt/remove-attributes-for-token-id attributes (:id token) %))]
|
||||
(let [remove-token #(when % (wtt/remove-attributes-for-token attributes token %))]
|
||||
(dwsh/update-shapes
|
||||
shape-ids
|
||||
(fn [shape]
|
||||
|
@ -137,6 +136,9 @@
|
|||
(zipmap (repeat value)))]
|
||||
{:layout-gap layout-gap}))
|
||||
|
||||
(defn update-layout-padding [value shape-ids attrs]
|
||||
(dwsl/update-layout shape-ids {:layout-padding (zipmap attrs (repeat value))}))
|
||||
|
||||
(defn update-layout-spacing [value shape-ids attributes]
|
||||
(ptk/reify ::update-layout-spacing
|
||||
ptk/WatchEvent
|
||||
|
@ -149,15 +151,6 @@
|
|||
(rx/of
|
||||
(dwsl/update-layout layout-shape-ids layout-attributes))))))
|
||||
|
||||
(defn update-layout-spacing-column [value shape-ids]
|
||||
(ptk/reify ::update-layout-spacing-column
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/concat
|
||||
(for [shape-id shape-ids]
|
||||
(let [layout-update {:layout-gap {:column-gap value :row-gap value}}]
|
||||
(dwsl/update-layout [shape-id] layout-update)))))))
|
||||
|
||||
(defn update-shape-position [value shape-ids attributes]
|
||||
(ptk/reify ::update-shape-position
|
||||
ptk/WatchEvent
|
||||
|
|
|
@ -81,8 +81,7 @@
|
|||
(concat [all-action] single-actions)))
|
||||
|
||||
(defn spacing-attribute-actions [{:keys [token selected-shapes] :as context-data}]
|
||||
(let [on-update-shape (fn [resolved-value shape-ids attrs]
|
||||
(dwsl/update-layout shape-ids {:layout-padding (zipmap attrs (repeat resolved-value))}))
|
||||
(let [on-update-shape-padding wtch/update-layout-padding
|
||||
padding-attrs {:p1 "Top"
|
||||
:p2 "Right"
|
||||
:p3 "Bottom"
|
||||
|
@ -105,7 +104,7 @@
|
|||
:shape-ids shape-ids}]
|
||||
(if all-selected?
|
||||
(st/emit! (wtch/unapply-token props))
|
||||
(st/emit! (wtch/apply-token (assoc props :on-update-shape on-update-shape))))))}
|
||||
(st/emit! (wtch/apply-token (assoc props :on-update-shape on-update-shape-padding))))))}
|
||||
{:title "Horizontal"
|
||||
:selected? horizontal-padding-selected?
|
||||
:action (fn []
|
||||
|
@ -116,7 +115,7 @@
|
|||
horizontal-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove horizontal-attributes))
|
||||
:else (wtch/apply-token (assoc props
|
||||
:attributes horizontal-attributes
|
||||
:on-update-shape on-update-shape)))]
|
||||
:on-update-shape on-update-shape-padding)))]
|
||||
(st/emit! event)))}
|
||||
{:title "Vertical"
|
||||
:selected? vertical-padding-selected?
|
||||
|
@ -128,7 +127,7 @@
|
|||
vertical-padding-selected? (wtch/apply-token (assoc props :attributes-to-remove vertical-attributes))
|
||||
:else (wtch/apply-token (assoc props
|
||||
:attributes vertical-attributes
|
||||
:on-update-shape on-update-shape)))]
|
||||
:on-update-shape on-update-shape-padding)))]
|
||||
(st/emit! event)))}]
|
||||
single-padding-items (->> padding-attrs
|
||||
(map (fn [[attr title]]
|
||||
|
@ -149,7 +148,7 @@
|
|||
all-selected? (-> (assoc props :attributes-to-remove all-padding-attrs)
|
||||
(wtch/apply-token))
|
||||
selected? (wtch/unapply-token props)
|
||||
:else (-> (assoc props :on-update-shape on-update-shape)
|
||||
:else (-> (assoc props :on-update-shape on-update-shape-padding)
|
||||
(wtch/apply-token)))]
|
||||
(st/emit! event))}))))
|
||||
gap-items (all-or-sepearate-actions {:attribute-labels {:column-gap "Column Gap"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
width: 100%;
|
||||
padding: $s-8;
|
||||
border-radius: $br-8;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
background: transparent;
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
["lodash.debounce" :as debounce]
|
||||
[app.main.ui.workspace.tokens.update :as wtu]
|
||||
[app.common.data :as d]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.tokens :as dt]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.workspace.tokens.common :as tokens.common]
|
||||
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
||||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[app.main.ui.workspace.tokens.update :as wtu]
|
||||
[app.util.dom :as dom]
|
||||
[cuerdas.core :as str]
|
||||
[malli.core :as m]
|
||||
|
@ -92,7 +93,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
;; When creating a new token we dont have a token name yet,
|
||||
;; so we use a temporary token name that hopefully doesn't clash with any of the users token names.
|
||||
token-name (if (str/empty? name-value) "__TOKEN_STUDIO_SYSTEM.TEMP" name-value)
|
||||
token-references (sd/find-token-references input)
|
||||
token-references (wtt/find-token-references input)
|
||||
direct-self-reference? (get token-references token-name)]
|
||||
(cond
|
||||
empty-input? (p/rejected nil)
|
||||
|
@ -104,7 +105,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
(-> (sd/resolve-tokens+ new-tokens #_ {:debug? true})
|
||||
(p/then
|
||||
(fn [resolved-tokens]
|
||||
(let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-id)]
|
||||
(let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-name)]
|
||||
(cond
|
||||
resolved-value (p/resolved resolved-token)
|
||||
(sd/missing-reference-error? errors) (p/rejected :error/token-missing-reference)
|
||||
|
@ -141,14 +142,15 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
(mf/defc form
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [token token-type] :as _args}]
|
||||
(let [tokens (sd/use-resolved-workspace-tokens)
|
||||
(let [tokens (mf/deref refs/workspace-tokens)
|
||||
resolved-tokens (sd/use-resolved-tokens tokens)
|
||||
token-path (mf/use-memo
|
||||
(mf/deps (:name token))
|
||||
#(wtt/token-name->path (:name token)))
|
||||
tokens-tree (mf/use-memo
|
||||
(mf/deps token-path tokens)
|
||||
(mf/deps token-path resolved-tokens)
|
||||
(fn []
|
||||
(-> (wtt/token-names-tree tokens)
|
||||
(-> (wtt/token-names-tree resolved-tokens)
|
||||
;; Allow setting editing token to it's own path
|
||||
(d/dissoc-in token-path))))
|
||||
|
||||
|
@ -177,7 +179,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
|
||||
;; Value
|
||||
value-ref (mf/use-var (:value token))
|
||||
token-resolve-result (mf/use-state (get-in tokens [(:id token) :resolved-value]))
|
||||
token-resolve-result (mf/use-state (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value]))
|
||||
set-resolve-value (mf/use-callback
|
||||
(fn [token-or-err]
|
||||
(let [v (cond
|
||||
|
@ -219,7 +221,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
(not valid-description-field?))
|
||||
|
||||
on-submit (mf/use-callback
|
||||
(mf/deps validate-name validate-descripion token tokens)
|
||||
(mf/deps validate-name validate-descripion token resolved-tokens)
|
||||
(fn [e]
|
||||
(dom/prevent-default e)
|
||||
;; We have to re-validate the current form values before submitting
|
||||
|
@ -236,7 +238,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
|||
(validate-token-value+ {:input final-value
|
||||
:name-value final-name
|
||||
:token token
|
||||
:tokens tokens})])
|
||||
:tokens resolved-tokens})])
|
||||
(p/finally (fn [result err]
|
||||
;; The result should be a vector of all resolved validations
|
||||
;; We do not handle the error case as it will be handled by the components validations
|
||||
|
|
|
@ -2,18 +2,15 @@
|
|||
(:require
|
||||
["@tokens-studio/sd-transforms" :as sd-transforms]
|
||||
["style-dictionary$default" :as sd]
|
||||
[app.common.data :as d]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]
|
||||
[shadow.resource]))
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def StyleDictionary
|
||||
"The global StyleDictionary instance used as an external library for now,
|
||||
as the package would need webpack to be bundled,
|
||||
because shadow-cljs doesn't support some of the more modern bundler features."
|
||||
"Initiates the global StyleDictionary instance with transforms
|
||||
from tokens-studio used to parse and resolved token values."
|
||||
(do
|
||||
(sd-transforms/registerTransforms sd)
|
||||
(.registerFormat sd #js {:name "custom/json"
|
||||
|
@ -23,13 +20,6 @@
|
|||
|
||||
;; Functions -------------------------------------------------------------------
|
||||
|
||||
(defn find-token-references
|
||||
"Finds token reference values in `value-string` and returns a set with all contained namespaces."
|
||||
[value-string]
|
||||
(some->> (re-seq #"\{([^}]*)\}" value-string)
|
||||
(map second)
|
||||
(into #{})))
|
||||
|
||||
(defn tokens->style-dictionary+
|
||||
"Resolves references and math expressions using StyleDictionary.
|
||||
Returns a promise with the resolved dictionary."
|
||||
|
@ -88,16 +78,16 @@
|
|||
(resolve-sd-tokens+ config))]
|
||||
(let [resolved-tokens (reduce
|
||||
(fn [acc ^js cur]
|
||||
(let [value (.-value cur)
|
||||
resolved-value (d/parse-double (.-value cur))
|
||||
original-value (-> cur .-original .-value)
|
||||
id (uuid (.-uuid (.-id cur)))
|
||||
missing-reference? (and (not resolved-value)
|
||||
(re-find #"\{" value)
|
||||
(= value original-value))]
|
||||
(cond-> (assoc-in acc [id :resolved-value] resolved-value)
|
||||
missing-reference? (update-in [id :errors] (fnil conj #{}) :style-dictionary/missing-reference))))
|
||||
tokens sd-tokens)]
|
||||
(let [id (uuid (.-uuid (.-id cur)))
|
||||
origin-token (get tokens id)
|
||||
parsed-value (wtt/parse-token-value (.-value cur))
|
||||
resolved-token (if (not parsed-value)
|
||||
(assoc origin-token :errors [:style-dictionary/missing-reference])
|
||||
(assoc origin-token
|
||||
:resolved-value (:value parsed-value)
|
||||
:resolved-unit (:unit parsed-value)))]
|
||||
(assoc acc (wtt/token-identifier resolved-token) resolved-token)))
|
||||
{} sd-tokens)]
|
||||
(when debug?
|
||||
(js/console.log "Resolved tokens" resolved-tokens))
|
||||
resolved-tokens)))
|
||||
|
@ -148,20 +138,31 @@
|
|||
(comment
|
||||
(defonce !output (atom nil))
|
||||
|
||||
(-> @refs/workspace-tokens
|
||||
(resolve-tokens+ {:debug? false})
|
||||
(.then js/console.log))
|
||||
|
||||
(-> (resolve-workspace-tokens+ {:debug? true})
|
||||
(p/then #(reset! !output %)))
|
||||
|
||||
@!output
|
||||
|
||||
(->> @refs/workspace-tokens
|
||||
(resolve-tokens+))
|
||||
(resolve-tokens+)
|
||||
(#(doto % js/console.log)))
|
||||
|
||||
(->
|
||||
(clj->js {"a" {:name "a" :value "5"}
|
||||
"b" {:name "b" :value "{a} * 2"}})
|
||||
|
||||
(#(resolve-sd-tokens+ % {:debug? true})))
|
||||
|
||||
(defonce output (atom nil))
|
||||
(require '[shadow.resource])
|
||||
(let [example (-> (shadow.resource/inline "./data/example-tokens-set.json")
|
||||
(js/JSON.parse)
|
||||
.-core)]
|
||||
(resolve-sd-tokens+ example {:debug? true}))
|
||||
(.then (resolve-sd-tokens+ example {:debug? true})
|
||||
#(reset! output %)))
|
||||
|
||||
nil)
|
||||
|
|
|
@ -4,6 +4,32 @@
|
|||
[clojure.set :as set]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(def parseable-token-value-regexp
|
||||
"Regexp that can be used to parse a number value out of resolved token value.
|
||||
This regexp also trims whitespace around the value."
|
||||
#"^\s*(-?[0-9]+\.?[0-9]*)(px|%)?\s*$")
|
||||
|
||||
(defn parse-token-value
|
||||
"Parses a resolved value and separates the unit from the value.
|
||||
Returns a map of {:value `number` :unit `string`}."
|
||||
[value]
|
||||
(cond
|
||||
(number? value) {:value value}
|
||||
(string? value) (when-let [[_ value unit] (re-find parseable-token-value-regexp value)]
|
||||
(when-let [parsed-value (d/parse-double value)]
|
||||
{:value parsed-value
|
||||
:unit unit}))))
|
||||
|
||||
(defn find-token-references
|
||||
"Finds token reference values in `value-string` and returns a set with all contained namespaces."
|
||||
[value-string]
|
||||
(some->> (re-seq #"\{([^}]*)\}" value-string)
|
||||
(map second)
|
||||
(into #{})))
|
||||
|
||||
(defn token-identifier [{:keys [name] :as _token}]
|
||||
name)
|
||||
|
||||
(defn resolve-token-value [{:keys [value resolved-value] :as _token}]
|
||||
(or
|
||||
resolved-value
|
||||
|
@ -11,17 +37,17 @@
|
|||
|
||||
(defn attributes-map
|
||||
"Creats an attributes map using collection of `attributes` for `id`."
|
||||
[attributes id]
|
||||
(->> (map (fn [attr] {attr id}) attributes)
|
||||
[attributes token]
|
||||
(->> (map (fn [attr] [attr (token-identifier token)]) attributes)
|
||||
(into {})))
|
||||
|
||||
(defn remove-attributes-for-token-id
|
||||
(defn remove-attributes-for-token
|
||||
"Removes applied tokens with `token-id` for the given `attributes` set from `applied-tokens`."
|
||||
[attributes token-id applied-tokens]
|
||||
[attributes token applied-tokens]
|
||||
(let [attr? (set attributes)]
|
||||
(->> (remove (fn [[k v]]
|
||||
(and (attr? k)
|
||||
(= v token-id)))
|
||||
(= v (token-identifier token))))
|
||||
applied-tokens)
|
||||
(into {}))))
|
||||
|
||||
|
@ -29,7 +55,7 @@
|
|||
"Test if `token` is applied to a `shape` on single `token-attribute`."
|
||||
[token shape token-attribute]
|
||||
(when-let [id (get-in shape [:applied-tokens token-attribute])]
|
||||
(= (:id token) id)))
|
||||
(= (token-identifier token) id)))
|
||||
|
||||
(defn token-applied?
|
||||
"Test if `token` is applied to a `shape` with at least one of the one of the given `token-attributes`."
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
(defn apply-token-to-shape [file shape-label token-label attributes]
|
||||
(let [first-page-id (get-in file [:data :pages 0])
|
||||
shape-id (thi/id shape-label)
|
||||
token-id (thi/id token-label)
|
||||
applied-attributes (wtt/attributes-map attributes token-id)]
|
||||
token (get-token file token-label)
|
||||
applied-attributes (wtt/attributes-map attributes token)]
|
||||
(update-in file [:data
|
||||
:pages-index first-page-id
|
||||
:objects shape-id
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[app.common.test-helpers.files :as cthf]
|
||||
[app.common.test-helpers.shapes :as cths]
|
||||
[app.main.ui.workspace.tokens.changes :as wtch]
|
||||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[frontend-tests.helpers.pages :as thp]
|
||||
[frontend-tests.helpers.state :as ths]
|
||||
|
@ -31,31 +32,58 @@
|
|||
:type :border-radius})))
|
||||
|
||||
(t/deftest test-apply-token
|
||||
(t/testing "applying a token twice with the same attributes will override the previous applied token"
|
||||
(t/testing "applies token to shape and updates shape attributes to resolved value"
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-1)
|
||||
:on-update-shape wtch/update-shape-radius-all})
|
||||
(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-2)
|
||||
:on-update-shape wtch/update-shape-radius-all})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-2' (toht/get-token file' :token-2)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:rx rect-1') 24))
|
||||
(t/is (= (:ry rect-1') 24)))))))))
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-2)
|
||||
:on-update-shape wtch/update-shape-radius-all})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-2' (toht/get-token file' :token-2)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/testing "shape `:applied-tokens` got updated"
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2'))))
|
||||
(t/testing "shape radius got update to the resolved token value."
|
||||
(t/is (= (:rx rect-1') 24))
|
||||
(t/is (= (:ry rect-1') 24))))))))))
|
||||
|
||||
(t/deftest test-apply-multiple-tokens
|
||||
(t/testing "applying a token twice with the same attributes will override the previously applied tokens values"
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-1)
|
||||
:on-update-shape wtch/update-shape-radius-all})
|
||||
(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-2)
|
||||
:on-update-shape wtch/update-shape-radius-all})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-2' (toht/get-token file' :token-2)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/testing "shape `:applied-tokens` got updated"
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2'))))
|
||||
(t/testing "shape radius got update to the resolved token value."
|
||||
(t/is (= (:rx rect-1') 24))
|
||||
(t/is (= (:ry rect-1') 24))))))))))
|
||||
|
||||
(t/deftest test-apply-token-overwrite
|
||||
(t/testing "removes old token attributes and applies only single attribute"
|
||||
|
@ -87,58 +115,37 @@
|
|||
(t/testing "other border-radius attributes got removed"
|
||||
(t/is (nil? (:rx (:applied-tokens rect-1')))))
|
||||
(t/testing "r1 got applied with :token-2"
|
||||
(t/is (= (:r1 (:applied-tokens rect-1')) (:id token-2'))))
|
||||
(t/is (= (:r1 (:applied-tokens rect-1')) (wtt/token-identifier token-2'))))
|
||||
(t/testing "while :r4 was kept"
|
||||
(t/is (= (:r4 (:applied-tokens rect-1')) (:id token-1')))))))))));)))))))))))
|
||||
|
||||
(t/deftest test-apply-border-radius
|
||||
(t/testing "applies radius token and updates the shapes radius"
|
||||
(t/async
|
||||
done
|
||||
(let [file (setup-file)
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:rx :ry}
|
||||
:token (toht/get-token file :token-2)
|
||||
:on-update-shape wtch/update-shape-radius-all})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-2' (toht/get-token file' :token-2)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:rx rect-1') 24))
|
||||
(t/is (= (:ry rect-1') 24)))))))))
|
||||
(t/is (= (:r4 (:applied-tokens rect-1')) (wtt/token-identifier token-1')))))))))));)))))))))))
|
||||
|
||||
(t/deftest test-apply-dimensions
|
||||
(t/testing "applies dimensions token and updates the shapes width and height"
|
||||
(t/async
|
||||
done
|
||||
(let [file (-> (setup-file)
|
||||
(toht/add-token :token-target {:value "100"
|
||||
:name "dimensions.sm"
|
||||
:type :dimensions}))
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:width :height}
|
||||
:token (toht/get-token file :token-target)
|
||||
:on-update-shape wtch/update-shape-dimensions})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-target' (toht/get-token file' :token-target)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:width (:applied-tokens rect-1')) (:id token-target')))
|
||||
(t/is (= (:height (:applied-tokens rect-1')) (:id token-target')))
|
||||
(t/is (= (:width rect-1') 100))
|
||||
(t/is (= (:height rect-1') 100)))))))))
|
||||
done
|
||||
(let [file (-> (setup-file)
|
||||
(toht/add-token :token-target {:value "100"
|
||||
:name "dimensions.sm"
|
||||
:type :dimensions}))
|
||||
store (ths/setup-store file)
|
||||
rect-1 (cths/get-shape file :rect-1)
|
||||
events [(wtch/apply-token {:shape-ids [(:id rect-1)]
|
||||
:attributes #{:width :height}
|
||||
:token (toht/get-token file :token-target)
|
||||
:on-update-shape wtch/update-shape-dimensions})]]
|
||||
(tohs/run-store-async
|
||||
store done events
|
||||
(fn [new-state]
|
||||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-target' (toht/get-token file' :token-target)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/testing "shape `:applied-tokens` got updated"
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target')))
|
||||
(t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target'))))
|
||||
(t/testing "shapes width and height got updated"
|
||||
(t/is (= (:width rect-1') 100))
|
||||
(t/is (= (:height rect-1') 100))))))))))
|
||||
|
||||
(t/deftest test-apply-sizing
|
||||
(t/testing "applies sizing token and updates the shapes width and height"
|
||||
|
@ -160,11 +167,13 @@
|
|||
(let [file' (ths/get-file-from-store new-state)
|
||||
token-target' (toht/get-token file' :token-target)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:width (:applied-tokens rect-1')) (:id token-target')))
|
||||
(t/is (= (:height (:applied-tokens rect-1')) (:id token-target')))
|
||||
(t/is (= (:width rect-1') 100))
|
||||
(t/is (= (:height rect-1') 100)))))))))
|
||||
(t/testing "shape `:applied-tokens` got updated"
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:width (:applied-tokens rect-1')) (wtt/token-identifier token-target')))
|
||||
(t/is (= (:height (:applied-tokens rect-1')) (wtt/token-identifier token-target'))))
|
||||
(t/testing "shapes width and height got updated"
|
||||
(t/is (= (:width rect-1') 100))
|
||||
(t/is (= (:height rect-1') 100))))))))))
|
||||
|
||||
(t/deftest test-apply-opacity
|
||||
(t/testing "applies opacity token and updates the shapes opacity"
|
||||
|
@ -207,13 +216,13 @@
|
|||
token-opacity-percent (toht/get-token file' :opacity-percent)
|
||||
token-opacity-invalid (toht/get-token file' :opacity-invalid)]
|
||||
(t/testing "float value got translated to float and applied to opacity"
|
||||
(t/is (= (:opacity (:applied-tokens rect-1')) (:id token-opacity-float)))
|
||||
(t/is (= (:opacity (:applied-tokens rect-1')) (wtt/token-identifier token-opacity-float)))
|
||||
(t/is (= (:opacity rect-1') 0.3)))
|
||||
(t/testing "percentage value got translated to float and applied to opacity"
|
||||
(t/is (= (:opacity (:applied-tokens rect-2')) (:id token-opacity-percent)))
|
||||
(t/is (= (:opacity (:applied-tokens rect-2')) (wtt/token-identifier token-opacity-percent)))
|
||||
(t/is (= (:opacity rect-2') 0.4)))
|
||||
(t/testing "invalid opacity value got applied but did not change shape"
|
||||
(t/is (= (:opacity (:applied-tokens rect-3')) (:id token-opacity-invalid)))
|
||||
(t/is (= (:opacity (:applied-tokens rect-3')) (wtt/token-identifier token-opacity-invalid)))
|
||||
(t/is (nil? (:opacity rect-3')))))))))))
|
||||
|
||||
(t/deftest test-apply-rotation
|
||||
|
@ -237,7 +246,7 @@
|
|||
token-target' (toht/get-token file' :token-target)
|
||||
rect-1' (cths/get-shape file' :rect-1)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (= (:rotation (:applied-tokens rect-1')) (:id token-target')))
|
||||
(t/is (= (:rotation (:applied-tokens rect-1')) (wtt/token-identifier token-target')))
|
||||
(t/is (= (:rotation rect-1') 120)))))))))
|
||||
|
||||
(t/deftest test-apply-stroke-width
|
||||
|
@ -267,10 +276,10 @@
|
|||
rect-with-stroke' (cths/get-shape file' :rect-1)
|
||||
rect-without-stroke' (cths/get-shape file' :rect-2)]
|
||||
(t/testing "token got applied to rect with stroke and shape stroke got updated"
|
||||
(t/is (= (:stroke-width (:applied-tokens rect-with-stroke')) (:id token-target')))
|
||||
(t/is (= (:stroke-width (:applied-tokens rect-with-stroke')) (wtt/token-identifier token-target')))
|
||||
(t/is (= (get-in rect-with-stroke' [:strokes 0 :stroke-width]) 10)))
|
||||
(t/testing "token got applied to rect without stroke but shape didnt get updated"
|
||||
(t/is (= (:stroke-width (:applied-tokens rect-without-stroke')) (:id token-target')))
|
||||
(t/is (= (:stroke-width (:applied-tokens rect-without-stroke')) (wtt/token-identifier token-target')))
|
||||
(t/is (empty? (:strokes rect-without-stroke')))))))))))
|
||||
|
||||
(t/deftest test-toggle-token-none
|
||||
|
@ -294,10 +303,10 @@
|
|||
rect-2' (cths/get-shape file' :rect-2)]
|
||||
(t/is (some? (:applied-tokens rect-1')))
|
||||
(t/is (some? (:applied-tokens rect-2')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:rx (:applied-tokens rect-2')) (:id token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (:id token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-2')) (:id token-2')))
|
||||
(t/is (= (:rx (:applied-tokens rect-1')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:rx (:applied-tokens rect-2')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-1')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:ry (:applied-tokens rect-2')) (wtt/token-identifier token-2')))
|
||||
(t/is (= (:rx rect-1') 24))
|
||||
(t/is (= (:rx rect-2') 24)))))))))
|
||||
|
||||
|
@ -361,10 +370,10 @@
|
|||
rect-with-other-token-2' (cths/get-shape file' :rect-3)]
|
||||
|
||||
(t/testing "token got applied to all shapes"
|
||||
(t/is (= (:rx (:applied-tokens rect-with-other-token-1')) (:id target-token)))
|
||||
(t/is (= (:rx (:applied-tokens rect-without-token')) (:id target-token)))
|
||||
(t/is (= (:rx (:applied-tokens rect-with-other-token-2')) (:id target-token)))
|
||||
(t/is (= (:rx (:applied-tokens rect-with-other-token-1')) (wtt/token-identifier target-token)))
|
||||
(t/is (= (:rx (:applied-tokens rect-without-token')) (wtt/token-identifier target-token)))
|
||||
(t/is (= (:rx (:applied-tokens rect-with-other-token-2')) (wtt/token-identifier target-token)))
|
||||
|
||||
(t/is (= (:ry (:applied-tokens rect-with-other-token-1')) (:id target-token)))
|
||||
(t/is (= (:ry (:applied-tokens rect-without-token')) (:id target-token)))
|
||||
(t/is (= (:ry (:applied-tokens rect-with-other-token-2')) (:id target-token)))))))))))
|
||||
(t/is (= (:ry (:applied-tokens rect-with-other-token-1')) (wtt/token-identifier target-token)))
|
||||
(t/is (= (:ry (:applied-tokens rect-without-token')) (wtt/token-identifier target-token)))
|
||||
(t/is (= (:ry (:applied-tokens rect-with-other-token-2')) (wtt/token-identifier target-token)))))))))))
|
||||
|
|
|
@ -1,20 +1,37 @@
|
|||
;; 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) KALEIDOS INC
|
||||
|
||||
(ns token-tests.style-dictionary-test
|
||||
(:require
|
||||
[app.main.ui.workspace.tokens.style-dictionary :as wtsd]
|
||||
[cljs.test :as t :include-macros true]))
|
||||
[app.main.ui.workspace.tokens.style-dictionary :as sd]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(t/deftest test-find-token-references
|
||||
;; Return references
|
||||
(t/is (= #{"foo" "bar"} (wtsd/find-token-references "{foo} + {bar}")))
|
||||
;; Ignore non reference text
|
||||
(t/is (= #{"foo.bar.baz"} (wtsd/find-token-references "{foo.bar.baz} + something")))
|
||||
;; No references found
|
||||
(t/is (nil? (wtsd/find-token-references "1 + 2")))
|
||||
;; Edge-case: Ignore unmatched closing parens
|
||||
(t/is (= #{"foo" "bar"} (wtsd/find-token-references "{foo}} + {bar}"))))
|
||||
(def border-radius-token
|
||||
{:id #uuid "8c868278-7c8d-431b-bbc9-7d8f15c8edb9"
|
||||
:value "12px"
|
||||
:name "borderRadius.sm"
|
||||
:type :border-radius})
|
||||
|
||||
(def reference-border-radius-token
|
||||
{:id #uuid "b9448d78-fd5b-4e3d-aa32-445904063f5b"
|
||||
:value "{borderRadius.sm} * 2"
|
||||
:name "borderRadius.md-with-dashes"
|
||||
:type :border-radius})
|
||||
|
||||
(def tokens {(:id border-radius-token) border-radius-token
|
||||
(:id reference-border-radius-token) reference-border-radius-token})
|
||||
|
||||
(t/deftest resolve-tokens-test
|
||||
(t/async
|
||||
done
|
||||
(t/testing "resolves tokens using style-dictionary"
|
||||
(-> (sd/resolve-tokens+ tokens)
|
||||
(p/finally (fn [resolved-tokens]
|
||||
(let [expected-tokens {"borderRadius.sm"
|
||||
(assoc border-radius-token
|
||||
:resolved-value 12
|
||||
:resolved-unit "px")
|
||||
"borderRadius.md-with-dashes"
|
||||
(assoc reference-border-radius-token
|
||||
:resolved-value 24
|
||||
:resolved-unit "px")}]
|
||||
(t/is (= expected-tokens resolved-tokens))
|
||||
(done))))))))
|
||||
|
|
|
@ -9,67 +9,95 @@
|
|||
[app.main.ui.workspace.tokens.token :as wtt]
|
||||
[cljs.test :as t :include-macros true]))
|
||||
|
||||
(t/deftest test-parse-token-value
|
||||
(t/testing "parses double from a token value"
|
||||
(t/is (= {:value 100.1 :unit nil} (wtt/parse-token-value "100.1")))
|
||||
(t/is (= {:value -9 :unit nil} (wtt/parse-token-value "-9"))))
|
||||
(t/testing "trims white-space"
|
||||
(t/is (= {:value -1.3 :unit nil} (wtt/parse-token-value " -1.3 "))))
|
||||
(t/testing "parses unit: px"
|
||||
(t/is (= {:value 70.3 :unit "px"} (wtt/parse-token-value " 70.3px "))))
|
||||
(t/testing "parses unit: %"
|
||||
(t/is (= {:value -10 :unit "%"} (wtt/parse-token-value "-10%"))))
|
||||
(t/testing "parses unit: px")
|
||||
(t/testing "returns nil for any invalid characters"
|
||||
(t/is (nil? (wtt/parse-token-value " -1.3a "))))
|
||||
(t/testing "doesnt accept invalid double"
|
||||
(t/is (nil? (wtt/parse-token-value ".3")))))
|
||||
|
||||
(t/deftest find-token-references
|
||||
(t/testing "finds references inside curly braces in a string"
|
||||
(t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo} + {bar}")))
|
||||
(t/testing "ignores extra text"
|
||||
(t/is (= #{"foo.bar.baz"} (wtt/find-token-references "{foo.bar.baz} + something"))))
|
||||
(t/testing "ignores string without references"
|
||||
(t/is (nil? (wtt/find-token-references "1 + 2"))))
|
||||
(t/testing "handles edge-case for extra curly braces"
|
||||
(t/is (= #{"foo" "bar"} (wtt/find-token-references "{foo}} + {bar}"))))))
|
||||
|
||||
(t/deftest remove-attributes-for-token-id
|
||||
(t/testing "removes attributes matching the `token-id`, keeps other attributes"
|
||||
(t/is (= {:ry :b}
|
||||
(wtt/remove-attributes-for-token-id
|
||||
#{:rx :ry} :a {:rx :a :ry :b})))))
|
||||
(t/testing "removes attributes matching the `token`, keeps other attributes"
|
||||
(t/is (= {:ry "b"}
|
||||
(wtt/remove-attributes-for-token #{:rx :ry} {:name "a"} {:rx "a" :ry "b"})))))
|
||||
|
||||
(t/deftest token-applied-test
|
||||
(t/testing "matches passed token with `:token-attributes`"
|
||||
(t/is (true? (wtt/token-applied? {:id :a} {:applied-tokens {:x :a}} #{:x}))))
|
||||
(t/is (true? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:x}))))
|
||||
(t/testing "doesn't match empty token"
|
||||
(t/is (nil? (wtt/token-applied? {} {:applied-tokens {:x :a}} #{:x}))))
|
||||
(t/is (nil? (wtt/token-applied? {} {:applied-tokens {:x "a"}} #{:x}))))
|
||||
(t/testing "does't match passed token `:id`"
|
||||
(t/is (nil? (wtt/token-applied? {:id :b} {:applied-tokens {:x :a}} #{:x}))))
|
||||
(t/is (nil? (wtt/token-applied? {:name "b"} {:applied-tokens {:x "a"}} #{:x}))))
|
||||
(t/testing "doesn't match passed `:token-attributes`"
|
||||
(t/is (nil? (wtt/token-applied? {:id :a} {:applied-tokens {:x :a}} #{:y})))))
|
||||
(t/is (nil? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:y})))))
|
||||
|
||||
(t/deftest token-applied-attributes
|
||||
(t/is (= #{:x} (wtt/token-applied-attributes {:id :a}
|
||||
{:applied-tokens {:x :a :y :b}}
|
||||
(t/is (= #{:x} (wtt/token-applied-attributes {:name "a"}
|
||||
{:applied-tokens {:x "a" :y "b"}}
|
||||
#{:x :missing}))))
|
||||
(t/deftest shapes-ids-by-applied-attributes
|
||||
(t/testing "Returns set of matched attributes that fit the applied token"
|
||||
(let [attributes #{:x :y :z}
|
||||
shape-applied-x {:id :shape-applied-x
|
||||
:applied-tokens {:x 1}}
|
||||
shape-applied-y {:id :shape-applied-y
|
||||
:applied-tokens {:y 1}}
|
||||
shape-applied-x-y {:id :shape-applied-x-y
|
||||
:applied-tokens {:x 1 :y 1}}
|
||||
shape-applied-none {:id :shape-applied-none
|
||||
shape-applied-x {:id "shape-applied-x"
|
||||
:applied-tokens {:x "1"}}
|
||||
shape-applied-y {:id "shape-applied-y"
|
||||
:applied-tokens {:y "1"}}
|
||||
shape-applied-x-y {:id "shape-applied-x-y"
|
||||
:applied-tokens {:x "1" :y "1"}}
|
||||
shape-applied-none {:id "shape-applied-none"
|
||||
:applied-tokens {}}
|
||||
shape-applied-all {:id :shape-applied-all
|
||||
:applied-tokens {:x 1 :y 1 :z 1}}
|
||||
ids-set (fn [& xs] (into #{} (map :id xs)))
|
||||
shape-applied-all {:id "shape-applied-all"
|
||||
:applied-tokens {:x "1" :y "1" :z "1"}}
|
||||
shape-ids (fn [& xs] (into #{} (map :id xs)))
|
||||
shapes [shape-applied-x
|
||||
shape-applied-y
|
||||
shape-applied-x-y
|
||||
shape-applied-all
|
||||
shape-applied-none]
|
||||
expected (wtt/shapes-ids-by-applied-attributes {:id 1} shapes attributes)]
|
||||
(t/is (= (:x expected) (ids-set shape-applied-x
|
||||
shape-applied-x-y
|
||||
shape-applied-all)))
|
||||
(t/is (= (:y expected) (ids-set shape-applied-y
|
||||
shape-applied-x-y
|
||||
shape-applied-all)))
|
||||
(t/is (= (:z expected) (ids-set shape-applied-all)))
|
||||
(t/is (true? (wtt/shapes-applied-all? expected (ids-set shape-applied-all) attributes)))
|
||||
(t/is (false? (wtt/shapes-applied-all? expected (apply ids-set shapes) attributes))))))
|
||||
expected (wtt/shapes-ids-by-applied-attributes {:name "1"} shapes attributes)]
|
||||
(t/is (= (:x expected) (shape-ids shape-applied-x
|
||||
shape-applied-x-y
|
||||
shape-applied-all)))
|
||||
(t/is (= (:y expected) (shape-ids shape-applied-y
|
||||
shape-applied-x-y
|
||||
shape-applied-all)))
|
||||
(t/is (= (:z expected) (shape-ids shape-applied-all)))
|
||||
(t/is (true? (wtt/shapes-applied-all? expected (shape-ids shape-applied-all) attributes)))
|
||||
(t/is (false? (wtt/shapes-applied-all? expected (apply shape-ids shapes) attributes)))
|
||||
(shape-ids shape-applied-x
|
||||
shape-applied-x-y
|
||||
shape-applied-all))))
|
||||
|
||||
(t/deftest tokens-applied-test
|
||||
(t/testing "is true when single shape matches the token and attributes"
|
||||
(t/is (true? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :a}}
|
||||
{:applied-tokens {:x :b}}]
|
||||
(t/is (true? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}}
|
||||
{:applied-tokens {:x "b"}}]
|
||||
#{:x}))))
|
||||
(t/testing "is false when no shape matches the token or attributes"
|
||||
(t/is (nil? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :b}}
|
||||
{:applied-tokens {:x :b}}]
|
||||
(t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "b"}}
|
||||
{:applied-tokens {:x "b"}}]
|
||||
#{:x})))
|
||||
(t/is (nil? (wtt/shapes-token-applied? {:id :a} [{:applied-tokens {:x :a}}
|
||||
{:applied-tokens {:x :a}}]
|
||||
(t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}}
|
||||
{:applied-tokens {:x "a"}}]
|
||||
#{:y})))))
|
||||
|
||||
(t/deftest name->path-test
|
||||
|
|
Loading…
Add table
Reference in a new issue