2024-01-01 14:58:21 -05:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-02-20 13:14:06 -05:00
|
|
|
|
2023-02-23 10:58:10 -05:00
|
|
|
use std::path::PathBuf;
|
2024-06-26 17:24:10 -04:00
|
|
|
use std::sync::Arc;
|
2023-02-20 13:14:06 -05:00
|
|
|
|
2024-07-03 20:54:33 -04:00
|
|
|
use deno_config::workspace::Workspace;
|
2024-09-04 10:00:44 -04:00
|
|
|
use deno_core::serde_json;
|
2024-10-31 11:35:17 -04:00
|
|
|
use deno_core::url::Url;
|
2024-07-23 17:34:46 -04:00
|
|
|
use deno_package_json::PackageJsonDepValue;
|
2024-10-04 03:52:00 -04:00
|
|
|
use deno_package_json::PackageJsonDepValueParseError;
|
2024-11-29 18:54:26 -05:00
|
|
|
use deno_package_json::PackageJsonDepWorkspaceReq;
|
2024-09-04 10:00:44 -04:00
|
|
|
use deno_semver::npm::NpmPackageReqReference;
|
2023-08-21 05:53:52 -04:00
|
|
|
use deno_semver::package::PackageReq;
|
2024-12-20 16:14:37 -05:00
|
|
|
use deno_semver::StackString;
|
2024-11-29 18:54:26 -05:00
|
|
|
use deno_semver::VersionReq;
|
2024-10-31 11:35:17 -04:00
|
|
|
use thiserror::Error;
|
2023-03-03 17:27:05 -05:00
|
|
|
|
2024-07-15 15:08:51 -04:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct InstallNpmRemotePkg {
|
2024-12-20 16:14:37 -05:00
|
|
|
pub alias: Option<StackString>,
|
2024-07-15 15:08:51 -04:00
|
|
|
pub base_dir: PathBuf,
|
|
|
|
pub req: PackageReq,
|
|
|
|
}
|
|
|
|
|
2024-07-03 20:54:33 -04:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct InstallNpmWorkspacePkg {
|
2024-12-20 16:14:37 -05:00
|
|
|
pub alias: Option<StackString>,
|
2024-07-15 15:08:51 -04:00
|
|
|
pub target_dir: PathBuf,
|
2023-05-10 20:06:59 -04:00
|
|
|
}
|
|
|
|
|
2024-10-31 11:35:17 -04:00
|
|
|
#[derive(Debug, Error, Clone)]
|
|
|
|
#[error("Failed to install '{}'\n at {}", alias, location)]
|
|
|
|
pub struct PackageJsonDepValueParseWithLocationError {
|
|
|
|
pub location: Url,
|
2024-12-20 16:14:37 -05:00
|
|
|
pub alias: StackString,
|
2024-10-31 11:35:17 -04:00
|
|
|
#[source]
|
|
|
|
pub source: PackageJsonDepValueParseError,
|
|
|
|
}
|
|
|
|
|
2024-07-03 20:54:33 -04:00
|
|
|
#[derive(Debug, Default)]
|
2024-09-04 10:00:44 -04:00
|
|
|
pub struct NpmInstallDepsProvider {
|
2024-07-15 15:08:51 -04:00
|
|
|
remote_pkgs: Vec<InstallNpmRemotePkg>,
|
2024-07-03 20:54:33 -04:00
|
|
|
workspace_pkgs: Vec<InstallNpmWorkspacePkg>,
|
2024-10-31 11:35:17 -04:00
|
|
|
pkg_json_dep_errors: Vec<PackageJsonDepValueParseWithLocationError>,
|
2024-07-03 20:54:33 -04:00
|
|
|
}
|
2023-02-23 10:58:10 -05:00
|
|
|
|
2024-09-04 10:00:44 -04:00
|
|
|
impl NpmInstallDepsProvider {
|
2024-07-03 20:54:33 -04:00
|
|
|
pub fn empty() -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
2023-02-23 10:58:10 -05:00
|
|
|
|
2024-07-03 20:54:33 -04:00
|
|
|
pub fn from_workspace(workspace: &Arc<Workspace>) -> Self {
|
2024-09-04 10:00:44 -04:00
|
|
|
// todo(dsherret): estimate capacity?
|
2024-07-03 20:54:33 -04:00
|
|
|
let mut workspace_pkgs = Vec::new();
|
2024-07-15 15:08:51 -04:00
|
|
|
let mut remote_pkgs = Vec::new();
|
2024-10-04 03:52:00 -04:00
|
|
|
let mut pkg_json_dep_errors = Vec::new();
|
2024-07-03 20:54:33 -04:00
|
|
|
let workspace_npm_pkgs = workspace.npm_packages();
|
2024-09-04 10:00:44 -04:00
|
|
|
|
|
|
|
for (_, folder) in workspace.config_folders() {
|
|
|
|
// deal with the deno.json first because it takes precedence during resolution
|
|
|
|
if let Some(deno_json) = &folder.deno_json {
|
|
|
|
// don't bother with externally referenced import maps as users
|
|
|
|
// should inline their import map to get this behaviour
|
|
|
|
if let Some(serde_json::Value::Object(obj)) = &deno_json.json.imports {
|
|
|
|
let mut pkg_pkgs = Vec::with_capacity(obj.len());
|
2024-09-09 16:19:29 -04:00
|
|
|
for (_alias, value) in obj {
|
2024-09-04 10:00:44 -04:00
|
|
|
let serde_json::Value::String(specifier) = value else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let Ok(npm_req_ref) = NpmPackageReqReference::from_str(specifier)
|
|
|
|
else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let pkg_req = npm_req_ref.into_inner().req;
|
|
|
|
let workspace_pkg = workspace_npm_pkgs
|
|
|
|
.iter()
|
|
|
|
.find(|pkg| pkg.matches_req(&pkg_req));
|
2024-07-15 15:08:51 -04:00
|
|
|
|
|
|
|
if let Some(pkg) = workspace_pkg {
|
2024-07-03 20:54:33 -04:00
|
|
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
2024-09-09 16:19:29 -04:00
|
|
|
alias: None,
|
2024-07-15 15:08:51 -04:00
|
|
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
2024-07-03 20:54:33 -04:00
|
|
|
});
|
|
|
|
} else {
|
2024-07-15 15:08:51 -04:00
|
|
|
pkg_pkgs.push(InstallNpmRemotePkg {
|
2024-09-09 16:19:29 -04:00
|
|
|
alias: None,
|
2024-09-04 10:00:44 -04:00
|
|
|
base_dir: deno_json.dir_path(),
|
2024-07-15 15:08:51 -04:00
|
|
|
req: pkg_req,
|
|
|
|
});
|
2024-07-03 20:54:33 -04:00
|
|
|
}
|
|
|
|
}
|
2024-09-04 10:00:44 -04:00
|
|
|
|
|
|
|
// sort within each package (more like npm resolution)
|
2024-09-09 16:19:29 -04:00
|
|
|
pkg_pkgs.sort_by(|a, b| a.req.cmp(&b.req));
|
2024-09-04 10:00:44 -04:00
|
|
|
remote_pkgs.extend(pkg_pkgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(pkg_json) = &folder.pkg_json {
|
|
|
|
let deps = pkg_json.resolve_local_package_json_deps();
|
2024-11-29 18:54:26 -05:00
|
|
|
let mut pkg_pkgs = Vec::with_capacity(
|
|
|
|
deps.dependencies.len() + deps.dev_dependencies.len(),
|
|
|
|
);
|
2024-12-20 16:14:37 -05:00
|
|
|
for (alias, dep) in
|
|
|
|
deps.dependencies.iter().chain(deps.dev_dependencies.iter())
|
2024-11-29 18:54:26 -05:00
|
|
|
{
|
2024-10-04 03:52:00 -04:00
|
|
|
let dep = match dep {
|
|
|
|
Ok(dep) => dep,
|
|
|
|
Err(err) => {
|
2024-10-31 11:35:17 -04:00
|
|
|
pkg_json_dep_errors.push(
|
|
|
|
PackageJsonDepValueParseWithLocationError {
|
|
|
|
location: pkg_json.specifier(),
|
2024-12-20 16:14:37 -05:00
|
|
|
alias: alias.clone(),
|
|
|
|
source: err.clone(),
|
2024-10-31 11:35:17 -04:00
|
|
|
},
|
|
|
|
);
|
2024-10-04 03:52:00 -04:00
|
|
|
continue;
|
|
|
|
}
|
2024-09-04 10:00:44 -04:00
|
|
|
};
|
|
|
|
match dep {
|
|
|
|
PackageJsonDepValue::Req(pkg_req) => {
|
|
|
|
let workspace_pkg = workspace_npm_pkgs.iter().find(|pkg| {
|
2024-12-20 16:14:37 -05:00
|
|
|
pkg.matches_req(pkg_req)
|
2024-09-04 10:00:44 -04:00
|
|
|
// do not resolve to the current package
|
|
|
|
&& pkg.pkg_json.path != pkg_json.path
|
2024-07-03 20:54:33 -04:00
|
|
|
});
|
2024-09-04 10:00:44 -04:00
|
|
|
|
|
|
|
if let Some(pkg) = workspace_pkg {
|
|
|
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
2024-12-20 16:14:37 -05:00
|
|
|
alias: Some(alias.clone()),
|
2024-09-04 10:00:44 -04:00
|
|
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
pkg_pkgs.push(InstallNpmRemotePkg {
|
2024-12-20 16:14:37 -05:00
|
|
|
alias: Some(alias.clone()),
|
2024-09-04 10:00:44 -04:00
|
|
|
base_dir: pkg_json.dir_path().to_path_buf(),
|
2024-12-20 16:14:37 -05:00
|
|
|
req: pkg_req.clone(),
|
2024-09-04 10:00:44 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-11-29 18:54:26 -05:00
|
|
|
PackageJsonDepValue::Workspace(workspace_version_req) => {
|
|
|
|
let version_req = match workspace_version_req {
|
|
|
|
PackageJsonDepWorkspaceReq::VersionReq(version_req) => {
|
2024-12-20 16:14:37 -05:00
|
|
|
version_req.clone()
|
2024-11-29 18:54:26 -05:00
|
|
|
}
|
|
|
|
PackageJsonDepWorkspaceReq::Tilde
|
|
|
|
| PackageJsonDepWorkspaceReq::Caret => {
|
|
|
|
VersionReq::parse_from_npm("*").unwrap()
|
|
|
|
}
|
|
|
|
};
|
2024-09-04 10:00:44 -04:00
|
|
|
if let Some(pkg) = workspace_npm_pkgs.iter().find(|pkg| {
|
2024-12-20 16:14:37 -05:00
|
|
|
pkg.matches_name_and_version_req(alias, &version_req)
|
2024-09-04 10:00:44 -04:00
|
|
|
}) {
|
|
|
|
workspace_pkgs.push(InstallNpmWorkspacePkg {
|
2024-12-20 16:14:37 -05:00
|
|
|
alias: Some(alias.clone()),
|
2024-09-04 10:00:44 -04:00
|
|
|
target_dir: pkg.pkg_json.dir_path().to_path_buf(),
|
|
|
|
});
|
|
|
|
}
|
2024-07-03 20:54:33 -04:00
|
|
|
}
|
2023-02-23 10:58:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-04 10:00:44 -04:00
|
|
|
// sort within each package as npm does
|
|
|
|
pkg_pkgs.sort_by(|a, b| a.alias.cmp(&b.alias));
|
|
|
|
remote_pkgs.extend(pkg_pkgs);
|
|
|
|
}
|
2024-07-03 20:54:33 -04:00
|
|
|
}
|
2024-09-04 10:00:44 -04:00
|
|
|
|
2024-07-15 15:08:51 -04:00
|
|
|
remote_pkgs.shrink_to_fit();
|
2024-07-03 20:54:33 -04:00
|
|
|
workspace_pkgs.shrink_to_fit();
|
|
|
|
Self {
|
2024-07-15 15:08:51 -04:00
|
|
|
remote_pkgs,
|
2024-07-03 20:54:33 -04:00
|
|
|
workspace_pkgs,
|
2024-10-04 03:52:00 -04:00
|
|
|
pkg_json_dep_errors,
|
2024-07-03 20:54:33 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-04 03:52:00 -04:00
|
|
|
pub fn remote_pkgs(&self) -> &[InstallNpmRemotePkg] {
|
2024-07-15 15:08:51 -04:00
|
|
|
&self.remote_pkgs
|
2023-02-23 10:58:10 -05:00
|
|
|
}
|
|
|
|
|
2024-10-04 03:52:00 -04:00
|
|
|
pub fn workspace_pkgs(&self) -> &[InstallNpmWorkspacePkg] {
|
2024-07-03 20:54:33 -04:00
|
|
|
&self.workspace_pkgs
|
|
|
|
}
|
2024-10-04 03:52:00 -04:00
|
|
|
|
2024-10-31 11:35:17 -04:00
|
|
|
pub fn pkg_json_dep_errors(
|
|
|
|
&self,
|
|
|
|
) -> &[PackageJsonDepValueParseWithLocationError] {
|
2024-10-04 03:52:00 -04:00
|
|
|
&self.pkg_json_dep_errors
|
|
|
|
}
|
2023-02-23 10:58:10 -05:00
|
|
|
}
|