harn_cli/package/manifest/
connector_module.rs1use std::path::{Path, PathBuf};
10
11use crate::package::manifest_search::nearest_manifest_or_warn;
12
13#[must_use]
20pub fn is_declared_connector_module(harn_file: &Path) -> bool {
21 let Some((manifest, dir)) = nearest_manifest_or_warn(harn_file) else {
22 return false;
23 };
24 let target = canonical(harn_file);
25 manifest
26 .providers
27 .iter()
28 .filter_map(|provider| provider.connector.harn.as_deref())
29 .any(|module| canonical(&dir.join(module)) == target)
30}
31
32fn canonical(path: &Path) -> PathBuf {
33 path.canonicalize().unwrap_or_else(|_| path.to_path_buf())
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use crate::package::MANIFEST;
40 use std::fs;
41
42 #[test]
43 fn connector_module_declaration_is_read_from_the_manifest() {
44 let tmp = tempfile::TempDir::new().unwrap();
45 let root = tmp.path();
46 fs::write(
47 root.join(MANIFEST),
48 "[package]\nname = \"probe-connector\"\nversion = \"0.1.0\"\n\n[[providers]]\nid = \"probe\"\nconnector = { harn = \"src/lib.harn\" }\n",
49 )
50 .unwrap();
51 fs::create_dir_all(root.join("src")).unwrap();
52 let declared = root.join("src").join("lib.harn");
53 let sibling = root.join("src").join("helpers.harn");
54 fs::write(&declared, "pub fn provider_id() { return \"probe\" }\n").unwrap();
55 fs::write(&sibling, "pub fn helper() { return 1 }\n").unwrap();
56
57 assert!(is_declared_connector_module(&declared));
58 assert!(
59 !is_declared_connector_module(&sibling),
60 "only the module the manifest names is a connector module"
61 );
62 }
63
64 #[test]
65 fn a_file_with_no_manifest_declares_nothing() {
66 let tmp = tempfile::TempDir::new().unwrap();
67 let orphan = tmp.path().join("lib.harn");
68 fs::write(&orphan, "pub fn provider_id() { return \"probe\" }\n").unwrap();
69
70 assert!(
71 !is_declared_connector_module(&orphan),
72 "no manifest means no declaration, so the lint falls back to inference"
73 );
74 }
75}