Skip to main content

astmap_core/
scanner.rs

1mod config;
2mod cross_file_deps;
3pub(crate) mod hasher;
4mod imports;
5mod indexing;
6mod reconcile;
7mod same_file_deps;
8mod types;
9
10use std::path::Path;
11
12use tracing::info;
13
14use crate::error::ScanError;
15use crate::port::{FileDiscovery, LanguageRegistry, ScanStore};
16
17pub use types::ScanResult;
18
19/// Run a full or incremental scan.
20pub fn scan(
21    project_dir: &Path,
22    db: &dyn ScanStore,
23    full: bool,
24    lang: &dyn LanguageRegistry,
25    discovery: &dyn FileDiscovery,
26) -> Result<ScanResult, ScanError> {
27    let project_dir = project_dir
28        .canonicalize()
29        .unwrap_or_else(|_| project_dir.to_path_buf());
30
31    let files = discovery.discover_files(&project_dir, lang.supported_extensions())?;
32    let scan_id = db.begin_scan()?;
33
34    info!("discovered {} source files", files.len());
35
36    // Check if config files changed (forces full re-scan for affected languages)
37    let force_full = full || config::config_changed(&project_dir, db, lang.config_files());
38
39    // Parse all files, insert symbols, collect imports
40    let indexing = indexing::index_files(&project_dir, &files, db, scan_id, force_full, lang)?;
41
42    // Remove stale files that no longer exist on disk
43    reconcile::reconcile_deleted_files(&project_dir, &files, db)?;
44
45    // Resolve imports to target file IDs and symbol-level cross-file deps
46    let (import_resolution, import_deps) =
47        imports::resolve(&project_dir, &indexing.pending_imports, db, lang)?;
48
49    // Resolve unresolved cross-file references using import resolution
50    let cross_file_deps = cross_file_deps::resolve_cross_file(
51        &indexing.unresolved_refs,
52        &indexing.file_import_names,
53        &import_resolution,
54        db,
55    )?;
56
57    let result = ScanResult {
58        files_total: indexing.files_total,
59        files_skipped: indexing.files_skipped,
60        files_partial: indexing.files_partial,
61        symbols: indexing.symbols,
62        dependencies: indexing.same_file_deps + import_deps + cross_file_deps,
63    };
64
65    db.complete_scan(
66        scan_id,
67        result.files_total,
68        result.symbols,
69        result.dependencies,
70    )?;
71
72    // Save config hash for next incremental scan
73    config::save_config_hash(&project_dir, db, lang.config_files());
74
75    info!(
76        "scan complete: {} files, {} symbols, {} deps",
77        result.files_total, result.symbols, result.dependencies
78    );
79
80    Ok(result)
81}