🐛 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 <niwi@niwi.nz>
This commit is contained in:
Andrey Antukh
2026-03-17 09:31:10 +01:00
committed by GitHub
parent efd6d19a12
commit 0779c9ca61
5 changed files with 25 additions and 14 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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)))

View File

@@ -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