From 0779c9ca615b50167b4f10e988c699b636b9deed Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 17 Mar 2026 09:31:10 +0100 Subject: [PATCH] :bug: Fix TypeError in get-points when content is not PathData (#8634) The with-cache macro in impl.cljc assumed the target was always a PathData instance (which has a cache field). When content was a plain vector, (.-cache content) returned undefined in JS, causing: TypeError: Cannot read properties of undefined (reading 'get') Fix: - path/get-points (app.common.types.path) is now the canonical safe entry point: converts non-PathData content via impl/path-data and handles nil safely before delegating to segment/get-points - segment/get-points remains a low-level function that expects a PathData instance (no defensive logic at that level) - streams.cljs: replace direct call to path.segm/get-points with path/get-points so the safe conversion path is always used - with-cache macro: guards against nil/undefined cache, falling back to direct evaluation for non-PathData targets Signed-off-by: Andrey Antukh --- common/src/app/common/types/path.cljc | 10 +++++++--- common/src/app/common/types/path/impl.cljc | 17 +++++++++-------- .../test/common_tests/types/path_data_test.cljc | 6 ++++++ .../app/main/data/workspace/path/changes.cljs | 2 +- .../app/main/data/workspace/path/streams.cljs | 4 ++-- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/types/path.cljc b/common/src/app/common/types/path.cljc index be0e15b1aa..67d8031efb 100644 --- a/common/src/app/common/types/path.cljc +++ b/common/src/app/common/types/path.cljc @@ -190,10 +190,14 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn get-points - "Returns points for the given segment, faster version of - the `content->points`." + "Returns points for the given content. Accepts PathData instances or + plain segment vectors. Returns nil for nil content." [content] - (some-> content segment/get-points)) + (when (some? content) + (let [content (if (impl/path-data? content) + content + (impl/path-data content))] + (segment/get-points content)))) (defn calc-selrect "Calculate selrect from a content. The content can be in a PathData diff --git a/common/src/app/common/types/path/impl.cljc b/common/src/app/common/types/path/impl.cljc index 8b2ed4a315..959a11bf6f 100644 --- a/common/src/app/common/types/path/impl.cljc +++ b/common/src/app/common/types/path/impl.cljc @@ -52,14 +52,15 @@ [target key & expr] (if (:ns &env) (let [target (with-meta target {:tag 'js})] - `(let [~'cache (.-cache ~target) - ~'result (.get ~'cache ~key)] - (if ~'result - (do - ~'result) - (let [~'result (do ~@expr)] - (.set ~'cache ~key ~'result) - ~'result)))) + `(let [~'cache (.-cache ~target)] + (if (some? ~'cache) + (let [~'result (.get ~'cache ~key)] + (if ~'result + ~'result + (let [~'result (do ~@expr)] + (.set ~'cache ~key ~'result) + ~'result))) + (do ~@expr)))) `(do ~@expr))) (defn- impl-transform-segment diff --git a/common/test/common_tests/types/path_data_test.cljc b/common/test/common_tests/types/path_data_test.cljc index 5e6298191e..672df228d8 100644 --- a/common/test/common_tests/types/path_data_test.cljc +++ b/common/test/common_tests/types/path_data_test.cljc @@ -279,6 +279,12 @@ (t/is (some? points)) (t/is (= 3 (count points)))))) +(t/deftest path-get-points-plain-vector-safe + (t/testing "path/get-points does not throw for plain vector content" + (let [points (path/get-points sample-content)] + (t/is (some? points)) + (t/is (= 3 (count points)))))) + (defn calculate-extremities "Calculate extremities for the provided content. A legacy implementation used mainly as reference for testing" diff --git a/frontend/src/app/main/data/workspace/path/changes.cljs b/frontend/src/app/main/data/workspace/path/changes.cljs index fc43b61fd5..c2bc293da3 100644 --- a/frontend/src/app/main/data/workspace/path/changes.cljs +++ b/frontend/src/app/main/data/workspace/path/changes.cljs @@ -68,7 +68,7 @@ (let [content (st/get-path state :content) content (if (and (not preserve-move-to) (= (-> content last :command) :move-to)) - (into [] (take (dec (count content)) content)) + (path/content (take (dec (count content)) content)) content)] (st/set-content state content))) diff --git a/frontend/src/app/main/data/workspace/path/streams.cljs b/frontend/src/app/main/data/workspace/path/streams.cljs index b6028eec11..907d50ab24 100644 --- a/frontend/src/app/main/data/workspace/path/streams.cljs +++ b/frontend/src/app/main/data/workspace/path/streams.cljs @@ -8,7 +8,7 @@ (:require [app.common.data.macros :as dm] [app.common.geom.point :as gpt] - [app.common.types.path.segment :as path.segm] + [app.common.types.path :as path] [app.main.data.workspace.path.state :as pst] [app.main.snap :as snap] [app.main.store :as st] @@ -167,7 +167,7 @@ ranges-stream (->> content-stream (rx/filter some?) - (rx/map path.segm/get-points) + (rx/map path/get-points) (rx/map snap/create-ranges))] (->> ms/mouse-position