0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-06 14:50:20 -05:00

🔧 add groups handling v2

This commit is contained in:
Andrés Moya 2024-09-12 10:04:03 +02:00
parent e2ff6f7ba6
commit 3a4ec32f8e
3 changed files with 766 additions and 219 deletions

View file

@ -57,6 +57,54 @@
#?(:cljs (instance? lkm/LinkedMap o)
:clj (instance? LinkedMap o)))
(defn oassoc
[o & kvs]
(apply assoc (or o (ordered-map)) kvs))
(defn oassoc-in
[o [k & ks] v]
(if ks
(oassoc o k (oassoc-in (get o k) ks v))
(oassoc o k v)))
#_(defn oupdate-in
[m ks f & args]
(let [up (fn up [m ks f args]
(let [[k & ks] ks]
(if ks
(oassoc m k (up (get m k) ks f args))
(oassoc m k (apply f (get m k) args)))))]
(up m ks f args)))
(declare index-of)
#_(defn oassoc-before
"Assoc a k v pair, in the order position just before the other key"
[o k v before-k]
(if-let [index (index-of (keys o) before-k)]
(-> (ordered-map)
(into (take index o))
(assoc k v)
(into (drop index o)))
(oassoc o k v)))
(defn oassoc-in-before
[o [old-k & old-ks] [k & ks] v]
(if-let [index (index-of (keys o) old-k)]
(let [new-v (if ks
(oassoc-in-before (get o k) old-ks ks v)
v)]
(if (= k old-k)
(-> (ordered-map)
(into (take index o))
(assoc k new-v)
(into (drop (inc index) o)))
(-> (ordered-map)
(into (take index o))
(assoc k new-v)
(into (drop index o)))))
(oassoc-in o (cons k ks) v)))
(defn vec2
"Creates a optimized vector compatible type of length 2 backed
internally with MapEntry impl because it has faster access method
@ -564,6 +612,7 @@
new-elems
(remove p? after))))
;; TODO: remove this
(defn addm-at-index
"Insert an element in an ordered map at an arbitrary index"
[coll index key element]

View file

@ -15,6 +15,86 @@
[cuerdas.core :as str]
#?(:clj [app.common.fressian :as fres])))
;; === Groups handling
(def schema:groupable-item
[:map {:title "Groupable item"}
[:name :string]])
(def valid-groupable-item?
(sm/validator schema:groupable-item))
(defn split-path
"Decompose a string in the form 'one.two.three' into a vector of strings, removing spaces."
[path separator]
(let [xf (comp (map str/trim)
(remove str/empty?))]
(->> (str/split path separator)
(into [] xf))))
(defn join-path
"Regenerate a path as a string, from a vector."
[path separator]
(str/join separator path))
(defn group-item
"Add a group to the item name, in the form group.name."
[item group-name separator]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(str group-name separator %)))
(defn ungroup-item
"Remove the first group from the item name."
[item separator]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(-> %
(split-path separator)
(rest)
(join-path separator))))
(defn get-path
"Get the groups part of the name as a vector. E.g. group.subgroup.name -> ['group' 'subrgoup']"
[item separator]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(split-path (:name item) separator))
(defn get-groups-str
"Get the groups part of the name. E.g. group.subgroup.name -> group.subrgoup"
[item separator]
(-> (get-path item separator)
(butlast)
(join-path separator)))
(defn get-final-name
"Get the final part of the name. E.g. group.subgroup.name -> name"
[item separator]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(-> (:name item)
(split-path separator)
(last)))
(defn group?
"Check if a node of the grouping tree is a group or a final item."
[item]
(d/ordered-map? item))
(defn get-children
"Get all children of a group of a grouping tree. Each child is
a tuple [name item], where item "
[group]
(dm/assert!
"expected group node"
(group? group))
(seq group))
;; === Token
(defrecord Token [name type value description modified-at])
@ -22,10 +102,10 @@
(def schema:token
[:and
[:map {:title "Token"}
[:name cto/token-name-ref] ;; not necessary to have uuid
[:name cto/token-name-ref] ;; not necessary to have uuid
[:type [::sm/one-of cto/token-types]]
[:value :any]
[:description [:maybe :string]] ;; defrecord always have the attributes, even with nil value
[:description [:maybe :string]] ;; defrecord always have the attributes, even with nil value
[:modified-at ::sm/inst]]
[:fn (partial instance? Token)]])
@ -62,42 +142,56 @@
ITokenSet
(add-token [_ token]
(dm/assert! "expected valid token" (check-token! token))
(TokenSet. name
description
(dt/now)
(assoc tokens (:name token) token)))
(let [path (split-path (:name token) ".")]
(TokenSet. name
description
(dt/now)
(d/oassoc-in tokens path token))))
(update-token [this token-name f]
(if-let [token (get tokens token-name)]
(let [token' (-> (make-token (f token))
(assoc :modified-at (dt/now)))]
(check-token! token')
(TokenSet. name
description
(dt/now)
(if (= (:name token) (:name token'))
(assoc tokens (:name token') token')
(let [index (d/index-of (keys tokens) (:name token))]
(let [path (split-path token-name ".")
token (get-in tokens path)]
(if token
(let [token' (-> (make-token (f token))
(assoc :modified-at (dt/now)))
path' (get-path token' ".")]
(check-token! token')
(TokenSet. name
description
(dt/now)
(if (= (:name token) (:name token'))
(d/oassoc-in tokens path token')
(-> tokens
(dissoc (:name token))
(d/addm-at-index index (:name token') token'))))))
this))
(d/oassoc-in-before path path' token')
(d/dissoc-in path)))))
this)))
(delete-token [_ token-name]
(TokenSet. name
description
(dt/now)
(dissoc tokens token-name)))
(let [path (split-path token-name ".")]
(TokenSet. name
description
(dt/now)
(d/dissoc-in tokens path))))
(get-tokens [_]
(vals tokens)))
(->> (tree-seq d/ordered-map? vals tokens)
(filter (partial instance? Token)))))
(def schema:token-node
[:schema {:registry {::node [:or ::token
[:and
[:map-of {:gen/max 5} :string [:ref ::node]]
[:fn d/ordered-map?]]]}}
[:ref ::node]])
(sm/register! ::token-node schema:token-node)
(def schema:token-set
[:and [:map {:title "TokenSet"}
[:name :string]
[:description [:maybe :string]]
[:modified-at ::sm/inst]
[:tokens [:and [:map-of {:gen/max 5} :string ::token]
[:tokens [:and [:map-of {:gen/max 5} :string ::token-node]
[:fn d/ordered-map?]]]]
[:fn (partial instance? TokenSet)]])
@ -140,6 +234,7 @@
(update-set [_ set-name f] "modify a set in the ilbrary")
(delete-set [_ set-name] "delete a set in the library")
(set-count [_] "get the total number if sets in the library")
(get-set-tree [_] "get a nested tree of all sets in the library")
(get-sets [_] "get an ordered sequence of all sets in the library")
(get-set [_ set-name] "get one set looking for name")
(get-set-group [_ set-group-path] "get the attributes of a set group"))
@ -215,6 +310,7 @@
(update-theme [_ theme-name f] "modify a theme in the ilbrary")
(delete-theme [_ theme-name] "delete a theme in the library")
(theme-count [_] "get the total number if themes in the library")
(get-theme-tree [_] "get a nested tree of all themes in the library")
(get-themes [_] "get an ordered sequence of all themes in the library")
(get-theme [_ theme-name] "get one theme looking for name"))
@ -242,8 +338,6 @@
(toggle-set-in-theme [_ theme-name set-name] "toggle a set used / not used in a theme")
(validate [_]))
(declare get-path)
(deftype TokensLib [sets set-groups themes]
;; NOTE: This is only for debug purposes, pending to properly
;; implement the toString and alternative printing.
@ -260,41 +354,50 @@
ITokenSets
(add-set [_ token-set]
(dm/assert! "expected valid token set" (check-token-set! token-set))
(let [path (get-path token-set)]
(TokensLib. (assoc sets (:name token-set) token-set)
(let [path (get-path token-set "/")
groups-str (get-groups-str token-set "/")]
(TokensLib. (d/oassoc-in sets path token-set)
(cond-> set-groups
(seq path)
(assoc path (make-token-set-group)))
(not (str/empty? groups-str))
(assoc groups-str (make-token-set-group)))
themes)))
(update-set [this set-name f]
(if-let [set (get sets set-name)]
(let [set' (-> (make-token-set (f set))
(assoc :modified-at (dt/now)))]
(check-token-set! set')
(TokensLib. (if (= (:name set) (:name set'))
(assoc sets (:name set') set')
(let [index (d/index-of (keys sets) (:name set))]
(let [path (split-path set-name "/")
set (get-in sets path)]
(if set
(let [set' (-> (make-token-set (f set))
(assoc :modified-at (dt/now)))
path' (get-path set' "/")]
(check-token-set! set')
(TokensLib. (if (= (:name set) (:name set'))
(d/oassoc-in sets path set')
(-> sets
(dissoc (:name set))
(d/addm-at-index index (:name set') set'))))
set-groups ;; TODO update set-groups as needed
themes))
this))
(d/oassoc-in-before path path' set')
(d/dissoc-in path)))
set-groups ;; TODO update set-groups as needed
themes))
this)))
(delete-set [_ set-name]
(TokensLib. (dissoc sets set-name)
set-groups ;; TODO remove set-group if needed
themes))
(let [path (split-path set-name "/")]
(TokensLib. (d/dissoc-in sets path)
set-groups ;; TODO remove set-group if needed
themes)))
(set-count [_]
(count sets))
(get-set-tree [_]
sets)
(get-sets [_]
(vals sets))
(->> (tree-seq d/ordered-map? vals sets)
(filter (partial instance? TokenSet))))
(set-count [this]
(count (get-sets this)))
(get-set [_ set-name]
(get sets set-name))
(let [path (split-path set-name "/")]
(get-in sets path)))
(get-set-group [_ set-group-path]
(get set-groups set-group-path))
@ -302,38 +405,47 @@
ITokenThemes
(add-theme [_ token-theme]
(dm/assert! "expected valid token theme" (check-token-theme! token-theme))
(TokensLib. sets
set-groups
(assoc themes (:name token-theme) token-theme)))
(let [path (get-path token-theme "/")]
(TokensLib. sets
set-groups
(d/oassoc-in themes path token-theme))))
(update-theme [this theme-name f]
(if-let [theme (get themes theme-name)]
(let [theme' (-> (make-token-theme (f theme))
(assoc :modified-at (dt/now)))]
(check-token-theme! theme')
(TokensLib. sets
set-groups
(if (= (:name theme) (:name theme'))
(assoc themes (:name theme') theme')
(let [index (d/index-of (keys themes) (:name theme))]
(let [path (split-path theme-name "/")
theme (get-in themes path)]
(if theme
(let [theme' (-> (make-token-theme (f theme))
(assoc :modified-at (dt/now)))
path' (get-path theme' "/")]
(check-token-theme! theme')
(TokensLib. sets
set-groups
(if (= (:name theme) (:name theme'))
(d/oassoc-in themes path theme')
(-> themes
(dissoc (:name theme))
(d/addm-at-index index (:name theme') theme'))))))
this))
(d/oassoc-in-before path path' theme')
(d/dissoc-in path)))))
this)))
(delete-theme [_ theme-name]
(TokensLib. sets
set-groups
(dissoc themes theme-name)))
(let [path (split-path theme-name "/")]
(TokensLib. sets
set-groups
(d/dissoc-in themes path))))
(theme-count [_]
(count themes))
(get-theme-tree [_]
themes)
(get-themes [_]
(vals themes))
(->> (tree-seq d/ordered-map? vals themes)
(filter (partial instance? TokenTheme))))
(theme-count [this]
(count (get-themes this)))
(get-theme [_ theme-name]
(get themes theme-name))
(let [path (split-path theme-name "/")]
(get-in themes path)))
ITokensLib
(add-token-in-set [this set-name token]
@ -478,90 +590,3 @@
set-groups (fres/read-object! r)
themes (fres/read-object! r)]
(->TokensLib sets set-groups themes)))}))
;; === Groups handling
(def schema:groupable-item
[:map {:title "Groupable item"}
[:name :string]])
(def valid-groupable-item?
(sm/validator schema:groupable-item))
(defn split-path
"Decompose a string in the form 'one.two.three' into a vector of strings, removing spaces."
[path]
(let [xf (comp (map str/trim)
(remove str/empty?))]
(->> (str/split path ".")
(into [] xf))))
(defn join-path
"Regenerate a path as a string, from a vector."
[path-vec]
(str/join "." path-vec))
(defn group-item
"Add a group to the item name, in the form group.name."
[item group-name]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(str group-name "." %)))
(defn ungroup-item
"Remove the first group from the item name."
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(update item :name #(-> %
(split-path)
(rest)
(join-path))))
(defn get-path
"Get the groups part of the name. E.g. group.subgroup.name -> group.subrgoup"
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(-> (:name item)
(split-path)
(butlast)
(join-path)))
(defn get-final-name
"Get the final part of the name. E.g. group.subgroup.name -> name"
[item]
(dm/assert!
"expected groupable item"
(valid-groupable-item? item))
(-> (:name item)
(split-path)
(last)))
(defn group-items
"Convert a sequence of items in a nested structure like this:
{'': [itemA itemB]
'group1': {'': [item1A item1B]
'subgroup11': {'': [item11A item11B item11C]}
'subgroup12': {'': [item12A]}}
'group2': {'subgroup21': {'': [item21A]}}}
"
[items & {:keys [reverse-sort?]}]
(when (seq items)
(reduce (fn [groups item]
(let [pathv (split-path (:name item))]
(update-in groups
pathv
(fn [group]
(if group
(cons group item)
item)))))
(sorted-map-by (fn [key1 key2] ;; TODO: this does not work well with ordered-map
(if reverse-sort? ;; we need to think a bit more of this
(compare key2 key1)
(compare key1 key2))))
items)))

