diff --git a/crates/engine/src/cmd/object.rs b/crates/engine/src/cmd/object.rs index 7e1693f86..13bf985fd 100644 --- a/crates/engine/src/cmd/object.rs +++ b/crates/engine/src/cmd/object.rs @@ -3201,7 +3201,11 @@ fn path_create(s: &mut Session, p: &Value) -> Result { fn path_append(s: &mut Session, p: &Value) -> Result { let id = super::id_param(p, "id").ok_or_else(|| bad("path.appendAnchor", "missing id"))?; let a = p.get("anchor").and_then(anchor_from).ok_or_else(|| bad("path.appendAnchor", "missing anchor"))?; - let subpath = p.get("subpath").and_then(Value::as_u64); + // An omitted subpath is the last one; one given must name a subpath (never falls back). + let subpath = match p.get("subpath") { + None | Some(Value::Null) => None, + Some(v) => Some(v.as_u64().ok_or_else(|| bad("path.appendAnchor", "`subpath` must be a subpath index"))?), + }; let at_start = match p.get("at") { None => false, Some(v) if v.as_str() == Some("end") => false, diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 4d3af2f81..baeb1b089 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -1705,7 +1705,10 @@ fn selected_points_follow_their_path() { let (_, si, ai) = st.selection.anchors[0]; let it = st.doc.item(id(l)).unwrap(); assert_eq!((it.xf * it.path.subpaths[si].anchors[ai].p).round(), designcraft_geom::Point::new(200.0, 100.0)); - assert!(s.execute("path.appendAnchor", &json!({"id": l, "anchor": {"p": [0, 0]}, "subpath": 3})).is_err(), "no such subpath"); + for bad in [json!(3), json!(-1), json!("0")] { + assert!(s.execute("path.appendAnchor", &json!({"id": l, "anchor": {"p": [0, 0]}, "subpath": bad})).is_err(), "subpath {bad}"); + } + assert_eq!(s.doc().unwrap().doc.item(id(l)).unwrap().path.subpaths[0].anchors.len(), 4, "nothing appended"); } #[test]