mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
fix(npm): handle an npm package that has itself as a dependency (#17425)
I'm not sure this properly handles scenarios where an npm package uses an alias that resolves to itself, we can fix that if we find a package that actually depends on that behavior. Closes #17420
This commit is contained in:
parent
01e02d3123
commit
7cd249db10
1 changed files with 75 additions and 11 deletions
|
@ -303,6 +303,7 @@ impl Graph {
|
||||||
parent_id: &NpmPackageId,
|
parent_id: &NpmPackageId,
|
||||||
) {
|
) {
|
||||||
let mut child = (*child).lock();
|
let mut child = (*child).lock();
|
||||||
|
assert_ne!(child.id, *parent_id);
|
||||||
let mut parent = (**self.packages.get(parent_id).unwrap_or_else(|| {
|
let mut parent = (**self.packages.get(parent_id).unwrap_or_else(|| {
|
||||||
panic!(
|
panic!(
|
||||||
"could not find {} in list of packages when setting child {}",
|
"could not find {} in list of packages when setting child {}",
|
||||||
|
@ -311,7 +312,6 @@ impl Graph {
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
.lock();
|
.lock();
|
||||||
assert_ne!(parent.id, child.id);
|
|
||||||
parent
|
parent
|
||||||
.children
|
.children
|
||||||
.insert(specifier.to_string(), child.id.clone());
|
.insert(specifier.to_string(), child.id.clone());
|
||||||
|
@ -476,7 +476,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
package_req: &NpmPackageReq,
|
package_req: &NpmPackageReq,
|
||||||
package_info: &NpmPackageInfo,
|
package_info: &NpmPackageInfo,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let node = self.resolve_node_from_info(
|
let (_, node) = self.resolve_node_from_info(
|
||||||
&package_req.name,
|
&package_req.name,
|
||||||
package_req,
|
package_req,
|
||||||
package_info,
|
package_info,
|
||||||
|
@ -498,7 +498,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
parent_id: &NpmPackageId,
|
parent_id: &NpmPackageId,
|
||||||
visited_versions: &Arc<VisitedVersionsPath>,
|
visited_versions: &Arc<VisitedVersionsPath>,
|
||||||
) -> Result<Arc<Mutex<Node>>, AnyError> {
|
) -> Result<Arc<Mutex<Node>>, AnyError> {
|
||||||
let node = self.resolve_node_from_info(
|
let (id, node) = self.resolve_node_from_info(
|
||||||
&entry.name,
|
&entry.name,
|
||||||
match entry.kind {
|
match entry.kind {
|
||||||
NpmDependencyEntryKind::Dep => &entry.version_req,
|
NpmDependencyEntryKind::Dep => &entry.version_req,
|
||||||
|
@ -514,12 +514,17 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
package_info,
|
package_info,
|
||||||
Some(parent_id),
|
Some(parent_id),
|
||||||
)?;
|
)?;
|
||||||
self.graph.set_child_parent(
|
// Some packages may resolves to themselves as a dependency. If this occurs,
|
||||||
&entry.bare_specifier,
|
// just ignore adding these as dependencies because this is likely a mistake
|
||||||
&node,
|
// in the package.
|
||||||
&NodeParent::Node(parent_id.clone()),
|
if id != *parent_id {
|
||||||
);
|
self.graph.set_child_parent(
|
||||||
self.try_add_pending_unresolved_node(Some(visited_versions), &node);
|
&entry.bare_specifier,
|
||||||
|
&node,
|
||||||
|
&NodeParent::Node(parent_id.clone()),
|
||||||
|
);
|
||||||
|
self.try_add_pending_unresolved_node(Some(visited_versions), &node);
|
||||||
|
}
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,7 +560,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
version_matcher: &impl NpmVersionMatcher,
|
version_matcher: &impl NpmVersionMatcher,
|
||||||
package_info: &NpmPackageInfo,
|
package_info: &NpmPackageInfo,
|
||||||
parent_id: Option<&NpmPackageId>,
|
parent_id: Option<&NpmPackageId>,
|
||||||
) -> Result<Arc<Mutex<Node>>, AnyError> {
|
) -> Result<(NpmPackageId, Arc<Mutex<Node>>), AnyError> {
|
||||||
let version_and_info = self
|
let version_and_info = self
|
||||||
.resolve_best_package_version_and_info(version_matcher, package_info)?;
|
.resolve_best_package_version_and_info(version_matcher, package_info)?;
|
||||||
let id = NpmPackageId {
|
let id = NpmPackageId {
|
||||||
|
@ -587,7 +592,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
node.no_peers = node.deps.is_empty();
|
node.no_peers = node.deps.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(node)
|
Ok((id, node))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resolve_pending(&mut self) -> Result<(), AnyError> {
|
pub async fn resolve_pending(&mut self) -> Result<(), AnyError> {
|
||||||
|
@ -2655,6 +2660,65 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn package_has_self_as_dependency() {
|
||||||
|
let api = TestNpmRegistryApi::default();
|
||||||
|
api.ensure_package_version("package-a", "1.0.0");
|
||||||
|
api.add_dependency(("package-a", "1.0.0"), ("package-a", "1"));
|
||||||
|
|
||||||
|
let (packages, package_reqs) =
|
||||||
|
run_resolver_and_get_output(api, vec!["npm:package-a@1.0"]).await;
|
||||||
|
assert_eq!(
|
||||||
|
packages,
|
||||||
|
vec![NpmResolutionPackage {
|
||||||
|
id: NpmPackageId::from_serialized("package-a@1.0.0").unwrap(),
|
||||||
|
copy_index: 0,
|
||||||
|
// in this case, we just ignore that the package did this
|
||||||
|
dependencies: Default::default(),
|
||||||
|
dist: Default::default(),
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
package_reqs,
|
||||||
|
vec![("package-a@1.0".to_string(), "package-a@1.0.0".to_string())]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn package_has_self_but_different_version_as_dependency() {
|
||||||
|
let api = TestNpmRegistryApi::default();
|
||||||
|
api.ensure_package_version("package-a", "1.0.0");
|
||||||
|
api.ensure_package_version("package-a", "0.5.0");
|
||||||
|
api.add_dependency(("package-a", "1.0.0"), ("package-a", "^0.5"));
|
||||||
|
|
||||||
|
let (packages, package_reqs) =
|
||||||
|
run_resolver_and_get_output(api, vec!["npm:package-a@1.0"]).await;
|
||||||
|
assert_eq!(
|
||||||
|
packages,
|
||||||
|
vec![
|
||||||
|
NpmResolutionPackage {
|
||||||
|
id: NpmPackageId::from_serialized("package-a@0.5.0").unwrap(),
|
||||||
|
copy_index: 0,
|
||||||
|
dependencies: Default::default(),
|
||||||
|
dist: Default::default(),
|
||||||
|
},
|
||||||
|
NpmResolutionPackage {
|
||||||
|
id: NpmPackageId::from_serialized("package-a@1.0.0").unwrap(),
|
||||||
|
copy_index: 0,
|
||||||
|
dependencies: HashMap::from([(
|
||||||
|
"package-a".to_string(),
|
||||||
|
NpmPackageId::from_serialized("package-a@0.5.0").unwrap(),
|
||||||
|
)]),
|
||||||
|
dist: Default::default(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
package_reqs,
|
||||||
|
vec![("package-a@1.0".to_string(), "package-a@1.0.0".to_string())]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_resolver_and_get_output(
|
async fn run_resolver_and_get_output(
|
||||||
api: TestNpmRegistryApi,
|
api: TestNpmRegistryApi,
|
||||||
reqs: Vec<&str>,
|
reqs: Vec<&str>,
|
||||||
|
|
Loading…
Reference in a new issue