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 Import,
138 Inherits,
139 Implements,
140 TypeUsage,
141}
142
143impl std::str::FromStr for SymbolKind {
144 type Err = String;
145
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 match s {
148 "function" => Ok(SymbolKind::Function),
149 "method" => Ok(SymbolKind::Method),
150 "class" => Ok(SymbolKind::Class),
151 "struct" => Ok(SymbolKind::Struct),
152 "enum" => Ok(SymbolKind::Enum),
153 "interface" => Ok(SymbolKind::Interface),
154 "type" => Ok(SymbolKind::Type),
155 "constant" => Ok(SymbolKind::Constant),
156 "module" => Ok(SymbolKind::Module),
157 "test" => Ok(SymbolKind::Test),
158 "field" => Ok(SymbolKind::Field),
159 "constructor" => Ok(SymbolKind::Constructor),
160 _ => Err(format!("Unknown SymbolKind: {s}")),
161 }
162 }
163}
164
165pub fn symbol_kind_from_str(s: &str) -> Option<SymbolKind> {
167 s.parse().ok()
168}
169
170pub fn visibility_from_str(s: &str) -> Visibility {
172 match s {
173 "public" => Visibility::Public,
174 "crate" => Visibility::Crate,
175 "protected" => Visibility::Protected,
176 _ => Visibility::Private,
177 }
178}
179
180fn symbol_kind_from_node_kind(nk: &codemem_core::NodeKind) -> SymbolKind {
186 match nk {
187 codemem_core::NodeKind::Function => SymbolKind::Function,
188 codemem_core::NodeKind::Method => SymbolKind::Method,
189 codemem_core::NodeKind::Class => SymbolKind::Class,
190 codemem_core::NodeKind::Interface => SymbolKind::Interface,
191 codemem_core::NodeKind::Type => SymbolKind::Type,
192 codemem_core::NodeKind::Constant => SymbolKind::Constant,
193 codemem_core::NodeKind::Module => SymbolKind::Module,
194 codemem_core::NodeKind::Test => SymbolKind::Test,
195 _ => SymbolKind::Function, }
197}
198
199pub fn symbol_from_graph_node(node: &codemem_core::GraphNode) -> Option<Symbol> {
204 let qualified_name = node.id.strip_prefix("sym:")?.to_string();
205
206 let kind = node
208 .payload
209 .get("symbol_kind")
210 .and_then(|v| v.as_str())
211 .and_then(symbol_kind_from_str)
212 .unwrap_or_else(|| symbol_kind_from_node_kind(&node.kind));
213
214 let file_path = node
215 .payload
216 .get("file_path")
217 .and_then(|v| v.as_str())
218 .unwrap_or("")
219 .to_string();
220
221 let signature = node
222 .payload
223 .get("signature")
224 .and_then(|v| v.as_str())
225 .unwrap_or("")
226 .to_string();
227
228 let visibility = node
229 .payload
230 .get("visibility")
231 .and_then(|v| v.as_str())
232 .map(visibility_from_str)
233 .unwrap_or(Visibility::Private);
234
235 let line_start = node
236 .payload
237 .get("line_start")
238 .and_then(|v| v.as_u64())
239 .unwrap_or(0) as usize;
240
241 let line_end = node
242 .payload
243 .get("line_end")
244 .and_then(|v| v.as_u64())
245 .unwrap_or(0) as usize;
246
247 let doc_comment = node
248 .payload
249 .get("doc_comment")
250 .and_then(|v| v.as_str())
251 .map(|s| s.to_string());
252
253 let name = qualified_name
255 .rsplit("::")
256 .next()
257 .unwrap_or(&qualified_name)
258 .to_string();
259
260 let parameters: Vec<Parameter> = node
261 .payload
262 .get("parameters")
263 .and_then(|v| serde_json::from_value(v.clone()).ok())
264 .unwrap_or_default();
265
266 let return_type = node
267 .payload
268 .get("return_type")
269 .and_then(|v| v.as_str())
270 .map(|s| s.to_string());
271
272 let is_async = node
273 .payload
274 .get("is_async")
275 .and_then(|v| v.as_bool())
276 .unwrap_or(false);
277
278 let attributes: Vec<String> = node
279 .payload
280 .get("attributes")
281 .and_then(|v| serde_json::from_value(v.clone()).ok())
282 .unwrap_or_default();
283
284 let throws: Vec<String> = node
285 .payload
286 .get("throws")
287 .and_then(|v| serde_json::from_value(v.clone()).ok())
288 .unwrap_or_default();
289
290 let generic_params = node
291 .payload
292 .get("generic_params")
293 .and_then(|v| v.as_str())
294 .map(|s| s.to_string());
295
296 let is_abstract = node
297 .payload
298 .get("is_abstract")
299 .and_then(|v| v.as_bool())
300 .unwrap_or(false);
301
302 let parent = node
303 .payload
304 .get("parent")
305 .and_then(|v| v.as_str())
306 .map(|s| s.to_string());
307
308 Some(Symbol {
309 name,
310 qualified_name,
311 kind,
312 signature,
313 visibility,
314 file_path,
315 line_start,
316 line_end,
317 doc_comment,
318 parent,
319 parameters,
320 return_type,
321 is_async,
322 attributes,
323 throws,
324 generic_params,
325 is_abstract,
326 })
327}
328
329impl From<SymbolKind> for codemem_core::NodeKind {
330 fn from(kind: SymbolKind) -> Self {
331 match kind {
332 SymbolKind::Function => codemem_core::NodeKind::Function,
333 SymbolKind::Method => codemem_core::NodeKind::Method,
334 SymbolKind::Class => codemem_core::NodeKind::Class,
335 SymbolKind::Struct => codemem_core::NodeKind::Class,
336 SymbolKind::Enum => codemem_core::NodeKind::Class,
337 SymbolKind::Interface => codemem_core::NodeKind::Interface,
338 SymbolKind::Type => codemem_core::NodeKind::Type,
339 SymbolKind::Constant => codemem_core::NodeKind::Constant,
340 SymbolKind::Module => codemem_core::NodeKind::Module,
341 SymbolKind::Test => codemem_core::NodeKind::Test,
342 SymbolKind::Field => codemem_core::NodeKind::Constant,
343 SymbolKind::Constructor => codemem_core::NodeKind::Method,
344 }
345 }
346}
347
348impl std::fmt::Display for ReferenceKind {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 match self {
351 Self::Call => write!(f, "call"),
352 Self::Import => write!(f, "import"),
353 Self::Inherits => write!(f, "inherits"),
354 Self::Implements => write!(f, "implements"),
355 Self::TypeUsage => write!(f, "type_usage"),
356 }
357 }
358}