1use graphy_core::Span;
2use tree_sitter::Node;
3
4pub fn node_text(node: &Node, source: &[u8]) -> String {
5 node.utf8_text(source).unwrap_or("").to_string()
6}
7
8pub fn node_span(node: &Node) -> Span {
9 let start = node.start_position();
10 let end = node.end_position();
11 Span::new(
12 start.row as u32,
13 start.column as u32,
14 end.row as u32,
15 end.column as u32,
16 )
17}
18
19pub fn clean_doc_comment(text: &str) -> String {
21 text.lines()
22 .map(|line| {
23 let trimmed = line.trim();
24 if trimmed.starts_with("///") {
25 trimmed[3..].trim()
26 } else if trimmed.starts_with("//!") {
27 trimmed[3..].trim()
28 } else if trimmed.starts_with("//") {
29 trimmed[2..].trim()
30 } else if trimmed.starts_with("/**") {
31 trimmed[3..].trim()
32 } else if trimmed == "*/" {
33 ""
34 } else if trimmed.starts_with("* ") {
35 trimmed[2..].trim()
36 } else if trimmed == "*" {
37 ""
38 } else if trimmed.starts_with('#') {
39 trimmed[1..].trim()
40 } else {
41 trimmed
42 }
43 })
44 .filter(|line| !line.is_empty())
45 .collect::<Vec<_>>()
46 .join("\n")
47}
48
49pub fn is_noise_method_call(name: &str) -> bool {
67 if name.contains("::") {
69 return false;
70 }
71
72 let (receiver, _method) = if let Some(pos) = name.rfind('.') {
74 (&name[..pos], &name[pos + 1..])
75 } else {
76 return false;
78 };
79
80 let root = receiver
82 .split('.')
83 .next()
84 .unwrap_or(receiver);
85
86 if matches!(root, "self" | "this" | "super" | "cls") {
88 return true;
89 }
90
91 let segment_count = name.split('.').count();
95
96 if segment_count >= 3 {
99 return false;
100 }
101
102 let first_char = root.chars().next().unwrap_or('a');
108 first_char.is_ascii_lowercase()
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn clean_c_style_doc() {
117 let input = "/**\n * Hello world\n * @param x the value\n */";
118 let cleaned = clean_doc_comment(input);
119 assert_eq!(cleaned, "Hello world\n@param x the value");
120 }
121
122 #[test]
123 fn clean_rust_doc() {
124 let input = "/// Hello world\n/// Second line";
125 let cleaned = clean_doc_comment(input);
126 assert_eq!(cleaned, "Hello world\nSecond line");
127 }
128
129 #[test]
130 fn clean_hash_doc() {
131 let input = "# Hello\n# World";
132 let cleaned = clean_doc_comment(input);
133 assert_eq!(cleaned, "Hello\nWorld");
134 }
135
136 #[test]
137 fn noise_method_call_basics() {
138 assert!(is_noise_method_call("result.map"));
140 assert!(is_noise_method_call("graph.all_nodes"));
141 assert!(is_noise_method_call("edge.weight"));
142 assert!(is_noise_method_call("vec.push"));
143 assert!(is_noise_method_call("self.method"));
144 assert!(is_noise_method_call("this.setState"));
145
146 assert!(!is_noise_method_call("node.name.clone"));
148 assert!(!is_noise_method_call("result.unwrap().method"));
149
150 assert!(!is_noise_method_call("my_function"));
152 assert!(!is_noise_method_call("resolve_calls"));
153
154 assert!(!is_noise_method_call("HashMap::new"));
156 assert!(!is_noise_method_call("Database::create"));
157 assert!(!is_noise_method_call("Path.join"));
158 assert!(!is_noise_method_call("React.createElement"));
159 assert!(!is_noise_method_call("JSON.parse"));
160 assert!(!is_noise_method_call("Math.floor"));
161
162 assert!(!is_noise_method_call("os.path.join"));
164 assert!(!is_noise_method_call("bincode::serialize"));
165 assert!(!is_noise_method_call("Ok"));
166 }
167
168 #[test]
169 fn clean_doc_comment_empty_and_unicode() {
170 assert_eq!(clean_doc_comment(""), "");
172
173 assert_eq!(clean_doc_comment(" \n \n"), "");
175
176 let input = "/// Calculates π (pi) value\n/// Returns: 3.14159…";
178 let cleaned = clean_doc_comment(input);
179 assert!(cleaned.contains("π"));
180 assert!(cleaned.contains("3.14159…"));
181
182 let input2 = "# 日本語のドキュメント\n# 関数の説明";
184 let cleaned2 = clean_doc_comment(input2);
185 assert_eq!(cleaned2, "日本語のドキュメント\n関数の説明");
186
187 let input3 = "/// 🚀 Launch the rocket";
189 let cleaned3 = clean_doc_comment(input3);
190 assert!(cleaned3.contains("🚀"));
191 }
192
193 #[test]
194 fn noise_method_call_empty_and_edge_cases() {
195 assert!(!is_noise_method_call(""));
197
198 assert!(is_noise_method_call(".method"));
200
201 assert!(is_noise_method_call("obj."));
203
204 assert!(is_noise_method_call("cls.create"));
206
207 assert!(is_noise_method_call("super.init"));
209
210 assert!(is_noise_method_call("x.foo"));
212
213 assert!(!is_noise_method_call("_private.call"));
216 }
217}