diff --git a/crates/fmm-core/src/manifest/dependency_matcher/path.rs b/crates/fmm-core/src/manifest/dependency_matcher/path.rs index e485bd4..1a2f1c4 100644 --- a/crates/fmm-core/src/manifest/dependency_matcher/path.rs +++ b/crates/fmm-core/src/manifest/dependency_matcher/path.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::sync::OnceLock; use crate::manifest::Manifest; -use crate::resolver::workspace::WorkspaceEcosystem; +use crate::resolver::{relative_importer_starts_with_package_dir, workspace::WorkspaceEcosystem}; const JS_TS_SOURCE_EXTENSIONS: &[&str] = &["ts", "tsx", "js", "jsx", "mjs", "cjs"]; const RUST_SOURCE_EXTENSIONS: &[&str] = &["rs"]; @@ -32,7 +32,10 @@ pub(super) fn is_cargo_workspace_source(path: &Path, manifest: &Manifest) -> boo && manifest .workspace_packages_for(WorkspaceEcosystem::Rust) .values() - .any(|dir| path.starts_with(dir) && dir.join("Cargo.toml").exists()) + .any(|dir| { + (path.starts_with(dir) || relative_importer_starts_with_package_dir(path, dir)) + && dir.join("Cargo.toml").exists() + }) } /// Return a reference to the lazily initialised set of source file extensions diff --git a/crates/fmm-core/src/manifest/dependency_matcher_review_tests.rs b/crates/fmm-core/src/manifest/dependency_matcher_review_tests.rs index 0ebc47a..aeac72e 100644 --- a/crates/fmm-core/src/manifest/dependency_matcher_review_tests.rs +++ b/crates/fmm-core/src/manifest/dependency_matcher_review_tests.rs @@ -206,3 +206,89 @@ rtm-core = { path = "../rtm-core" } ); assert!(lib_importers.contains(&cli_main_key), "{lib_importers:?}"); } + +#[test] +fn rust_crate_import_with_relative_manifest_keys_stays_in_importer_crate() { + let tmp = tempfile::TempDir::new().unwrap(); + write_file( + tmp.path(), + "crates/fmm-core/Cargo.toml", + r#" +[package] +name = "fmm-core" +version = "0.1.0" +edition = "2024" +"#, + ); + write_file( + tmp.path(), + "crates/fmm-cli/Cargo.toml", + r#" +[package] +name = "fmm-cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +fmm-core = { path = "../fmm-core" } +"#, + ); + write_file(tmp.path(), "crates/fmm-core/src/lib.rs", "pub mod dupes;"); + write_file( + tmp.path(), + "crates/fmm-core/src/dupes.rs", + "pub struct DupeClustersResult;", + ); + write_file( + tmp.path(), + "crates/fmm-core/src/format/search_formatters.rs", + "use crate::dupes::DupeClustersResult;", + ); + write_file( + tmp.path(), + "crates/fmm-cli/src/cli/commands/dupes.rs", + "pub fn dupes() {}", + ); + + let core_dupes_key = "crates/fmm-core/src/dupes.rs".to_string(); + let search_formatters_key = "crates/fmm-core/src/format/search_formatters.rs".to_string(); + let cli_dupes_key = "crates/fmm-cli/src/cli/commands/dupes.rs".to_string(); + let mut manifest = Manifest::new(); + manifest.workspace_packages = HashMap::from([ + ("fmm_core".to_string(), tmp.path().join("crates/fmm-core")), + ("fmm_cli".to_string(), tmp.path().join("crates/fmm-cli")), + ]); + manifest.files.insert( + core_dupes_key.clone(), + crate::manifest::FileEntry::default(), + ); + manifest.files.insert( + search_formatters_key.clone(), + crate::manifest::FileEntry { + dependencies: vec!["crate::dupes".to_string()], + ..Default::default() + }, + ); + manifest + .files + .insert(cli_dupes_key.clone(), crate::manifest::FileEntry::default()); + + let reverse_deps = build_reverse_deps(&manifest); + let core_dupes_importers = reverse_deps + .get(&core_dupes_key) + .cloned() + .unwrap_or_default(); + let cli_dupes_importers = reverse_deps + .get(&cli_dupes_key) + .cloned() + .unwrap_or_default(); + + assert!( + core_dupes_importers.contains(&search_formatters_key), + "{core_dupes_importers:?}" + ); + assert!( + !cli_dupes_importers.contains(&search_formatters_key), + "{cli_dupes_importers:?}" + ); +} diff --git a/crates/fmm-core/src/resolver/mod.rs b/crates/fmm-core/src/resolver/mod.rs index b2bb579..99cf05c 100644 --- a/crates/fmm-core/src/resolver/mod.rs +++ b/crates/fmm-core/src/resolver/mod.rs @@ -23,7 +23,8 @@ pub use go::GoImportResolver; pub(crate) use module_hierarchy::is_direct_module_hierarchy_relative; pub use rust::RustImportResolver; pub(crate) use rust_path::{ - normal_components, rust_module_name_from_path, rust_module_name_from_specifier, + normal_components, relative_importer_starts_with_package_dir, rust_module_name_from_path, + rust_module_name_from_specifier, }; /// Resolve an import specifier from a source file into an indexed file path. diff --git a/crates/fmm-core/src/resolver/rust_path.rs b/crates/fmm-core/src/resolver/rust_path.rs index 119ea13..737c8a3 100644 --- a/crates/fmm-core/src/resolver/rust_path.rs +++ b/crates/fmm-core/src/resolver/rust_path.rs @@ -1,6 +1,6 @@ use std::path::{Component, Path}; -pub(super) fn relative_importer_starts_with_package_dir( +pub(crate) fn relative_importer_starts_with_package_dir( importer: &Path, package_dir: &Path, ) -> bool {