1use serde::{Deserialize, Serialize};
2use strum::{Display, EnumString};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
7#[serde(rename_all = "snake_case")]
8#[strum(serialize_all = "snake_case")]
9pub enum SymbolKind {
10 Class,
11 Struct,
12 Trait,
13 Enum,
14 Function,
15 Method,
16 Module,
17 Interface,
18 Const,
19 TypeAlias,
20 Impl,
21 Variable,
22 Component,
23 Annotation,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
27#[serde(rename_all = "snake_case")]
28#[strum(serialize_all = "snake_case")]
29pub enum ScanStatus {
30 Running,
31 Completed,
32 Failed,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
36#[serde(rename_all = "snake_case")]
37#[strum(serialize_all = "snake_case")]
38pub enum ParseStatus {
39 Ok,
40 Partial,
41 Error,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
45#[serde(rename_all = "snake_case")]
46#[strum(serialize_all = "snake_case")]
47pub enum DepType {
48 Imports,
49 Calls,
50 Extends,
51 Implements,
52 TypeRef,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
56#[serde(rename_all = "snake_case")]
57#[strum(serialize_all = "snake_case")]
58pub enum DepLevel {
59 File,
60 Symbol,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
64#[serde(rename_all = "snake_case")]
65#[strum(serialize_all = "snake_case")]
66pub enum FileChangeStatus {
67 Added,
68 Modified,
69 Deleted,
70 Renamed,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Scan {
77 pub id: i64,
78 pub started_at: u64,
79 pub completed_at: Option<u64>,
80 pub status: ScanStatus,
81 pub file_count: i64,
82 pub symbol_count: i64,
83 pub dep_count: i64,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct File {
88 pub id: i64,
89 pub scan_id: i64,
90 pub path: String,
91 pub language: String,
92 pub size_bytes: i64,
93 pub content_hash: String,
94 pub last_modified: u64,
95 pub parse_status: ParseStatus,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct Symbol {
100 pub id: i64,
101 pub file_id: i64,
102 pub parent_id: Option<i64>,
103 pub name: String,
104 pub kind: SymbolKind,
105 pub signature: Option<String>,
106 pub summary: Option<String>,
107 pub start_line: i64,
108 pub end_line: i64,
109 pub start_byte: i64,
110 pub end_byte: i64,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Dependency {
115 pub id: i64,
116 pub source_file_id: i64,
117 pub source_symbol_id: Option<i64>,
118 pub target_file_id: Option<i64>,
119 pub target_symbol_id: Option<i64>,
120 pub dep_type: DepType,
121 pub level: DepLevel,
122 pub raw_import: Option<String>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Config {
127 pub key: String,
128 pub value: String,
129 pub updated_at: u64,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct SymbolResult {
135 pub id: i64,
136 pub name: String,
137 pub kind: SymbolKind,
138 pub file_path: String,
139 pub start_line: i64,
140 pub end_line: i64,
141 pub signature: Option<String>,
142 pub summary: Option<String>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct SymbolWithParent {
148 pub id: i64,
149 pub name: String,
150 pub kind: SymbolKind,
151 pub file_path: String,
152 pub start_line: i64,
153 pub end_line: i64,
154 pub signature: Option<String>,
155 pub parent_name: Option<String>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct ImpactEntry {
161 pub symbol_id: i64,
162 pub symbol_name: String,
163 pub symbol_kind: SymbolKind,
164 pub file_path: String,
165 pub depth: i64,
166 pub dep_type: DepType,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct PathStep {
172 pub symbol_id: i64,
173 pub symbol_name: String,
174 pub file_path: String,
175 pub dep_type: DepType,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct InspectResult {
181 pub symbol: Symbol,
182 pub children: Vec<Symbol>,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ImpactResult {
188 pub symbol_id: i64,
189 pub entries: Vec<ImpactEntry>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct WhyResult {
195 pub from_name: String,
196 pub to_name: String,
197 pub path: Vec<PathStep>,
198}
199
200#[derive(Debug, Clone)]
202pub struct VcsFileChange {
203 pub path: String,
204 pub old_path: Option<String>,
205 pub status: FileChangeStatus,
206 pub changed_lines: Vec<(i64, i64)>,
207}
208
209#[derive(Debug, Clone)]
213pub struct ExtractedSymbol {
214 pub name: String,
215 pub kind: SymbolKind,
216 pub signature: Option<String>,
217 pub start_line: usize,
218 pub end_line: usize,
219 pub start_byte: usize,
220 pub end_byte: usize,
221 pub parent_index: Option<usize>, }
223
224#[derive(Debug, Clone)]
226pub struct ExtractedImport {
227 pub path: String,
228 pub imported_symbols: Vec<String>, }
230
231#[derive(Debug, Clone)]
233pub struct ExtractedCall {
234 pub caller_name: String, pub callee_name: String, pub line: usize,
237}
238
239#[derive(Debug, Clone)]
241pub struct ExtractedTypeRef {
242 pub from_symbol: String, pub to_type: String, pub line: usize,
245}
246
247#[derive(Debug)]
249pub struct ParseResult {
250 pub symbols: Vec<ExtractedSymbol>,
251 pub imports: Vec<ExtractedImport>,
252 pub calls: Vec<ExtractedCall>,
253 pub type_refs: Vec<ExtractedTypeRef>,
254 pub has_errors: bool,
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260
261 #[test]
262 fn test_symbol_kind_roundtrip() {
263 let variants = [
264 SymbolKind::Class,
265 SymbolKind::Struct,
266 SymbolKind::Trait,
267 SymbolKind::Enum,
268 SymbolKind::Function,
269 SymbolKind::Method,
270 SymbolKind::Module,
271 SymbolKind::Interface,
272 SymbolKind::Const,
273 SymbolKind::TypeAlias,
274 SymbolKind::Impl,
275 SymbolKind::Variable,
276 SymbolKind::Component,
277 SymbolKind::Annotation,
278 ];
279 for v in variants {
280 let s = v.to_string();
281 let parsed: SymbolKind = s.parse().unwrap();
282 assert_eq!(v, parsed, "roundtrip failed for {:?}", v);
283 }
284 }
285
286 #[test]
287 fn test_symbol_kind_unknown() {
288 let result = "bogus".parse::<SymbolKind>();
289 assert!(result.is_err());
290 }
291
292 #[test]
293 fn test_scan_status_roundtrip() {
294 for v in [
295 ScanStatus::Running,
296 ScanStatus::Completed,
297 ScanStatus::Failed,
298 ] {
299 let parsed: ScanStatus = v.to_string().parse().unwrap();
300 assert_eq!(v, parsed);
301 }
302 }
303
304 #[test]
305 fn test_scan_status_unknown() {
306 assert!("bogus".parse::<ScanStatus>().is_err());
307 }
308
309 #[test]
310 fn test_parse_status_roundtrip() {
311 for v in [ParseStatus::Ok, ParseStatus::Partial, ParseStatus::Error] {
312 let parsed: ParseStatus = v.to_string().parse().unwrap();
313 assert_eq!(v, parsed);
314 }
315 }
316
317 #[test]
318 fn test_parse_status_unknown() {
319 assert!("bogus".parse::<ParseStatus>().is_err());
320 }
321
322 #[test]
323 fn test_dep_type_roundtrip() {
324 for v in [
325 DepType::Imports,
326 DepType::Calls,
327 DepType::Extends,
328 DepType::Implements,
329 DepType::TypeRef,
330 ] {
331 let parsed: DepType = v.to_string().parse().unwrap();
332 assert_eq!(v, parsed);
333 }
334 }
335
336 #[test]
337 fn test_dep_type_unknown() {
338 assert!("bogus".parse::<DepType>().is_err());
339 }
340
341 #[test]
342 fn test_dep_level_roundtrip() {
343 for v in [DepLevel::File, DepLevel::Symbol] {
344 let parsed: DepLevel = v.to_string().parse().unwrap();
345 assert_eq!(v, parsed);
346 }
347 }
348
349 #[test]
350 fn test_dep_level_unknown() {
351 assert!("bogus".parse::<DepLevel>().is_err());
352 }
353
354 #[test]
355 fn test_file_change_status_roundtrip() {
356 for v in [
357 FileChangeStatus::Added,
358 FileChangeStatus::Modified,
359 FileChangeStatus::Deleted,
360 FileChangeStatus::Renamed,
361 ] {
362 let parsed: FileChangeStatus = v.to_string().parse().unwrap();
363 assert_eq!(v, parsed);
364 }
365 }
366
367 #[test]
368 fn test_file_change_status_unknown() {
369 assert!("bogus".parse::<FileChangeStatus>().is_err());
370 }
371}