Skip to main content

jellyflow_core/ops/fragment/
clipboard.rs

1use serde_json as json;
2
3use super::model::GraphFragment;
4
5/// Clipboard header for `GraphFragment` payloads.
6pub const GRAPH_FRAGMENT_CLIPBOARD_PREFIX: &str = "jellyflow.fragment.v1\n";
7
8impl GraphFragment {
9    /// Serializes this fragment to a clipboard-friendly text payload.
10    pub fn to_clipboard_text(&self) -> Result<String, json::Error> {
11        let json = json::to_string(self)?;
12        Ok(format!("{GRAPH_FRAGMENT_CLIPBOARD_PREFIX}{json}"))
13    }
14
15    /// Parses a fragment from clipboard text.
16    ///
17    /// Accepts both:
18    /// - the canonical `jellyflow.fragment.v1` header format,
19    /// - raw JSON (useful for debugging and external tooling).
20    pub fn from_clipboard_text(text: &str) -> Result<Self, json::Error> {
21        let payload = text
22            .strip_prefix(GRAPH_FRAGMENT_CLIPBOARD_PREFIX)
23            .unwrap_or(text);
24        json::from_str(payload)
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use super::GRAPH_FRAGMENT_CLIPBOARD_PREFIX;
31    use crate::ops::fragment::GraphFragment;
32
33    #[test]
34    fn clipboard_text_roundtrips_with_prefix() {
35        let fragment = GraphFragment::default();
36        let text = fragment.to_clipboard_text().expect("serialize");
37        assert!(text.starts_with(GRAPH_FRAGMENT_CLIPBOARD_PREFIX));
38        let parsed = GraphFragment::from_clipboard_text(&text).expect("parse");
39        assert_eq!(parsed.version, fragment.version);
40        assert_eq!(parsed.nodes.len(), 0);
41    }
42
43    #[test]
44    fn clipboard_text_accepts_raw_json() {
45        let fragment = GraphFragment::default();
46        let json = serde_json::to_string(&fragment).expect("serialize");
47        let parsed = GraphFragment::from_clipboard_text(&json).expect("parse");
48        assert_eq!(parsed.version, fragment.version);
49    }
50}