Fix #263: explain property-group references in property commands

This commit is contained in:
DWAA1660
2026-10-08 08:49:42 -06:00
parent 6943872cf6
commit 69310216fb
5 changed files with 55 additions and 4 deletions
+15 -2
View File
@@ -13,10 +13,23 @@ pub(crate) fn prop_ref(s: &Session, p: &Value, cmd: &str) -> Result<(ItemId, Lay
let (cid, lid) = layer_p(s, p, cmd)?;
let layer = s.project.comp(cid).and_then(|c| c.layer(lid)).ok_or(EngineError::NoComp)?;
if let Some(u) = p.get("prop").and_then(Value::as_u64) {
return layer.props.find(u).map(|pr| (cid, lid, pr.uid)).ok_or_else(|| bad(cmd, format!("no property @{u}")));
return layer.props.find(u).map(|pr| (cid, lid, pr.uid)).ok_or_else(|| {
if layer.props.find_group(u).is_some() {
bad(cmd, format!("@{u} is a property group; use layer.tree (MCP: get_layer) to inspect its children, then select a leaf property"))
} else {
bad(cmd, format!("no property @{u}"))
}
});
}
let path = str_p(p, "path").ok_or_else(|| bad(cmd, "missing `path` (e.g. transform/position) or `prop` uid"))?;
let pr = layer.props.prop(path).ok_or_else(|| bad(cmd, format!("no property `{path}`")))?;
let pr = layer.props.prop(path).ok_or_else(|| {
let group = layer.props.group(path).or_else(|| path.trim().strip_prefix('@')?.parse().ok().and_then(|uid| layer.props.find_group(uid)));
if group.is_some() {
bad(cmd, format!("`{path}` is a property group; use layer.tree (MCP: get_layer) to inspect its children, then select a leaf property"))
} else {
bad(cmd, format!("no property `{path}`"))
}
})?;
Ok((cid, lid, pr.uid))
}
+20
View File
@@ -402,6 +402,26 @@ fn set_text_paragraph_fill_and_leading() {
assert_eq!((d.h_scale, d.v_scale, d.baseline_shift, d.small_caps, d.stroke_over_fill), (120.0, 80.0, 4.0, true, true));
}
#[test]
fn property_groups_report_actionable_errors() {
let mut s = Session::default();
s.execute("comp.new", json!({"name": "T"})).unwrap();
let l = s.execute("layer.newText", json!({"text": "Hi"})).unwrap()["layer"].as_u64().unwrap();
let uid = s.active_comp().unwrap().layer(crate::project::LayerId(l)).unwrap().props.group("text/pathOptions").unwrap().uid;
for selector in [json!({"path": "text"}), json!({"path": "text/pathOptions"}), json!({"path": format!("@{uid}")}), json!({"prop": uid})] {
let mut params = selector;
params["layer"] = json!(l);
for cmd in ["prop.get", "prop.set"] {
let err = s.execute(cmd, params.clone()).unwrap_err().to_string();
assert!(err.contains("is a property group"), "{cmd}: {err}");
assert!(err.contains("get_layer"), "{cmd}: {err}");
}
}
assert!(s.execute("prop.get", json!({"layer": l, "path": "text/sourceText"})).is_ok());
let err = s.execute("prop.get", json!({"layer": l, "path": "missing"})).unwrap_err().to_string();
assert!(err.contains("no property `missing`"), "{err}");
}
#[test]
fn prop_get_and_render_rgba8() {
let mut s = Session::default();