1use blake3::Hasher;
8use serde::{Deserialize, Serialize};
9use std::path::{Path, PathBuf};
10
11#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct NodeId([u8; 16]);
14
15impl NodeId {
16 pub fn new(repo_id: &str, file_path: &Path, span: &Span, kind: &NodeKind) -> Self {
18 let mut hasher = Hasher::new();
19 hasher.update(repo_id.as_bytes());
20 hasher.update(file_path.to_string_lossy().as_bytes());
21 hasher.update(&span.start_byte.to_le_bytes());
22 hasher.update(&span.end_byte.to_le_bytes());
23 hasher.update(format!("{kind:?}").as_bytes());
24
25 let hash = hasher.finalize();
26 let mut id = [0u8; 16];
27 id.copy_from_slice(&hash.as_bytes()[..16]);
28 Self(id)
29 }
30
31 pub fn to_hex(&self) -> String {
33 hex::encode(self.0)
34 }
35}
36
37impl std::fmt::Debug for NodeId {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "NodeId({})", &self.to_hex()[..8])
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum NodeKind {
47 Module,
49 Class,
51 Function,
53 Method,
55 Parameter,
57 Variable,
59 Call,
61 Import,
63 Literal,
65 Route,
67 SqlQuery,
69 Event,
71
72 Interface,
75 Enum,
77 Package,
79 Annotation,
81 Constructor,
83 Field,
85 StaticBlock,
87 InstanceBlock,
89 TryBlock,
91 CatchClause,
93 FinallyClause,
95 ThrowStatement,
97 Lambda,
99 MethodReference,
101 TypeParameter,
103 WildcardType,
105 ArrayCreation,
107 SynchronizedBlock,
109 AssertStatement,
111
112 Unknown,
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
118#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
119pub enum EdgeKind {
120 Calls,
122 Reads,
124 Writes,
126 Imports,
128 Emits,
130 RoutesTo,
132 Raises,
134 Extends,
136 Implements,
138
139 ImplementsInterface,
142 ImportsPackage,
144 Annotates,
146 TypeParameterBinds,
148 Throws,
150 Catches,
152 Overrides,
154 Accesses,
156 Casts,
158 Instantiates,
160 StaticAccess,
162 Synchronizes,
164 Captures,
166 Contains,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
172pub struct Span {
173 pub start_byte: usize,
175 pub end_byte: usize,
177 pub start_line: usize,
179 pub end_line: usize,
181 pub start_column: usize,
183 pub end_column: usize,
185}
186
187impl Span {
188 pub fn new(
190 start_byte: usize,
191 end_byte: usize,
192 start_line: usize,
193 end_line: usize,
194 start_column: usize,
195 end_column: usize,
196 ) -> Self {
197 Self {
198 start_byte,
199 end_byte,
200 start_line,
201 end_line,
202 start_column,
203 end_column,
204 }
205 }
206
207 pub fn from_node(node: &tree_sitter::Node) -> Self {
209 let start_pos = node.start_position();
210 let end_pos = node.end_position();
211
212 Self {
213 start_byte: node.start_byte(),
214 end_byte: node.end_byte(),
215 start_line: start_pos.row + 1, end_line: end_pos.row + 1,
217 start_column: start_pos.column + 1,
218 end_column: end_pos.column + 1,
219 }
220 }
221}
222
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
225#[serde(rename_all = "lowercase")]
226pub enum Language {
227 Java,
229 Python,
231 Rust,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct Node {
237 pub id: NodeId,
239 pub kind: NodeKind,
241 pub name: String,
243 pub lang: Language,
245 pub file: PathBuf,
247 pub span: Span,
249 pub signature: Option<String>,
251 pub metadata: serde_json::Value,
253}
254
255impl Node {
256 pub fn new(
258 repo_id: &str,
259 kind: NodeKind,
260 name: String,
261 lang: Language,
262 file: PathBuf,
263 span: Span,
264 ) -> Self {
265 let id = NodeId::new(repo_id, &file, &span, &kind);
266 Self {
267 id,
268 kind,
269 name,
270 lang,
271 file,
272 span,
273 signature: None,
274 metadata: serde_json::Value::Null,
275 }
276 }
277
278 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
280 self.metadata = metadata;
281 self
282 }
283
284 pub fn with_signature(mut self, signature: String) -> Self {
286 self.signature = Some(signature);
287 self
288 }
289}
290
291#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
293pub struct Edge {
294 pub source: NodeId,
296 pub target: NodeId,
298 pub kind: EdgeKind,
300}
301
302impl Edge {
303 pub fn new(source: NodeId, target: NodeId, kind: EdgeKind) -> Self {
305 Self {
306 source,
307 target,
308 kind,
309 }
310 }
311}