use cairo_lang_defs::ids::{LookupItemId, ModuleId, ModuleItemId, SubmoduleId};
use cairo_lang_doc::db::DocGroup;
use cairo_lang_doc::documentable_item::DocumentableItemId;
use cairo_lang_filesystem::ids::CrateId;
use cairo_lang_syntax::node::SyntaxNode;
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
use crate::lang::db::AnalysisDatabase;
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct ModuleDef<'db> {
id: NonMacroModuleId<'db>,
parent_full_path: Option<String>,
definition_stable_ptr: SyntaxStablePtrId<'db>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum NonMacroModuleId<'db> {
CrateRoot(CrateId<'db>),
Submodule(SubmoduleId<'db>),
}
impl<'db> TryFrom<ModuleId<'db>> for NonMacroModuleId<'db> {
type Error = ();
fn try_from(value: ModuleId<'db>) -> Result<Self, Self::Error> {
match value {
ModuleId::CrateRoot(id) => Ok(Self::CrateRoot(id)),
ModuleId::Submodule(id) => Ok(Self::Submodule(id)),
ModuleId::MacroCall { .. } => Err(()),
}
}
}
impl<'db> From<NonMacroModuleId<'db>> for ModuleId<'db> {
fn from(value: NonMacroModuleId<'db>) -> Self {
match value {
NonMacroModuleId::CrateRoot(id) => Self::CrateRoot(id),
NonMacroModuleId::Submodule(id) => Self::Submodule(id),
}
}
}
impl<'db> ModuleDef<'db> {
pub(super) fn new(
db: &'db AnalysisDatabase,
id: NonMacroModuleId<'db>,
definition_node: SyntaxNode<'db>,
) -> Self {
let module_id: ModuleId = id.into();
let parent_full_path = module_id
.full_path(db)
.strip_suffix(module_id.name(db).to_string(db).as_str())
.unwrap()
.strip_suffix("::")
.map(String::from);
ModuleDef { id, parent_full_path, definition_stable_ptr: definition_node.stable_ptr(db) }
}
pub fn definition_stable_ptr(&self) -> SyntaxStablePtrId<'db> {
self.definition_stable_ptr
}
pub fn signature(&self, db: &'db AnalysisDatabase) -> String {
let prefix = if self.parent_full_path.is_some() { "mod" } else { "crate" };
format!("{prefix} {}", self.name(db))
}
pub fn definition_path(&self) -> String {
self.parent_full_path.clone().unwrap_or_default()
}
pub fn documentation(&self, db: &'db AnalysisDatabase) -> Option<String> {
let doc_id = match self.id {
NonMacroModuleId::CrateRoot(id) => DocumentableItemId::Crate(id),
NonMacroModuleId::Submodule(id) => DocumentableItemId::LookupItem(
LookupItemId::ModuleItem(ModuleItemId::Submodule(id)),
),
};
db.get_item_documentation(doc_id)
}
pub fn name(&self, db: &'db AnalysisDatabase) -> String {
self.module_id().name(db).to_string(db)
}
pub fn non_macro_module_id(&self) -> NonMacroModuleId<'db> {
self.id
}
pub fn module_id(&self) -> ModuleId<'db> {
self.id.into()
}
}