Skip to main content

infigraph_core/model/
mod.rs

1use serde::{Deserialize, Serialize};
2
3/// The kind of symbol extracted from source code.
4/// Language-agnostic — Python classes, Rust structs, Java interfaces all map here.
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub enum SymbolKind {
7    Function,
8    Method,
9    Class,
10    Struct,
11    Interface,
12    Trait,
13    Enum,
14    Module,
15    Variable,
16    Constant,
17    Test,
18    Section,
19    Route,
20    Field,
21}
22
23impl SymbolKind {
24    pub fn as_str(&self) -> &'static str {
25        match self {
26            Self::Function => "Function",
27            Self::Method => "Method",
28            Self::Class => "Class",
29            Self::Struct => "Struct",
30            Self::Interface => "Interface",
31            Self::Trait => "Trait",
32            Self::Enum => "Enum",
33            Self::Module => "Module",
34            Self::Variable => "Variable",
35            Self::Constant => "Constant",
36            Self::Test => "Test",
37            Self::Section => "Section",
38            Self::Route => "Route",
39            Self::Field => "Field",
40        }
41    }
42}
43
44/// A location span in a source file.
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct Span {
47    pub file: String,
48    pub start_line: u32,
49    pub start_col: u32,
50    pub end_line: u32,
51    pub end_col: u32,
52}
53
54/// A symbol (entity) extracted from the AST.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct Symbol {
57    /// Unique ID: "file::name" or "file::class::method"
58    pub id: String,
59    pub name: String,
60    pub kind: SymbolKind,
61    pub span: Span,
62    /// Hash of the AST subtree — used for incremental analysis
63    pub signature_hash: String,
64    /// Parent symbol ID (e.g., method's class)
65    pub parent: Option<String>,
66    /// Language this was extracted from
67    pub language: String,
68    /// Visibility: public, private, etc.
69    pub visibility: Option<String>,
70    /// Docstring extracted from the AST
71    pub docstring: Option<String>,
72    /// Cyclomatic complexity (1 = no branches; only set for Function/Method/Test)
73    pub complexity: u32,
74    /// Function/method parameter list (raw text from AST)
75    pub parameters: Option<String>,
76    /// Return type annotation (raw text from AST)
77    pub return_type: Option<String>,
78}
79
80/// The kind of relationship between two symbols.
81#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
82pub enum RelationKind {
83    Calls,
84    CalledBy,
85    Imports,
86    ImportedBy,
87    Contains,
88    ContainedBy,
89    Inherits,
90    InheritedBy,
91    Implements,
92    ImplementedBy,
93    Reads,
94    Writes,
95    TestedBy,
96    Tests,
97    Custom(String),
98}
99
100impl RelationKind {
101    pub fn as_str(&self) -> &str {
102        match self {
103            Self::Calls => "CALLS",
104            Self::CalledBy => "CALLED_BY",
105            Self::Imports => "IMPORTS",
106            Self::ImportedBy => "IMPORTED_BY",
107            Self::Contains => "CONTAINS",
108            Self::ContainedBy => "CONTAINED_BY",
109            Self::Inherits => "INHERITS",
110            Self::InheritedBy => "INHERITED_BY",
111            Self::Implements => "IMPLEMENTS",
112            Self::ImplementedBy => "IMPLEMENTED_BY",
113            Self::Reads => "READS",
114            Self::Writes => "WRITES",
115            Self::TestedBy => "TESTED_BY",
116            Self::Tests => "TESTS",
117            Self::Custom(name) => name.as_str(),
118        }
119    }
120}
121
122/// A relationship (edge) between two symbols.
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct Relation {
125    pub source_id: String,
126    pub target_id: String,
127    pub kind: RelationKind,
128    pub span: Option<Span>,
129    #[serde(default, skip_serializing_if = "Option::is_none")]
130    pub receiver: Option<String>,
131}
132
133/// Kind of cross-language bridge detected.
134#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
135pub enum BridgeKind {
136    /// Rust `extern "C"` / C `extern` FFI
137    Ffi,
138    /// Java Native Interface
139    Jni,
140    /// Go cgo (`import "C"`)
141    Cgo,
142    /// gRPC service definition or generated stub call
143    Grpc,
144    /// .NET P/Invoke (`DllImport`)
145    PInvoke,
146    /// Python `ctypes` / `cffi` foreign call
147    Ctypes,
148    /// WASM import/export boundary
149    Wasm,
150    /// COM interop / CLR bridge (VB6, VBA)
151    Com,
152    /// Generic foreign call pattern
153    Other(String),
154}
155
156impl BridgeKind {
157    pub fn as_str(&self) -> &str {
158        match self {
159            Self::Ffi => "FFI",
160            Self::Jni => "JNI",
161            Self::Cgo => "CGO",
162            Self::Grpc => "GRPC",
163            Self::PInvoke => "P_INVOKE",
164            Self::Ctypes => "CTYPES",
165            Self::Wasm => "WASM",
166            Self::Com => "COM",
167            Self::Other(s) => s,
168        }
169    }
170}
171
172/// A detected cross-language bridge point.
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct Bridge {
175    pub file: String,
176    pub line: u32,
177    pub kind: BridgeKind,
178    /// Name of the foreign symbol/function being bridged to
179    pub foreign_symbol: String,
180    /// Source language
181    pub source_language: String,
182    /// Target language (if determinable)
183    pub target_language: Option<String>,
184    /// Additional context (e.g., library name, proto service)
185    pub detail: String,
186}
187
188/// The kind of control-flow statement extracted from a function body.
189#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
190pub enum StatementKind {
191    If,
192    ElseIf,
193    Else,
194    For,
195    While,
196    DoWhile,
197    Loop,
198    Match,
199    Case,
200    Try,
201    Catch,
202    Ternary,
203    Guard,
204}
205
206impl StatementKind {
207    pub fn as_str(&self) -> &'static str {
208        match self {
209            Self::If => "If",
210            Self::ElseIf => "ElseIf",
211            Self::Else => "Else",
212            Self::For => "For",
213            Self::While => "While",
214            Self::DoWhile => "DoWhile",
215            Self::Loop => "Loop",
216            Self::Match => "Match",
217            Self::Case => "Case",
218            Self::Try => "Try",
219            Self::Catch => "Catch",
220            Self::Ternary => "Ternary",
221            Self::Guard => "Guard",
222        }
223    }
224}
225
226/// A control-flow statement inside a function/method body.
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct Statement {
229    pub id: String,
230    pub kind: StatementKind,
231    pub condition: String,
232    pub start_line: u32,
233    pub end_line: u32,
234    pub depth: u32,
235    pub parent_symbol: String,
236}
237
238/// Result of extracting a single file.
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct FileExtraction {
241    pub file: String,
242    pub language: String,
243    pub content_hash: String,
244    pub symbols: Vec<Symbol>,
245    pub relations: Vec<Relation>,
246    pub statements: Vec<Statement>,
247}