mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-30 13:26:54 -06:00
Reject non-boolean values for node.set flag properties
Found while testing crates/engine/src/cmd/props.rs:614 (also :708, :717, :718, :826 and :1007) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
3108d5bee7
commit
0876f6dbc9
@@ -611,7 +611,7 @@ fn apply_corners(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value)
|
||||
"cornerSmoothing" => doc.get_mut(id)?.corners.smoothing = f64_of(v).unwrap_or(0.0).clamp(0.0, 1.0),
|
||||
"effects" => doc.get_mut(id)?.effects = effects_from(cmd, v)?,
|
||||
"clip" | "clipsContent" => doc.get_mut(id)?.clip = v.as_bool().ok_or_else(|| bad(cmd, "`clip` must be a boolean"))?,
|
||||
"isMask" => doc.get_mut(id)?.is_mask = v.as_bool().unwrap_or(false),
|
||||
"isMask" => doc.get_mut(id)?.is_mask = v.as_bool().ok_or_else(|| bad(cmd, format!("`{k}` must be a boolean")))?,
|
||||
"devStatus" => {
|
||||
let st = if v.is_null() {
|
||||
Some(DevStatus::None)
|
||||
@@ -705,7 +705,7 @@ fn apply_layout(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value) -
|
||||
"contentAlign" | "counterAxisAlignContent" => {
|
||||
layout_mut(cmd, k, doc.get_mut(id)?)?.content_align = enum_of(v).ok_or_else(|| bad(cmd, "contentAlign: auto|spaceBetween"))?
|
||||
}
|
||||
"wrap" => layout_mut(cmd, k, doc.get_mut(id)?)?.wrap = v.as_bool().unwrap_or(false),
|
||||
"wrap" => layout_mut(cmd, k, doc.get_mut(id)?)?.wrap = v.as_bool().ok_or_else(|| bad(cmd, format!("`{k}` must be a boolean")))?,
|
||||
"gridColumns" | "gridRows" => {
|
||||
let count = f64_of(v).ok_or_else(|| bad(cmd, format!("`{k}` must be a number")))?.clamp(1.0, 1000.0) as u32;
|
||||
let l = layout_mut(cmd, k, doc.get_mut(id)?)?;
|
||||
@@ -714,8 +714,10 @@ fn apply_layout(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value) -
|
||||
*n = count;
|
||||
tracks.truncate(count as usize);
|
||||
}
|
||||
"strokesIncluded" => layout_mut(cmd, k, doc.get_mut(id)?)?.strokes_included = v.as_bool().unwrap_or(false),
|
||||
"reverseZ" => layout_mut(cmd, k, doc.get_mut(id)?)?.reverse_z = v.as_bool().unwrap_or(false),
|
||||
"strokesIncluded" => {
|
||||
layout_mut(cmd, k, doc.get_mut(id)?)?.strokes_included = v.as_bool().ok_or_else(|| bad(cmd, format!("`{k}` must be a boolean")))?
|
||||
}
|
||||
"reverseZ" => layout_mut(cmd, k, doc.get_mut(id)?)?.reverse_z = v.as_bool().ok_or_else(|| bad(cmd, format!("`{k}` must be a boolean")))?,
|
||||
_ => return Ok(false),
|
||||
}
|
||||
Ok(true)
|
||||
@@ -823,7 +825,7 @@ fn apply_meta(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value) ->
|
||||
"interactions" => doc.get_mut(id)?.interactions = serde_json::from_value(v.clone()).map_err(|e| bad(cmd, format!("interactions: {e}")))?,
|
||||
"overflow" => doc.get_mut(id)?.overflow = enum_of(v).ok_or_else(|| bad(cmd, "overflow: none|horizontal|vertical|both"))?,
|
||||
"scrollPosition" => doc.get_mut(id)?.scroll_position = enum_of(v).ok_or_else(|| bad(cmd, "scrollPosition: scrolls|fixed|sticky"))?,
|
||||
"constrainProportions" => doc.get_mut(id)?.constrain_proportions = v.as_bool().unwrap_or(false),
|
||||
"constrainProportions" => doc.get_mut(id)?.constrain_proportions = v.as_bool().ok_or_else(|| bad(cmd, format!("`{k}` must be a boolean")))?,
|
||||
_ => return Ok(false),
|
||||
}
|
||||
Ok(true)
|
||||
@@ -1004,7 +1006,7 @@ fn apply_shape(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value) ->
|
||||
"operandOperation" => set_operand_op(doc, id, v, cmd)?,
|
||||
"sectionContentsHidden" => {
|
||||
if let NodeKind::Section { contents_hidden } = &mut doc.get_mut(id)?.kind {
|
||||
*contents_hidden = v.as_bool().unwrap_or(false);
|
||||
*contents_hidden = v.as_bool().ok_or_else(|| bad(cmd, "`sectionContentsHidden` must be a boolean"))?;
|
||||
}
|
||||
}
|
||||
"background" => {
|
||||
|
||||
@@ -194,3 +194,27 @@ fn node_find_leaves_document_selection_page_and_history_untouched() {
|
||||
assert_ne!(s.doc().unwrap().get(layer).unwrap().name, "Previous edit");
|
||||
assert_eq!(s.ds().unwrap().history.undo.len(), undo - 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn node_set_rejects_non_boolean_flags() {
|
||||
let mut s = Session::new();
|
||||
let page = s.page().unwrap();
|
||||
let rect = add(&mut s, page, NodeKind::Rectangle, "R");
|
||||
let frame = add(&mut s, page, NodeKind::Frame, "F");
|
||||
ex(&mut s, "node.set", json!({"ids": [rect], "props": {"isMask": true, "constrainProportions": true}}));
|
||||
ex(&mut s, "node.set", json!({"ids": [frame], "props": {"layoutMode": "HORIZONTAL", "wrap": true, "strokesIncluded": true, "reverseZ": true}}));
|
||||
for (id, key) in [(rect, "isMask"), (rect, "constrainProportions"), (frame, "wrap"), (frame, "strokesIncluded"), (frame, "reverseZ")] {
|
||||
let r = s.execute("node.set", &json!({"ids": [id], "props": {key: "yes"}}));
|
||||
assert!(r.is_err(), "{key} accepted a non-boolean");
|
||||
}
|
||||
let sec = add(&mut s, page, NodeKind::Section { contents_hidden: false }, "S");
|
||||
ex(&mut s, "node.set", json!({"ids": [sec], "props": {"sectionContentsHidden": true}}));
|
||||
let r = s.execute("node.set", &json!({"ids": [sec], "props": {"sectionContentsHidden": "yes"}}));
|
||||
assert!(r.is_err(), "sectionContentsHidden accepted a non-boolean");
|
||||
let doc = s.doc().unwrap();
|
||||
assert!(matches!(doc.get(sec).unwrap().kind, figcraft_doc::NodeKind::Section { contents_hidden: true }));
|
||||
assert!(doc.get(rect).unwrap().is_mask && doc.get(rect).unwrap().constrain_proportions);
|
||||
let l = doc.get(frame).unwrap();
|
||||
let l = l.layout.as_ref().unwrap();
|
||||
assert!(l.wrap && l.strokes_included && l.reverse_z);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user