This commit is contained in:
Andrés Moya
2026-03-18 17:44:56 +01:00
parent 81375e20ba
commit de9aef04c9
4 changed files with 202 additions and 28 deletions

View File

@@ -6,8 +6,26 @@
(ns app.common.files.comp-processors
(:require
[app.common.types.component :as ctk]
[app.common.types.file :as ctf]))
(defn fix-missing-swap-slots
[file]
file)
(defn fix-missing-swap-slots
[file libraries]
(ctf/update-all-shapes
file
(fn [shape]
(if (and (ctk/instance-head? shape) (ctk/in-component-copy? shape))
(let [{:keys [container]}
(meta shape)
ref-shape
(ctf/find-ref-shape file container libraries shape :include-deleted? true :with-context? true)]
(println "comparing" (:name shape) "with ref" (some-> ref-shape :name))
(if ref-shape
(if (and (not= (:shape-ref shape) (:id ref-shape))
(nil? (ctk/get-swap-slot shape)))
(let [updated-shape (ctk/set-swap-slot shape (:id ref-shape))]
{:result :update :updated-shape updated-shape})
{:result :keep})
{:result :keep}))
{:result :keep}))))

View File

@@ -16,6 +16,7 @@
[app.common.types.components-list :as ctkl]
[app.common.types.pages-list :as ctpl]
[app.common.types.plugins :refer [schema:plugin-data]]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
[app.common.types.text :as cttx]
@@ -55,6 +56,10 @@
[page-or-component type]
(assoc page-or-component :type type))
(defn unmake-container
[container]
(dissoc container :type))
(defn page?
[container]
(= (:type container) :page))

View File

