From 79851eef0e842fbd46c7a5328bbd6851ec3c0f54 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Tue, 29 Sep 2026 14:31:12 +0200 Subject: [PATCH] :wrench: Fix false validation errors on nested instances and swaps generate-instantiate-component validated the new instance on its own. When the parent is inside another component, the new instance is a nested copy. The validator starts with a :not-component context, so it reported :nested-copy-not-allowed. Validate the root of the enclosing component instead, which walks the new copy with the right context. During a component swap, generate-new-shape-for-swap sets the swap slot after the instance is created. Validating at instantiation time then reported :missing-slot. Add a :skip-validation? option to generate-instantiate-component. The swap sets it and validates the enclosing root once the swap slot is in place. These false errors broke 34 common tests on JS. AI-assisted-by: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 --- common/src/app/common/logic/libraries.cljc | 31 +++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index aca26744e5..ae683dd2ce 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -241,8 +241,8 @@ ([changes objects file-id component-id position page libraries old-id parent-id frame-id params] (generate-instantiate-component changes objects file-id component-id position page libraries old-id parent-id frame-id {} params)) ([changes objects file-id component-id position page libraries old-id parent-id frame-id ids-map - {:keys [force-frame?] - :or {force-frame? false}}] + {:keys [force-frame? skip-validation?] + :or {force-frame? false skip-validation? false}}] (let [component (ctf/get-component libraries file-id component-id) library (get libraries file-id) @@ -317,12 +317,17 @@ (reduce #(pcb/add-object %1 %2 {:ignore-touched true}) changes (rest new-shapes)) - - ids-to-validate (cond-> [(:id first-shape)] - grid-parent? - (conj (:parent-id first-shape))) - changes (if (seq ids-to-validate) + ;; A copy nested inside another component can't be validated on + ;; its own, as the validator needs the context of its ancestors. + ;; Validate the root of the enclosing component instead. + ids-to-validate (if (ctk/instance-root? first-shape) + (cond-> [(:id first-shape)] + grid-parent? + (conj (:parent-id first-shape))) + (ctn/get-all-instance-roots objects [(:parent-id first-shape)])) + + changes (if (and (not skip-validation?) (seq ids-to-validate)) (pcb/validate-shapes changes (:id page) ids-to-validate @@ -2721,7 +2726,9 @@ (:parent-id shape) (:frame-id shape) {(:id shape) (:id shape)} ;; keep the id of the original shape - {:force-frame? true}) + ;; The swap slot is set below, so validate at the end + {:force-frame? true + :skip-validation? true}) new-shape (cond-> new-shape ;; if the shape isn't inside a main component, it shouldn't have a swap slot @@ -2743,7 +2750,13 @@ (change-touched new-shape shape (ctn/make-container page :page) - {}))])) + {}) + ;; The new shape keeps the id of the old one, so this finds the + ;; new shape itself or the root of the component that holds it + (pcb/validate-shapes (:id page) + (ctn/get-all-instance-roots objects [(:id shape)]) + (str "generate-new-shape-for-swap: " (:id shape) + " to component " id-new-component)))])) (defn generate-component-swap [changes objects shape file page libraries id-new-component