1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Parameter {
8 pub name: String,
10 pub type_annotation: Option<String>,
12 pub default_value: Option<String>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct Symbol {
19 pub name: String,
21 pub qualified_name: String,
23 pub kind: SymbolKind,
25 pub signature: String,
27 pub visibility: Visibility,
29 pub file_path: String,
31 pub line_start: usize,
33 pub line_end: usize,
35 pub doc_comment: Option<String>,
37 pub parent: Option<String>,
39 #[serde(default)]
41 pub parameters: Vec<Parameter>,
42 #[serde(default)]
44 pub return_type: Option<String>,
45 #[serde(default)]
47 pub is_async: bool,
48 #[serde(default)]
50 pub attributes: Vec<String>,
51 #[serde(default)]
53 pub throws: Vec<String>,
54 #[serde(default)]
56 pub generic_params: Option<String>,
57 #[serde(default)]
59 pub is_abstract: bool,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
64pub enum SymbolKind {
65 Function,
66 Method,
67 Class,
68 Struct,
69 Enum,
70 Interface, Type, Constant,
73 Module,
74 Test,
75 Field, Constructor, }
78
79impl std::fmt::Display for SymbolKind {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 match self {
82 Self::Function => write!(f, "function"),
83 Self::Method => write!(f, "method"),
84 Self::Class => write!(f, "class"),
85 Self::Struct => write!(f, "struct"),
86 Self::Enum => write!(f, "enum"),
87 Self::Interface => write!(f, "interface"),
88 Self::Type => write!(f, "type"),
89 Self::Constant => write!(f, "constant"),
90 Self::Module => write!(f, "module"),
91 Self::Test => write!(f, "test"),
92 Self::Field => write!(f, "field"),
93 Self::Constructor => write!(f, "constructor"),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
100pub enum Visibility {
101 Public,
102 Private,
103 Crate, Protected, }
106
107impl std::fmt::Display for Visibility {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 match self {
110 Self::Public => write!(f, "public"),
111 Self::Private => write!(f, "private"),
112 Self::Crate => write!(f, "crate"),
113 Self::Protected => write!(f, "protected"),
114 }
115 }
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct Reference {
121 pub source_qualified_name: String,
123 pub target_name: String,
125 pub kind: ReferenceKind,
127 pub file_path: String,
129 pub line: usize,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
135pub enum ReferenceKind {
136 Call,
137 Callback,
138 Import,
139 Inherits,
140 Implements,
141 TypeUsage,
142}
143
144impl std::str::FromStr for SymbolKind {
145 type Err = String;
146
147 fn from_str(s: &str) -> Result<Self, Self::Err> {
148 match s {
149 "function" => Ok(SymbolKind::Function),
150 "method" => Ok(SymbolKind::Method),
151 "class" => Ok(SymbolKind::Class),
152 "struct" => Ok(SymbolKind::Struct),
153 "enum" => Ok(SymbolKind::Enum),
154 "interface" => Ok(SymbolKind::Interface),
155 "type" => Ok(SymbolKind::Type),
156 "constant" => Ok(SymbolKind::Constant),
157 "module" => Ok(SymbolKind::Module),
158 "test" => Ok(SymbolKind::Test),
159 "field" => Ok(SymbolKind::Field),
160 "constructor" => Ok(SymbolKind::Constructor),
161 _ => Err(format!("Unknown SymbolKind: {s}")),
162 }
163 }
164}
165
166pub fn symbol_kind_from_str(s: &str) -> Option<SymbolKind> {
168 s.parse().ok()
169}
170
171pub fn visibility_from_str(s: &str) -> Visibility {
173 match s {
174 "public" => Visibility::Public,
175 "crate" => Visibility::Crate,
176 "protected" => Visibility::Protected,
177 _ => Visibility::Private,
178 }
179}
180
181fn symbol_kind_from_node_kind(nk: &codemem_core::NodeKind) -> SymbolKind {
187 match nk {
188 codemem_core::NodeKind::Function => SymbolKind::Function,
189 codemem_core::NodeKind::Method => SymbolKind::Method,
190 codemem_core::NodeKind::Class => SymbolKind::Class,
191 codemem_core::NodeKind::Interface | codemem_core::NodeKind::Trait => SymbolKind::Interface,
192 codemem_core::NodeKind::Type => SymbolKind::Type,
193 codemem_core::NodeKind::Constant => SymbolKind::Constant,
194 codemem_core::NodeKind::Module => SymbolKind::Module,
195 codemem_core::NodeKind::Test => SymbolKind::Test,
196 codemem_core::NodeKind::Enum => SymbolKind::Enum,
197 codemem_core::NodeKind::Field | codemem_core::NodeKind::Property => SymbolKind::Field,
198 _ => SymbolKind::Function, }
200}
201
202pub fn symbol_from_graph_node(node: &codemem_core::GraphNode) -> Option<Symbol> {
207 let qualified_name = node.id.strip_prefix("sym:")?.to_string();
208
209 let kind = node
211 .payload
212 .get("symbol_kind")
213 .and_then(|v| v.as_str())
214 .and_then(symbol_kind_from_str)
215 .unwrap_or_else(|| symbol_kind_from_node_kind(&node.kind));
216
217 let file_path = node
218 .payload
219 .get("file_path")
220 .and_then(|v| v.as_str())
221 .unwrap_or("")
222 .to_string();
223
224 let signature = node
225 .payload
226 .get("signature")
227 .and_then(|v| v.as_str())
228 .unwrap_or("")
229 .to_string();
230
231 let visibility = node
232 .payload
233 .get("visibility")
234 .and_then(|v| v.as_str())
235 .map(visibility_from_str)
236 .unwrap_or(Visibility::Private);
237
238 let line_start = node
239 .payload
240 .get("line_start")
241 .and_then(|v| v.as_u64())
242 .unwrap_or(0) as usize;
243
244 let line_end = node
245 .payload
246 .get("line_end")
247 .and_then(|v| v.as_u64())
248 .unwrap_or(0) as usize;
249
250 let doc_comment = node
251 .payload
252 .get("doc_comment")
253 .and_then(|v| v.as_str())
254 .map(|s| s.to_string());
255
256 let name = qualified_name
258 .rsplit("::")
259 .next()
260 .unwrap_or(&qualified_name)
261 .to_string();
262
263 let parameters: Vec<Parameter> = node
264 .payload
265 .get("parameters")
266 .and_then(|v| serde_json::from_value(v.clone()).ok())
267 .unwrap_or_default();
268
269 let return_type = node
270 .payload
271 .get("return_type")
272 .and_then(|v| v.as_str())
273 .map(|s| s.to_string());
274
275 let is_async = node
276 .payload
277 .get("is_async")
278 .and_then(|v| v.as_bool())
279 .unwrap_or(false);
280
281 let attributes: Vec<String> = node
282 .payload
283 .get("attributes")
284 .and_then(|v| serde_json::from_value(v.clone()).ok())
285 .unwrap_or_default();
286
287 let throws: Vec<String> = node
288 .payload
289 .get("throws")
290 .and_then(|v| serde_json::from_value(v.clone()).ok())
291 .unwrap_or_default();
292
293 let generic_params = node
294 .payload
295 .get("generic_params")
296 .and_then(|v| v.as_str())
297 .map(|s| s.to_string());
298
299 let is_abstract = node
300 .payload
301 .get("is_abstract")
302 .and_then(|v| v.as_bool())
303 .unwrap_or(false);
304
305 let parent = node
306 .payload
307 .get("parent")
308 .and_then(|v| v.as_str())
309 .map(|s| s.to_string());
310
311 Some(Symbol {
312 name,
313 qualified_name,
314 kind,
315 signature,
316 visibility,
317 file_path,
318 line_start,
319 line_end,
320 doc_comment,
321 parent,
322 parameters,
323 return_type,
324 is_async,
325 attributes,
326 throws,
327 generic_params,
328 is_abstract,
329 })
330}
331
332impl From<SymbolKind> for codemem_core::NodeKind {
333 fn from(kind: SymbolKind) -> Self {
334 match kind {
335 SymbolKind::Function => codemem_core::NodeKind::Function,
336 SymbolKind::Method => codemem_core::NodeKind::Method,
337 SymbolKind::Class => codemem_core::NodeKind::Class,
338 SymbolKind::Struct => codemem_core::NodeKind::Class,
339 SymbolKind::Enum => codemem_core::NodeKind::Enum,
340 SymbolKind::Interface => codemem_core::NodeKind::Interface,
341 SymbolKind::Type => codemem_core::NodeKind::Type,
342 SymbolKind::Constant => codemem_core::NodeKind::Constant,
343 SymbolKind::Module => codemem_core::NodeKind::Module,
344 SymbolKind::Test => codemem_core::NodeKind::Test,
345 SymbolKind::Field => codemem_core::NodeKind::Field,
346 SymbolKind::Constructor => codemem_core::NodeKind::Method,
347 }
348 }
349}
350
351impl std::fmt::Display for ReferenceKind {
352 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353 match self {
354 Self::Call => write!(f, "call"),
355 Self::Callback => write!(f, "callback"),
356 Self::Import => write!(f, "import"),
357 Self::Inherits => write!(f, "inherits"),
358 Self::Implements => write!(f, "implements"),
359 Self::TypeUsage => write!(f, "type_usage"),
360 }
361 }
362}