From 813c804d4573e46bf2922b16e10dcef809b0d348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 16 Feb 2026 11:18:55 +0100 Subject: [PATCH] :wrench: Enhance schema validation of token application --- frontend/src/app/plugins/shape.cljs | 27 ++++++++++++++++---------- frontend/src/app/plugins/tokens.cljs | 23 +++++++++++----------- frontend/src/app/plugins/utils.cljs | 29 ++++++++++++---------------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 3f8d655a5b..014736e4d8 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -175,6 +175,10 @@ (defn shape-proxy? [p] (obj/type-of? p "ShapeProxy")) +;; Cannot use token/token-proxy? here because of circular dependency in applyToShapes in token proxy +(defn token-proxy? [t] + (obj/type-of? t "TokenProxy")) + (defn shape-proxy ([plugin-id id] (shape-proxy plugin-id (:current-file-id @st/state) (:current-page-id @st/state) id)) @@ -1301,16 +1305,19 @@ tokens)))} :applyToken - (fn [token attrs] - (let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id")) - kw-attrs (into #{} (map keyword attrs))] - (if (some #(not (cto/token-attr? %)) kw-attrs) - (u/display-not-valid :applyToken attrs) - (st/emit! - (dwta/toggle-token {:token token - :attrs kw-attrs - :shape-ids [id] - :expand-with-children false}))))) + {:schema [:tuple + [:fn token-proxy?] + [:maybe [:set [:and ::sm/keyword [:fn cto/token-attr?]]]]] + :fn (fn [token attrs] + (let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id")) + kw-attrs (into #{} (map keyword attrs))] + (if (some #(not (cto/token-attr? %)) kw-attrs) + (u/display-not-valid :applyToken attrs) + (st/emit! + (dwta/toggle-token {:token token + :attrs kw-attrs + :shape-ids [id] + :expand-with-children false})))))} :isVariantHead (fn [] diff --git a/frontend/src/app/plugins/tokens.cljs b/frontend/src/app/plugins/tokens.cljs index f46722884a..99eb45b093 100644 --- a/frontend/src/app/plugins/tokens.cljs +++ b/frontend/src/app/plugins/tokens.cljs @@ -16,7 +16,6 @@ [app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.store :as st] - ;; [app.plugins.shape :as shape] [app.plugins.utils :as u] [app.util.object :as obj] [beicon.v2.core :as rx] @@ -38,10 +37,14 @@ (defn token-proxy? [p] (obj/type-of? p "TokenProxy")) +;; Cannot use shape/shape-proxy? here because of circular dependency in applyToken in shape proxy +(defn shape-proxy? [s] + (obj/type-of? s "ShapeProxy")) + (defn token-proxy [plugin-id file-id set-id id] (obj/reify {:name "TokenProxy" - :wrap u/wrap-errors} + :on-error u/handle-error} :$plugin {:enumerable false :get (constantly plugin-id)} :$file-id {:enumerable false :get (constantly file-id)} :$set-id {:enumerable false :get (constantly set-id)} @@ -113,14 +116,10 @@ :applyToShapes {:schema [:tuple - ;; FIXME: the schema decoder is interpreting the array of shape-proxys and converting - ;; them to plain maps. For now we adapt the schema to accept it, but the decoder - ;; should be fixed to keep the original proxy objects coming from the plugin. - ;; [:vector [:fn shape/shape-proxy?]] - [:vector [:map [:id ::sm/uuid]]] - [:maybe [:set [:set [:and ::sm/keyword [:fn cto/token-attr?]]]]]] + [:vector [:fn shape-proxy?]] + [:maybe [:set [:and ::sm/keyword [:fn cto/token-attr?]]]]] :fn (fn [shapes attrs] - (apply-token-to-shapes file-id set-id id (map :id shapes) attrs))} + (apply-token-to-shapes file-id set-id id (map #(obj/get % "$id") shapes) attrs))} :applyToSelected {:schema [:tuple [:maybe [:set [:and ::sm/keyword [:fn cto/token-attr?]]]]] @@ -136,7 +135,7 @@ (defn token-set-proxy [plugin-id file-id id] (obj/reify {:name "TokenSetProxy" - :wrap u/wrap-errors} + :on-error u/handle-error} :$plugin {:enumerable false :get (constantly plugin-id)} :$file-id {:enumerable false :get (constantly file-id)} :$id {:enumerable false :get (constantly id)} @@ -257,7 +256,7 @@ (defn token-theme-proxy [plugin-id file-id id] (obj/reify {:name "TokenThemeProxy" - :wrap u/wrap-errors} + :on-error u/handle-error} :$plugin {:enumerable false :get (constantly plugin-id)} :$file-id {:enumerable false :get (constantly file-id)} :$id {:enumerable false :get (constantly id)} @@ -352,7 +351,7 @@ (defn tokens-catalog [plugin-id file-id] (obj/reify {:name "TokensCatalog" - :wrap u/wrap-errors} + :on-error u/handle-error} :$plugin {:enumerable false :get (constantly plugin-id)} :$id {:enumerable false :get (constantly file-id)} diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index 8df47b2995..dfb8242a12 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -223,7 +223,9 @@ (defn display-not-valid [code value] - (.error js/console (dm/str "[PENPOT PLUGIN] Value not valid: " value ". Code: " code)) + (if (some? value) + (.error js/console (dm/str "[PENPOT PLUGIN] Value not valid: " value ". Code: " code)) + (.error js/console (dm/str "[PENPOT PLUGIN] Value not valid. Code: " code))) nil) (defn reject-not-valid @@ -248,19 +250,12 @@ (let [s (set values)] (if (= (count s) 1) (first s) "mixed"))) -(defn wrap-errors - "Function wrapper to be used in plugin proxies methods to handle errors. - When an exception is thrown, a readable error message is output to the console - and the exception is captured." - [f] - (fn [] - (let [args (js-arguments)] - (try - (.apply f nil args) - (catch :default cause - (display-not-valid (ex-message cause) (obj/stringify args)) - (if-let [explain (-> cause ex-data ::sm/explain)] - (println (sm/humanize-explain explain)) - (js/console.log (ex-data cause))) - (js/console.log (.-stack cause)) - nil))))) \ No newline at end of file +(defn handle-error + "Function to be used in plugin proxies methods to handle errors and print a readable + message to the console." + [cause] + (display-not-valid (ex-message cause) nil) + (if-let [explain (-> cause ex-data ::sm/explain)] + (println (sm/humanize-explain explain)) + (js/console.log (ex-data cause))) + (js/console.log (.-stack cause))) \ No newline at end of file