summaryrefslogtreecommitdiff
path: root/cli/lsp/resolver.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/lsp/resolver.rs')
-rw-r--r--cli/lsp/resolver.rs287
1 files changed, 183 insertions, 104 deletions
diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs
index f5df24d57..37f63b912 100644
--- a/cli/lsp/resolver.rs
+++ b/cli/lsp/resolver.rs
@@ -2,16 +2,18 @@
use dashmap::DashMap;
use deno_ast::MediaType;
-use deno_ast::ParsedSource;
use deno_cache_dir::npm::NpmCacheDir;
use deno_cache_dir::HttpCache;
+use deno_config::deno_json::JsxImportSourceConfig;
use deno_config::workspace::PackageJsonDepResolution;
use deno_config::workspace::WorkspaceResolver;
use deno_core::url::Url;
-use deno_graph::source::Resolver;
+use deno_graph::source::ResolutionMode;
use deno_graph::GraphImport;
use deno_graph::ModuleSpecifier;
+use deno_graph::Range;
use deno_npm::NpmSystemInfo;
+use deno_path_util::url_from_directory_path;
use deno_path_util::url_to_file_path;
use deno_runtime::deno_fs;
use deno_runtime::deno_node::NodeResolver;
@@ -24,6 +26,7 @@ use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use node_resolver::errors::ClosestPkgJsonError;
use node_resolver::InNpmPackageChecker;
+use node_resolver::NodeModuleKind;
use node_resolver::NodeResolutionMode;
use std::borrow::Cow;
use std::collections::BTreeMap;
@@ -33,6 +36,7 @@ use std::collections::HashSet;
use std::sync::Arc;
use super::cache::LspCache;
+use super::documents::Document;
use super::jsr::JsrCacheResolver;
use crate::args::create_default_npmrc;
use crate::args::CacheSetting;
@@ -53,21 +57,20 @@ use crate::npm::CliNpmResolverCreateOptions;
use crate::npm::CliNpmResolverManagedSnapshotOption;
use crate::npm::CreateInNpmPkgCheckerOptions;
use crate::npm::ManagedCliNpmResolver;
-use crate::resolver::CjsTracker;
-use crate::resolver::CjsTrackerOptions;
use crate::resolver::CliDenoResolverFs;
-use crate::resolver::CliGraphResolver;
-use crate::resolver::CliGraphResolverOptions;
use crate::resolver::CliNodeResolver;
+use crate::resolver::CliResolver;
+use crate::resolver::CliResolverOptions;
+use crate::resolver::IsCjsResolver;
use crate::resolver::WorkerCliNpmGraphResolver;
use crate::tsc::into_specifier_and_media_type;
+use crate::util::fs::canonicalize_path_maybe_not_exists;
use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle;
#[derive(Debug, Clone)]
struct LspScopeResolver {
- cjs_tracker: Option<Arc<LspCjsTracker>>,
- graph_resolver: Arc<CliGraphResolver>,
+ resolver: Arc<CliResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
node_resolver: Option<Arc<CliNodeResolver>>,
@@ -81,8 +84,7 @@ struct LspScopeResolver {
impl Default for LspScopeResolver {
fn default() -> Self {
Self {
- cjs_tracker: None,
- graph_resolver: create_graph_resolver(None, None, None),
+ resolver: create_cli_resolver(None, None, None),
jsr_resolver: None,
npm_resolver: None,
node_resolver: None,
@@ -103,7 +105,6 @@ impl LspScopeResolver {
) -> Self {
let mut npm_resolver = None;
let mut node_resolver = None;
- let mut lsp_cjs_tracker = None;
let fs = Arc::new(deno_fs::RealFs);
let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
@@ -118,14 +119,7 @@ impl LspScopeResolver {
.await;
if let Some(npm_resolver) = &npm_resolver {
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
- let cjs_tracker = create_cjs_tracker(
- in_npm_pkg_checker.clone(),
- pkg_json_resolver.clone(),
- );
- lsp_cjs_tracker =
- Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
node_resolver = Some(create_node_resolver(
- cjs_tracker,
fs.clone(),
in_npm_pkg_checker,
npm_resolver,
@@ -133,7 +127,7 @@ impl LspScopeResolver {
));
}
}
- let graph_resolver = create_graph_resolver(
+ let cli_resolver = create_cli_resolver(
config_data.map(|d| d.as_ref()),
npm_resolver.as_ref(),
node_resolver.as_ref(),
@@ -146,7 +140,9 @@ impl LspScopeResolver {
cache.for_specifier(config_data.map(|d| d.scope.as_ref())),
config_data.and_then(|d| d.lockfile.clone()),
)));
- let npm_graph_resolver = graph_resolver.create_graph_npm_resolver();
+ let npm_graph_resolver = cli_resolver.create_graph_npm_resolver();
+ let maybe_jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
let graph_imports = config_data
.and_then(|d| d.member_dir.workspace.to_compiler_option_types().ok())
.map(|imports| {
@@ -154,11 +150,18 @@ impl LspScopeResolver {
imports
.into_iter()
.map(|(referrer, imports)| {
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &referrer,
+ referrer_kind: NodeModuleKind::Esm,
+ cli_resolver: &cli_resolver,
+ jsx_import_source_config: maybe_jsx_import_source_config
+ .as_ref(),
+ };
let graph_import = GraphImport::new(
&referrer,
imports,
&CliJsrUrlProvider,
- Some(graph_resolver.as_ref()),
+ Some(&resolver),
Some(&npm_graph_resolver),
);
(referrer, graph_import)
@@ -182,6 +185,8 @@ impl LspScopeResolver {
.resolve_req_reference(
&req_ref,
&referrer,
+ // todo(dsherret): this is wrong because it doesn't consider CJS referrers
+ NodeModuleKind::Esm,
NodeResolutionMode::Types,
)
.ok()?,
@@ -195,8 +200,7 @@ impl LspScopeResolver {
let package_json_deps_by_resolution =
Arc::new(package_json_deps_by_resolution.unwrap_or_default());
Self {
- cjs_tracker: lsp_cjs_tracker,
- graph_resolver,
+ resolver: cli_resolver,
jsr_resolver,
npm_resolver,
node_resolver,
@@ -216,30 +220,22 @@ impl LspScopeResolver {
deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
));
let mut node_resolver = None;
- let mut lsp_cjs_tracker = None;
if let Some(npm_resolver) = &npm_resolver {
let in_npm_pkg_checker = create_in_npm_pkg_checker(npm_resolver);
- let cjs_tracker = create_cjs_tracker(
- in_npm_pkg_checker.clone(),
- pkg_json_resolver.clone(),
- );
- lsp_cjs_tracker = Some(Arc::new(LspCjsTracker::new(cjs_tracker.clone())));
node_resolver = Some(create_node_resolver(
- cjs_tracker,
fs,
in_npm_pkg_checker,
npm_resolver,
pkg_json_resolver.clone(),
));
}
- let graph_resolver = create_graph_resolver(
+ let graph_resolver = create_cli_resolver(
self.config_data.as_deref(),
npm_resolver.as_ref(),
node_resolver.as_ref(),
);
Arc::new(Self {
- cjs_tracker: lsp_cjs_tracker,
- graph_resolver,
+ resolver: graph_resolver,
jsr_resolver: self.jsr_resolver.clone(),
npm_resolver,
node_resolver,
@@ -334,12 +330,12 @@ impl LspResolver {
}
}
- pub fn as_graph_resolver(
+ pub fn as_cli_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
- ) -> &dyn Resolver {
+ ) -> &CliResolver {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.graph_resolver.as_ref()
+ resolver.resolver.as_ref()
}
pub fn create_graph_npm_resolver(
@@ -347,15 +343,15 @@ impl LspResolver {
file_referrer: Option<&ModuleSpecifier>,
) -> WorkerCliNpmGraphResolver {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.graph_resolver.create_graph_npm_resolver()
+ resolver.resolver.create_graph_npm_resolver()
}
- pub fn maybe_cjs_tracker(
+ pub fn as_config_data(
&self,
file_referrer: Option<&ModuleSpecifier>,
- ) -> Option<&Arc<LspCjsTracker>> {
+ ) -> Option<&Arc<ConfigData>> {
let resolver = self.get_scope_resolver(file_referrer);
- resolver.cjs_tracker.as_ref()
+ resolver.config_data.as_ref()
}
pub fn maybe_node_resolver(
@@ -429,13 +425,19 @@ impl LspResolver {
&self,
req_ref: &NpmPackageReqReference,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
let resolver = self.get_scope_resolver(file_referrer);
let node_resolver = resolver.node_resolver.as_ref()?;
Some(into_specifier_and_media_type(Some(
node_resolver
- .resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
+ .resolve_req_reference(
+ req_ref,
+ referrer,
+ referrer_kind,
+ NodeResolutionMode::Types,
+ )
.ok()?,
)))
}
@@ -478,6 +480,7 @@ impl LspResolver {
&self,
specifier_text: &str,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
) -> bool {
let resolver = self.get_scope_resolver(Some(referrer));
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
@@ -487,6 +490,7 @@ impl LspResolver {
.resolve_if_for_npm_pkg(
specifier_text,
referrer,
+ referrer_kind,
NodeResolutionMode::Types,
)
.ok()
@@ -615,21 +619,6 @@ async fn create_npm_resolver(
Some(create_cli_npm_resolver_for_lsp(options).await)
}
-fn create_cjs_tracker(
- in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
- pkg_json_resolver: Arc<PackageJsonResolver>,
-) -> Arc<CjsTracker> {
- Arc::new(CjsTracker::new(
- in_npm_pkg_checker,
- pkg_json_resolver,
- CjsTrackerOptions {
- // todo(dsherret): support in the lsp by stabilizing the feature
- // so that we don't have to pipe the config in here
- unstable_detect_cjs: false,
- },
- ))
-}
-
fn create_in_npm_pkg_checker(
npm_resolver: &Arc<dyn CliNpmResolver>,
) -> Arc<dyn InNpmPackageChecker> {
@@ -649,7 +638,6 @@ fn create_in_npm_pkg_checker(
}
fn create_node_resolver(
- cjs_tracker: Arc<CjsTracker>,
fs: Arc<dyn deno_fs::FileSystem>,
in_npm_pkg_checker: Arc<dyn InNpmPackageChecker>,
npm_resolver: &Arc<dyn CliNpmResolver>,
@@ -662,7 +650,6 @@ fn create_node_resolver(
pkg_json_resolver.clone(),
));
Arc::new(CliNodeResolver::new(
- cjs_tracker.clone(),
fs,
in_npm_pkg_checker,
node_resolver_inner,
@@ -670,13 +657,12 @@ fn create_node_resolver(
))
}
-fn create_graph_resolver(
+fn create_cli_resolver(
config_data: Option<&ConfigData>,
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
node_resolver: Option<&Arc<CliNodeResolver>>,
-) -> Arc<CliGraphResolver> {
- let workspace = config_data.map(|d| &d.member_dir.workspace);
- Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
+) -> Arc<CliResolver> {
+ Arc::new(CliResolver::new(CliResolverOptions {
node_resolver: node_resolver.cloned(),
npm_resolver: npm_resolver.cloned(),
workspace_resolver: config_data.map(|d| d.resolver.clone()).unwrap_or_else(
@@ -691,9 +677,6 @@ fn create_graph_resolver(
))
},
),
- maybe_jsx_import_source_config: workspace.and_then(|workspace| {
- workspace.to_maybe_jsx_import_source_config().ok().flatten()
- }),
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
bare_node_builtins_enabled: config_data
.is_some_and(|d| d.unstable.contains("bare-node-builtins")),
@@ -726,6 +709,141 @@ impl std::fmt::Debug for RedirectResolver {
}
}
+#[derive(Debug)]
+pub struct LspIsCjsResolver {
+ inner: IsCjsResolver,
+}
+
+impl Default for LspIsCjsResolver {
+ fn default() -> Self {
+ LspIsCjsResolver::new(&Default::default())
+ }
+}
+
+impl LspIsCjsResolver {
+ pub fn new(cache: &LspCache) -> Self {
+ #[derive(Debug)]
+ struct LspInNpmPackageChecker {
+ global_cache_dir: ModuleSpecifier,
+ }
+
+ impl LspInNpmPackageChecker {
+ pub fn new(cache: &LspCache) -> Self {
+ let npm_folder_path = cache.deno_dir().npm_folder_path();
+ Self {
+ global_cache_dir: url_from_directory_path(
+ &canonicalize_path_maybe_not_exists(&npm_folder_path)
+ .unwrap_or(npm_folder_path),
+ )
+ .unwrap_or_else(|_| {
+ ModuleSpecifier::parse("file:///invalid/").unwrap()
+ }),
+ }
+ }
+ }
+
+ impl InNpmPackageChecker for LspInNpmPackageChecker {
+ fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
+ if specifier.scheme() != "file" {
+ return false;
+ }
+ if specifier
+ .as_str()
+ .starts_with(self.global_cache_dir.as_str())
+ {
+ return true;
+ }
+ specifier.as_str().contains("/node_modules/")
+ }
+ }
+
+ let fs = Arc::new(deno_fs::RealFs);
+ let pkg_json_resolver = Arc::new(PackageJsonResolver::new(
+ deno_runtime::deno_node::DenoFsNodeResolverEnv::new(fs.clone()),
+ ));
+
+ LspIsCjsResolver {
+ inner: IsCjsResolver::new(
+ Arc::new(LspInNpmPackageChecker::new(cache)),
+ pkg_json_resolver,
+ crate::resolver::IsCjsResolverOptions {
+ detect_cjs: true,
+ is_node_main: false,
+ },
+ ),
+ }
+ }
+
+ pub fn get_maybe_doc_module_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ maybe_document: Option<&Document>,
+ ) -> NodeModuleKind {
+ self.get_lsp_referrer_kind(
+ specifier,
+ maybe_document.and_then(|d| d.is_script()),
+ )
+ }
+
+ pub fn get_doc_module_kind(&self, document: &Document) -> NodeModuleKind {
+ self.get_lsp_referrer_kind(document.specifier(), document.is_script())
+ }
+
+ pub fn get_lsp_referrer_kind(
+ &self,
+ specifier: &ModuleSpecifier,
+ is_script: Option<bool>,
+ ) -> NodeModuleKind {
+ self.inner.get_lsp_referrer_kind(specifier, is_script)
+ }
+}
+
+#[derive(Debug)]
+pub struct SingleReferrerGraphResolver<'a> {
+ pub valid_referrer: &'a ModuleSpecifier,
+ pub referrer_kind: NodeModuleKind,
+ pub cli_resolver: &'a CliResolver,
+ pub jsx_import_source_config: Option<&'a JsxImportSourceConfig>,
+}
+
+impl<'a> deno_graph::source::Resolver for SingleReferrerGraphResolver<'a> {
+ fn default_jsx_import_source(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .and_then(|c| c.default_specifier.clone())
+ }
+
+ fn default_jsx_import_source_types(&self) -> Option<String> {
+ self
+ .jsx_import_source_config
+ .and_then(|c| c.default_types_specifier.clone())
+ }
+
+ fn jsx_import_source_module(&self) -> &str {
+ self
+ .jsx_import_source_config
+ .map(|c| c.module.as_str())
+ .unwrap_or(deno_graph::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE)
+ }
+
+ fn resolve(
+ &self,
+ specifier_text: &str,
+ referrer_range: &Range,
+ mode: ResolutionMode,
+ ) -> Result<ModuleSpecifier, deno_graph::source::ResolveError> {
+ // this resolver assumes it will only be used with a single referrer
+ // with the provided referrer kind
+ debug_assert_eq!(referrer_range.specifier, *self.valid_referrer);
+ self.cli_resolver.resolve(
+ specifier_text,
+ referrer_range,
+ self.referrer_kind,
+ mode,
+ )
+ }
+}
+
impl RedirectResolver {
fn new(
cache: Arc<dyn HttpCache>,
@@ -842,45 +960,6 @@ impl RedirectResolver {
}
}
-#[derive(Debug)]
-pub struct LspCjsTracker {
- cjs_tracker: Arc<CjsTracker>,
-}
-
-impl LspCjsTracker {
- pub fn new(cjs_tracker: Arc<CjsTracker>) -> Self {
- Self { cjs_tracker }
- }
-
- pub fn is_cjs(
- &self,
- specifier: &ModuleSpecifier,
- media_type: MediaType,
- maybe_parsed_source: Option<&ParsedSource>,
- ) -> bool {
- if let Some(module_kind) =
- self.cjs_tracker.get_known_kind(specifier, media_type)
- {
- module_kind.is_cjs()
- } else {
- let maybe_is_script = maybe_parsed_source.map(|p| p.compute_is_script());
- maybe_is_script
- .and_then(|is_script| {
- self
- .cjs_tracker
- .is_cjs_with_known_is_script(specifier, media_type, is_script)
- .ok()
- })
- .unwrap_or_else(|| {
- self
- .cjs_tracker
- .is_maybe_cjs(specifier, media_type)
- .unwrap_or(false)
- })
- }
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;