summaryrefslogtreecommitdiff
path: root/cli/resolver.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-02-22 14:15:25 -0500
committerGitHub <noreply@github.com>2023-02-22 14:15:25 -0500
commita6ca4d0d61c95b9f7fa79ecce81a31a6d1f6cc5d (patch)
tree278a915d7722a8a3d1fffbfa1f3a12752f44d13f /cli/resolver.rs
parent0f9daaeacb402a7199e58b14ad01ec0091ac2c8d (diff)
refactor: use deno_graph for npm specifiers (#17858)
This changes npm specifiers to be handled by deno_graph and resolved to an npm package name and version when the specifier is encountered. It also slightly changes how npm specifier resolution occurs—previously it would collect all the npm specifiers and resolve them all at once, but now it resolves them on the fly as they are encountered in the module graph. https://github.com/denoland/deno_graph/pull/232 --------- Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Diffstat (limited to 'cli/resolver.rs')
-rw-r--r--cli/resolver.rs113
1 files changed, 111 insertions, 2 deletions
diff --git a/cli/resolver.rs b/cli/resolver.rs
index aa58549a7..76e1715b5 100644
--- a/cli/resolver.rs
+++ b/cli/resolver.rs
@@ -1,19 +1,29 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use deno_core::anyhow::bail;
use deno_core::error::AnyError;
+use deno_core::futures::future;
+use deno_core::futures::future::LocalBoxFuture;
+use deno_core::futures::FutureExt;
use deno_core::ModuleSpecifier;
+use deno_graph::npm::NpmPackageNv;
+use deno_graph::npm::NpmPackageReq;
+use deno_graph::source::NpmResolver;
use deno_graph::source::Resolver;
+use deno_graph::source::UnknownBuiltInNodeModuleError;
use deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE;
+use deno_runtime::deno_node::is_builtin_node_module;
use import_map::ImportMap;
use std::collections::HashMap;
use std::sync::Arc;
use crate::args::JsxImportSourceConfig;
-use deno_graph::npm::NpmPackageReq;
+use crate::npm::NpmRegistryApi;
+use crate::npm::NpmResolution;
/// A resolver that takes care of resolution, taking into account loaded
/// import map, JSX settings.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
pub struct CliGraphResolver {
maybe_import_map: Option<Arc<ImportMap>>,
// TODO(bartlomieju): actually use in `resolver`, once
@@ -22,12 +32,39 @@ pub struct CliGraphResolver {
maybe_package_json_deps: Option<HashMap<String, NpmPackageReq>>,
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
+ no_npm: bool,
+ npm_registry_api: NpmRegistryApi,
+ npm_resolution: NpmResolution,
+ sync_download_semaphore: Option<Arc<tokio::sync::Semaphore>>,
+}
+
+impl Default for CliGraphResolver {
+ fn default() -> Self {
+ // This is not ideal, but necessary for the LSP. In the future, we should
+ // refactor the LSP and force this to be initialized.
+ let npm_registry_api = NpmRegistryApi::new_uninitialized();
+ let npm_resolution =
+ NpmResolution::new(npm_registry_api.clone(), None, None);
+ Self {
+ maybe_import_map: Default::default(),
+ maybe_default_jsx_import_source: Default::default(),
+ maybe_jsx_import_source_module: Default::default(),
+ no_npm: false,
+ npm_registry_api,
+ npm_resolution,
+ maybe_package_json_deps: Default::default(),
+ sync_download_semaphore: Self::create_sync_download_semaphore(),
+ }
+ }
}
impl CliGraphResolver {
pub fn new(
maybe_jsx_import_source_config: Option<JsxImportSourceConfig>,
maybe_import_map: Option<Arc<ImportMap>>,
+ no_npm: bool,
+ npm_registry_api: NpmRegistryApi,
+ npm_resolution: NpmResolution,
maybe_package_json_deps: Option<HashMap<String, NpmPackageReq>>,
) -> Self {
Self {
@@ -37,13 +74,29 @@ impl CliGraphResolver {
.and_then(|c| c.default_specifier.clone()),
maybe_jsx_import_source_module: maybe_jsx_import_source_config
.map(|c| c.module),
+ no_npm,
+ npm_registry_api,
+ npm_resolution,
maybe_package_json_deps,
+ sync_download_semaphore: Self::create_sync_download_semaphore(),
+ }
+ }
+
+ fn create_sync_download_semaphore() -> Option<Arc<tokio::sync::Semaphore>> {
+ if crate::npm::should_sync_download() {
+ Some(Arc::new(tokio::sync::Semaphore::new(1)))
+ } else {
+ None
}
}
pub fn as_graph_resolver(&self) -> &dyn Resolver {
self
}
+
+ pub fn as_graph_npm_resolver(&self) -> &dyn NpmResolver {
+ self
+ }
}
impl Resolver for CliGraphResolver {
@@ -74,3 +127,59 @@ impl Resolver for CliGraphResolver {
}
}
}
+
+impl NpmResolver for CliGraphResolver {
+ fn resolve_builtin_node_module(
+ &self,
+ specifier: &ModuleSpecifier,
+ ) -> Result<Option<String>, UnknownBuiltInNodeModuleError> {
+ if specifier.scheme() != "node" {
+ return Ok(None);
+ }
+
+ let module_name = specifier.path().to_string();
+ if is_builtin_node_module(&module_name) {
+ Ok(Some(module_name))
+ } else {
+ Err(UnknownBuiltInNodeModuleError { module_name })
+ }
+ }
+
+ fn load_and_cache_npm_package_info(
+ &self,
+ package_name: &str,
+ ) -> LocalBoxFuture<'static, Result<(), String>> {
+ if self.no_npm {
+ // return it succeeded and error at the import site below
+ return Box::pin(future::ready(Ok(())));
+ }
+ // this will internally cache the package information
+ let package_name = package_name.to_string();
+ let api = self.npm_registry_api.clone();
+ let mut maybe_sync_download_semaphore =
+ self.sync_download_semaphore.clone();
+ async move {
+ let result = if let Some(semaphore) = maybe_sync_download_semaphore.take()
+ {
+ let _permit = semaphore.acquire().await.unwrap();
+ api.package_info(&package_name).await
+ } else {
+ api.package_info(&package_name).await
+ };
+ result.map(|_| ()).map_err(|err| format!("{err:#}"))
+ }
+ .boxed()
+ }
+
+ fn resolve_npm(
+ &self,
+ package_req: &NpmPackageReq,
+ ) -> Result<NpmPackageNv, AnyError> {
+ if self.no_npm {
+ bail!("npm specifiers were requested; but --no-npm is specified")
+ }
+ self
+ .npm_resolution
+ .resolve_package_req_for_deno_graph(package_req)
+ }
+}