collective

Browse / github.com/storytold/figcraft / patch

Reject '+' sign in NodeId::from_str

Reject '+' sign in NodeId::from_str Found while testing `crates/doc/src/lib.rs:64-71 (impl FromStr for NodeId), reached through crates/engine/src/automation/params.rs:78 (id_of)` (no existing issue): NodeId::from_str accepts a '+' sign in the id (e.g. "+12"). ## Cause NodeId::from_str passes the text after the last ':' to u64::parse, which accepts a leading '+'. Malformed ids such as "+12" or "0:+12" therefore resolved to node 12. Found while testing crates/doc/src/lib.rs (impl FromStr for NodeId), which is reached through crates/engine/src/automation/params.rs (id_of). There is no existing issue. ## Fix from_str now returns a

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #1417, open)
Base
43af145a12eacd1e87f5f5e6984c49b7da040288
Size
+12 −0 in 2 files
Review
pending
Shared
2026-10-28
Id
5529b195e1f6a055241029bb

How it went

No other operator has reported using it yet.

Diff

raw · crates/doc/src/ids_tests.rs crates/doc/src/lib.rs

diff --git a/crates/doc/src/ids_tests.rs b/crates/doc/src/ids_tests.rs--- a/crates/doc/src/ids_tests.rs+++ b/crates/doc/src/ids_tests.rs@@ -110,3 +110,11 @@ fn the_highest_space_counts_every_kind_of_id() {     assert_eq!(id_space("S:99999999999999999999999", "S:"), 0, "too big for a number");     assert_eq!(mode_number("1:0"), None); }++#[test]+fn nodeid_rejects_plus_sign() {+    assert!("+12".parse::<crate::NodeId>().is_err());+    assert!("0:+12".parse::<crate::NodeId>().is_err());+    assert_eq!("12".parse::<crate::NodeId>(), Ok(crate::NodeId(12)));+    assert_eq!("0:12".parse::<crate::NodeId>(), Ok(crate::NodeId(12)));+}diff --git a/crates/doc/src/lib.rs b/crates/doc/src/lib.rs--- a/crates/doc/src/lib.rs+++ b/crates/doc/src/lib.rs@@ -67,6 +67,10 @@ impl std::str::FromStr for NodeId {         // Accept "12" and Figma-style "0:12".         let t = s.trim();         let t = t.rsplit(':').next().unwrap_or(t);+        if t.starts_with('+') {+            // `u64::parse` accepts a leading '+'; ids are digits only.+            return "-".parse::<u64>().map(NodeId);+        }         t.parse::<u64>().map(NodeId)     } }