diff options
Diffstat (limited to 'cli/lsp/resolver.rs')
-rw-r--r-- | cli/lsp/resolver.rs | 287 |
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::*; |