impl UnifiedNode {
pub fn new(kind: NodeKind, name: &str, language: Language) -> Self {
let id = format!("{}:{}:{}", language.name(), kind.as_str(), name);
Self {
id,
kind,
name: name.to_string(),
fqn: name.to_string(),
language,
file_path: std::path::PathBuf::new(),
position: SourcePosition::default(),
attributes: HashMap::new(),
children: Vec::new(),
parent: None,
references: Vec::new(),
type_info: None,
signature: None,
documentation: None,
original_item: None,
metadata: HashMap::new(),
}
}
pub fn from_ast_item(
item: &AstItem,
language: Language,
file_path: &Path,
id_prefix: Option<&str>,
) -> Self {
let prefix = id_prefix.unwrap_or(language.name());
let (name, line, visibility, namespace) = match item {
AstItem::Function {
name,
line,
visibility,
..
} => (name.clone(), *line, visibility.clone(), None::<String>),
AstItem::Struct {
name,
line,
visibility,
..
} => (name.clone(), *line, visibility.clone(), None::<String>),
AstItem::Enum {
name,
line,
visibility,
..
} => (name.clone(), *line, visibility.clone(), None::<String>),
AstItem::Trait {
name,
line,
visibility,
..
} => (name.clone(), *line, visibility.clone(), None::<String>),
AstItem::Module {
name,
line,
visibility,
..
} => (name.clone(), *line, visibility.clone(), None::<String>),
AstItem::Use { path, line } => {
(path.clone(), *line, "public".to_string(), None::<String>)
}
AstItem::Impl {
type_name, line, ..
} => (
type_name.clone(),
*line,
"public".to_string(),
None::<String>,
),
AstItem::Import { module, line, .. } => {
(module.clone(), *line, "public".to_string(), None::<String>)
}
};
let kind = NodeKind::from_ast_item(item);
let id = format!("{}:{}:{}", prefix, kind.as_str(), name);
let position = SourcePosition {
start_line: line,
start_col: 0,
end_line: line + 1, end_col: 0,
};
let mut attributes = HashMap::new();
attributes.insert("access".to_string(), visibility);
match item {
AstItem::Function { is_async, .. } => {
if *is_async {
attributes.insert("modifier:async".to_string(), "true".to_string());
}
}
AstItem::Struct { derives, .. } => {
for derive in derives {
attributes.insert(format!("derive:{}", derive), "true".to_string());
}
}
_ => {}
}
let fqn = if let Some(ns) = namespace {
if !ns.is_empty() {
format!("{}.{}", ns, name)
} else {
name.clone()
}
} else {
match item {
AstItem::Struct { name, .. }
| AstItem::Enum { name, .. }
| AstItem::Trait { name, .. } => {
let file_name = file_path.file_stem().and_then(|s| s.to_str()).unwrap_or("");
if file_name != name {
format!("{}.{}", file_name, name)
} else {
name.clone()
}
}
_ => name.clone(),
}
};
UnifiedNode {
id,
kind,
name,
fqn,
language,
file_path: file_path.to_path_buf(),
position,
attributes,
children: Vec::new(), parent: None, references: Vec::new(), type_info: None, signature: None, documentation: None, original_item: Some(item.clone()),
metadata: HashMap::new(),
}
}
pub fn extract_name_from_item(item: &AstItem) -> String {
match item {
AstItem::Function { name, .. } => name.clone(),
AstItem::Struct { name, .. } => name.clone(),
AstItem::Enum { name, .. } => name.clone(),
AstItem::Trait { name, .. } => name.clone(),
AstItem::Impl { type_name, .. } => type_name.clone(),
AstItem::Use { path, .. } => path.clone(),
AstItem::Module { name, .. } => name.clone(),
AstItem::Import { module, .. } => module.clone(),
}
}
pub fn access(&self) -> Option<&str> {
self.attributes.get("access").map(AsRef::as_ref)
}
pub fn has_modifier(&self, modifier: &str) -> bool {
self.attributes
.contains_key(&format!("modifier:{}", modifier))
}
pub fn is_abstract(&self) -> bool {
self.has_modifier("abstract")
}
pub fn is_static(&self) -> bool {
self.has_modifier("static")
}
pub fn is_final(&self) -> bool {
self.has_modifier("final")
}
pub fn add_child(&mut self, child_id: String) {
self.children.push(child_id);
}
pub fn set_parent(&mut self, parent_id: String) {
self.parent = Some(parent_id);
}
pub fn add_reference(
&mut self,
kind: ReferenceKind,
target_name: String,
target_id: Option<String>,
) {
let reference = NodeReference {
kind,
target_id: target_id.unwrap_or_default(),
target_name,
target_language: None, };
self.references.push(reference);
}
pub fn get_references_by_kind(&self, kind: ReferenceKind) -> Vec<&NodeReference> {
self.references.iter().filter(|r| r.kind == kind).collect()
}
pub fn set_type_info(&mut self, type_info: TypeInfo) {
self.type_info = Some(type_info);
}
pub fn add_metadata(&mut self, key: &str, value: &str) {
self.metadata.insert(key.to_string(), value.to_string());
}
}