use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum SymbolKind {
Class,
Struct,
Trait,
Enum,
Function,
Method,
Module,
Interface,
Const,
TypeAlias,
Impl,
Variable,
Component,
Annotation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ScanStatus {
Running,
Completed,
Failed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ParseStatus {
Ok,
Partial,
Error,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum DepType {
Imports,
Calls,
Extends,
Implements,
TypeRef,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum DepLevel {
File,
Symbol,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Display, EnumString)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum FileChangeStatus {
Added,
Modified,
Deleted,
Renamed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Scan {
pub id: i64,
pub started_at: u64,
pub completed_at: Option<u64>,
pub status: ScanStatus,
pub file_count: i64,
pub symbol_count: i64,
pub dep_count: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct File {
pub id: i64,
pub scan_id: i64,
pub path: String,
pub language: String,
pub size_bytes: i64,
pub content_hash: String,
pub last_modified: u64,
pub parse_status: ParseStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Symbol {
pub id: i64,
pub file_id: i64,
pub parent_id: Option<i64>,
pub name: String,
pub kind: SymbolKind,
pub signature: Option<String>,
pub summary: Option<String>,
pub start_line: i64,
pub end_line: i64,
pub start_byte: i64,
pub end_byte: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Dependency {
pub id: i64,
pub source_file_id: i64,
pub source_symbol_id: Option<i64>,
pub target_file_id: Option<i64>,
pub target_symbol_id: Option<i64>,
pub dep_type: DepType,
pub level: DepLevel,
pub raw_import: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub key: String,
pub value: String,
pub updated_at: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolResult {
pub id: i64,
pub name: String,
pub kind: SymbolKind,
pub file_path: String,
pub start_line: i64,
pub end_line: i64,
pub signature: Option<String>,
pub summary: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolWithParent {
pub id: i64,
pub name: String,
pub kind: SymbolKind,
pub file_path: String,
pub start_line: i64,
pub end_line: i64,
pub signature: Option<String>,
pub parent_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImpactEntry {
pub symbol_id: i64,
pub symbol_name: String,
pub symbol_kind: SymbolKind,
pub file_path: String,
pub depth: i64,
pub dep_type: DepType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathStep {
pub symbol_id: i64,
pub symbol_name: String,
pub file_path: String,
pub dep_type: DepType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InspectResult {
pub symbol: Symbol,
pub children: Vec<Symbol>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImpactResult {
pub symbol_id: i64,
pub entries: Vec<ImpactEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WhyResult {
pub from_name: String,
pub to_name: String,
pub path: Vec<PathStep>,
}
#[derive(Debug, Clone)]
pub struct VcsFileChange {
pub path: String,
pub old_path: Option<String>,
pub status: FileChangeStatus,
pub changed_lines: Vec<(i64, i64)>,
}
#[derive(Debug, Clone)]
pub struct ExtractedSymbol {
pub name: String,
pub kind: SymbolKind,
pub signature: Option<String>,
pub start_line: usize,
pub end_line: usize,
pub start_byte: usize,
pub end_byte: usize,
pub parent_index: Option<usize>, }
#[derive(Debug, Clone)]
pub struct ExtractedImport {
pub path: String,
pub imported_symbols: Vec<String>, }
#[derive(Debug, Clone)]
pub struct ExtractedCall {
pub caller_name: String, pub callee_name: String, pub line: usize,
}
#[derive(Debug, Clone)]
pub struct ExtractedTypeRef {
pub from_symbol: String, pub to_type: String, pub line: usize,
}
#[derive(Debug)]
pub struct ParseResult {
pub symbols: Vec<ExtractedSymbol>,
pub imports: Vec<ExtractedImport>,
pub calls: Vec<ExtractedCall>,
pub type_refs: Vec<ExtractedTypeRef>,
pub has_errors: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_kind_roundtrip() {
let variants = [
SymbolKind::Class,
SymbolKind::Struct,
SymbolKind::Trait,
SymbolKind::Enum,
SymbolKind::Function,
SymbolKind::Method,
SymbolKind::Module,
SymbolKind::Interface,
SymbolKind::Const,
SymbolKind::TypeAlias,
SymbolKind::Impl,
SymbolKind::Variable,
SymbolKind::Component,
SymbolKind::Annotation,
];
for v in variants {
let s = v.to_string();
let parsed: SymbolKind = s.parse().unwrap();
assert_eq!(v, parsed, "roundtrip failed for {:?}", v);
}
}
#[test]
fn test_symbol_kind_unknown() {
let result = "bogus".parse::<SymbolKind>();
assert!(result.is_err());
}
#[test]
fn test_scan_status_roundtrip() {
for v in [
ScanStatus::Running,
ScanStatus::Completed,
ScanStatus::Failed,
] {
let parsed: ScanStatus = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn test_scan_status_unknown() {
assert!("bogus".parse::<ScanStatus>().is_err());
}
#[test]
fn test_parse_status_roundtrip() {
for v in [ParseStatus::Ok, ParseStatus::Partial, ParseStatus::Error] {
let parsed: ParseStatus = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn test_parse_status_unknown() {
assert!("bogus".parse::<ParseStatus>().is_err());
}
#[test]
fn test_dep_type_roundtrip() {
for v in [
DepType::Imports,
DepType::Calls,
DepType::Extends,
DepType::Implements,
DepType::TypeRef,
] {
let parsed: DepType = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn test_dep_type_unknown() {
assert!("bogus".parse::<DepType>().is_err());
}
#[test]
fn test_dep_level_roundtrip() {
for v in [DepLevel::File, DepLevel::Symbol] {
let parsed: DepLevel = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn test_dep_level_unknown() {
assert!("bogus".parse::<DepLevel>().is_err());
}
#[test]
fn test_file_change_status_roundtrip() {
for v in [
FileChangeStatus::Added,
FileChangeStatus::Modified,
FileChangeStatus::Deleted,
FileChangeStatus::Renamed,
] {
let parsed: FileChangeStatus = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn test_file_change_status_unknown() {
assert!("bogus".parse::<FileChangeStatus>().is_err());
}
}