1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5#[serde(rename_all = "lowercase")]
6pub enum Language {
7 TypeScript,
8 JavaScript,
9 Tsx,
10 Jsx,
11 Python,
12 Go,
13 Rust,
14 Java,
15 C,
16 Cpp,
17 CSharp,
18 Php,
19 Ruby,
20 Swift,
21 Kotlin,
22 Dart,
23 Svelte,
24 Vue,
25 Liquid,
26 Pascal,
27 Scala,
28 MoonBit,
29 Unknown,
30}
31
32impl Language {
33 pub fn as_str(self) -> &'static str {
34 match self {
35 Self::TypeScript => "typescript",
36 Self::JavaScript => "javascript",
37 Self::Tsx => "tsx",
38 Self::Jsx => "jsx",
39 Self::Python => "python",
40 Self::Go => "go",
41 Self::Rust => "rust",
42 Self::Java => "java",
43 Self::C => "c",
44 Self::Cpp => "cpp",
45 Self::CSharp => "csharp",
46 Self::Php => "php",
47 Self::Ruby => "ruby",
48 Self::Swift => "swift",
49 Self::Kotlin => "kotlin",
50 Self::Dart => "dart",
51 Self::Svelte => "svelte",
52 Self::Vue => "vue",
53 Self::Liquid => "liquid",
54 Self::Pascal => "pascal",
55 Self::Scala => "scala",
56 Self::MoonBit => "moonbit",
57 Self::Unknown => "unknown",
58 }
59 }
60
61 pub fn is_unknown(self) -> bool {
62 self == Self::Unknown
63 }
64}
65
66impl fmt::Display for Language {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 f.write_str(self.as_str())
69 }
70}
71
72impl std::str::FromStr for Language {
73 type Err = ();
74
75 fn from_str(s: &str) -> Result<Self, Self::Err> {
76 Ok(match s {
77 "typescript" => Self::TypeScript,
78 "javascript" => Self::JavaScript,
79 "tsx" => Self::Tsx,
80 "jsx" => Self::Jsx,
81 "python" => Self::Python,
82 "go" => Self::Go,
83 "rust" => Self::Rust,
84 "java" => Self::Java,
85 "c" => Self::C,
86 "cpp" => Self::Cpp,
87 "csharp" => Self::CSharp,
88 "php" => Self::Php,
89 "ruby" => Self::Ruby,
90 "swift" => Self::Swift,
91 "kotlin" => Self::Kotlin,
92 "dart" => Self::Dart,
93 "svelte" => Self::Svelte,
94 "vue" => Self::Vue,
95 "liquid" => Self::Liquid,
96 "pascal" => Self::Pascal,
97 "scala" => Self::Scala,
98 "moonbit" => Self::MoonBit,
99 _ => Self::Unknown,
100 })
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
105#[serde(rename_all = "snake_case")]
106pub enum NodeKind {
107 File,
108 Module,
109 Class,
110 Struct,
111 Interface,
112 Trait,
113 Protocol,
114 Function,
115 Method,
116 Property,
117 Field,
118 Variable,
119 Constant,
120 Enum,
121 EnumMember,
122 TypeAlias,
123 Namespace,
124 Parameter,
125 Import,
126 Export,
127 Route,
128 Component,
129}
130
131impl NodeKind {
132 pub fn as_str(self) -> &'static str {
133 match self {
134 Self::File => "file",
135 Self::Module => "module",
136 Self::Class => "class",
137 Self::Struct => "struct",
138 Self::Interface => "interface",
139 Self::Trait => "trait",
140 Self::Protocol => "protocol",
141 Self::Function => "function",
142 Self::Method => "method",
143 Self::Property => "property",
144 Self::Field => "field",
145 Self::Variable => "variable",
146 Self::Constant => "constant",
147 Self::Enum => "enum",
148 Self::EnumMember => "enum_member",
149 Self::TypeAlias => "type_alias",
150 Self::Namespace => "namespace",
151 Self::Parameter => "parameter",
152 Self::Import => "import",
153 Self::Export => "export",
154 Self::Route => "route",
155 Self::Component => "component",
156 }
157 }
158}
159
160impl fmt::Display for NodeKind {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.write_str(self.as_str())
163 }
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
167#[serde(rename_all = "snake_case")]
168pub enum EdgeKind {
169 Contains,
170 Calls,
171 Imports,
172 Exports,
173 Extends,
174 Implements,
175 References,
176 TypeOf,
177 Returns,
178 Instantiates,
179 Overrides,
180 Decorates,
181}
182
183impl EdgeKind {
184 pub fn as_str(self) -> &'static str {
185 match self {
186 Self::Contains => "contains",
187 Self::Calls => "calls",
188 Self::Imports => "imports",
189 Self::Exports => "exports",
190 Self::Extends => "extends",
191 Self::Implements => "implements",
192 Self::References => "references",
193 Self::TypeOf => "type_of",
194 Self::Returns => "returns",
195 Self::Instantiates => "instantiates",
196 Self::Overrides => "overrides",
197 Self::Decorates => "decorates",
198 }
199 }
200}
201
202impl fmt::Display for EdgeKind {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 f.write_str(self.as_str())
205 }
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct Node {
210 pub id: String,
211 pub kind: NodeKind,
212 pub name: String,
213 pub qualified_name: String,
214 pub file_path: String,
215 pub language: Language,
216 pub start_line: i64,
217 pub end_line: i64,
218 pub start_column: i64,
219 pub end_column: i64,
220 pub docstring: Option<String>,
221 pub signature: Option<String>,
222 pub visibility: Option<String>,
223 pub is_exported: bool,
224 pub is_async: bool,
225 pub is_static: bool,
226 pub is_abstract: bool,
227 pub updated_at: i64,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct Edge {
232 pub id: Option<i64>,
233 pub source: String,
234 pub target: String,
235 pub kind: EdgeKind,
236 pub line: Option<i64>,
237 pub col: Option<i64>,
238 pub provenance: Option<String>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct UnresolvedReference {
243 pub from_node_id: String,
244 pub reference_name: String,
245 pub reference_kind: EdgeKind,
246 pub line: i64,
247 pub column: i64,
248 pub file_path: String,
249 pub language: Language,
250}
251
252#[derive(Debug, Clone)]
253pub struct ExtractionResult {
254 pub nodes: Vec<Node>,
255 pub edges: Vec<Edge>,
256 pub unresolved_references: Vec<UnresolvedReference>,
257}
258
259#[derive(Debug, Clone)]
260pub struct FileRecord {
261 pub path: String,
262 pub content_hash: String,
263 pub language: Language,
264 pub size: u64,
265 pub modified_at: i64,
266 pub indexed_at: i64,
267 pub node_count: i64,
268}
269
270#[derive(Debug, Clone, Copy, PartialEq, Eq)]
271pub enum FileListFormat {
272 Grouped,
273 Flat,
274 Tree,
275}
276
277impl std::str::FromStr for FileListFormat {
278 type Err = ();
279
280 fn from_str(s: &str) -> Result<Self, Self::Err> {
281 Ok(match s {
282 "grouped" => Self::Grouped,
283 "flat" => Self::Flat,
284 "tree" => Self::Tree,
285 _ => return Err(()),
286 })
287 }
288}
289
290#[derive(Debug, Clone)]
291pub struct FileListOptions {
292 pub format: FileListFormat,
293 pub path_filter: Option<String>,
294 pub pattern: Option<String>,
295 pub include_metadata: bool,
296 pub max_depth: Option<usize>,
297}
298
299#[derive(Debug, Clone, Serialize)]
300#[serde(rename_all = "camelCase")]
301pub struct FileListReport {
302 pub format: String,
303 pub path_filter: Option<String>,
304 pub pattern: Option<String>,
305 pub include_metadata: bool,
306 pub max_depth: Option<usize>,
307 pub total_files: usize,
308 pub files: Vec<FileListEntry>,
309 pub groups: Vec<FileLanguageGroup>,
310 pub tree: Vec<FileTreeEntry>,
311}
312
313#[derive(Debug, Clone, Serialize)]
314#[serde(rename_all = "camelCase")]
315pub struct FileListEntry {
316 pub path: String,
317 pub language: Language,
318 pub node_count: i64,
319 pub size: Option<u64>,
320 pub modified_at: Option<i64>,
321 pub indexed_at: Option<i64>,
322}
323
324#[derive(Debug, Clone, Serialize)]
325pub struct FileLanguageGroup {
326 pub language: Language,
327 pub count: usize,
328 pub files: Vec<FileListEntry>,
329}
330
331#[derive(Debug, Clone, Serialize)]
332#[serde(rename_all = "camelCase")]
333pub struct FileTreeEntry {
334 pub name: String,
335 pub path: String,
336 pub kind: String,
337 pub language: Option<Language>,
338 pub node_count: Option<i64>,
339 pub size: Option<u64>,
340 pub children: Vec<FileTreeEntry>,
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
344#[serde(rename_all = "snake_case")]
345pub enum IndexErrorCategory {
346 Read,
347 Parse,
348 Unsupported,
349 Lock,
350}
351
352impl IndexErrorCategory {
353 pub fn as_str(self) -> &'static str {
354 match self {
355 Self::Read => "read",
356 Self::Parse => "parse",
357 Self::Unsupported => "unsupported",
358 Self::Lock => "lock",
359 }
360 }
361}
362
363impl fmt::Display for IndexErrorCategory {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 f.write_str(self.as_str())
366 }
367}
368
369#[derive(Debug, Clone, Serialize)]
370pub struct IndexError {
371 pub category: IndexErrorCategory,
372 pub path: String,
373 pub message: String,
374}
375
376#[derive(Debug, Clone, Default, Serialize)]
377pub struct IndexResult {
378 pub success: bool,
379 pub files_indexed: i64,
380 pub files_skipped: i64,
381 pub files_deleted: i64,
382 pub files_errored: i64,
383 pub nodes_created: i64,
384 pub edges_created: i64,
385 pub errors: Vec<IndexError>,
386 pub duration_ms: i64,
387}
388
389#[derive(Debug, Clone, Default, Serialize)]
390pub struct GraphStats {
391 pub file_count: i64,
392 pub node_count: i64,
393 pub edge_count: i64,
394 pub db_size_bytes: i64,
395 pub oldest_indexed_at: Option<i64>,
396 pub last_indexed_at: Option<i64>,
397 pub newest_modified_at: Option<i64>,
398 pub stale_file_count: i64,
399 pub files_by_language: Vec<(String, i64)>,
400 pub nodes_by_kind: Vec<(String, i64)>,
401}
402
403#[derive(Debug, Clone, Default)]
404pub struct SearchOptions {
405 pub limit: i64,
406 pub kind: Option<NodeKind>,
407 pub language: Option<Language>,
408}
409
410#[derive(Debug, Clone, Serialize)]
411pub struct SearchResult {
412 pub node: Node,
413 pub score: f64,
414}
415
416#[derive(Debug, Clone, Serialize)]
417pub struct ContextReport {
418 pub query: String,
419 pub search_terms: Vec<String>,
420 pub matches: Vec<ContextMatch>,
421 pub files: Vec<ContextFileSummary>,
422 pub symbols: Vec<ContextSymbolSummary>,
423 pub warnings: Vec<String>,
424}
425
426#[derive(Debug, Clone, Serialize)]
427pub struct ContextMatch {
428 pub search_term: String,
429 pub reason: String,
430 pub score: f64,
431 pub node: Node,
432 pub code: Option<String>,
433}
434
435#[derive(Debug, Clone, Serialize)]
436pub struct ContextFileSummary {
437 pub path: String,
438 pub language: Language,
439 pub match_count: i64,
440 pub symbols: Vec<String>,
441}
442
443#[derive(Debug, Clone, Serialize)]
444pub struct ContextSymbolSummary {
445 pub name: String,
446 pub kind: NodeKind,
447 pub file_path: String,
448 pub start_line: i64,
449}
450
451#[derive(Debug, Clone, Serialize)]
452#[serde(rename_all = "camelCase")]
453pub struct ExploreReport {
454 pub query: String,
455 pub max_files: usize,
456 pub budget_guidance: String,
457 pub source_files: Vec<ExploreSourceFile>,
458 pub relationships: Vec<ExploreRelationship>,
459 pub additional_files: Vec<String>,
460 pub warnings: Vec<String>,
461 pub truncated: bool,
462 pub truncated_reason: Option<String>,
463}
464
465#[derive(Debug, Clone, Serialize)]
466#[serde(rename_all = "camelCase")]
467pub struct ExploreSourceFile {
468 pub path: String,
469 pub language: Language,
470 pub sections: Vec<ExploreSourceSection>,
471}
472
473#[derive(Debug, Clone, Serialize)]
474#[serde(rename_all = "camelCase")]
475pub struct ExploreSourceSection {
476 pub symbol: String,
477 pub kind: NodeKind,
478 pub start_line: i64,
479 pub end_line: i64,
480 pub reason: String,
481 pub code: String,
482 pub truncated: bool,
483}
484
485#[derive(Debug, Clone, Serialize)]
486#[serde(rename_all = "camelCase")]
487pub struct ExploreRelationship {
488 pub source: String,
489 pub target: String,
490 pub kind: EdgeKind,
491 pub file_path: String,
492 pub direction: String,
493}
494
495#[derive(Debug, Clone, Serialize)]
496#[serde(rename_all = "camelCase")]
497pub struct AffectedReport {
498 pub changed_files: Vec<String>,
499 pub affected_tests: Vec<String>,
500 pub debug: Vec<AffectedDebugEntry>,
501 pub warnings: Vec<String>,
502}
503
504#[derive(Debug, Clone, Serialize)]
505#[serde(rename_all = "camelCase")]
506pub struct AffectedDebugEntry {
507 pub changed_file: String,
508 pub reason: String,
509 pub matched_tests: Vec<String>,
510 pub matched_by: AffectedMatchSources,
511}
512
513#[derive(Debug, Clone, Serialize)]
514#[serde(rename_all = "camelCase")]
515pub struct AffectedMatchSources {
516 pub direct_test_input: Vec<String>,
517 pub import_dependents: Vec<String>,
518 pub moonbit_same_package: Vec<String>,
519 pub moonbit_package_dependents: Vec<String>,
520 pub rust_name_heuristic: Vec<String>,
521 pub rust_workspace_heuristic: Vec<String>,
522}
523
524#[derive(Debug, Clone, Serialize)]
525pub struct NodeEdge {
526 pub node: Node,
527 pub edge: Edge,
528 pub depth: usize,
529}
530
531#[derive(Debug, Clone, Serialize)]
532pub struct GraphPath {
533 pub nodes: Vec<Node>,
534 pub edges: Vec<Edge>,
535}