From 972ccc6a1741a1ab97f70f40ba2ebd7180c99d3b Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Tue, 3 Nov 2026 23:01:44 -0500 Subject: [PATCH] fix(engine): count each id Shape Builder is given once (#1974) --- crates/engine/src/canvas/shapebuilder.rs | 4 +++- crates/engine/src/shapebuilder_tests.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/canvas/shapebuilder.rs b/crates/engine/src/canvas/shapebuilder.rs index b68f1e71d..fb4c3d699 100644 --- a/crates/engine/src/canvas/shapebuilder.rs +++ b/crates/engine/src/canvas/shapebuilder.rs @@ -109,7 +109,9 @@ pub fn eligible(doc: &Document, ids: &[NodeId]) -> Vec { out.push(id); } } - let ids: Vec = ids.iter().copied().filter(|i| doc.contains(*i)).collect(); + // Each id counts once: a repeated group must not be walked once per repeat. + let mut seen = std::collections::BTreeSet::new(); + let ids: Vec = ids.iter().copied().filter(|i| doc.contains(*i) && seen.insert(*i)).collect(); let mut out = Vec::new(); for id in roots(doc, &ids) { walk(doc, id, 0, &mut out); diff --git a/crates/engine/src/shapebuilder_tests.rs b/crates/engine/src/shapebuilder_tests.rs index 3b0cc7efb..a52bf1767 100644 --- a/crates/engine/src/shapebuilder_tests.rs +++ b/crates/engine/src/shapebuilder_tests.rs @@ -217,6 +217,15 @@ fn remove_mode_and_escape() { assert!(s.execute("shapeBuilder.mode", &json!({"mode": "sideways"})).is_err()); } +#[test] +fn a_group_named_many_times_is_walked_once() { + let mut s = Session::new(); + let (a, b) = squares(&mut s); + let g = id(&ex(&mut s, "object.group", json!({"ids": [a, b]}))); + let r = ex(&mut s, "shapeBuilder.regions", json!({"ids": vec![g; 500]})); + assert_eq!(r["sources"], json!([a, b])); +} + #[test] fn groups_rotated_and_ineligible_layers() { let mut s = Session::new();