gitcortex_core/schema.rs
1use serde::{Deserialize, Serialize};
2
3/// Bumped whenever the on-disk graph schema changes.
4/// Stores compare this against the persisted version and re-index on mismatch.
5pub const SCHEMA_VERSION: u32 = 12;
6
7/// Every named, referenceable syntactic entity becomes a node of one of these kinds.
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum NodeKind {
11 Folder,
12 File,
13 Module,
14 Struct,
15 Enum,
16 /// Rust trait. Languages with a separate notion of interface use [`NodeKind::Interface`].
17 Trait,
18 /// Language interface (Java, TypeScript, Go) — semantically distinct from Rust traits.
19 Interface,
20 TypeAlias,
21 Function,
22 Method,
23 /// Property (Python `@property`, TypeScript `readonly` field, getter/setter pair).
24 Property,
25 Constant,
26 Macro,
27 /// Decorator / annotation declaration (e.g. `@dataclass`, `@Override`, `#[derive(...)]`).
28 Annotation,
29 /// Member of an enum (`Color::Red`, `Direction.NORTH`).
30 EnumMember,
31 /// A Markdown heading section (`## Installation`). File-level prose lives
32 /// directly on the synthesized `File` node; this kind only covers headings.
33 Section,
34}
35
36impl std::fmt::Display for NodeKind {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 let s = match self {
39 NodeKind::Folder => "folder",
40 NodeKind::File => "file",
41 NodeKind::Module => "module",
42 NodeKind::Struct => "struct",
43 NodeKind::Enum => "enum",
44 NodeKind::Trait => "trait",
45 NodeKind::Interface => "interface",
46 NodeKind::TypeAlias => "type_alias",
47 NodeKind::Function => "function",
48 NodeKind::Method => "method",
49 NodeKind::Property => "property",
50 NodeKind::Constant => "constant",
51 NodeKind::Macro => "macro",
52 NodeKind::Annotation => "annotation",
53 NodeKind::EnumMember => "enum_member",
54 NodeKind::Section => "section",
55 };
56 f.write_str(s)
57 }
58}
59
60/// Directed relationship between two nodes.
61#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
62#[serde(rename_all = "snake_case")]
63pub enum EdgeKind {
64 /// Parent–child containment: File→Module, Module→Struct, Struct→Method.
65 Contains,
66 /// Resolved call site: Function→Function or Method→Method.
67 Calls,
68 /// `impl Trait for Struct`, `class Foo implements Bar` — Struct→Trait/Interface.
69 Implements,
70 /// `class Foo extends Bar`, embedded struct in Go — subtype→supertype.
71 /// Distinct from `Implements`: this is "is-a" inheritance vs "can-do" interface
72 /// satisfaction.
73 Inherits,
74 /// A type appears as a parameter or return type: fn→Struct/Trait.
75 Uses,
76 /// `use path::to::Thing` import.
77 Imports,
78 /// A symbol is decorated/annotated by another (`@Override`, `@dataclass`,
79 /// `#[derive(Debug)]`).
80 Annotated,
81 /// Java `throws ExceptionType` — method→exception class.
82 Throws,
83 /// A Markdown section (or file-level prose) mentions a code symbol, via
84 /// an inline code-span or link text matching a known identifier.
85 /// Source can be cross-language by design (docs reference any language).
86 References,
87}
88
89impl std::fmt::Display for EdgeKind {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 let s = match self {
92 EdgeKind::Contains => "contains",
93 EdgeKind::Calls => "calls",
94 EdgeKind::Implements => "implements",
95 EdgeKind::Inherits => "inherits",
96 EdgeKind::Uses => "uses",
97 EdgeKind::Imports => "imports",
98 EdgeKind::Annotated => "annotated",
99 EdgeKind::Throws => "throws",
100 EdgeKind::References => "references",
101 };
102 f.write_str(s)
103 }
104}
105
106/// How confident the indexer is that an edge is real. Direct edges resolved
107/// within a single file are `Extracted`; cross-file edges resolved by matching
108/// an unqualified name against the symbol table are `Inferred` (a same-named
109/// symbol in another module could in principle be the true target).
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
111#[serde(rename_all = "snake_case")]
112pub enum EdgeConfidence {
113 /// Directly observed in the source (same-file resolution). High confidence.
114 #[default]
115 Extracted,
116 /// Resolved cross-file by name match. Lower confidence.
117 Inferred,
118}
119
120impl std::fmt::Display for EdgeConfidence {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 f.write_str(match self {
123 EdgeConfidence::Extracted => "extracted",
124 EdgeConfidence::Inferred => "inferred",
125 })
126 }
127}
128
129impl EdgeConfidence {
130 /// Parse from the stored string form; unknown/empty defaults to `Extracted`.
131 pub fn from_label(s: &str) -> Self {
132 match s {
133 "inferred" => EdgeConfidence::Inferred,
134 _ => EdgeConfidence::Extracted,
135 }
136 }
137}
138
139/// Symbol visibility in the source language.
140#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
141#[serde(rename_all = "snake_case")]
142pub enum Visibility {
143 #[default]
144 Private,
145 PubCrate,
146 Pub,
147}
148
149impl std::fmt::Display for Visibility {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Visibility::Pub => f.write_str("pub"),
153 Visibility::PubCrate => f.write_str("pub_crate"),
154 Visibility::Private => f.write_str("private"),
155 }
156 }
157}
158
159// ── LLD labels ──────────────────────────────────────────────────────────────
160
161/// Which SOLID principle a node may be violating (populated in pass 2).
162#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
164pub enum SolidHint {
165 /// Too many responsibilities in one type.
166 Srp,
167 /// Logic closed for extension but open for modification.
168 Ocp,
169 /// Subtype breaks contract of supertype.
170 Lsp,
171 /// Interface has too many unrelated methods.
172 Isp,
173 /// Depends on concrete type instead of abstraction.
174 Dip,
175}
176
177/// Common design patterns detectable syntactically.
178#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
179#[serde(rename_all = "snake_case")]
180pub enum DesignPattern {
181 Builder,
182 Factory,
183 Observer,
184 Strategy,
185 Decorator,
186 Singleton,
187 Repository,
188}
189
190/// Code quality smells detectable without full type resolution.
191#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
192#[serde(rename_all = "snake_case")]
193pub enum CodeSmell {
194 /// Struct with too many methods or dependencies.
195 GodStruct,
196 /// Function body too long.
197 LongMethod,
198 /// Nesting depth exceeds threshold.
199 DeepNesting,
200 /// Trait with too many methods.
201 FatInterface,
202}