View file

@ -130,10 +130,10 @@
(t/deftest add-token-set-with-group
(let [tokens-lib (ctob/make-tokens-lib)
token-set (ctob/make-token-set :name "test-group.test-token-set")
token-set (ctob/make-token-set :name "test-group/test-token-set")
tokens-lib' (ctob/add-set tokens-lib token-set)
set-group (ctob/get-set-group tokens-lib' "test-group")]
set-group (ctob/get-set-group tokens-lib' "test-group")]
(t/is (= (:attr1 set-group) "one"))
(t/is (= (:attr2 set-group) "two"))))
@ -423,8 +423,8 @@
(t/testing "grouping"
(t/deftest split-and-join
(let [name "group.subgroup.name"
path (ctob/split-path name)
name' (ctob/join-path path)]
path (ctob/split-path name ".")
name' (ctob/join-path path ".")]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))
@ -432,7 +432,7 @@
(t/deftest remove-spaces
(let [name "group . subgroup . name"
path (ctob/split-path name)]
path (ctob/split-path name ".")]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))))
@ -441,82 +441,555 @@
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some group.token2" :type :boolean :value true)
token1' (ctob/group-item token1 "big group")
token2' (ctob/group-item token2 "big group")
token1'' (ctob/ungroup-item token1')
token2'' (ctob/ungroup-item token2')]
token1' (ctob/group-item token1 "big group" ".")
token2' (ctob/group-item token2 "big group" ".")
token1'' (ctob/ungroup-item token1' ".")
token2'' (ctob/ungroup-item token2' ".")]
(t/is (= (:name token1') "big group.token1"))
(t/is (= (:name token2') "big group.some group.token2"))
(t/is (= (:name token1'') "token1"))
(t/is (= (:name token2'') "some group.token2"))))
(t/deftest get-path
(t/deftest get-groups-str
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some-group.token2" :type :boolean :value true)
token3 (ctob/make-token :name "some-group.some-subgroup.token3" :type :boolean :value true)]
(t/is (= (ctob/get-path token1) ""))
(t/is (= (ctob/get-path token2) "some-group"))
(t/is (= (ctob/get-path token3) "some-group.some-subgroup"))))
(t/is (= (ctob/get-groups-str token1 ".") ""))
(t/is (= (ctob/get-groups-str token2 ".") "some-group"))
(t/is (= (ctob/get-groups-str token3 ".") "some-group.some-subgroup"))))
(t/deftest get-final-name
(let [token1 (ctob/make-token :name "token1" :type :boolean :value true)
token2 (ctob/make-token :name "some-group.token2" :type :boolean :value true)
token3 (ctob/make-token :name "some-group.some-subgroup.token3" :type :boolean :value true)]
(t/is (= (ctob/get-final-name token1) "token1"))
(t/is (= (ctob/get-final-name token2) "token2"))
(t/is (= (ctob/get-final-name token3) "token3"))))
(t/deftest group-items
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set1"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.token-set2"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.token-set3"))
(ctob/add-set (ctob/make-token-set :name "sgroup1.ssubgroup1.token-set4"))
(ctob/add-set (ctob/make-token-set :name "sgroup2.token-set5"))
(ctob/add-token-in-set "sgroup2.token-set5"
(ctob/make-token :name "tgroup1.tsubgroup1.token1"
(t/is (= (ctob/get-final-name token1 ".") "token1"))
(t/is (= (ctob/get-final-name token2 ".") "token2"))
(t/is (= (ctob/get-final-name token3 ".") "token3"))))
(t/testing "grouped tokens"
(t/deftest grouped-tokens
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "token1"
:type :boolean
:value true))
(ctob/add-token-in-set "sgroup2.token-set5"
(ctob/make-token :name "tgroup1.tsubgroup1.token2"
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.token2"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.token3"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.subgroup11.token4"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group2.token5"
:type :boolean
:value true)))
sets (ctob/get-sets tokens-lib)
set (ctob/get-set tokens-lib "sgroup2.token-set5")
tokens (ctob/get-tokens set)
set-groups (ctob/group-items sets)
set (ctob/get-set tokens-lib "test-token-set")
tokens-list (ctob/get-tokens set)
token-set1 (get set-groups "token-set1")
sgroup1 (get set-groups "sgroup1")
token-set2 (get sgroup1 "token-set2")
token-set3 (get sgroup1 "token-set3")
ssubgroup1 (get sgroup1 "ssubgroup1")
token-set4 (get ssubgroup1 "token-set4")
sgroup2 (get set-groups "sgroup2")
token-set5 (get sgroup2 "token-set5")
tokens-tree (:tokens set)
[node-token1 node-group1 node-group2]
(ctob/get-children tokens-tree)
token-groups (ctob/group-items tokens)
tgroup1 (get token-groups "tgroup1")
tsubgroup1 (get tgroup1 "tsubgroup1")
token1 (get tsubgroup1 "token1")
token2 (get tsubgroup1 "token2")]
[node-token2 node-token3 node-subgroup11]
(ctob/get-children (second node-group1))
;; {"sgroup1"
;; {"token-set2" {:name "sgroup1.token-set2" ...}
;; "token-set3" {:name "sgroup1.token-set3" ...}
;; "ssubgroup1"
;; {"token-set4" {:name "sgroup1.ssubgroup1.token-set4" ...}}}
;; "sgroup2"
;; {"token-set5" {:name "sgroup2.token-set5" ...}}
;; "token-set1" {:name "token-set1" ...}}
[node-token4]
(ctob/get-children (second node-subgroup11))
(t/is (= (:name token-set1) "token-set1"))
(t/is (= (:name token-set2) "sgroup1.token-set2"))
(t/is (= (:name token-set3) "sgroup1.token-set3"))
(t/is (= (:name token-set4) "sgroup1.ssubgroup1.token-set4"))
(t/is (= (:name token-set5) "sgroup2.token-set5"))
[node-token5]
(ctob/get-children (second node-group2))]
(t/is (= (:name token1) "tgroup1.tsubgroup1.token1"))
(t/is (= (:name token2) "tgroup1.tsubgroup1.token2")))))
(t/is (= (count tokens-list) 5))
(t/is (= (:name (nth tokens-list 0)) "token1"))
(t/is (= (:name (nth tokens-list 1)) "group1.token2"))
(t/is (= (:name (nth tokens-list 2)) "group1.token3"))
(t/is (= (:name (nth tokens-list 3)) "group1.subgroup11.token4"))
(t/is (= (:name (nth tokens-list 4)) "group2.token5"))
(t/is (= (first node-token1) "token1"))
(t/is (= (ctob/group? (second node-token1)) false))
(t/is (= (:name (second node-token1)) "token1"))
(t/is (= (first node-group1) "group1"))
(t/is (= (ctob/group? (second node-group1)) true))
(t/is (= (count (second node-group1)) 3))
(t/is (= (first node-token2) "token2"))
(t/is (= (ctob/group? (second node-token2)) false))
(t/is (= (:name (second node-token2)) "group1.token2"))
(t/is (= (first node-token3) "token3"))
(t/is (= (ctob/group? (second node-token3)) false))
(t/is (= (:name (second node-token3)) "group1.token3"))
(t/is (= (first node-subgroup11) "subgroup11"))
(t/is (= (ctob/group? (second node-subgroup11)) true))
(t/is (= (count (second node-subgroup11)) 1))
(t/is (= (first node-token4) "token4"))
(t/is (= (ctob/group? (second node-token4)) false))
(t/is (= (:name (second node-token4)) "group1.subgroup11.token4"))
(t/is (= (first node-token5) "token5"))
(t/is (= (ctob/group? (second node-token5)) false))
(t/is (= (:name (second node-token5)) "group2.token5"))))
(t/deftest update-token-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "test-token-1"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-2"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-3"
:type :boolean
:value true)))
tokens-lib' (-> tokens-lib
(ctob/update-token-in-set "test-token-set" "group1.test-token-2"
(fn [token]
(assoc token
:description "some description"
:value false))))
token-set (ctob/get-set tokens-lib "test-token-set")
token-set' (ctob/get-set tokens-lib' "test-token-set")
group1' (get-in token-set' [:tokens "group1"])
token (get-in token-set [:tokens "group1" "test-token-2"])
token' (get-in token-set' [:tokens "group1" "test-token-2"])]
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (count group1') 2))
(t/is (= (d/index-of (keys group1') "test-token-2") 0))
(t/is (= (:name token') "group1.test-token-2"))
(t/is (= (:description token') "some description"))
(t/is (= (:value token') false))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
(t/deftest rename-token-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "test-token-1"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-2"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-3"
:type :boolean
:value true)))
tokens-lib' (-> tokens-lib
(ctob/update-token-in-set "test-token-set" "group1.test-token-2"
(fn [token]
(assoc token
:name "group1.updated-name"))))
token-set (ctob/get-set tokens-lib "test-token-set")
token-set' (ctob/get-set tokens-lib' "test-token-set")
group1' (get-in token-set' [:tokens "group1"])
token (get-in token-set [:tokens "group1" "test-token-2"])
token' (get-in token-set' [:tokens "group1" "updated-name"])]
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (count group1') 2))
(t/is (= (d/index-of (keys group1') "updated-name") 0))
(t/is (= (:name token') "group1.updated-name"))
(t/is (= (:description token') nil))
(t/is (= (:value token') true))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
(t/deftest move-token-of-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "test-token-1"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-2"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-3"
:type :boolean
:value true)))
tokens-lib' (-> tokens-lib
(ctob/update-token-in-set "test-token-set" "group1.test-token-2"
(fn [token]
(assoc token
:name "group2.updated-name"))))
token-set (ctob/get-set tokens-lib "test-token-set")
token-set' (ctob/get-set tokens-lib' "test-token-set")
group1' (get-in token-set' [:tokens "group1"])
group2' (get-in token-set' [:tokens "group2"])
token (get-in token-set [:tokens "group1" "test-token-2"])
token' (get-in token-set' [:tokens "group2" "updated-name"])]
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (count group1') 1))
(t/is (= (count group2') 1))
(t/is (= (d/index-of (keys group2') "updated-name") 0))
(t/is (= (:name token') "group2.updated-name"))
(t/is (= (:description token') nil))
(t/is (= (:value token') true))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))
(t/is (dt/is-after? (:modified-at token') (:modified-at token)))))
(t/deftest delete-token-in-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "test-token-1"
:type :boolean
:value true))
(ctob/add-token-in-set "test-token-set"
(ctob/make-token :name "group1.test-token-2"
:type :boolean
:value true)))
tokens-lib' (-> tokens-lib
(ctob/delete-token-from-set "test-token-set" "group1.test-token-2"))
token-set (ctob/get-set tokens-lib "test-token-set")
token-set' (ctob/get-set tokens-lib' "test-token-set")
token' (get-in token-set' [:tokens "group1" "test-token-2"])]
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (count (:tokens token-set')) 1))
(t/is (nil? token'))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set))))))
(t/testing "grouped sets"
(t/deftest grouped-sets
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-2"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-3"))
(ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4"))
(ctob/add-set (ctob/make-token-set :name "group2/token-set-5")))
sets-list (ctob/get-sets tokens-lib)
sets-tree (ctob/get-set-tree tokens-lib)
[node-set1 node-group1 node-group2]
(ctob/get-children sets-tree)
[node-set2 node-set3 node-subgroup11]
(ctob/get-children (second node-group1))
[node-set4]
(ctob/get-children (second node-subgroup11))
[node-set5]
(ctob/get-children (second node-group2))]
(t/is (= (count sets-list) 5))
(t/is (= (:name (nth sets-list 0)) "token-set-1"))
(t/is (= (:name (nth sets-list 1)) "group1/token-set-2"))
(t/is (= (:name (nth sets-list 2)) "group1/token-set-3"))
(t/is (= (:name (nth sets-list 3)) "group1/subgroup11/token-set-4"))
(t/is (= (:name (nth sets-list 4)) "group2/token-set-5"))
(t/is (= (first node-set1) "token-set-1"))
(t/is (= (ctob/group? (second node-set1)) false))
(t/is (= (:name (second node-set1)) "token-set-1"))
(t/is (= (first node-group1) "group1"))
(t/is (= (ctob/group? (second node-group1)) true))
(t/is (= (count (second node-group1)) 3))
(t/is (= (first node-set2) "token-set-2"))
(t/is (= (ctob/group? (second node-set2)) false))
(t/is (= (:name (second node-set2)) "group1/token-set-2"))
(t/is (= (first node-set3) "token-set-3"))
(t/is (= (ctob/group? (second node-set3)) false))
(t/is (= (:name (second node-set3)) "group1/token-set-3"))
(t/is (= (first node-subgroup11) "subgroup11"))
(t/is (= (ctob/group? (second node-subgroup11)) true))
(t/is (= (count (second node-subgroup11)) 1))
(t/is (= (first node-set4) "token-set-4"))
(t/is (= (ctob/group? (second node-set4)) false))
(t/is (= (:name (second node-set4)) "group1/subgroup11/token-set-4"))
(t/is (= (first node-set5) "token-set-5"))
(t/is (= (ctob/group? (second node-set5)) false))
(t/is (= (:name (second node-set5)) "group2/token-set-5"))))
(t/deftest update-set-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-2"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-3"))
(ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4"))
(ctob/add-set (ctob/make-token-set :name "group2/token-set-5")))
tokens-lib' (-> tokens-lib
(ctob/update-set "group1/token-set-2"
(fn [token-set]
(assoc token-set :description "some description"))))
sets-tree (ctob/get-set-tree tokens-lib)
sets-tree' (ctob/get-set-tree tokens-lib')
group1' (get sets-tree' "group1")
token-set (get-in sets-tree ["group1" "token-set-2"])
token-set' (get-in sets-tree' ["group1" "token-set-2"])]
(t/is (= (ctob/set-count tokens-lib') 5))
(t/is (= (count group1') 3))
(t/is (= (d/index-of (keys group1') "token-set-2") 0))
(t/is (= (:name token-set') "group1/token-set-2"))
(t/is (= (:description token-set') "some description"))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
(t/deftest rename-set-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-2"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-3"))
(ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4"))
(ctob/add-set (ctob/make-token-set :name "group2/token-set-5")))
tokens-lib' (-> tokens-lib
(ctob/update-set "group1/token-set-2"
(fn [token-set]
(assoc token-set
:name "group1/updated-name"))))
sets-tree (ctob/get-set-tree tokens-lib)
sets-tree' (ctob/get-set-tree tokens-lib')
group1' (get sets-tree' "group1")
token-set (get-in sets-tree ["group1" "token-set-2"])
token-set' (get-in sets-tree' ["group1" "updated-name"])]
(t/is (= (ctob/set-count tokens-lib') 5))
(t/is (= (count group1') 3))
(t/is (= (d/index-of (keys group1') "updated-name") 0))
(t/is (= (:name token-set') "group1/updated-name"))
(t/is (= (:description token-set') nil))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
(t/deftest move-set-of-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-2"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-3"))
(ctob/add-set (ctob/make-token-set :name "group1/subgroup11/token-set-4"))
#_(ctob/add-set (ctob/make-token-set :name "group2/token-set-5")))
tokens-lib' (-> tokens-lib
(ctob/update-set "group1/token-set-2"
(fn [token-set]
(assoc token-set
:name "group2/updated-name"))))
sets-tree (ctob/get-set-tree tokens-lib)
sets-tree' (ctob/get-set-tree tokens-lib')
group1' (get sets-tree' "group1")
group2' (get sets-tree' "group2")
token-set (get-in sets-tree ["group1" "token-set-2"])
token-set' (get-in sets-tree' ["group2" "updated-name"])]
(t/is (= (ctob/set-count tokens-lib') 4))
(t/is (= (count group1') 2))
(t/is (= (count group2') 1))
(t/is (= (d/index-of (keys group2') "updated-name") 0))
(t/is (= (:name token-set') "group2/updated-name"))
(t/is (= (:description token-set') nil))
(t/is (dt/is-after? (:modified-at token-set') (:modified-at token-set)))))
(t/deftest delete-set-in-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :name "token-set-1"))
(ctob/add-set (ctob/make-token-set :name "group1/token-set-2")))
tokens-lib' (-> tokens-lib
(ctob/delete-set "group1/token-set-2"))
sets-tree' (ctob/get-set-tree tokens-lib')
token-set' (get-in sets-tree' ["group1" "token-set-2"])]
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (count sets-tree') 1))
(t/is (nil? token-set')))))
(t/testing "grouped themes"
(t/deftest grouped-themes
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-theme (ctob/make-token-theme :name "token-theme-1"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3"))
(ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4"))
(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5")))
themes-list (ctob/get-themes tokens-lib)
themes-tree (ctob/get-theme-tree tokens-lib)
[node-theme1 node-group1 node-group2]
(ctob/get-children themes-tree)
[node-theme2 node-theme3 node-subgroup11]
(ctob/get-children (second node-group1))
[node-theme4]
(ctob/get-children (second node-subgroup11))
[node-theme5]
(ctob/get-children (second node-group2))]
(t/is (= (count themes-list) 5))
(t/is (= (:name (nth themes-list 0)) "token-theme-1"))
(t/is (= (:name (nth themes-list 1)) "group1/token-theme-2"))
(t/is (= (:name (nth themes-list 2)) "group1/token-theme-3"))
(t/is (= (:name (nth themes-list 3)) "group1/subgroup11/token-theme-4"))
(t/is (= (:name (nth themes-list 4)) "group2/token-theme-5"))
(t/is (= (first node-theme1) "token-theme-1"))
(t/is (= (ctob/group? (second node-theme1)) false))
(t/is (= (:name (second node-theme1)) "token-theme-1"))
(t/is (= (first node-group1) "group1"))
(t/is (= (ctob/group? (second node-group1)) true))
(t/is (= (count (second node-group1)) 3))
(t/is (= (first node-theme2) "token-theme-2"))
(t/is (= (ctob/group? (second node-theme2)) false))
(t/is (= (:name (second node-theme2)) "group1/token-theme-2"))
(t/is (= (first node-theme3) "token-theme-3"))
(t/is (= (ctob/group? (second node-theme3)) false))
(t/is (= (:name (second node-theme3)) "group1/token-theme-3"))
(t/is (= (first node-subgroup11) "subgroup11"))
(t/is (= (ctob/group? (second node-subgroup11)) true))
(t/is (= (count (second node-subgroup11)) 1))
(t/is (= (first node-theme4) "token-theme-4"))
(t/is (= (ctob/group? (second node-theme4)) false))
(t/is (= (:name (second node-theme4)) "group1/subgroup11/token-theme-4"))
(t/is (= (first node-theme5) "token-theme-5"))
(t/is (= (ctob/group? (second node-theme5)) false))
(t/is (= (:name (second node-theme5)) "group2/token-theme-5"))))
(t/deftest update-theme-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-theme (ctob/make-token-theme :name "token-theme-1"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3"))
(ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4"))
(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5")))
tokens-lib' (-> tokens-lib
(ctob/update-theme "group1/token-theme-2"
(fn [token-theme]
(assoc token-theme :description "some description"))))
themes-tree (ctob/get-theme-tree tokens-lib)
themes-tree' (ctob/get-theme-tree tokens-lib')
group1' (get themes-tree' "group1")
token-theme (get-in themes-tree ["group1" "token-theme-2"])
token-theme' (get-in themes-tree' ["group1" "token-theme-2"])]
(t/is (= (ctob/theme-count tokens-lib') 5))
(t/is (= (count group1') 3))
(t/is (= (d/index-of (keys group1') "token-theme-2") 0))
(t/is (= (:name token-theme') "group1/token-theme-2"))
(t/is (= (:description token-theme') "some description"))
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
(t/deftest rename-theme-in-groups
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-theme (ctob/make-token-theme :name "token-theme-1"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3"))
(ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4"))
(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5")))
tokens-lib' (-> tokens-lib
(ctob/update-theme "group1/token-theme-2"
(fn [token-theme]
(assoc token-theme
:name "group1/updated-name"))))
themes-tree (ctob/get-theme-tree tokens-lib)
themes-tree' (ctob/get-theme-tree tokens-lib')
group1' (get themes-tree' "group1")
token-theme (get-in themes-tree ["group1" "token-theme-2"])
token-theme' (get-in themes-tree' ["group1" "updated-name"])]
(t/is (= (ctob/theme-count tokens-lib') 5))
(t/is (= (count group1') 3))
(t/is (= (d/index-of (keys group1') "updated-name") 0))
(t/is (= (:name token-theme') "group1/updated-name"))
(t/is (= (:description token-theme') nil))
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
(t/deftest move-theme-of-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-theme (ctob/make-token-theme :name "token-theme-1"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-3"))
(ctob/add-theme (ctob/make-token-theme :name "group1/subgroup11/token-theme-4"))
#_(ctob/add-theme (ctob/make-token-theme :name "group2/token-theme-5")))
tokens-lib' (-> tokens-lib
(ctob/update-theme "group1/token-theme-2"
(fn [token-theme]
(assoc token-theme
:name "group2/updated-name"))))
themes-tree (ctob/get-theme-tree tokens-lib)
themes-tree' (ctob/get-theme-tree tokens-lib')
group1' (get themes-tree' "group1")
group2' (get themes-tree' "group2")
token-theme (get-in themes-tree ["group1" "token-theme-2"])
token-theme' (get-in themes-tree' ["group2" "updated-name"])]
(t/is (= (ctob/theme-count tokens-lib') 4))
(t/is (= (count group1') 2))
(t/is (= (count group2') 1))
(t/is (= (d/index-of (keys group2') "updated-name") 0))
(t/is (= (:name token-theme') "group2/updated-name"))
(t/is (= (:description token-theme') nil))
(t/is (dt/is-after? (:modified-at token-theme') (:modified-at token-theme)))))
(t/deftest delete-theme-in-group
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-theme (ctob/make-token-theme :name "token-theme-1"))
(ctob/add-theme (ctob/make-token-theme :name "group1/token-theme-2")))
tokens-lib' (-> tokens-lib
(ctob/delete-theme "group1/token-theme-2"))
themes-tree' (ctob/get-theme-tree tokens-lib')
token-theme' (get-in themes-tree' ["group1" "token-theme-2"])]
(t/is (= (ctob/theme-count tokens-lib') 1))
(t/is (= (count themes-tree') 1))
(t/is (nil? token-theme'))))))