diff --git a/common/src/app/common/files/repair.cljc b/common/src/app/common/files/repair.cljc index 9e9fc29d4b..67f90dafeb 100644 --- a/common/src/app/common/files/repair.cljc +++ b/common/src/app/common/files/repair.cljc @@ -496,6 +496,36 @@ (pcb/with-file-data file-data) (pcb/update-shapes (map :id child-with-duplicate) repair-shape)))) + + +(defmethod repair-error :component-duplicate-slot + [_ {:keys [shape] :as error} file-data _] + (let [main-shape (get-in shape [:objects (:main-instance-id shape)]) + childs (map #(get (:objects shape) %) (:shapes main-shape)) + childs-with-duplicate (let [result (reduce (fn [[seen duplicates] item] + (let [swap-slot (ctk/get-swap-slot item)] + (if (contains? seen swap-slot) + [seen (conj duplicates item)] + [(conj seen swap-slot) duplicates]))) + [#{} []] + childs)] + (second result)) + duplicated-ids (set (mapv :id childs-with-duplicate)) + repair-component + (fn [component] + (let [objects (reduce-kv (fn [acc k v] + (if (contains? duplicated-ids k) + (assoc acc k (ctk/remove-swap-slot v)) + (assoc acc k v))) + {} + (:objects component))] + (assoc component :objects objects)))] + + (log/dbg :hint "repairing component :component-duplicated-slot" :id (:id shape) :name (:name shape)) + (-> (pcb/empty-changes nil) + (pcb/with-library-data file-data) + (pcb/update-component (:id shape) repair-component)))) + (defmethod repair-error :missing-slot [_ {:keys [shape page-id args] :as error} file-data _] (let [repair-shape diff --git a/common/src/app/common/files/validate.cljc b/common/src/app/common/files/validate.cljc index cd4f3b43ae..5eb708ab34 100644 --- a/common/src/app/common/files/validate.cljc +++ b/common/src/app/common/files/validate.cljc @@ -31,6 +31,7 @@ :child-not-found :frame-not-found :invalid-frame + :component-duplicate-slot :component-not-main :component-main-external :component-not-found @@ -65,7 +66,7 @@ [:shape {:optional true} :map] ; Cannot validate a shape because here it may be broken [:shape-id {:optional true} ::sm/uuid] [:file-id ::sm/uuid] - [:page-id ::sm/uuid]])) + [:page-id {:optional true} [:maybe ::sm/uuid]]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ERROR HANDLING @@ -297,17 +298,21 @@ "This shape should not have swap slot" shape file page))) -(defn- check-duplicate-swap-slot - "Validate that the children of this shape does not have duplicated slots." - [shape file page] - (let [shapes (map #(get (:objects page) %) (:shapes shape)) +(defn- has-duplicate-swap-slot? + [shape container] + (let [shapes (map #(get (:objects container) %) (:shapes shape)) slots (->> (map #(ctk/get-swap-slot %) shapes) (remove nil?)) counts (frequencies slots)] - (when (some (fn [[_ count]] (> count 1)) counts) - (report-error :duplicate-slot - "This shape has children with the same swap slot" - shape file page)))) + (some (fn [[_ count]] (> count 1)) counts))) + +(defn- check-duplicate-swap-slot + "Validate that the children of this shape does not have duplicated slots." + [shape file page] + (when (has-duplicate-swap-slot? shape page) + (report-error :duplicate-slot + "This shape has children with the same swap slot" + shape file page))) (defn- check-shape-main-root-top "Root shape of a top main instance: @@ -468,13 +473,24 @@ shape file page) (check-shape-not-component shape file page libraries)))))))) +(defn check-component-duplicate-swap-slot + [component file] + (let [shape (get-in component [:objects (:main-instance-id component)])] + (when (has-duplicate-swap-slot? shape component) + (report-error :component-duplicate-slot + "This deleted component has children with the same swap slot" + component file nil)))) + + (defn- check-component "Validate semantic coherence of a component. Report all errors found." [component file] (when (and (contains? component :objects) (nil? (:objects component))) (report-error :component-nil-objects-not-allowed "Objects list cannot be nil" - component file nil))) + component file nil)) + (when (:deleted component) + (check-component-duplicate-swap-slot component file))) (defn- get-orphan-shapes [{:keys [objects] :as page}]