mirror of
https://github.com/denoland/deno.git
synced 2024-11-30 16:40:57 -05:00
fix(workspace): do not resolve to self for npm pkg depending on matching req (#24591)
Closes #24584
This commit is contained in:
parent
70a9631696
commit
29186d7e59
6 changed files with 77 additions and 29 deletions
|
@ -8,17 +8,26 @@ use deno_config::workspace::Workspace;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstallNpmWorkspacePkg {
|
pub struct InstallNpmRemotePkg {
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
pub pkg_dir: PathBuf,
|
// todo(24419): use this when setting up the node_modules dir
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub base_dir: PathBuf,
|
||||||
|
pub req: PackageReq,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstallNpmWorkspacePkg {
|
||||||
|
pub alias: String,
|
||||||
|
// todo(24419): use this when setting up the node_modules dir
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub base_dir: PathBuf,
|
||||||
|
pub target_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(#24419): this is not correct, but it's good enough for now.
|
|
||||||
// We need deno_npm to be able to understand workspace packages and
|
|
||||||
// then have a way to properly lay them out on the file system
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PackageJsonInstallDepsProvider {
|
pub struct PackageJsonInstallDepsProvider {
|
||||||
remote_pkg_reqs: Vec<PackageReq>,
|
remote_pkgs: Vec<InstallNpmRemotePkg>,
|
||||||
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,27 +38,35 @@ impl PackageJsonInstallDepsProvider {
|
||||||
|
|
||||||
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
|
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
|
||||||
let mut workspace_pkgs = Vec::new();
|
let mut workspace_pkgs = Vec::new();
|
||||||
let mut remote_pkg_reqs = Vec::new();
|
let mut remote_pkgs = Vec::new();
|
||||||
let workspace_npm_pkgs = workspace.npm_packages();
|
let workspace_npm_pkgs = workspace.npm_packages();
|
||||||
for pkg_json in workspace.package_jsons() {
|
for pkg_json in workspace.package_jsons() {
|
||||||
let deps = pkg_json.resolve_local_package_json_deps();
|
let deps = pkg_json.resolve_local_package_json_deps();
|
||||||
let mut pkg_reqs = Vec::with_capacity(deps.len());
|
let mut pkg_pkgs = Vec::with_capacity(deps.len());
|
||||||
for (alias, dep) in deps {
|
for (alias, dep) in deps {
|
||||||
let Ok(dep) = dep else {
|
let Ok(dep) = dep else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
match dep {
|
match dep {
|
||||||
PackageJsonDepValue::Req(pkg_req) => {
|
PackageJsonDepValue::Req(pkg_req) => {
|
||||||
if let Some(pkg) = workspace_npm_pkgs
|
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
|
||||||
.iter()
|
pkg.matches_req(&pkg_req)
|
||||||
.find(|pkg| pkg.matches_req(&pkg_req))
|
// do not resolve to the current package
|
||||||
{
|
&& pkg.pkg_json.path != pkg_json.path
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(pkg) = workspace_pkg {
|
||||||
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
||||||
alias,
|
alias,
|
||||||
pkg_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
base_dir: pkg_json.dir_path().to_path_buf(),
|
||||||
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
pkg_reqs.push(pkg_req)
|
pkg_pkgs.push(InstallNpmRemotePkg {
|
||||||
|
alias,
|
||||||
|
base_dir: pkg_json.dir_path().to_path_buf(),
|
||||||
|
req: pkg_req,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PackageJsonDepValue::Workspace(version_req) => {
|
PackageJsonDepValue::Workspace(version_req) => {
|
||||||
|
@ -58,27 +75,28 @@ impl PackageJsonInstallDepsProvider {
|
||||||
}) {
|
}) {
|
||||||
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
||||||
alias,
|
alias,
|
||||||
pkg_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
base_dir: pkg_json.dir_path().to_path_buf(),
|
||||||
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sort within each package
|
// sort within each package
|
||||||
pkg_reqs.sort();
|
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
|
||||||
|
|
||||||
remote_pkg_reqs.extend(pkg_reqs);
|
remote_pkgs.extend(pkg_pkgs);
|
||||||
}
|
}
|
||||||
remote_pkg_reqs.shrink_to_fit();
|
remote_pkgs.shrink_to_fit();
|
||||||
workspace_pkgs.shrink_to_fit();
|
workspace_pkgs.shrink_to_fit();
|
||||||
Self {
|
Self {
|
||||||
remote_pkg_reqs,
|
remote_pkgs,
|
||||||
workspace_pkgs,
|
workspace_pkgs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remote_pkg_reqs(&self) -> &Vec<PackageReq> {
|
pub fn remote_pkgs(&self) -> &Vec<InstallNpmRemotePkg> {
|
||||||
&self.remote_pkg_reqs
|
&self.remote_pkgs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_pkgs(&self) -> &Vec<InstallNpmWorkspacePkg> {
|
pub fn workspace_pkgs(&self) -> &Vec<InstallNpmWorkspacePkg> {
|
||||||
|
|
|
@ -475,24 +475,30 @@ impl ManagedCliNpmResolver {
|
||||||
if !self.top_level_install_flag.raise() {
|
if !self.top_level_install_flag.raise() {
|
||||||
return Ok(false); // already did this
|
return Ok(false); // already did this
|
||||||
}
|
}
|
||||||
let reqs = self.package_json_deps_provider.remote_pkg_reqs();
|
let pkg_json_remote_pkgs = self.package_json_deps_provider.remote_pkgs();
|
||||||
if reqs.is_empty() {
|
if pkg_json_remote_pkgs.is_empty() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if something needs resolving before bothering to load all
|
// check if something needs resolving before bothering to load all
|
||||||
// the package information (which is slow)
|
// the package information (which is slow)
|
||||||
if reqs
|
if pkg_json_remote_pkgs.iter().all(|pkg| {
|
||||||
.iter()
|
self
|
||||||
.all(|req| self.resolution.resolve_pkg_id_from_pkg_req(req).is_ok())
|
.resolution
|
||||||
{
|
.resolve_pkg_id_from_pkg_req(&pkg.req)
|
||||||
|
.is_ok()
|
||||||
|
}) {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"All package.json deps resolvable. Skipping top level install."
|
"All package.json deps resolvable. Skipping top level install."
|
||||||
);
|
);
|
||||||
return Ok(false); // everything is already resolvable
|
return Ok(false); // everything is already resolvable
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_package_reqs(reqs).await.map(|_| true)
|
let pkg_reqs = pkg_json_remote_pkgs
|
||||||
|
.iter()
|
||||||
|
.map(|pkg| pkg.req.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.add_package_reqs(&pkg_reqs).await.map(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cache_package_info(
|
pub async fn cache_package_info(
|
||||||
|
|
|
@ -672,7 +672,7 @@ async fn sync_resolution_with_fs(
|
||||||
// but this is good enough for a first pass
|
// but this is good enough for a first pass
|
||||||
for workspace in pkg_json_deps_provider.workspace_pkgs() {
|
for workspace in pkg_json_deps_provider.workspace_pkgs() {
|
||||||
symlink_package_dir(
|
symlink_package_dir(
|
||||||
&workspace.pkg_dir,
|
&workspace.target_dir,
|
||||||
&root_node_modules_dir_path.join(&workspace.alias),
|
&root_node_modules_dir_path.join(&workspace.alias),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
13
tests/specs/npm/npm_pkg_depend_dep_same_name/__test__.jsonc
Normal file
13
tests/specs/npm/npm_pkg_depend_dep_same_name/__test__.jsonc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"tempDir": true,
|
||||||
|
"envs": {
|
||||||
|
"DENO_FUTURE": "1"
|
||||||
|
},
|
||||||
|
"steps": [{
|
||||||
|
"args": "install",
|
||||||
|
"output": "[WILDCARD]"
|
||||||
|
}, {
|
||||||
|
"args": "run index.ts",
|
||||||
|
"output": "3\n"
|
||||||
|
}]
|
||||||
|
}
|
4
tests/specs/npm/npm_pkg_depend_dep_same_name/index.ts
Normal file
4
tests/specs/npm/npm_pkg_depend_dep_same_name/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// this should resolve to the remote package and not itself
|
||||||
|
import { add } from "@denotest/add";
|
||||||
|
|
||||||
|
console.log(add(1, 2));
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "@denotest/add",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@denotest/add": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue