Skip to main content

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}