diff --git a/rs-lib/src/lib.rs b/rs-lib/src/lib.rs index e951333..52596b0 100644 --- a/rs-lib/src/lib.rs +++ b/rs-lib/src/lib.rs @@ -1176,6 +1176,18 @@ fn get_dependencies( } }) .collect::>(); + // a package.json lists a package as a peer dependency or a dependency, but + // never both, so a package mapped as a peer dependency stays one even when + // another specifier resolves to it (ex. a sub path of the same package, + // whose `npm:` specifier the user has no reason to map on its own) + let peer_names = dependencies + .iter() + .filter(|d| d.peer_dependency) + .map(|d| d.name.clone()) + .collect::>(); + for dependency in dependencies.iter_mut() { + dependency.peer_dependency |= peer_names.contains(&dependency.name); + } dependencies.sort_by(|a, b| a.name.cmp(&b.name)); dependencies.dedup(); // only works after sorting dependencies diff --git a/rs-lib/tests/integration/test_builder.rs b/rs-lib/tests/integration/test_builder.rs index a9d7581..b6a57da 100644 --- a/rs-lib/tests/integration/test_builder.rs +++ b/rs-lib/tests/integration/test_builder.rs @@ -180,6 +180,24 @@ impl TestBuilder { self } + pub fn add_peer_package_specifier_mapping( + &mut self, + specifier: impl AsRef, + bare_specifier: impl AsRef, + version: Option<&str>, + ) -> &mut Self { + self.specifier_mappings.insert( + normalize_urls(specifier.as_ref()), + MappedSpecifier::Package(PackageMappedSpecifier { + name: bare_specifier.as_ref().to_string(), + version: version.map(|v| v.to_string()), + sub_path: None, + peer_dependency: true, + }), + ); + self + } + pub fn add_module_specifier_mapping( &mut self, from: impl AsRef, diff --git a/rs-lib/tests/integration_test.rs b/rs-lib/tests/integration_test.rs index fe8cdae..e3221af 100644 --- a/rs-lib/tests/integration_test.rs +++ b/rs-lib/tests/integration_test.rs @@ -3125,6 +3125,40 @@ async fn npm_specifier() { ); } +#[tokio::test] +async fn npm_specifier_peer_dependency_with_sub_path() { + let result = TestBuilder::new() + .with_loader(|loader| { + loader.add_local_file( + "/mod.ts", + concat!( + "import * as pkg from 'npm:using-statement@^0.4';\n", + "import * as sub from 'npm:using-statement@^0.4/sub';\n", + "console.log(pkg, sub);\n", + ), + ); + }) + .add_peer_package_specifier_mapping( + "npm:using-statement@^0.4", + "using-statement", + Some("^0.4"), + ) + .transform() + .await + .unwrap(); + + // the sub path resolves to the same package, so it must not also + // show up as a non-peer dependency + assert_eq!( + result.main.dependencies, + &[Dependency { + name: "using-statement".to_string(), + version: "^0.4".to_string(), + peer_dependency: true, + }] + ); +} + #[tokio::test] async fn npm_types_specifier() { let result = TestBuilder::new()