oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use serde_json::{json, Value};
2use yrs::{ReadTxn, Text, Xml, XmlFragment, XmlFragmentRef, XmlOut};
3
4pub fn node_id(node: &XmlOut) -> String {
5 serde_json::to_string(&node.id()).expect("branch identity serializes")
6}
7pub fn children<T: ReadTxn>(root: &XmlFragmentRef, txn: &T) -> Vec<Value> {
8 (0..root.len(txn)).filter_map(|i| root.get(txn, i)).map(|node| project(&node, txn)).collect()
9}
10fn project<T: ReadTxn>(node: &XmlOut, txn: &T) -> Value {
11 match node {
12 XmlOut::Text(text) => {
13 let runs: Vec<_> = text.diff(txn, |_| ()).iter().map(|run| {
14 json!({"insert": run.insert.clone().to_string(txn), "marks": run.attributes})
15 }).collect();
16 json!({"id": node_id(node), "type": "text", "runs": runs})
17 },
18 XmlOut::Element(element) => {
19 let attrs: serde_json::Map<String, Value> = element.attributes(txn)
20 .map(|(key,value)| (key.to_string(), Value::String(value))).collect();
21 json!({"id": node_id(node), "type": element.tag().as_ref(), "attrs": attrs, "children": children(element.as_ref(), txn)})
22 },
23 XmlOut::Fragment(fragment) => json!({"id": node_id(node), "type": "fragment", "children": children(fragment, txn)}),
24 }
25}
26pub fn find<T: ReadTxn>(root: &XmlFragmentRef, txn: &T, id: &str) -> Option<XmlOut> {
27 for index in 0..root.len(txn) {
28 let node = root.get(txn, index)?;
29 if node_id(&node) == id { return Some(node); }
30 let nested = match &node {
31 XmlOut::Element(el) => find(el.as_ref(), txn, id),
32 XmlOut::Fragment(f) => find(f, txn, id),
33 _ => None,
34 };
35 if nested.is_some() { return nested; }
36 }
37 None
38}
39