use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Parameter {
pub name: String,
pub type_annotation: Option<String>,
pub default_value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Symbol {
pub name: String,
pub qualified_name: String,
pub kind: SymbolKind,
pub signature: String,
pub visibility: Visibility,
pub file_path: String,
pub line_start: usize,
pub line_end: usize,
pub doc_comment: Option<String>,
pub parent: Option<String>,
#[serde(default)]
pub parameters: Vec<Parameter>,
#[serde(default)]
pub return_type: Option<String>,
#[serde(default)]
pub is_async: bool,
#[serde(default)]
pub attributes: Vec<String>,
#[serde(default)]
pub throws: Vec<String>,
#[serde(default)]
pub generic_params: Option<String>,
#[serde(default)]
pub is_abstract: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SymbolKind {
Function,
Method,
Class,
Struct,
Enum,
Interface, Type, Constant,
Module,
Test,
Field, Constructor, }
impl std::fmt::Display for SymbolKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Function => write!(f, "function"),
Self::Method => write!(f, "method"),
Self::Class => write!(f, "class"),
Self::Struct => write!(f, "struct"),
Self::Enum => write!(f, "enum"),
Self::Interface => write!(f, "interface"),
Self::Type => write!(f, "type"),
Self::Constant => write!(f, "constant"),
Self::Module => write!(f, "module"),
Self::Test => write!(f, "test"),
Self::Field => write!(f, "field"),
Self::Constructor => write!(f, "constructor"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Visibility {
Public,
Private,
Crate, Protected, }
impl std::fmt::Display for Visibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Public => write!(f, "public"),
Self::Private => write!(f, "private"),
Self::Crate => write!(f, "crate"),
Self::Protected => write!(f, "protected"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reference {
pub source_qualified_name: String,
pub target_name: String,
pub kind: ReferenceKind,
pub file_path: String,
pub line: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ReferenceKind {
Call,
Callback,
Import,
Inherits,
Implements,
TypeUsage,
}
impl std::str::FromStr for SymbolKind {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"function" => Ok(SymbolKind::Function),
"method" => Ok(SymbolKind::Method),
"class" => Ok(SymbolKind::Class),
"struct" => Ok(SymbolKind::Struct),
"enum" => Ok(SymbolKind::Enum),
"interface" => Ok(SymbolKind::Interface),
"type" => Ok(SymbolKind::Type),
"constant" => Ok(SymbolKind::Constant),
"module" => Ok(SymbolKind::Module),
"test" => Ok(SymbolKind::Test),
"field" => Ok(SymbolKind::Field),
"constructor" => Ok(SymbolKind::Constructor),
_ => Err(format!("Unknown SymbolKind: {s}")),
}
}
}
pub fn symbol_kind_from_str(s: &str) -> Option<SymbolKind> {
s.parse().ok()
}
pub fn visibility_from_str(s: &str) -> Visibility {
match s {
"public" => Visibility::Public,
"crate" => Visibility::Crate,
"protected" => Visibility::Protected,
_ => Visibility::Private,
}
}
fn symbol_kind_from_node_kind(nk: &codemem_core::NodeKind) -> SymbolKind {
match nk {
codemem_core::NodeKind::Function => SymbolKind::Function,
codemem_core::NodeKind::Method => SymbolKind::Method,
codemem_core::NodeKind::Class => SymbolKind::Class,
codemem_core::NodeKind::Interface | codemem_core::NodeKind::Trait => SymbolKind::Interface,
codemem_core::NodeKind::Type => SymbolKind::Type,
codemem_core::NodeKind::Constant => SymbolKind::Constant,
codemem_core::NodeKind::Module => SymbolKind::Module,
codemem_core::NodeKind::Test => SymbolKind::Test,
codemem_core::NodeKind::Enum => SymbolKind::Enum,
codemem_core::NodeKind::Field | codemem_core::NodeKind::Property => SymbolKind::Field,
_ => SymbolKind::Function, }
}
pub fn symbol_from_graph_node(node: &codemem_core::GraphNode) -> Option<Symbol> {
let qualified_name = node.id.strip_prefix("sym:")?.to_string();
let kind = node
.payload
.get("symbol_kind")
.and_then(|v| v.as_str())
.and_then(symbol_kind_from_str)
.unwrap_or_else(|| symbol_kind_from_node_kind(&node.kind));
let file_path = node
.payload
.get("file_path")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let signature = node
.payload
.get("signature")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let visibility = node
.payload
.get("visibility")
.and_then(|v| v.as_str())
.map(visibility_from_str)
.unwrap_or(Visibility::Private);
let line_start = node
.payload
.get("line_start")
.and_then(|v| v.as_u64())
.unwrap_or(0) as usize;
let line_end = node
.payload
.get("line_end")
.and_then(|v| v.as_u64())
.unwrap_or(0) as usize;
let doc_comment = node
.payload
.get("doc_comment")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let name = qualified_name
.rsplit("::")
.next()
.unwrap_or(&qualified_name)
.to_string();
let parameters: Vec<Parameter> = node
.payload
.get("parameters")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.unwrap_or_default();
let return_type = node
.payload
.get("return_type")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let is_async = node
.payload
.get("is_async")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let attributes: Vec<String> = node
.payload
.get("attributes")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.unwrap_or_default();
let throws: Vec<String> = node
.payload
.get("throws")
.and_then(|v| serde_json::from_value(v.clone()).ok())
.unwrap_or_default();
let generic_params = node
.payload
.get("generic_params")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let is_abstract = node
.payload
.get("is_abstract")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let parent = node
.payload
.get("parent")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
Some(Symbol {
name,
qualified_name,
kind,
signature,
visibility,
file_path,
line_start,
line_end,
doc_comment,
parent,
parameters,
return_type,
is_async,
attributes,
throws,
generic_params,
is_abstract,
})
}
impl From<SymbolKind> for codemem_core::NodeKind {
fn from(kind: SymbolKind) -> Self {
match kind {
SymbolKind::Function => codemem_core::NodeKind::Function,
SymbolKind::Method => codemem_core::NodeKind::Method,
SymbolKind::Class => codemem_core::NodeKind::Class,
SymbolKind::Struct => codemem_core::NodeKind::Class,
SymbolKind::Enum => codemem_core::NodeKind::Enum,
SymbolKind::Interface => codemem_core::NodeKind::Interface,
SymbolKind::Type => codemem_core::NodeKind::Type,
SymbolKind::Constant => codemem_core::NodeKind::Constant,
SymbolKind::Module => codemem_core::NodeKind::Module,
SymbolKind::Test => codemem_core::NodeKind::Test,
SymbolKind::Field => codemem_core::NodeKind::Field,
SymbolKind::Constructor => codemem_core::NodeKind::Method,
}
}
}
impl std::fmt::Display for ReferenceKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Call => write!(f, "call"),
Self::Callback => write!(f, "callback"),
Self::Import => write!(f, "import"),
Self::Inherits => write!(f, "inherits"),
Self::Implements => write!(f, "implements"),
Self::TypeUsage => write!(f, "type_usage"),
}
}
}