@@ -225,6 +225,86 @@
(ctpl/update-page file-data (:id container) f)
(ctkl/update-component file-data (:id container) f)))
(defn update-pages
"Update all pages inside the file"
[file-data f]
(update file-data :pages-index d/update-vals
(fn [page]
(-> page
(ctn/make-container :page)
(f)
(ctn/unmake-container)))))
(defn update-components
"Update all components inside the file"
[file-data f]
(d/update-when file-data :components d/update-vals
(fn [component]
(-> component
(ctn/make-container :component)
(f)
(ctn/unmake-container)))))
(defn update-containers
"Update all pages and components inside the file"
[file-data f]
(-> file-data
(update-pages f)
(update-components f)))
(defn update-objects-tree
"Do a depth-first traversal of the shapes in a container, doing different kinds of updates.
The function f receives a shape with a context metadata with the container.
It must return a map with the following keys:
- :result -> :keep, :update or :remove
- :updated-shape -> the updated shape if result is :update"
[container f]
(letfn [(update-shape-recursive
[container shape-id]
(let [shape (ctst/get-shape container shape-id)]
(when (not shape)
(throw (ex-info "Shape not found" {:shape-id shape-id})))
(let [shape (with-meta shape {:container container})
{:keys [result updated-shape]} (f shape)
container'
(case result
:keep
container
:update
(ctst/set-shape container updated-shape)
:remove
(ctst/delete-shape container shape-id true)
:else
(throw (ex-info "Invalid result from update function" {:result result})))]
(reduce update-shape-recursive
container'
(:shapes shape)))))]
(let [root-id (if (ctn/page? container)
uuid/zero
(:main-instance-id container))]
(if (:objects container)
(update-shape-recursive container root-id)
container))))
(defn update-all-shapes
"Update all shapes in the file, using the update-objects-tree function for each container"
[file f]
(update-file-data
file
(fn [file-data]
(update-containers
file-data
(fn [container]
(update-objects-tree container f))))))
;; Asset helpers
(defn find-component-file
[file libraries component-file]

View File

@@ -6,47 +6,118 @@
(ns common-tests.files.comp-processors-test
(:require
[app.common.files.comp-processors :as cfcp]
;; [app.common.test-helpers.components :as thc]
[app.common.data :as d]
[app.common.files.comp-processors :as cfcp]
[app.common.test-helpers.components :as thc]
[app.common.test-helpers.compositions :as tho]
[app.common.test-helpers.files :as thf]
;; [app.common.test-helpers.ids-map :as thi]
;; [app.common.test-helpers.shapes :as ths]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.shapes :as ths]
[app.common.types.component :as ctk]
[clojure.test :as t]))
(t/deftest test-fix-missing-swap-slots
(t/testing "empty file should not need any action"
(let [file (thf/sample-file :file1)]
(t/is (= file (cfcp/fix-missing-swap-slots file)))))
(let [file (thf/sample-file :file1)
file' (cfcp/fix-missing-swap-slots file {})]
(t/is (empty? (d/map-diff file file')))))
(t/testing "file without components should not need any action"
(let [file
;; :frame1 [:name Frame1]
;; :child1 [:name Rect1]
(-> (thf/sample-file :file1)
(tho/add-frame-with-child :frame1 :shape1))]
(tho/add-frame-with-child :frame1 :shape1))
(t/is (= file (cfcp/fix-missing-swap-slots file)))))
(t/testing "file with not swapped components should not need any action"
file' (cfcp/fix-missing-swap-slots file {})]
(t/is (empty? (d/map-diff file file')))))
(t/testing "file with nested not swapped components should not need any action"
(let [file
;; {:main1-root} [:name Frame1] # [Component :component1]
;; :main1-child [:name Rect1]
;;
;; {:main2-root} [:name Frame2] # [Component :component2]
;; :nested-head [:name Frame1] @--> [Component :component1] :main1-root
;; <no-label> [:name Rect1] ---> :main1-child
;;
;; :copy2 [:name Frame2] #--> [Component :component2] :main2-root
;; <no-label> [:name Frame1] @--> [Component :component1] :nested-head
;; <no-label> [:name Rect1] ---> <no-label>
;; {:main1-root} [:name Frame1] # [Component :component1]
;; :main1-child [:name Rect1]
;;
;; {:main2-root} [:name Frame2] # [Component :component2]
;; :nested-head [:name Frame1] @--> [Component :component1] :main1-root
;; <no-label> [:name Rect1] ---> :main1-child
;;
;; :copy2 [:name Frame2] #--> [Component :component2] :main2-root
;; <no-label> [:name Frame1] @--> [Component :component1] :nested-head
;; <no-label> [:name Rect1] ---> <no-label>
(-> (thf/sample-file :file1)
(tho/add-nested-component-with-copy :component1 :main1-root :main1-child
:component2 :main2-root :nested-head
:copy2 :copy2-root))]
:copy2 :copy2-root))
(t/is (= file (cfcp/fix-missing-swap-slots file)))))
)
file' (cfcp/fix-missing-swap-slots file {})]
(t/is (empty? (d/map-diff file file')))))
(t/testing "file with a normally swapped copy should not need any action"
(let [file
;; {:main1-root} [:name Frame1] # [Component :component1]
;; :main1-child [:name Rect1]
;;
;; {:main2-root} [:name Frame2] # [Component :component2]
;; :nested-head [:name Frame1] @--> [Component :component1] :main1-root
;; <no-label> [:name Rect1] ---> :main1-child
;;
;; {:main3-root} [:name Frame3] # [Component :component3]
;; :main3-child [:name Rect3]
;;
;; :copy2 [:name Frame2] #--> [Component :component2] :main2-root
;; :copy2-nested-head [:name Frame3] @--> [Component :component3] :main3-root
;; {swap-slot :nested-head}
;; <no-label> [:name Rect3] ---> :main3-child
(-> (thf/sample-file :file1)
(tho/add-nested-component :component1 :main1-root :main1-child
:component2 :main2-root :nested-head)
(thc/instantiate-component :component2 :copy2 :children-labels [:copy2-nested-head])
(tho/add-simple-component :component3 :main3-root :main3-child
:root-params {:name "Frame3"}
:child-params {:name "Rect3"})
(tho/swap-component-in-first-child :copy2 :component3))
file' (cfcp/fix-missing-swap-slots file {})]
(t/is (empty? (d/map-diff file file')))))
(t/testing "file with a swapped copy with broken slot should have it repaired"
(println "==start test==================================================")
(let [file
;; {:main1-root} [:name Frame1] # [Component :component1]
;; :main1-child [:name Rect1]
;;
;; {:main2-root} [:name Frame2] # [Component :component2]
;; :nested-head [:name Frame1] @--> [Component :component1] :main1-root
;; <no-label> [:name Rect1] ---> :main1-child
;;
;; {:main3-root} [:name Frame3] # [Component :component3]
;; :main3-child [:name Rect3]
;;
;; :copy2 [:name Frame2] #--> [Component :component2] :main2-root
;; :copy2-nested-head [:name Frame3] @--> [Component :component3] :main3-root
;; NO SWAP SLOT
;; <no-label> [:name Rect3] ---> :main3-child
(-> (thf/sample-file :file1)
(tho/add-nested-component :component1 :main1-root :main1-child
:component2 :main2-root :nested-head)
(thc/instantiate-component :component2 :copy2 :children-labels [:copy2-nested-head])
(tho/add-simple-component :component3 :main3-root :main3-child
:root-params {:name "Frame3"}
:child-params {:name "Rect3"})
(tho/swap-component-in-first-child :copy2 :component3)
(ths/update-shape :copy2-nested-head :touched nil))
file' (cfcp/fix-missing-swap-slots file {})
diff (d/map-diff file file')
copy2-nested-head' (ths/get-shape file' :copy2-nested-head)]
(thf/dump-file file :keys [:name :swap-slot-label] :show-refs? true)
(println "====================================================")
(prn "diff" diff)
(t/is (= (ctk/get-swap-slot copy2-nested-head') (thi/id :nested-head))))))