mod config;
mod cross_file_deps;
pub(crate) mod hasher;
mod imports;
mod indexing;
mod reconcile;
mod same_file_deps;
mod types;
use std::path::Path;
use tracing::info;
use crate::error::ScanError;
use crate::port::{FileDiscovery, LanguageRegistry, ScanStore};
pub use types::ScanResult;
pub fn scan(
project_dir: &Path,
db: &dyn ScanStore,
full: bool,
lang: &dyn LanguageRegistry,
discovery: &dyn FileDiscovery,
) -> Result<ScanResult, ScanError> {
let project_dir = project_dir
.canonicalize()
.unwrap_or_else(|_| project_dir.to_path_buf());
let files = discovery.discover_files(&project_dir, lang.supported_extensions())?;
let scan_id = db.begin_scan()?;
info!("discovered {} source files", files.len());
let force_full = full || config::config_changed(&project_dir, db, lang.config_files());
let indexing = indexing::index_files(&project_dir, &files, db, scan_id, force_full, lang)?;
reconcile::reconcile_deleted_files(&project_dir, &files, db)?;
let (import_resolution, import_deps) =
imports::resolve(&project_dir, &indexing.pending_imports, db, lang)?;
let cross_file_deps = cross_file_deps::resolve_cross_file(
&indexing.unresolved_refs,
&indexing.file_import_names,
&import_resolution,
db,
)?;
let result = ScanResult {
files_total: indexing.files_total,
files_skipped: indexing.files_skipped,
files_partial: indexing.files_partial,
symbols: indexing.symbols,
dependencies: indexing.same_file_deps + import_deps + cross_file_deps,
};
db.complete_scan(
scan_id,
result.files_total,
result.symbols,
result.dependencies,
)?;
config::save_config_hash(&project_dir, db, lang.config_files());
info!(
"scan complete: {} files, {} symbols, {} deps",
result.files_total, result.symbols, result.dependencies
);
Ok(result)
}