1use std::path::PathBuf;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum NodeType {
6 Root,
8 Translation,
10 KeyPath,
12 CodeRef,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Location {
19 pub file: PathBuf,
20 pub line: usize,
21}
22
23impl Location {
24 pub fn new(file: PathBuf, line: usize) -> Self {
25 Self { file, line }
26 }
27}
28
29#[derive(Debug, Clone)]
31pub struct TreeNode {
32 pub node_type: NodeType,
33 pub content: String,
34 pub location: Option<Location>,
35 pub children: Vec<TreeNode>,
36}
37
38impl TreeNode {
39 pub fn new(node_type: NodeType, content: String) -> Self {
41 Self {
42 node_type,
43 content,
44 location: None,
45 children: Vec::new(),
46 }
47 }
48
49 pub fn with_location(node_type: NodeType, content: String, location: Location) -> Self {
51 Self {
52 node_type,
53 content,
54 location: Some(location),
55 children: Vec::new(),
56 }
57 }
58
59 pub fn add_child(&mut self, child: TreeNode) {
61 self.children.push(child);
62 }
63
64 pub fn has_children(&self) -> bool {
66 !self.children.is_empty()
67 }
68
69 pub fn child_count(&self) -> usize {
71 self.children.len()
72 }
73
74 pub fn node_count(&self) -> usize {
76 1 + self.children.iter().map(|c| c.node_count()).sum::<usize>()
77 }
78
79 pub fn max_depth(&self) -> usize {
81 if self.children.is_empty() {
82 1
83 } else {
84 1 + self
85 .children
86 .iter()
87 .map(|c| c.max_depth())
88 .max()
89 .unwrap_or(0)
90 }
91 }
92}
93
94#[derive(Debug)]
96pub struct ReferenceTree {
97 pub root: TreeNode,
98}
99
100impl ReferenceTree {
101 pub fn new(root: TreeNode) -> Self {
103 Self { root }
104 }
105
106 pub fn with_search_text(search_text: String) -> Self {
108 Self {
109 root: TreeNode::new(NodeType::Root, search_text),
110 }
111 }
112
113 pub fn node_count(&self) -> usize {
115 self.root.node_count()
116 }
117
118 pub fn max_depth(&self) -> usize {
120 self.root.max_depth()
121 }
122
123 pub fn has_results(&self) -> bool {
125 self.root.has_children()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn test_create_tree_node() {
135 let node = TreeNode::new(NodeType::Root, "add new".to_string());
136 assert_eq!(node.content, "add new");
137 assert_eq!(node.node_type, NodeType::Root);
138 assert!(node.location.is_none());
139 assert!(node.children.is_empty());
140 }
141
142 #[test]
143 fn test_create_tree_node_with_location() {
144 let location = Location::new(PathBuf::from("test.yml"), 10);
145 let node = TreeNode::with_location(
146 NodeType::Translation,
147 "add_new: 'add new'".to_string(),
148 location.clone(),
149 );
150
151 assert_eq!(node.content, "add_new: 'add new'");
152 assert_eq!(node.node_type, NodeType::Translation);
153 assert!(node.location.is_some());
154 assert_eq!(node.location.unwrap().line, 10);
155 }
156
157 #[test]
158 fn test_add_child() {
159 let mut parent = TreeNode::new(NodeType::Root, "root".to_string());
160 let child = TreeNode::new(NodeType::Translation, "child".to_string());
161
162 assert_eq!(parent.child_count(), 0);
163 parent.add_child(child);
164 assert_eq!(parent.child_count(), 1);
165 assert!(parent.has_children());
166 }
167
168 #[test]
169 fn test_node_count() {
170 let mut root = TreeNode::new(NodeType::Root, "root".to_string());
171 let mut child1 = TreeNode::new(NodeType::Translation, "child1".to_string());
172 let child2 = TreeNode::new(NodeType::Translation, "child2".to_string());
173 let grandchild = TreeNode::new(NodeType::KeyPath, "grandchild".to_string());
174
175 child1.add_child(grandchild);
176 root.add_child(child1);
177 root.add_child(child2);
178
179 assert_eq!(root.node_count(), 4);
181 }
182
183 #[test]
184 fn test_max_depth() {
185 let mut root = TreeNode::new(NodeType::Root, "root".to_string());
186 let mut child = TreeNode::new(NodeType::Translation, "child".to_string());
187 let grandchild = TreeNode::new(NodeType::KeyPath, "grandchild".to_string());
188
189 assert_eq!(root.max_depth(), 1);
191
192 root.add_child(child.clone());
194 assert_eq!(root.max_depth(), 2);
195
196 child.add_child(grandchild);
198 root.children[0] = child;
199 assert_eq!(root.max_depth(), 3);
200 }
201
202 #[test]
203 fn test_reference_tree_creation() {
204 let tree = ReferenceTree::with_search_text("add new".to_string());
205 assert_eq!(tree.root.content, "add new");
206 assert_eq!(tree.root.node_type, NodeType::Root);
207 assert!(!tree.has_results());
208 }
209
210 #[test]
211 fn test_reference_tree_with_results() {
212 let mut root = TreeNode::new(NodeType::Root, "add new".to_string());
213 let child = TreeNode::new(NodeType::Translation, "translation".to_string());
214 root.add_child(child);
215
216 let tree = ReferenceTree::new(root);
217 assert!(tree.has_results());
218 assert_eq!(tree.node_count(), 2);
219 assert_eq!(tree.max_depth(), 2);
220 }
221
222 #[test]
223 fn test_location_creation() {
224 let location = Location::new(PathBuf::from("test.yml"), 42);
225 assert_eq!(location.file, PathBuf::from("test.yml"));
226 assert_eq!(location.line, 42);
227 }
228
229 #[test]
230 fn test_node_types() {
231 let root = NodeType::Root;
232 let translation = NodeType::Translation;
233 let key_path = NodeType::KeyPath;
234 let code_ref = NodeType::CodeRef;
235
236 assert_eq!(root, NodeType::Root);
237 assert_eq!(translation, NodeType::Translation);
238 assert_eq!(key_path, NodeType::KeyPath);
239 assert_eq!(code_ref, NodeType::CodeRef);
240 }
241
242 #[test]
243 fn test_complex_tree_structure() {
244 let mut root = TreeNode::new(NodeType::Root, "add new".to_string());
246
247 let mut translation = TreeNode::with_location(
248 NodeType::Translation,
249 "add_new: 'add new'".to_string(),
250 Location::new(PathBuf::from("en.yml"), 4),
251 );
252
253 let mut key_path = TreeNode::new(NodeType::KeyPath, "invoice.labels.add_new".to_string());
254
255 let code_ref = TreeNode::with_location(
256 NodeType::CodeRef,
257 "I18n.t('invoice.labels.add_new')".to_string(),
258 Location::new(PathBuf::from("invoices.ts"), 14),
259 );
260
261 key_path.add_child(code_ref);
262 translation.add_child(key_path);
263 root.add_child(translation);
264
265 let tree = ReferenceTree::new(root);
266
267 assert_eq!(tree.node_count(), 4);
268 assert_eq!(tree.max_depth(), 4);
269 assert!(tree.has_results());
270 }
271}