Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions rs-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,18 @@ fn get_dependencies(
}
})
.collect::<Vec<_>>();
// 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::<HashSet<_>>();
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
Expand Down
18 changes: 18 additions & 0 deletions rs-lib/tests/integration/test_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ impl TestBuilder {
self
}

pub fn add_peer_package_specifier_mapping(
&mut self,
specifier: impl AsRef<str>,
bare_specifier: impl AsRef<str>,
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<str>,
Expand Down
34 changes: 34 additions & 0 deletions rs-lib/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down