moduforge_transform/
node_step.rs

1use std::sync::Arc;
2
3use moduforge_model::{
4    node_type::NodeEnum, schema::Schema, tree::Tree, types::NodeId,
5};
6
7use crate::transform_error;
8
9use super::{
10    step::{Step, StepResult},
11    TransformResult,
12};
13use serde::{Deserialize, Serialize};
14/// 添加节点的步骤
15#[derive(Debug, Serialize, Deserialize, Clone)]
16pub struct AddNodeStep {
17    parent_id: NodeId,
18    nodes: Vec<NodeEnum>,
19}
20impl AddNodeStep {
21    pub fn new(
22        parent_id: NodeId,
23        nodes: Vec<NodeEnum>,
24    ) -> Self {
25        AddNodeStep { parent_id, nodes }
26    }
27}
28impl Step for AddNodeStep {
29    fn name(&self) -> String {
30        "add_node_step".to_string()
31    }
32    fn apply(
33        &self,
34        dart: &mut Tree,
35        schema: Arc<Schema>,
36    ) -> TransformResult<StepResult> {
37        let _ = schema;
38        let result = dart.add(&self.parent_id, self.nodes.clone());
39        match result {
40            Ok(_) => Ok(StepResult::ok()),
41            Err(e) => Err(transform_error(e.to_string())),
42        }
43    }
44    fn serialize(&self) -> Option<Vec<u8>> {
45        serde_json::to_vec(self).ok()
46    }
47
48    fn invert(
49        &self,
50        _: &Arc<Tree>,
51    ) -> Option<Arc<dyn Step>> {
52        // 递归收集单个节点枚举的所有子节点 id
53        fn collect_node_ids(node_enum: &NodeEnum) -> Vec<NodeId> {
54            let mut ids: Vec<String> = vec![node_enum.0.id.clone()];
55            for child in &node_enum.1 {
56                ids.extend(collect_node_ids(child));
57            }
58            ids
59        }
60
61        // 收集所有节点的 id(包括顶级节点和所有子节点)
62        let mut all_node_ids = Vec::new();
63        for node_enum in &self.nodes {
64            all_node_ids.extend(collect_node_ids(node_enum));
65        }
66
67        if !all_node_ids.is_empty() {
68            return Some(Arc::new(RemoveNodeStep::new(
69                self.parent_id.clone(),
70                all_node_ids,
71            )));
72        }
73        None
74    }
75}
76/// 删除节点的步骤
77#[derive(Debug, Serialize, Deserialize, Clone)]
78pub struct RemoveNodeStep {
79    parent_id: NodeId,
80    node_ids: Vec<NodeId>,
81}
82impl RemoveNodeStep {
83    pub fn new(
84        parent_id: NodeId,
85        node_ids: Vec<NodeId>,
86    ) -> Self {
87        RemoveNodeStep { parent_id, node_ids }
88    }
89}
90impl Step for RemoveNodeStep {
91    fn name(&self) -> String {
92        "remove_node_step".to_string()
93    }
94    fn apply(
95        &self,
96        dart: &mut Tree,
97        schema: Arc<Schema>,
98    ) -> TransformResult<StepResult> {
99        let _ = schema;
100        let result = dart.remove_node(&self.parent_id, self.node_ids.clone());
101        match result {
102            Ok(_) => Ok(StepResult::ok()),
103            Err(e) => Err(transform_error(e.to_string())), // 修复:失败时返回Err保持一致性
104        }
105    }
106    fn serialize(&self) -> Option<Vec<u8>> {
107        serde_json::to_vec(self).ok()
108    }
109
110    fn invert(
111        &self,
112        dart: &Arc<Tree>,
113    ) -> Option<Arc<dyn Step>> {
114        // 收集所有要删除的节点及其子树
115        let mut nodes_to_restore = Vec::new();
116
117        for node_id in &self.node_ids {
118            if let Some(node_enum) = dart.all_children(node_id, None) {
119                nodes_to_restore.push(node_enum);
120            }
121        }
122
123        if !nodes_to_restore.is_empty() {
124            Some(Arc::new(AddNodeStep::new(
125                self.parent_id.clone(),
126                nodes_to_restore,
127            )))
128        } else {
129            None
130        }
131    }
132}
133
134#[derive(Debug, Serialize, Deserialize, Clone)]
135pub struct MoveNodeStep {
136    source_parent_id: NodeId,
137    target_parent_id: NodeId,
138    node_id: NodeId,
139    position: Option<usize>, // 目标位置,None 表示追加到末尾
140}
141
142impl MoveNodeStep {
143    pub fn new(
144        source_parent_id: NodeId,
145        target_parent_id: NodeId,
146        node_id: NodeId,
147        position: Option<usize>,
148    ) -> Self {
149        MoveNodeStep { source_parent_id, target_parent_id, node_id, position }
150    }
151}
152
153impl Step for MoveNodeStep {
154    fn name(&self) -> String {
155        "move_node_step".to_string()
156    }
157    fn apply(
158        &self,
159        dart: &mut Tree,
160        schema: Arc<Schema>,
161    ) -> TransformResult<StepResult> {
162        let _ = schema;
163
164        match dart.move_node(
165            &self.source_parent_id,
166            &self.target_parent_id,
167            &self.node_id,
168            self.position,
169        ) {
170            Ok(()) => Ok(StepResult::ok()),
171            Err(err) => Err(transform_error(err.to_string())),
172        }
173    }
174    fn serialize(&self) -> Option<Vec<u8>> {
175        serde_json::to_vec(self).ok()
176    }
177
178    fn invert(
179        &self,
180        dart: &Arc<Tree>,
181    ) -> Option<Arc<dyn Step>> {
182        match dart.get_node(&self.node_id) {
183            Some(_) => Some(Arc::new(MoveNodeStep::new(
184                self.target_parent_id.clone(),
185                self.source_parent_id.clone(),
186                self.node_id.clone(),
187                self.position,
188            ))),
189            None => None,
190        }
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197    use moduforge_model::{
198        node::Node,
199        node_type::{NodeEnum, NodeType, NodeSpec},
200        schema::{Schema, SchemaSpec, AttributeSpec},
201        tree::Tree,
202        attrs::Attrs,
203        mark::Mark,
204    };
205    use std::collections::HashMap;
206    use std::sync::Arc;
207
208    fn create_test_node(id: &str) -> Node {
209        Node::new(id, "test".to_string(), Attrs::default(), vec![], vec![])
210    }
211
212    fn create_test_schema() -> Arc<Schema> {
213        let mut nodes = HashMap::new();
214        nodes.insert(
215            "test".to_string(),
216            NodeSpec {
217                content: None,
218                marks: None,
219                group: None,
220                desc: Some("Test node".to_string()),
221                attrs: None,
222            },
223        );
224
225        let spec = SchemaSpec {
226            nodes,
227            marks: HashMap::new(),
228            top_node: Some("test".to_string()),
229        };
230
231        Arc::new(Schema::compile(spec).unwrap())
232    }
233
234    fn create_test_tree() -> Tree {
235        let root = create_test_node("root");
236        Tree::new(root)
237    }
238
239    #[test]
240    fn test_add_node_step() {
241        let mut tree = create_test_tree();
242        let schema = create_test_schema();
243
244        // Create a test node to add
245        let node = create_test_node("root");
246        let test = create_test_node("test");
247        let node_enum = NodeEnum(node, vec![NodeEnum(test, vec![])]);
248        let step =
249            AddNodeStep::new("root".to_string(), vec![node_enum.clone()]);
250        let result = step.apply(&mut tree, schema.clone());
251        assert!(result.is_ok());
252
253        // Verify node was added
254        assert!(tree.get_node(&"test".to_string()).is_some());
255
256        // Test invert
257        let inverted = step.invert(&Arc::new(tree.clone()));
258        assert!(inverted.is_some());
259
260        // Apply inverted step
261        if let Some(inverted_step) = inverted {
262            let result = inverted_step.apply(&mut tree, schema);
263            assert!(result.is_ok());
264            // Verify node was removed
265            assert!(tree.get_node(&"test".to_string()).is_none());
266        }
267    }
268
269    #[test]
270    fn test_remove_node_step() {
271        let mut tree = create_test_tree();
272        let schema = create_test_schema();
273
274        // Add a node first
275        let node = create_test_node("test");
276        tree.add_node(&"root".to_string(), &vec![node]).unwrap();
277
278        let step =
279            RemoveNodeStep::new("root".to_string(), vec!["test".to_string()]);
280        let result = step.apply(&mut tree, schema.clone());
281        assert!(result.is_ok());
282
283        // Verify node was removed
284        assert!(tree.get_node(&"test".to_string()).is_none());
285
286        // Test invert
287        let inverted = step.invert(&Arc::new(tree.clone()));
288        assert!(inverted.is_some());
289    }
290
291    #[test]
292    fn test_move_node_step() {
293        let mut tree = create_test_tree();
294        let schema = create_test_schema();
295
296        // Add source and target nodes
297        let source = create_test_node("source");
298        let target = create_test_node("target");
299        let node = create_test_node("node");
300
301        tree.add_node(&"root".to_string(), &vec![source]).unwrap();
302        tree.add_node(&"root".to_string(), &vec![target]).unwrap();
303        tree.add_node(&"source".to_string(), &vec![node]).unwrap();
304
305        let step = MoveNodeStep::new(
306            "source".to_string(),
307            "target".to_string(),
308            "node".to_string(),
309            None,
310        );
311
312        let result = step.apply(&mut tree, schema.clone());
313        assert!(result.is_ok());
314
315        // Verify node was moved
316        let target_node = tree.get_node(&"target".to_string()).unwrap();
317        assert!(target_node.content.contains(&"node".to_string()));
318
319        // Test invert
320        let inverted = step.invert(&Arc::new(tree.clone()));
321        assert!(inverted.is_some());
322    }
323}