use std::collections::HashMap;
use std::path::{Path, PathBuf};
use harn_parser::SNode;
use super::{
build_inner, normalize_path, ModuleGraph, ModuleGraphBuild, PackageContext,
ParsedSourceRetention,
};
pub fn build(files: &[PathBuf]) -> ModuleGraph {
build_inner(
files,
ParsedSourceRetention::None,
None,
PackageContext::Project,
None,
)
.graph
}
pub fn build_with_parsed_sources(files: &[PathBuf]) -> ModuleGraphBuild {
let parsed_source_targets = files.iter().map(|file| normalize_path(file)).collect();
build_inner(
files,
ParsedSourceRetention::Seeds(&parsed_source_targets),
None,
PackageContext::Project,
None,
)
}
pub fn build_closed_program(files: &[PathBuf]) -> ModuleGraphBuild {
build_inner(
files,
ParsedSourceRetention::All,
None,
PackageContext::Project,
None,
)
}
pub fn build_with_module_projection<T: Send>(
files: &[PathBuf],
project: impl Fn(&Path, &str, Option<&[SNode]>) -> T + Sync,
) -> (ModuleGraph, HashMap<PathBuf, T>) {
let projections = std::sync::Mutex::new(HashMap::new());
let observer = |path: &Path, source: &str, program: Option<&[SNode]>| {
let projection = project(path, source, program);
projections
.lock()
.expect("module projection lock poisoned")
.insert(path.to_path_buf(), projection);
};
let graph = build_inner(
files,
ParsedSourceRetention::None,
None,
PackageContext::Project,
Some(&observer),
)
.graph;
(
graph,
projections
.into_inner()
.expect("module projection lock poisoned"),
)
}
pub fn build_for_reference_index(
files: &[PathBuf],
source_overrides: Option<&HashMap<PathBuf, String>>,
) -> ModuleGraphBuild {
build_inner(
files,
ParsedSourceRetention::All,
source_overrides,
PackageContext::Project,
None,
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn projection_and_graph_share_the_parsed_source_snapshot() {
let dir = tempfile::tempdir().unwrap();
let paths = (0..12)
.map(|index| {
let path = dir.path().join(format!("module{index}.harn"));
std::fs::write(&path, "pub fn original() { 1 }\n").unwrap();
path
})
.collect::<Vec<_>>();
let observed = std::sync::atomic::AtomicUsize::new(0);
let (graph, projections) = build_with_module_projection(&paths, |path, source, program| {
observed.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
assert_eq!(program.unwrap().len(), 1);
std::fs::write(path, "pub fn replacement() { 2 }\n").unwrap();
source.to_owned()
});
assert_eq!(
observed.load(std::sync::atomic::Ordering::Relaxed),
paths.len()
);
assert_eq!(graph.module_paths().len(), paths.len());
assert_eq!(projections.len(), paths.len());
for path in &paths {
assert_eq!(
projections[&normalize_path(path)],
"pub fn original() { 1 }\n"
);
assert_eq!(
graph.exported_kind(path, "original"),
Some(super::super::DefKind::Function)
);
assert_eq!(graph.exported_kind(path, "replacement"), None);
}
let refreshed = build(&paths);
for path in &paths {
assert_eq!(refreshed.exported_kind(path, "original"), None);
assert_eq!(
refreshed.exported_kind(path, "replacement"),
Some(super::super::DefKind::Function)
);
}
}
}