Add Anchor: an invalid subpath is an error, not the last subpath

path.appendAnchor read `subpath` with as_u64, so -1 or "0" counted as omitted
and the point went onto the last subpath. Only an omitted (or null) subpath
means the last one now; any other value must be a valid index.

Found by CodeRabbit on #1657.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
moppeeer
2026-10-23 19:38:24 +02:00
co-authored by Claude Opus 5.5
parent 9442f5d9c8
commit 8daf036a3e
2 changed files with 9 additions and 2 deletions
+5 -1
View File
@@ -3201,7 +3201,11 @@ fn path_create(s: &mut Session, p: &Value) -> Result<Value> {
fn path_append(s: &mut Session, p: &Value) -> Result<Value> {
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,
+4 -1
View File
@@ -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]