summaryrefslogtreecommitdiff
path: root/cli/resolver.rs
diff options
context:
space:
mode:
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)
+ }
+}