summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorNathan Whitaker <17734409+nathanwhit@users.noreply.github.com>2024-08-21 15:23:32 -0700
committerGitHub <noreply@github.com>2024-08-21 15:23:32 -0700
commit48da3c17ea905f50b82948e6f94795e1589f852e (patch)
treee65d5da97ef0cd4b9f67972b8ba647420d39952e /cli
parent9aaad3064a412b24e88e308750e038d4e1df6f3c (diff)
fix(add): Handle packages without root exports (#25102)
Fixes #24607. This PR makes the logic that caches top level dependencies (things present in import map) smarter, so we handle JSR dependencies without root exports.
Diffstat (limited to 'cli')
-rw-r--r--cli/module_loader.rs49
-rw-r--r--cli/tools/installer.rs2
-rw-r--r--cli/tools/registry/mod.rs2
-rw-r--r--cli/tools/registry/pm.rs25
-rw-r--r--cli/tools/registry/pm/cache_deps.rs115
5 files changed, 134 insertions, 59 deletions
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index 9f5208936..3208d1365 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -18,7 +18,6 @@ use crate::cache::CodeCache;
use crate::cache::FastInsecureHasher;
use crate::cache::ParsedSourceCache;
use crate::emit::Emitter;
-use crate::factory::CliFactory;
use crate::graph_container::MainModuleGraphContainer;
use crate::graph_container::ModuleGraphContainer;
use crate::graph_container::ModuleGraphUpdatePermit;
@@ -70,54 +69,6 @@ use deno_runtime::deno_permissions::PermissionsContainer;
use deno_semver::npm::NpmPackageReqReference;
use node_resolver::NodeResolutionMode;
-pub async fn load_top_level_deps(factory: &CliFactory) -> Result<(), AnyError> {
- let npm_resolver = factory.npm_resolver().await?;
- let cli_options = factory.cli_options()?;
- if let Some(npm_resolver) = npm_resolver.as_managed() {
- if !npm_resolver.ensure_top_level_package_json_install().await? {
- if let Some(lockfile) = cli_options.maybe_lockfile() {
- lockfile.error_if_changed()?;
- }
-
- npm_resolver.cache_packages().await?;
- }
- }
- // cache as many entries in the import map as we can
- let resolver = factory.workspace_resolver().await?;
- if let Some(import_map) = resolver.maybe_import_map() {
- let roots = import_map
- .imports()
- .entries()
- .filter_map(|entry| {
- if entry.key.ends_with('/') {
- None
- } else {
- entry.value.cloned()
- }
- })
- .collect::<Vec<_>>();
- let mut graph_permit = factory
- .main_module_graph_container()
- .await?
- .acquire_update_permit()
- .await;
- let graph = graph_permit.graph_mut();
- factory
- .module_load_preparer()
- .await?
- .prepare_module_load(
- graph,
- &roots,
- false,
- factory.cli_options()?.ts_type_lib_window(),
- deno_runtime::deno_permissions::PermissionsContainer::allow_all(),
- )
- .await?;
- }
-
- Ok(())
-}
-
pub struct ModuleLoadPreparer {
options: Arc<CliOptions>,
lockfile: Option<Arc<CliLockfile>>,
diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs
index 456e5c1a6..1809e1f16 100644
--- a/cli/tools/installer.rs
+++ b/cli/tools/installer.rs
@@ -275,7 +275,7 @@ async fn install_local(
}
let factory = CliFactory::from_flags(flags);
- crate::module_loader::load_top_level_deps(&factory).await?;
+ crate::tools::registry::cache_top_level_deps(&factory, None).await?;
if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() {
lockfile.write_if_changed()?;
diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs
index d6e06fb58..ee3204dc7 100644
--- a/cli/tools/registry/mod.rs
+++ b/cli/tools/registry/mod.rs
@@ -52,6 +52,7 @@ use crate::util::display::human_size;
mod api;
mod auth;
+
mod diagnostics;
mod graph;
mod paths;
@@ -64,6 +65,7 @@ mod unfurl;
use auth::get_auth_method;
use auth::AuthMethod;
pub use pm::add;
+pub use pm::cache_top_level_deps;
pub use pm::remove;
pub use pm::AddCommandName;
use publish_order::PublishOrderGraph;
diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs
index 3cdef071f..87a5ea69a 100644
--- a/cli/tools/registry/pm.rs
+++ b/cli/tools/registry/pm.rs
@@ -1,5 +1,9 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+mod cache_deps;
+
+pub use cache_deps::cache_top_level_deps;
+
use std::borrow::Cow;
use std::path::Path;
use std::path::PathBuf;
@@ -236,13 +240,16 @@ pub async fn add(
let package_futures = package_reqs
.into_iter()
- .map(move |package_req| {
- find_package_and_select_version_for_req(
- jsr_resolver.clone(),
- npm_resolver.clone(),
- package_req,
- )
- .boxed_local()
+ .map({
+ let jsr_resolver = jsr_resolver.clone();
+ move |package_req| {
+ find_package_and_select_version_for_req(
+ jsr_resolver.clone(),
+ npm_resolver.clone(),
+ package_req,
+ )
+ .boxed_local()
+ }
})
.collect::<Vec<_>>();
@@ -350,7 +357,7 @@ pub async fn add(
// make a new CliFactory to pick up the updated config file
let cli_factory = CliFactory::from_flags(flags);
// cache deps
- crate::module_loader::load_top_level_deps(&cli_factory).await?;
+ cache_deps::cache_top_level_deps(&cli_factory, Some(jsr_resolver)).await?;
Ok(())
}
@@ -597,7 +604,7 @@ pub async fn remove(
// Update deno.lock
node_resolver::PackageJsonThreadLocalCache::clear();
let cli_factory = CliFactory::from_flags(flags);
- crate::module_loader::load_top_level_deps(&cli_factory).await?;
+ cache_deps::cache_top_level_deps(&cli_factory, None).await?;
}
Ok(())
diff --git a/cli/tools/registry/pm/cache_deps.rs b/cli/tools/registry/pm/cache_deps.rs
new file mode 100644
index 000000000..d292c32f5
--- /dev/null
+++ b/cli/tools/registry/pm/cache_deps.rs
@@ -0,0 +1,115 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+use std::sync::Arc;
+
+use crate::factory::CliFactory;
+use crate::graph_container::ModuleGraphContainer;
+use crate::graph_container::ModuleGraphUpdatePermit;
+use deno_core::error::AnyError;
+use deno_core::futures::stream::FuturesUnordered;
+use deno_core::futures::StreamExt;
+use deno_semver::package::PackageReq;
+
+pub async fn cache_top_level_deps(
+ factory: &CliFactory,
+ jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
+) -> Result<(), AnyError> {
+ let npm_resolver = factory.npm_resolver().await?;
+ let cli_options = factory.cli_options()?;
+ if let Some(npm_resolver) = npm_resolver.as_managed() {
+ if !npm_resolver.ensure_top_level_package_json_install().await? {
+ if let Some(lockfile) = cli_options.maybe_lockfile() {
+ lockfile.error_if_changed()?;
+ }
+
+ npm_resolver.cache_packages().await?;
+ }
+ }
+ // cache as many entries in the import map as we can
+ let resolver = factory.workspace_resolver().await?;
+ if let Some(import_map) = resolver.maybe_import_map() {
+ let jsr_resolver = if let Some(resolver) = jsr_resolver {
+ resolver
+ } else {
+ Arc::new(crate::jsr::JsrFetchResolver::new(
+ factory.file_fetcher()?.clone(),
+ ))
+ };
+
+ let mut roots = Vec::new();
+
+ let mut info_futures = FuturesUnordered::new();
+
+ let mut seen_reqs = std::collections::HashSet::new();
+
+ for entry in import_map.imports().entries() {
+ let Some(specifier) = entry.value else {
+ continue;
+ };
+
+ match specifier.scheme() {
+ "jsr" => {
+ let specifier_str = specifier.as_str();
+ let specifier_str =
+ specifier_str.strip_prefix("jsr:").unwrap_or(specifier_str);
+ if let Ok(req) = PackageReq::from_str(specifier_str) {
+ if !seen_reqs.insert(req.clone()) {
+ continue;
+ }
+ let jsr_resolver = jsr_resolver.clone();
+ info_futures.push(async move {
+ if let Some(nv) = jsr_resolver.req_to_nv(&req).await {
+ if let Some(info) = jsr_resolver.package_version_info(&nv).await
+ {
+ return Some((specifier.clone(), info));
+ }
+ }
+ None
+ });
+ }
+ }
+ "npm" => roots.push(specifier.clone()),
+ _ => {
+ if entry.key.ends_with('/') && specifier.as_str().ends_with('/') {
+ continue;
+ }
+ roots.push(specifier.clone());
+ }
+ }
+ }
+
+ while let Some(info_future) = info_futures.next().await {
+ if let Some((specifier, info)) = info_future {
+ if info.export(".").is_some() {
+ roots.push(specifier.clone());
+ continue;
+ }
+ let exports = info.exports();
+ for (k, _) in exports {
+ if let Ok(spec) = specifier.join(k) {
+ roots.push(spec);
+ }
+ }
+ }
+ }
+ let mut graph_permit = factory
+ .main_module_graph_container()
+ .await?
+ .acquire_update_permit()
+ .await;
+ let graph = graph_permit.graph_mut();
+ factory
+ .module_load_preparer()
+ .await?
+ .prepare_module_load(
+ graph,
+ &roots,
+ false,
+ deno_config::deno_json::TsTypeLib::DenoWorker,
+ deno_runtime::deno_permissions::PermissionsContainer::allow_all(),
+ )
+ .await?;
+ }
+
+ Ok(())
+}