use std::path::Path;
use crate::payload::ParsedFilePayload;
pub mod python;
pub mod rust;
pub mod typescript;
pub use python::PythonAstParser;
pub use rust::{
ExtractedUseItem, RustAstParser, crate_root_for, dependency_module_path_for,
extract_type_members, extract_use_items, module_path_for,
};
pub use typescript::TypeScriptAstParser;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum ParseMode {
#[default]
Workspace,
DependencyPublicSurface {
crate_name: String,
},
}
impl ParseMode {
pub fn is_dependency_public_surface(&self) -> bool {
matches!(self, Self::DependencyPublicSurface { .. })
}
pub fn crate_name(&self) -> Option<&str> {
match self {
Self::Workspace => None,
Self::DependencyPublicSurface { crate_name } => Some(crate_name.as_str()),
}
}
}
pub fn parse_file(
relative_path: &Path,
content: &[u8],
content_hash: &str,
mode: ParseMode,
) -> anyhow::Result<ParsedFilePayload> {
let ext = relative_path
.extension()
.and_then(|e| e.to_str())
.unwrap_or("")
.to_ascii_lowercase();
match ext.as_str() {
"rs" => RustAstParser::parse(relative_path, content, content_hash, mode),
"py" => PythonAstParser::parse(relative_path, content, content_hash),
"ts" | "tsx" | "js" | "jsx" => {
TypeScriptAstParser::parse(relative_path, content, content_hash)
}
other => anyhow::bail!(
"Unsupported file extension '{other}' for {}",
relative_path.display()
),
}
}
pub fn module_name_for(rel_path: &Path) -> Option<String> {
match rel_path.extension()?.to_str()? {
"rs" => Some(module_path_for(rel_path)),
"py" => Some(python::compute_base_module(rel_path)),
"ts" | "tsx" | "js" | "jsx" => Some(typescript::compute_base_module(rel_path)),
_ => None,
}
}
fn language_family(path: &Path) -> Option<&'static str> {
let ext = path.extension()?.to_str()?;
let is = |candidates: &[&str]| candidates.iter().any(|c| ext.eq_ignore_ascii_case(c));
if is(&["rs"]) {
Some("rust")
} else if is(&["py"]) {
Some("python")
} else if is(&["ts", "tsx", "js", "jsx"]) {
Some("typescript")
} else {
None
}
}
pub(crate) fn same_language(a: &Path, b: &Path) -> bool {
match (language_family(a), language_family(b)) {
(Some(x), Some(y)) => x == y,
_ => true,
}
}