From c8f46408bcbdf3ad8f78d1d242ccc04229b7c32f Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 7 May 2026 11:20:54 +0200 Subject: [PATCH] WIP --- common/src/app/common/files/migrations.cljc | 9 +- common/src/app/common/fressian.clj | 40 +++++-- common/src/app/common/geom/rect.cljc | 2 +- common/src/app/common/types/shape.cljc | 3 +- common/src/app/common/types/tokens_lib.cljc | 124 +++++++++++++------- 5 files changed, 124 insertions(+), 54 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index eeb11e9067..b717f194a4 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1805,6 +1805,12 @@ {})] (cfcp/sync-component-id-with-ref-shape data libraries))) + +(defmethod migrate-data "0021-dummy" + [data _] + data) + + (def available-migrations (into (d/ordered-set) ["legacy-2" @@ -1882,4 +1888,5 @@ "0017-fix-layout-flex-dir" "0018-remove-unneeded-objects-from-components" "0019-fix-missing-swap-slots" - "0020-sync-component-id-with-near-main"])) + "0020-sync-component-id-with-near-main" + "0021-dummy")) diff --git a/common/src/app/common/fressian.clj b/common/src/app/common/fressian.clj index f005df743b..c03e423648 100644 --- a/common/src/app/common/fressian.clj +++ b/common/src/app/common/fressian.clj @@ -12,6 +12,7 @@ clojure.lang.Ratio java.io.ByteArrayInputStream java.io.ByteArrayOutputStream + java.lang.reflect.Method java.time.Instant java.time.OffsetDateTime java.util.List @@ -125,11 +126,33 @@ (write [_ w o] (wfn name w o)))}]) + +(defn- get-max-arity + [^Object f] + (let [^Class cls (.getClass f) + methods (.getDeclaredMethods cls)] + (->> methods + (filter #(= "invoke" (.getName ^Method %))) + (map #(.getParameterCount ^Method %)) + (map long) + (reduce max 0)))) + (defn- adapt-read-handler [{:keys [name rfn]}] - [name (reify ReadHandler - (read [_ rdr _ _] - (rfn rdr)))]) + (let [arity (get-max-arity rfn)] + (case (long arity) + 3 + (do + [name (reify ReadHandler + (read [_ rdr tag n] + (prn "AAAAAAAA" tag rfn) + (rfn rdr tag n)))]) + + + 1 + [name (reify ReadHandler + (read [_ rdr _ _] + (rfn rdr)))]))) (defn- merge-handlers [m1 m2] @@ -294,12 +317,14 @@ {:name "clj/set" :class clojure.lang.IPersistentSet :wfn write-list-like - :rfn (comp set read-object!)} + :rfn (fn [r] + (-> r read-object! set))} {:name "clj/vector" :class clojure.lang.IPersistentVector :wfn write-list-like - :rfn (comp vec read-object!)} + :rfn (fn [r] + (-> r read-object! vec))} {:name "clj/list" ;; :class clojure.lang.IPersistentList @@ -309,12 +334,13 @@ {:name "clj/seq" :class clojure.lang.ISeq :wfn write-list-like - :rfn (comp sequence read-object!)} + :rfn (fn [r] (-> r read-object! sequence))} {:name "linked/set" :class LinkedSet :wfn write-list-like - :rfn (comp #(into (d/ordered-set) %) read-object!)}) + :rfn (fn [r] + (->> r read-object! (into (d/ordered-set))))}) ;; --- PUBLIC API diff --git a/common/src/app/common/geom/rect.cljc b/common/src/app/common/geom/rect.cljc index f53024ca02..7e79b4157c 100644 --- a/common/src/app/common/geom/rect.cljc +++ b/common/src/app/common/geom/rect.cljc @@ -27,7 +27,7 @@ {:name "penpot/geom/rect" :class Rect :wfn fres/write-map-like - :rfn (comp map->Rect fres/read-map-like)})) + :rfn (fn [r] (-> r fres/read-map-like map->Rect))})) (t/add-handlers! {:id "rect" diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 5f6ac22ad3..2b537ecbcf 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -639,7 +639,8 @@ {:name "penpot/shape" :class Shape :wfn fres/write-map-like - :rfn (comp map->Shape fres/read-map-like)})) + :rfn (fn [r] + (-> r fres/read-map-like map->Shape))})) ;; --- SHAPE COPY/PASTE PROPS diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 177e12ff54..2674bf5a7f 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -947,13 +947,25 @@ Will return a value that matches this schema: (declare read-multi-set-dtcg) (declare export-dtcg-json) -(deftype TokensLib [sets themes active-themes] +(deftype TokensLib [sets themes active-themes metadata] ;; This is to convert the TokensLib to a plain map, for debugging or unit tests. cp/Datafiable (datafy [_] {:sets sets :themes themes - :active-themes active-themes}) + :active-themes active-themes + :metadata metadata}) + + #?@(:cljs + [cljs.core/IWithMeta + (-with-meta [_o meta] (TokensLib. sets themes active-themes meta)) + cljs.core/IMeta + (-meta [_o] metadata)] + + :clj + [clojure.lang.IObj + (withMeta [_o meta] (TokensLib. sets themes active-themes meta)) + (meta [_o] metadata)]) #?@(:clj [c.json/JSONWriter @@ -978,7 +990,8 @@ Will return a value that matches this schema: (let [path (get-set-prefixed-path token-set)] (TokensLib. (d/oassoc-in sets path token-set) themes - active-themes))) + active-themes + metadata))) (update-set [this id f] (assert (uuid? id) "expected uuid for `id`") @@ -992,7 +1005,8 @@ Will return a value that matches this schema: (if (= name name') (TokensLib. (d/oassoc-in sets prefixed-full-path set') themes - active-themes) + active-themes + metadata) (TokensLib. (-> sets (d/oassoc-in-before prefixed-full-path prefixed-full-path' set') (d/dissoc-in prefixed-full-path)) @@ -1002,7 +1016,8 @@ Will return a value that matches this schema: (update-set-name form name name') form)) themes) - active-themes))) + active-themes + metadata))) this))) (delete-set [this id] @@ -1017,7 +1032,8 @@ Will return a value that matches this schema: (disable-set form set-name) form)) themes) - active-themes))) + active-themes + metadata))) (move-set [_ from-path to-path before-path before-group?] (let [prefixed-from-path (set-full-path->set-prefixed-full-path from-path) @@ -1059,8 +1075,9 @@ Will return a value that matches this schema: (update-set-name form (get-name prev-set) (get-name set)) form)) themes)) - active-themes)) - (TokensLib. sets themes active-themes)))) + active-themes + metadata)) + (TokensLib. sets themes active-themes metadata)))) (move-set-group [this from-path to-path before-path before-group?] (let [prefixed-from-path (set-group-path->set-group-prefixed-path from-path) @@ -1104,10 +1121,8 @@ Will return a value that matches this schema: (update form :sets #(set (replace rename-sets-map %))) form)) themes)))] - (TokensLib. sets' - themes' - active-themes)) - (TokensLib. sets themes active-themes)))) + (TokensLib. sets' themes' active-themes metadata)) + (TokensLib. sets themes active-themes metadata)))) (get-set-tree [_] sets) @@ -1154,7 +1169,8 @@ Will return a value that matches this schema: (let [token-theme (check-token-theme token-theme)] (TokensLib. sets (update themes (:group token-theme) d/oassoc (:name token-theme) token-theme) - active-themes))) + active-themes + metadata))) (update-theme [this id f] (if-let [theme (get-theme this id)] @@ -1177,7 +1193,8 @@ Will return a value that matches this schema: (d/dissoc-in [group name]))) (if same-path? active-themes - (disj active-themes (join-theme-path group name))))))) + (disj active-themes (join-theme-path group name))) + metadata)))) this)) (delete-theme [this id] @@ -1186,7 +1203,8 @@ Will return a value that matches this schema: (if theme (TokensLib. sets (d/dissoc-in themes [group name]) - (disj active-themes (join-theme-path group name))) + (disj active-themes (join-theme-path group name)) + metadata) this))) (get-theme-tree [_] @@ -1215,7 +1233,8 @@ Will return a value that matches this schema: (set-active-themes [_ active-themes] (TokensLib. sets themes - active-themes)) + active-themes + metadata)) (activate-theme [this id] (if-let [theme (get-theme this id)] @@ -1227,14 +1246,16 @@ Will return a value that matches this schema: (conj (get-theme-path theme)))] (TokensLib. sets themes - active-themes')) + active-themes' + metadata)) this)) (deactivate-theme [this id] (if-let [theme (get-theme this id)] (TokensLib. sets themes - (disj active-themes (get-theme-path theme))) + (disj active-themes (get-theme-path theme)) + metadata) this)) (theme-active? [this id] @@ -1297,7 +1318,8 @@ Will return a value that matches this schema: (TokensLib. sets (d/oupdate-in themes [(:group theme) (:name theme)] #(toggle-set % set-name)) - active-themes) + active-themes + metadata) this)) (get-active-themes-set-names [this] @@ -1438,8 +1460,8 @@ Will return a value that matches this schema: "Make a new instance of TokensLib from a map, but skiping all validation; it is used for create new instances from trusted sources" - [& {:keys [sets themes active-themes]}] - (TokensLib. sets themes active-themes)) + [& {:keys [sets themes active-themes metadata]}] + (TokensLib. sets themes active-themes metadata)) (defn make-tokens-lib "Make a new instance of TokensLib from a map and validates the input" @@ -1552,7 +1574,7 @@ Will return a value that matches this schema: current-path: the path of the group being renamed, e.g. \"foo.bar\" current-name: the current name of the group being renamed, e.g. \"bar\" new-name: the new name for the group being renamed, e.g. \"baz\" - + Returns a sequence of [name token] for each renamed token." [active-tokens current-path current-name new-name] @@ -2413,36 +2435,53 @@ Will return a value that matches this schema: (fix-conflicting-token-names) (fix-missing-sets-in-themes))))) -#?(:clj - (defn- read-tokens-lib-v1-4 - "Reads the tokens lib data structure and fix conflicting token names." - [r] - (let [sets (fres/read-object! r) - themes (fres/read-object! r) - active-themes (fres/read-object! r)] +;; #?(:clj +;; (defn- read-tokens-lib-v1-4 +;; "Reads the tokens lib data structure and fix conflicting token names." +;; [r] +;; (let [sets (fres/read-object! r) +;; themes (fres/read-object! r) +;; active-themes (fres/read-object! r)] - (-> {:sets sets - :themes themes - :active-themes active-themes} - (map->tokens-lib) - (fix-conflicting-token-names) - (fix-missing-sets-in-themes))))) +;; (-> {:sets sets +;; :themes themes +;; :active-themes active-themes} +;; (map->tokens-lib) +;; (fix-conflicting-token-names) +;; (fix-missing-sets-in-themes))))) #?(:clj (defn- write-tokens-lib [n w ^TokensLib o] - (fres/write-tag! w n 3) + (fres/write-tag! w n 4) (fres/write-object! w (.-sets o)) (fres/write-object! w (.-themes o)) - (fres/write-object! w (.-active-themes o)))) + (fres/write-object! w (.-active-themes o)) + (fres/write-object! w (.-metadata o)))) + +#?(:clj + (defn- apply-internal-migration + "A helper for conditionally apply internal migrations to the tokens + data structure." + [instance migration-name migration-fn] + (let [migrations (-> instance meta :migrations)] + (if (contains? migrations migration-name) + instance + (-> instance + (migration-fn) + (vary-meta update :migrations (fnil conj #{}) migration-name)))))) #?(:clj (defn- read-tokens-lib - [r] + [r _ n] (let [sets (fres/read-object! r) themes (fres/read-object! r) - active-themes (fres/read-object! r)] - (->TokensLib sets themes active-themes)))) + active-themes (fres/read-object! r) + metadata (when (= n 4) + (fres/read-object! r))] + (-> (->TokensLib sets themes active-themes metadata) + (apply-internal-migration "conflicting-token-names" fix-conflicting-token-names) + (apply-internal-migration "fix-missing-sets-in-themes" fix-missing-sets-in-themes))))) #?(:clj (fres/add-handlers! @@ -2487,11 +2526,8 @@ Will return a value that matches this schema: {:name "penpot/tokens-lib/v1.3" :rfn read-tokens-lib-v1-3} - {:name "penpot/tokens-lib/v1.4" - :rfn read-tokens-lib-v1-4} - ;; CURRENT TOKENS LIB READER & WRITTER - {:name "penpot/tokens-lib/v1.5" + {:name "penpot/tokens-lib/v1.4" :class TokensLib :wfn write-tokens-lib :rfn read-tokens-lib}))