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 | codemem_core::NodeKind::Trait => 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 codemem_core::NodeKind::Enum => SymbolKind::Enum,
196 codemem_core::NodeKind::Field | codemem_core::NodeKind::Property => SymbolKind::Field,
197 _ => SymbolKind::Function, }
199}
200
201pub fn symbol_from_graph_node(node: &codemem_core::GraphNode) -> Option<Symbol> {
206 let qualified_name = node.id.strip_prefix("sym:")?.to_string();
207
208 let kind = node
210 .payload
211 .get("symbol_kind")
212 .and_then(|v| v.as_str())
213 .and_then(symbol_kind_from_str)
214 .unwrap_or_else(|| symbol_kind_from_node_kind(&node.kind));
215
216 let file_path = node
217 .payload
218 .get("file_path")
219 .and_then(|v| v.as_str())
220 .unwrap_or("")
221 .to_string();
222
223 let signature = node
224 .payload
225 .get("signature")
226 .and_then(|v| v.as_str())
227 .unwrap_or("")
228 .to_string();
229
230 let visibility = node
231 .payload
232 .get("visibility")
233 .and_then(|v| v.as_str())
234 .map(visibility_from_str)
235 .unwrap_or(Visibility::Private);
236
237 let line_start = node
238 .payload
239 .get("line_start")
240 .and_then(|v| v.as_u64())
241 .unwrap_or(0) as usize;
242
243 let line_end = node
244 .payload
245 .get("line_end")
246 .and_then(|v| v.as_u64())
247 .unwrap_or(0) as usize;
248
249 let doc_comment = node
250 .payload
251 .get("doc_comment")
252 .and_then(|v| v.as_str())
253 .map(|s| s.to_string());
254
255 let name = qualified_name
257 .rsplit("::")
258 .next()
259 .unwrap_or(&qualified_name)
260 .to_string();
261
262 let parameters: Vec<Parameter> = node
263 .payload
264 .get("parameters")
265 .and_then(|v| serde_json::from_value(v.clone()).ok())
266 .unwrap_or_default();
267
268 let return_type = node
269 .payload
270 .get("return_type")
271 .and_then(|v| v.as_str())
272 .map(|s| s.to_string());
273
274 let is_async = node
275 .payload
276 .get("is_async")
277 .and_then(|v| v.as_bool())
278 .unwrap_or(false);
279
280 let attributes: Vec<String> = node
281 .payload
282 .get("attributes")
283 .and_then(|v| serde_json::from_value(v.clone()).ok())
284 .unwrap_or_default();
285
286 let throws: Vec<String> = node
287 .payload
288 .get("throws")
289 .and_then(|v| serde_json::from_value(v.clone()).ok())
290 .unwrap_or_default();
291
292 let generic_params = node
293 .payload
294 .get("generic_params")
295 .and_then(|v| v.as_str())
296 .map(|s| s.to_string());
297
298 let is_abstract = node
299 .payload
300 .get("is_abstract")
301 .and_then(|v| v.as_bool())
302 .unwrap_or(false);
303
304 let parent = node
305 .payload
306 .get("parent")
307 .and_then(|v| v.as_str())
308 .map(|s| s.to_string());
309
310 Some(Symbol {
311 name,
312 qualified_name,
313 kind,
314 signature,
315 visibility,
316 file_path,
317 line_start,
318 line_end,
319 doc_comment,
320 parent,
321 parameters,
322 return_type,
323 is_async,
324 attributes,
325 throws,
326 generic_params,
327 is_abstract,
328 })
329}
330
331impl From<SymbolKind> for codemem_core::NodeKind {
332 fn from(kind: SymbolKind) -> Self {
333 match kind {
334 SymbolKind::Function => codemem_core::NodeKind::Function,
335 SymbolKind::Method => codemem_core::NodeKind::Method,
336 SymbolKind::Class => codemem_core::NodeKind::Class,
337 SymbolKind::Struct => codemem_core::NodeKind::Class,
338 SymbolKind::Enum => codemem_core::NodeKind::Enum,
339 SymbolKind::Interface => codemem_core::NodeKind::Interface,
340 SymbolKind::Type => codemem_core::NodeKind::Type,
341 SymbolKind::Constant => codemem_core::NodeKind::Constant,
342 SymbolKind::Module => codemem_core::NodeKind::Module,
343 SymbolKind::Test => codemem_core::NodeKind::Test,
344 SymbolKind::Field => codemem_core::NodeKind::Field,
345 SymbolKind::Constructor => codemem_core::NodeKind::Method,
346 }
347 }
348}
349
350impl std::fmt::Display for ReferenceKind {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 match self {
353 Self::Call => write!(f, "call"),
354 Self::Import => write!(f, "import"),
355 Self::Inherits => write!(f, "inherits"),
356 Self::Implements => write!(f, "implements"),
357 Self::TypeUsage => write!(f, "type_usage"),
358 }
359 }
360}