use std::path::Path;
#[cfg(feature = "shell-ast")]
use crate::services::unified_bash_analyzer::UnifiedBashAnalyzer;
#[cfg(feature = "python-ast")]
use crate::services::unified_python_analyzer::UnifiedPythonAnalyzer;
use crate::services::unified_typescript_analyzer::UnifiedTypeScriptAnalyzer;
#[cfg(feature = "shell-ast")]
use super::metrics::BASH_UNIFIED_CACHE;
#[cfg(feature = "python-ast")]
use super::metrics::PYTHON_UNIFIED_CACHE;
use super::metrics::TYPESCRIPT_UNIFIED_CACHE;
pub async fn analyze_typescript_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
let analyzer = UnifiedTypeScriptAnalyzer::new(file_path.to_path_buf());
let analysis = analyzer
.analyze()
.await
.map_err(|e| anyhow::anyhow!("Unified TypeScript analysis failed: {}", e))?;
TYPESCRIPT_UNIFIED_CACHE.insert(file_path.to_path_buf(), analysis.file_metrics.clone());
Ok(analysis.ast_items)
}
#[cfg(feature = "python-ast")]
pub async fn analyze_python_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
let analyzer = UnifiedPythonAnalyzer::new(file_path.to_path_buf());
let analysis = analyzer
.analyze()
.await
.map_err(|e| anyhow::anyhow!("Unified Python analysis failed: {}", e))?;
PYTHON_UNIFIED_CACHE.insert(file_path.to_path_buf(), analysis.file_metrics.clone());
Ok(analysis.ast_items)
}
#[cfg(not(feature = "python-ast"))]
pub async fn analyze_python_language(
_file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
#[cfg(feature = "shell-ast")]
pub async fn analyze_bash_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
tracing::debug!("Analyzing Bash script file: {}", file_path.display());
let analyzer = UnifiedBashAnalyzer::new(file_path.to_path_buf());
match analyzer.analyze().await {
Ok(analysis) => {
BASH_UNIFIED_CACHE.insert(file_path.to_path_buf(), analysis.file_metrics.clone());
tracing::debug!("Bash analysis returned {} items", analysis.ast_items.len());
Ok(analysis.ast_items)
}
Err(_) => {
let items = analyze_bash_file(file_path).await?;
tracing::debug!("Bash analysis returned {} items", items.len());
Ok(items)
}
}
}
#[cfg(not(feature = "shell-ast"))]
pub async fn analyze_bash_language(
_file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
pub async fn analyze_ruby_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
analyze_ruby_file(file_path).await
}
#[cfg(feature = "lua-ast")]
pub async fn analyze_lua_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
use crate::services::context::AstItem;
let content = tokio::fs::read_to_string(file_path).await?;
let mut items = Vec::new();
let patterns = [
r"(?m)^\s*function\s+(\w+(?:[.:]\w+)*)\s*\(",
r"(?m)^\s*local\s+function\s+(\w+)\s*\(",
];
for pat in &patterns {
if let Ok(re) = regex::Regex::new(pat) {
for cap in re.captures_iter(&content) {
if let Some(name_match) = cap.get(1) {
let line = content
.get(..name_match.start())
.unwrap_or_default()
.lines()
.count();
items.push(AstItem::Function {
name: name_match.as_str().to_string(),
visibility: "public".to_string(),
is_async: false,
line,
});
}
}
}
}
if let Ok(re) = regex::Regex::new(r#"(?m)require\s*\(\s*["']([^"']+)["']\s*\)"#) {
for cap in re.captures_iter(&content) {
if let Some(module_match) = cap.get(1) {
let line = content
.get(..module_match.start())
.unwrap_or_default()
.lines()
.count();
items.push(AstItem::Import {
module: module_match.as_str().to_string(),
items: vec![],
alias: None,
line,
});
}
}
}
tracing::debug!("Lua analysis returned {} items", items.len());
Ok(items)
}
#[cfg(not(feature = "lua-ast"))]
pub async fn analyze_lua_language(
_file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
pub async fn analyze_elixir_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
analyze_elixir_file(file_path).await
}
pub async fn analyze_erlang_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
analyze_erlang_file(file_path).await
}
pub async fn analyze_haskell_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
analyze_haskell_file(file_path).await
}
pub async fn analyze_ocaml_language(
file_path: &std::path::Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
analyze_ocaml_file(file_path).await
}
#[allow(dead_code)]
async fn analyze_typescript_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
#[cfg(feature = "typescript-ast")]
{
use crate::services::ast_typescript::analyze_typescript_file as analyze_ts;
match analyze_ts(_file_path).await {
Ok(file_context) => Ok(file_context.items),
Err(_) => Ok(Vec::new()), }
}
#[cfg(not(feature = "typescript-ast"))]
Ok(Vec::new())
}
#[allow(dead_code)]
async fn analyze_python_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
#[cfg(feature = "python-ast")]
{
use crate::services::ast_python::analyze_python_file_with_classifier;
match analyze_python_file_with_classifier(_file_path, None).await {
Ok(file_context) => Ok(file_context.items),
Err(_) => Ok(Vec::new()), }
}
#[cfg(not(feature = "python-ast"))]
Ok(Vec::new())
}
#[cfg(feature = "shell-ast")]
async fn analyze_bash_file(
file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
use crate::services::languages::bash::BashScriptAnalyzer;
use std::fs;
match fs::read_to_string(file_path) {
Ok(source) => {
let analyzer = BashScriptAnalyzer::new(file_path);
match analyzer.analyze_bash_script(&source) {
Ok(items) => Ok(items),
Err(_) => Ok(Vec::new()), }
}
Err(_) => Ok(Vec::new()), }
}
#[cfg(not(feature = "shell-ast"))]
#[allow(dead_code)]
async fn analyze_bash_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
async fn analyze_ruby_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
#[cfg(feature = "ruby-ast")]
{
Ok(Vec::new())
}
#[cfg(not(feature = "ruby-ast"))]
{
#[cfg(feature = "ruchy-ast")]
{
Ok(Vec::new())
}
#[cfg(not(feature = "ruchy-ast"))]
Ok(Vec::new())
}
}
async fn analyze_elixir_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
async fn analyze_erlang_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
async fn analyze_haskell_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}
async fn analyze_ocaml_file(
_file_path: &Path,
) -> anyhow::Result<Vec<crate::services::context::AstItem>> {
Ok(Vec::new())
}