mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 08:33:43 -05:00
refactor(lsp): unify resolver types into LspResolver (#23514)
This commit is contained in:
parent
c519355624
commit
f8ddcc4f78
8 changed files with 451 additions and 376 deletions
|
@ -4,11 +4,10 @@ use super::diagnostics::DenoDiagnostic;
|
|||
use super::diagnostics::DiagnosticSource;
|
||||
use super::documents::Documents;
|
||||
use super::language_server;
|
||||
use super::resolver::LspResolver;
|
||||
use super::tsc;
|
||||
|
||||
use crate::args::jsr_url;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::tools::lint::create_linter;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
|
@ -27,7 +26,6 @@ use deno_lint::diagnostic::LintDiagnostic;
|
|||
use deno_lint::rules::LintRule;
|
||||
use deno_runtime::deno_node::NpmResolver;
|
||||
use deno_runtime::deno_node::PathClean;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrPackageNvReference;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
|
@ -217,22 +215,19 @@ fn code_as_string(code: &Option<lsp::NumberOrString>) -> String {
|
|||
pub struct TsResponseImportMapper<'a> {
|
||||
documents: &'a Documents,
|
||||
maybe_import_map: Option<&'a ImportMap>,
|
||||
node_resolver: Option<&'a CliNodeResolver>,
|
||||
npm_resolver: Option<&'a dyn CliNpmResolver>,
|
||||
resolver: &'a LspResolver,
|
||||
}
|
||||
|
||||
impl<'a> TsResponseImportMapper<'a> {
|
||||
pub fn new(
|
||||
documents: &'a Documents,
|
||||
maybe_import_map: Option<&'a ImportMap>,
|
||||
node_resolver: Option<&'a CliNodeResolver>,
|
||||
npm_resolver: Option<&'a dyn CliNpmResolver>,
|
||||
resolver: &'a LspResolver,
|
||||
) -> Self {
|
||||
Self {
|
||||
documents,
|
||||
maybe_import_map,
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,9 +299,7 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
return Some(spec_str);
|
||||
}
|
||||
|
||||
if let Some(npm_resolver) =
|
||||
self.npm_resolver.as_ref().and_then(|r| r.as_managed())
|
||||
{
|
||||
if let Some(npm_resolver) = self.resolver.maybe_managed_npm_resolver() {
|
||||
if npm_resolver.in_npm_package(specifier) {
|
||||
if let Ok(Some(pkg_id)) =
|
||||
npm_resolver.resolve_pkg_id_from_specifier(specifier)
|
||||
|
@ -370,9 +363,9 @@ impl<'a> TsResponseImportMapper<'a> {
|
|||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
) -> Option<String> {
|
||||
let node_resolver = self.node_resolver?;
|
||||
let package_json = node_resolver
|
||||
.get_closest_package_json(specifier, &PermissionsContainer::allow_all())
|
||||
let package_json = self
|
||||
.resolver
|
||||
.get_closest_package_json(specifier)
|
||||
.ok()
|
||||
.flatten()?;
|
||||
let root_folder = package_json.path.parent()?;
|
||||
|
|
|
@ -1150,6 +1150,7 @@ pub enum ConfigWatchedFileType {
|
|||
/// Contains the config file and dependent information.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConfigData {
|
||||
pub scope: ModuleSpecifier,
|
||||
pub config_file: Option<Arc<ConfigFile>>,
|
||||
pub fmt_options: Arc<FmtOptions>,
|
||||
pub lint_options: Arc<LintOptions>,
|
||||
|
@ -1487,6 +1488,7 @@ impl ConfigData {
|
|||
let ts_config = LspTsConfig::new(config_file.as_ref(), import_map.as_ref());
|
||||
|
||||
ConfigData {
|
||||
scope: scope.clone(),
|
||||
config_file: config_file.map(Arc::new),
|
||||
fmt_options,
|
||||
lint_options,
|
||||
|
|
|
@ -809,10 +809,8 @@ fn generate_lint_diagnostics(
|
|||
break;
|
||||
}
|
||||
// ignore any npm package files
|
||||
if let Some(npm) = &snapshot.npm {
|
||||
if npm.node_resolver.in_npm_package(specifier) {
|
||||
continue;
|
||||
}
|
||||
if snapshot.resolver.in_npm_package(specifier) {
|
||||
continue;
|
||||
}
|
||||
let version = document.maybe_lsp_version();
|
||||
let (lint_options, lint_rules) = config
|
||||
|
@ -1347,6 +1345,7 @@ fn diagnose_resolution(
|
|||
diagnostics.push(DenoDiagnostic::DenoWarn(message));
|
||||
}
|
||||
}
|
||||
let managed_npm_resolver = snapshot.resolver.maybe_managed_npm_resolver();
|
||||
if let Some(doc) = snapshot.documents.get(specifier) {
|
||||
if let Some(diagnostic) = check_redirect_diagnostic(specifier, &doc) {
|
||||
diagnostics.push(diagnostic);
|
||||
|
@ -1375,11 +1374,7 @@ fn diagnose_resolution(
|
|||
} else if let Ok(pkg_ref) =
|
||||
NpmPackageReqReference::from_specifier(specifier)
|
||||
{
|
||||
if let Some(npm_resolver) = snapshot
|
||||
.npm
|
||||
.as_ref()
|
||||
.and_then(|n| n.npm_resolver.as_managed())
|
||||
{
|
||||
if let Some(npm_resolver) = managed_npm_resolver {
|
||||
// show diagnostics for npm package references that aren't cached
|
||||
let req = pkg_ref.into_inner().req;
|
||||
if !npm_resolver.is_pkg_req_folder_cached(&req) {
|
||||
|
@ -1406,11 +1401,7 @@ fn diagnose_resolution(
|
|||
diagnostics
|
||||
.push(DenoDiagnostic::BareNodeSpecifier(module_name.to_string()));
|
||||
}
|
||||
} else if let Some(npm_resolver) = snapshot
|
||||
.npm
|
||||
.as_ref()
|
||||
.and_then(|n| n.npm_resolver.as_managed())
|
||||
{
|
||||
} else if let Some(npm_resolver) = managed_npm_resolver {
|
||||
// check that a @types/node package exists in the resolver
|
||||
let types_node_req = PackageReq::from_str("@types/node").unwrap();
|
||||
if !npm_resolver.is_pkg_req_folder_cached(&types_node_req) {
|
||||
|
@ -1451,10 +1442,8 @@ fn diagnose_dependency(
|
|||
dependency_key: &str,
|
||||
dependency: &deno_graph::Dependency,
|
||||
) {
|
||||
if let Some(npm) = &snapshot.npm {
|
||||
if npm.npm_resolver.in_npm_package(referrer) {
|
||||
return; // ignore, surface typescript errors instead
|
||||
}
|
||||
if snapshot.resolver.in_npm_package(referrer) {
|
||||
return; // ignore, surface typescript errors instead
|
||||
}
|
||||
|
||||
let import_map = snapshot.config.tree.root_import_map();
|
||||
|
@ -1592,6 +1581,7 @@ mod tests {
|
|||
use crate::lsp::documents::Documents;
|
||||
use crate::lsp::documents::LanguageId;
|
||||
use crate::lsp::language_server::StateSnapshot;
|
||||
use crate::lsp::resolver::LspResolver;
|
||||
use deno_config::ConfigFile;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
|
@ -1630,6 +1620,9 @@ mod tests {
|
|||
.unwrap();
|
||||
config.tree.inject_config_file(config_file).await;
|
||||
}
|
||||
let resolver = LspResolver::default()
|
||||
.with_new_config(&config, None, None)
|
||||
.await;
|
||||
StateSnapshot {
|
||||
project_version: 0,
|
||||
documents,
|
||||
|
@ -1638,7 +1631,7 @@ mod tests {
|
|||
GlobalHttpCache::new(location.to_path_buf(), RealDenoCacheEnv),
|
||||
)),
|
||||
config: config.snapshot(),
|
||||
npm: None,
|
||||
resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,22 +3,17 @@
|
|||
use super::cache::calculate_fs_version;
|
||||
use super::cache::LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY;
|
||||
use super::config::Config;
|
||||
use super::language_server::StateNpmSnapshot;
|
||||
use super::resolver::LspResolver;
|
||||
use super::testing::TestCollector;
|
||||
use super::testing::TestModule;
|
||||
use super::text::LineIndex;
|
||||
use super::tsc;
|
||||
use super::tsc::AssetDocument;
|
||||
|
||||
use crate::args::package_json;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::graph_util::CliJsrUrlProvider;
|
||||
use crate::jsr::JsrCacheResolver;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::resolver::SloppyImportsFsEntry;
|
||||
use crate::resolver::SloppyImportsResolution;
|
||||
use crate::resolver::SloppyImportsResolver;
|
||||
|
@ -43,12 +38,10 @@ use deno_lockfile::Lockfile;
|
|||
use deno_runtime::deno_node;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
use indexmap::IndexMap;
|
||||
use package_json::PackageJsonDepsProvider;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
|
@ -294,7 +287,7 @@ pub struct Document {
|
|||
media_type: MediaType,
|
||||
/// Present if and only if this is an open document.
|
||||
open_data: Option<DocumentOpenData>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<LspResolver>,
|
||||
specifier: ModuleSpecifier,
|
||||
text_info: SourceTextInfo,
|
||||
}
|
||||
|
@ -308,8 +301,7 @@ impl Document {
|
|||
maybe_lsp_version: Option<i32>,
|
||||
maybe_language_id: Option<LanguageId>,
|
||||
maybe_headers: Option<HashMap<String, String>>,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
maybe_node_resolver: Option<&CliNodeResolver>,
|
||||
resolver: Arc<LspResolver>,
|
||||
config: Arc<Config>,
|
||||
cache: &Arc<dyn HttpCache>,
|
||||
) -> Arc<Self> {
|
||||
|
@ -318,7 +310,7 @@ impl Document {
|
|||
&specifier,
|
||||
maybe_headers.as_ref(),
|
||||
maybe_language_id,
|
||||
maybe_node_resolver,
|
||||
&resolver,
|
||||
);
|
||||
let (maybe_parsed_source, maybe_module) =
|
||||
if media_type_is_diagnosable(media_type) {
|
||||
|
@ -366,17 +358,14 @@ impl Document {
|
|||
|
||||
fn with_new_config(
|
||||
&self,
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
maybe_node_resolver: Option<&CliNodeResolver>,
|
||||
resolver: Arc<LspResolver>,
|
||||
config: Arc<Config>,
|
||||
) -> Arc<Self> {
|
||||
let graph_resolver = resolver.as_graph_resolver();
|
||||
let npm_resolver = resolver.as_graph_npm_resolver();
|
||||
let media_type = resolve_media_type(
|
||||
&self.specifier,
|
||||
self.maybe_headers.as_ref(),
|
||||
self.maybe_language_id,
|
||||
maybe_node_resolver,
|
||||
&resolver,
|
||||
);
|
||||
let dependencies;
|
||||
let maybe_types_dependency;
|
||||
|
@ -403,6 +392,8 @@ impl Document {
|
|||
maybe_test_module_fut =
|
||||
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &config);
|
||||
} else {
|
||||
let graph_resolver = resolver.as_graph_resolver();
|
||||
let npm_resolver = resolver.as_graph_npm_resolver();
|
||||
dependencies = Arc::new(
|
||||
self
|
||||
.dependencies
|
||||
|
@ -682,20 +673,19 @@ fn resolve_media_type(
|
|||
specifier: &ModuleSpecifier,
|
||||
maybe_headers: Option<&HashMap<String, String>>,
|
||||
maybe_language_id: Option<LanguageId>,
|
||||
maybe_node_resolver: Option<&CliNodeResolver>,
|
||||
resolver: &LspResolver,
|
||||
) -> MediaType {
|
||||
if let Some(node_resolver) = maybe_node_resolver {
|
||||
if node_resolver.in_npm_package(specifier) {
|
||||
match node_resolver.url_to_node_resolution(specifier.clone()) {
|
||||
Ok(resolution) => {
|
||||
let (_, media_type) =
|
||||
NodeResolution::into_specifier_and_media_type(Some(resolution));
|
||||
return media_type;
|
||||
}
|
||||
Err(err) => {
|
||||
lsp_warn!("Node resolution failed for '{}': {}", specifier, err);
|
||||
}
|
||||
if resolver.in_npm_package(specifier) {
|
||||
match resolver.url_to_node_resolution(specifier.clone()) {
|
||||
Ok(Some(resolution)) => {
|
||||
let (_, media_type) =
|
||||
NodeResolution::into_specifier_and_media_type(Some(resolution));
|
||||
return media_type;
|
||||
}
|
||||
Err(err) => {
|
||||
lsp_warn!("Node resolution failed for '{}': {}", specifier, err);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -794,8 +784,7 @@ impl FileSystemDocuments {
|
|||
pub fn get(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
resolver: &Arc<CliGraphResolver>,
|
||||
maybe_node_resolver: Option<&CliNodeResolver>,
|
||||
resolver: &Arc<LspResolver>,
|
||||
config: &Arc<Config>,
|
||||
cache: &Arc<dyn HttpCache>,
|
||||
) -> Option<Arc<Document>> {
|
||||
|
@ -814,13 +803,7 @@ impl FileSystemDocuments {
|
|||
};
|
||||
if dirty {
|
||||
// attempt to update the file on the file system
|
||||
self.refresh_document(
|
||||
specifier,
|
||||
resolver,
|
||||
maybe_node_resolver,
|
||||
config,
|
||||
cache,
|
||||
)
|
||||
self.refresh_document(specifier, resolver, config, cache)
|
||||
} else {
|
||||
old_doc
|
||||
}
|
||||
|
@ -831,8 +814,7 @@ impl FileSystemDocuments {
|
|||
fn refresh_document(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
resolver: &Arc<CliGraphResolver>,
|
||||
maybe_node_resolver: Option<&CliNodeResolver>,
|
||||
resolver: &Arc<LspResolver>,
|
||||
config: &Arc<Config>,
|
||||
cache: &Arc<dyn HttpCache>,
|
||||
) -> Option<Arc<Document>> {
|
||||
|
@ -848,7 +830,6 @@ impl FileSystemDocuments {
|
|||
None,
|
||||
None,
|
||||
resolver.clone(),
|
||||
maybe_node_resolver,
|
||||
config.clone(),
|
||||
cache,
|
||||
)
|
||||
|
@ -864,7 +845,6 @@ impl FileSystemDocuments {
|
|||
None,
|
||||
None,
|
||||
resolver.clone(),
|
||||
maybe_node_resolver,
|
||||
config.clone(),
|
||||
cache,
|
||||
)
|
||||
|
@ -893,7 +873,6 @@ impl FileSystemDocuments {
|
|||
None,
|
||||
maybe_headers,
|
||||
resolver.clone(),
|
||||
maybe_node_resolver,
|
||||
config.clone(),
|
||||
cache,
|
||||
)
|
||||
|
@ -942,11 +921,9 @@ pub struct Documents {
|
|||
/// Any imports to the context supplied by configuration files. This is like
|
||||
/// the imports into the a module graph in CLI.
|
||||
imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>,
|
||||
/// Resolver for node_modules.
|
||||
maybe_node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
/// A resolver that takes into account currently loaded import map and JSX
|
||||
/// settings.
|
||||
resolver: Arc<CliGraphResolver>,
|
||||
resolver: Arc<LspResolver>,
|
||||
jsr_resolver: Arc<JsrCacheResolver>,
|
||||
lockfile: Option<Arc<Mutex<Lockfile>>>,
|
||||
/// The npm package requirements found in npm specifiers.
|
||||
|
@ -969,17 +946,7 @@ impl Documents {
|
|||
open_docs: HashMap::default(),
|
||||
file_system_docs: Default::default(),
|
||||
imports: Default::default(),
|
||||
maybe_node_resolver: None,
|
||||
resolver: Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||
node_resolver: None,
|
||||
npm_resolver: None,
|
||||
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::default()),
|
||||
maybe_jsx_import_source_config: None,
|
||||
maybe_import_map: None,
|
||||
maybe_vendor_dir: None,
|
||||
bare_node_builtins_enabled: false,
|
||||
sloppy_imports_resolver: None,
|
||||
})),
|
||||
resolver: Default::default(),
|
||||
jsr_resolver: Arc::new(JsrCacheResolver::new(cache.clone(), None)),
|
||||
lockfile: None,
|
||||
npm_specifier_reqs: Default::default(),
|
||||
|
@ -1022,7 +989,6 @@ impl Documents {
|
|||
// x-typescript-types?
|
||||
None,
|
||||
self.resolver.clone(),
|
||||
self.maybe_node_resolver.as_deref(),
|
||||
self.config.clone(),
|
||||
&self.cache,
|
||||
);
|
||||
|
@ -1218,7 +1184,6 @@ impl Documents {
|
|||
self.file_system_docs.get(
|
||||
&specifier,
|
||||
&self.resolver,
|
||||
self.maybe_node_resolver.as_deref(),
|
||||
&self.config,
|
||||
&self.cache,
|
||||
)
|
||||
|
@ -1280,29 +1245,21 @@ impl Documents {
|
|||
&self,
|
||||
specifiers: &[String],
|
||||
referrer: &ModuleSpecifier,
|
||||
maybe_npm: Option<&StateNpmSnapshot>,
|
||||
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
|
||||
let document = self.get(referrer);
|
||||
let dependencies = document.as_ref().map(|d| d.dependencies());
|
||||
let mut results = Vec::new();
|
||||
for specifier in specifiers {
|
||||
if let Some(npm) = maybe_npm {
|
||||
if npm.node_resolver.in_npm_package(referrer) {
|
||||
// we're in an npm package, so use node resolution
|
||||
results.push(Some(NodeResolution::into_specifier_and_media_type(
|
||||
npm
|
||||
.node_resolver
|
||||
.resolve(
|
||||
specifier,
|
||||
referrer,
|
||||
NodeResolutionMode::Types,
|
||||
&PermissionsContainer::allow_all(),
|
||||
)
|
||||
.ok()
|
||||
.flatten(),
|
||||
)));
|
||||
continue;
|
||||
}
|
||||
if self.resolver.in_npm_package(referrer) {
|
||||
// we're in an npm package, so use node resolution
|
||||
results.push(Some(NodeResolution::into_specifier_and_media_type(
|
||||
self
|
||||
.resolver
|
||||
.node_resolve(specifier, referrer, NodeResolutionMode::Types)
|
||||
.ok()
|
||||
.flatten(),
|
||||
)));
|
||||
continue;
|
||||
}
|
||||
if specifier.starts_with("asset:") {
|
||||
if let Ok(specifier) = ModuleSpecifier::parse(specifier) {
|
||||
|
@ -1315,9 +1272,9 @@ impl Documents {
|
|||
dependencies.as_ref().and_then(|d| d.get(specifier))
|
||||
{
|
||||
if let Some(specifier) = dep.maybe_type.maybe_specifier() {
|
||||
results.push(self.resolve_dependency(specifier, maybe_npm, referrer));
|
||||
results.push(self.resolve_dependency(specifier, referrer));
|
||||
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
|
||||
results.push(self.resolve_dependency(specifier, maybe_npm, referrer));
|
||||
results.push(self.resolve_dependency(specifier, referrer));
|
||||
} else {
|
||||
results.push(None);
|
||||
}
|
||||
|
@ -1325,14 +1282,14 @@ impl Documents {
|
|||
.resolve_imports_dependency(specifier)
|
||||
.and_then(|r| r.maybe_specifier())
|
||||
{
|
||||
results.push(self.resolve_dependency(specifier, maybe_npm, referrer));
|
||||
results.push(self.resolve_dependency(specifier, referrer));
|
||||
} else if let Ok(npm_req_ref) =
|
||||
NpmPackageReqReference::from_str(specifier)
|
||||
{
|
||||
results.push(node_resolve_npm_req_ref(
|
||||
&npm_req_ref,
|
||||
maybe_npm,
|
||||
referrer,
|
||||
&self.resolver,
|
||||
));
|
||||
} else if let Ok(specifier) = self.resolver.as_graph_resolver().resolve(
|
||||
specifier,
|
||||
|
@ -1343,7 +1300,7 @@ impl Documents {
|
|||
},
|
||||
ResolutionMode::Types,
|
||||
) {
|
||||
results.push(self.resolve_dependency(&specifier, maybe_npm, referrer));
|
||||
results.push(self.resolve_dependency(&specifier, referrer));
|
||||
} else {
|
||||
results.push(None);
|
||||
}
|
||||
|
@ -1372,36 +1329,13 @@ impl Documents {
|
|||
pub fn update_config(
|
||||
&mut self,
|
||||
config: &Config,
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
resolver: &Arc<LspResolver>,
|
||||
workspace_files: &BTreeSet<ModuleSpecifier>,
|
||||
) {
|
||||
self.config = Arc::new(config.clone());
|
||||
let config_data = config.tree.root_data();
|
||||
let config_file = config_data.and_then(|d| d.config_file.as_deref());
|
||||
self.maybe_node_resolver = node_resolver.clone();
|
||||
self.resolver = Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||
node_resolver,
|
||||
npm_resolver,
|
||||
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::new(
|
||||
config_data
|
||||
.and_then(|d| d.package_json.as_ref())
|
||||
.map(|package_json| {
|
||||
package_json::get_local_package_json_version_reqs(package_json)
|
||||
}),
|
||||
)),
|
||||
maybe_jsx_import_source_config: config_file
|
||||
.and_then(|cf| cf.to_maybe_jsx_import_source_config().ok().flatten()),
|
||||
maybe_import_map: config_data.and_then(|d| d.import_map.clone()),
|
||||
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
|
||||
bare_node_builtins_enabled: config_file
|
||||
.map(|config| config.has_unstable("bare-node-builtins"))
|
||||
.unwrap_or(false),
|
||||
// Don't set this for the LSP because instead we'll use the OpenDocumentsLoader
|
||||
// because it's much easier and we get diagnostics/quick fixes about a redirected
|
||||
// specifier for free.
|
||||
sloppy_imports_resolver: None,
|
||||
}));
|
||||
self.resolver = resolver.clone();
|
||||
self.jsr_resolver = Arc::new(JsrCacheResolver::new(
|
||||
self.cache.clone(),
|
||||
config.tree.root_lockfile().cloned(),
|
||||
|
@ -1452,21 +1386,14 @@ impl Documents {
|
|||
if !config.specifier_enabled(doc.specifier()) {
|
||||
continue;
|
||||
}
|
||||
*doc = doc.with_new_config(
|
||||
self.resolver.clone(),
|
||||
self.maybe_node_resolver.as_deref(),
|
||||
self.config.clone(),
|
||||
);
|
||||
*doc = doc.with_new_config(self.resolver.clone(), self.config.clone());
|
||||
}
|
||||
for mut doc in self.file_system_docs.docs.iter_mut() {
|
||||
if !config.specifier_enabled(doc.specifier()) {
|
||||
continue;
|
||||
}
|
||||
*doc.value_mut() = doc.with_new_config(
|
||||
self.resolver.clone(),
|
||||
self.maybe_node_resolver.as_deref(),
|
||||
self.config.clone(),
|
||||
);
|
||||
*doc.value_mut() =
|
||||
doc.with_new_config(self.resolver.clone(), self.config.clone());
|
||||
}
|
||||
self.open_docs = open_docs;
|
||||
let mut preload_count = 0;
|
||||
|
@ -1484,7 +1411,6 @@ impl Documents {
|
|||
fs_docs.refresh_document(
|
||||
specifier,
|
||||
&self.resolver,
|
||||
self.maybe_node_resolver.as_deref(),
|
||||
&self.config,
|
||||
&self.cache,
|
||||
);
|
||||
|
@ -1566,7 +1492,6 @@ impl Documents {
|
|||
fn resolve_dependency(
|
||||
&self,
|
||||
specifier: &ModuleSpecifier,
|
||||
maybe_npm: Option<&StateNpmSnapshot>,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||
if let Some(module_name) = specifier.as_str().strip_prefix("node:") {
|
||||
|
@ -1579,13 +1504,13 @@ impl Documents {
|
|||
}
|
||||
|
||||
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(specifier) {
|
||||
return node_resolve_npm_req_ref(&npm_ref, maybe_npm, referrer);
|
||||
return node_resolve_npm_req_ref(&npm_ref, referrer, &self.resolver);
|
||||
}
|
||||
let Some(doc) = self.get(specifier) else {
|
||||
return Some((specifier.clone(), MediaType::from_specifier(specifier)));
|
||||
};
|
||||
if let Some(specifier) = doc.maybe_types_dependency().maybe_specifier() {
|
||||
self.resolve_dependency(specifier, maybe_npm, referrer)
|
||||
self.resolve_dependency(specifier, referrer)
|
||||
} else {
|
||||
let media_type = doc.media_type();
|
||||
Some((doc.specifier().clone(), media_type))
|
||||
|
@ -1608,22 +1533,19 @@ impl Documents {
|
|||
|
||||
fn node_resolve_npm_req_ref(
|
||||
npm_req_ref: &NpmPackageReqReference,
|
||||
maybe_npm: Option<&StateNpmSnapshot>,
|
||||
referrer: &ModuleSpecifier,
|
||||
resolver: &LspResolver,
|
||||
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||
maybe_npm.map(|npm| {
|
||||
NodeResolution::into_specifier_and_media_type(
|
||||
npm
|
||||
.node_resolver
|
||||
.resolve_req_reference(
|
||||
npm_req_ref,
|
||||
&PermissionsContainer::allow_all(),
|
||||
referrer,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok(),
|
||||
)
|
||||
})
|
||||
Some(NodeResolution::into_specifier_and_media_type(
|
||||
resolver
|
||||
.resolve_npm_req_reference(
|
||||
npm_req_ref,
|
||||
referrer,
|
||||
NodeResolutionMode::Types,
|
||||
)
|
||||
.ok()
|
||||
.flatten(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Loader that will look at the open documents.
|
||||
|
@ -1717,7 +1639,7 @@ fn parse_and_analyze_module(
|
|||
text_info: SourceTextInfo,
|
||||
maybe_headers: Option<&HashMap<String, String>>,
|
||||
media_type: MediaType,
|
||||
resolver: &CliGraphResolver,
|
||||
resolver: &LspResolver,
|
||||
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) {
|
||||
let parsed_source_result = parse_source(specifier, text_info, media_type);
|
||||
let module_result =
|
||||
|
@ -1744,7 +1666,7 @@ fn analyze_module(
|
|||
specifier: &ModuleSpecifier,
|
||||
parsed_source_result: &ParsedSourceResult,
|
||||
maybe_headers: Option<&HashMap<String, String>>,
|
||||
resolver: &CliGraphResolver,
|
||||
resolver: &LspResolver,
|
||||
) -> ModuleResult {
|
||||
match parsed_source_result {
|
||||
Ok(parsed_source) => Ok(deno_graph::parse_module_from_ast(
|
||||
|
@ -1939,7 +1861,10 @@ console.log(b, "hello deno");
|
|||
)
|
||||
.await;
|
||||
|
||||
documents.update_config(&config, None, None, &workspace_files);
|
||||
let resolver = LspResolver::default()
|
||||
.with_new_config(&config, None, None)
|
||||
.await;
|
||||
documents.update_config(&config, &resolver, &workspace_files);
|
||||
|
||||
// open the document
|
||||
let document = documents.open(
|
||||
|
@ -1980,7 +1905,10 @@ console.log(b, "hello deno");
|
|||
)
|
||||
.await;
|
||||
|
||||
documents.update_config(&config, None, None, &workspace_files);
|
||||
let resolver = LspResolver::default()
|
||||
.with_new_config(&config, None, None)
|
||||
.await;
|
||||
documents.update_config(&config, &resolver, &workspace_files);
|
||||
|
||||
// check the document's dependencies
|
||||
let document = documents.get(&file1_specifier).unwrap();
|
||||
|
|
|
@ -13,9 +13,6 @@ use deno_core::url;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_graph::GraphKind;
|
||||
use deno_graph::Resolution;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_tls::rustls::RootCertStore;
|
||||
use deno_runtime::deno_tls::RootCertStoreProvider;
|
||||
use deno_semver::jsr::JsrPackageReqReference;
|
||||
|
@ -29,7 +26,6 @@ use std::collections::HashSet;
|
|||
use std::collections::VecDeque;
|
||||
use std::env;
|
||||
use std::fmt::Write as _;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::unbounded_channel;
|
||||
|
@ -52,7 +48,6 @@ use super::client::Client;
|
|||
use super::code_lens;
|
||||
use super::completions;
|
||||
use super::config::Config;
|
||||
use super::config::ConfigData;
|
||||
use super::config::ConfigSnapshot;
|
||||
use super::config::UpdateImportsOnFileMoveEnabled;
|
||||
use super::config::WorkspaceSettings;
|
||||
|
@ -79,6 +74,7 @@ use super::performance::Performance;
|
|||
use super::performance::PerformanceMark;
|
||||
use super::refactor;
|
||||
use super::registries::ModuleRegistry;
|
||||
use super::resolver::LspResolver;
|
||||
use super::testing;
|
||||
use super::text;
|
||||
use super::tsc;
|
||||
|
@ -94,7 +90,6 @@ use crate::args::CacheSetting;
|
|||
use crate::args::CliOptions;
|
||||
use crate::args::Flags;
|
||||
use crate::cache::DenoDir;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::cache::LocalLspHttpCache;
|
||||
|
@ -106,14 +101,6 @@ use crate::lsp::config::ConfigWatchedFileType;
|
|||
use crate::lsp::logging::init_log_file;
|
||||
use crate::lsp::tsc::file_text_changes_to_workspace_edit;
|
||||
use crate::lsp::urls::LspUrlKind;
|
||||
use crate::npm::create_cli_npm_resolver_for_lsp;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedPackageJsonInstallerOption;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::tools::fmt::format_file;
|
||||
use crate::tools::fmt::format_parsed_source;
|
||||
use crate::tools::upgrade::check_for_upgrades_for_lsp;
|
||||
|
@ -121,8 +108,6 @@ use crate::tools::upgrade::upgrade_check_enabled;
|
|||
use crate::util::fs::remove_dir_all_if_exists;
|
||||
use crate::util::path::is_importable_ext;
|
||||
use crate::util::path::to_percent_decoded_str;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
|
||||
struct LspRootCertStoreProvider(RootCertStore);
|
||||
|
@ -133,46 +118,9 @@ impl RootCertStoreProvider for LspRootCertStoreProvider {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LspNpmServices {
|
||||
/// When this hash changes, the services need updating
|
||||
config_hash: LspNpmConfigHash,
|
||||
/// Npm's search api.
|
||||
search_api: CliNpmSearchApi,
|
||||
/// Node resolver.
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
/// Resolver for npm packages.
|
||||
resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct LspNpmConfigHash(u64);
|
||||
|
||||
impl LspNpmConfigHash {
|
||||
pub fn from_inner(inner: &Inner) -> Self {
|
||||
let config_data = inner.config.tree.root_data();
|
||||
let node_modules_dir =
|
||||
config_data.and_then(|d| d.node_modules_dir.as_ref());
|
||||
let lockfile = config_data.and_then(|d| d.lockfile.as_ref());
|
||||
let mut hasher = FastInsecureHasher::new();
|
||||
hasher.write_hashable(node_modules_dir);
|
||||
hasher.write_hashable(&inner.maybe_global_cache_path);
|
||||
if let Some(lockfile) = lockfile {
|
||||
hasher.write_hashable(&*lockfile.lock());
|
||||
}
|
||||
Self(hasher.finish())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LanguageServer(Arc<tokio::sync::RwLock<Inner>>, CancellationToken);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StateNpmSnapshot {
|
||||
pub node_resolver: Arc<CliNodeResolver>,
|
||||
pub npm_resolver: Arc<dyn CliNpmResolver>,
|
||||
}
|
||||
|
||||
/// Snapshot of the state used by TSC.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StateSnapshot {
|
||||
|
@ -181,7 +129,7 @@ pub struct StateSnapshot {
|
|||
pub cache_metadata: cache::CacheMetadata,
|
||||
pub config: Arc<ConfigSnapshot>,
|
||||
pub documents: Documents,
|
||||
pub npm: Option<StateNpmSnapshot>,
|
||||
pub resolver: Arc<LspResolver>,
|
||||
}
|
||||
|
||||
type LanguageServerTaskFn = Box<dyn FnOnce(LanguageServer) + Send + Sync>;
|
||||
|
@ -253,11 +201,11 @@ pub struct Inner {
|
|||
maybe_global_cache_path: Option<PathBuf>,
|
||||
/// A lazily create "server" for handling test run requests.
|
||||
maybe_testing_server: Option<testing::TestServer>,
|
||||
/// Services used for dealing with npm related functionality.
|
||||
npm: LspNpmServices,
|
||||
npm_search_api: CliNpmSearchApi,
|
||||
project_version: usize,
|
||||
/// A collection of measurements which instrument that performance of the LSP.
|
||||
performance: Arc<Performance>,
|
||||
resolver: Arc<LspResolver>,
|
||||
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
|
||||
ts_fixable_diagnostics: Vec<String>,
|
||||
/// An abstraction that handles interactions with TypeScript.
|
||||
|
@ -544,13 +492,9 @@ impl Inner {
|
|||
maybe_testing_server: None,
|
||||
module_registries,
|
||||
module_registries_location,
|
||||
npm: LspNpmServices {
|
||||
config_hash: LspNpmConfigHash(0), // this will be updated in initialize
|
||||
search_api: npm_search_api,
|
||||
node_resolver: None,
|
||||
resolver: None,
|
||||
},
|
||||
npm_search_api,
|
||||
performance,
|
||||
resolver: Default::default(),
|
||||
ts_fixable_diagnostics: Default::default(),
|
||||
ts_server,
|
||||
url_map: Default::default(),
|
||||
|
@ -645,35 +589,13 @@ impl Inner {
|
|||
}
|
||||
|
||||
pub fn snapshot(&self) -> Arc<StateSnapshot> {
|
||||
let maybe_state_npm_snapshot = self
|
||||
.npm
|
||||
.resolver
|
||||
.as_ref()
|
||||
.map(|resolver| resolver.clone_snapshotted())
|
||||
.map(|resolver| {
|
||||
let fs = Arc::new(deno_fs::RealFs);
|
||||
let node_resolver = Arc::new(NodeResolver::new(
|
||||
fs.clone(),
|
||||
resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
let cli_node_resolver = Arc::new(CliNodeResolver::new(
|
||||
None,
|
||||
fs,
|
||||
node_resolver,
|
||||
resolver.clone(),
|
||||
));
|
||||
StateNpmSnapshot {
|
||||
node_resolver: cli_node_resolver,
|
||||
npm_resolver: resolver,
|
||||
}
|
||||
});
|
||||
Arc::new(StateSnapshot {
|
||||
project_version: self.project_version,
|
||||
assets: self.assets.snapshot(),
|
||||
cache_metadata: self.cache_metadata.clone(),
|
||||
config: self.config.snapshot(),
|
||||
documents: self.documents.clone(),
|
||||
npm: maybe_state_npm_snapshot,
|
||||
resolver: self.resolver.snapshot(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -747,7 +669,7 @@ impl Inner {
|
|||
);
|
||||
self.jsr_search_api =
|
||||
CliJsrSearchApi::new(self.module_registries.file_fetcher.clone());
|
||||
self.npm.search_api =
|
||||
self.npm_search_api =
|
||||
CliNpmSearchApi::new(self.module_registries.file_fetcher.clone());
|
||||
// update the cache path
|
||||
let global_cache = Arc::new(GlobalHttpCache::new(
|
||||
|
@ -773,42 +695,6 @@ impl Inner {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn recreate_npm_services_if_necessary(&mut self) {
|
||||
let deno_dir = match DenoDir::new(self.maybe_global_cache_path.clone()) {
|
||||
Ok(deno_dir) => deno_dir,
|
||||
Err(err) => {
|
||||
lsp_warn!("Error getting deno dir: {:#}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config_hash = LspNpmConfigHash::from_inner(self);
|
||||
if config_hash == self.npm.config_hash {
|
||||
return; // no need to do anything
|
||||
}
|
||||
let config_data = self.config.tree.root_data();
|
||||
let npm_resolver = create_npm_resolver(
|
||||
&deno_dir,
|
||||
&self.initial_cwd,
|
||||
&self.http_client,
|
||||
config_data,
|
||||
)
|
||||
.await;
|
||||
let node_resolver = Arc::new(NodeResolver::new(
|
||||
Arc::new(deno_fs::RealFs),
|
||||
npm_resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
self.npm.node_resolver = Some(Arc::new(CliNodeResolver::new(
|
||||
None,
|
||||
Arc::new(deno_fs::RealFs),
|
||||
node_resolver,
|
||||
npm_resolver.clone(),
|
||||
)));
|
||||
self.npm.resolver = Some(npm_resolver);
|
||||
|
||||
// update the hash
|
||||
self.npm.config_hash = config_hash;
|
||||
}
|
||||
|
||||
fn create_file_fetcher(&self, cache_setting: CacheSetting) -> FileFetcher {
|
||||
let mut file_fetcher = FileFetcher::new(
|
||||
self.deps_http_cache.clone(),
|
||||
|
@ -844,52 +730,6 @@ impl Inner {
|
|||
}
|
||||
}
|
||||
|
||||
async fn create_npm_resolver(
|
||||
deno_dir: &DenoDir,
|
||||
initial_cwd: &Path,
|
||||
http_client: &Arc<HttpClient>,
|
||||
config_data: Option<&ConfigData>,
|
||||
) -> Arc<dyn CliNpmResolver> {
|
||||
let byonm = config_data.map(|d| d.byonm).unwrap_or(false);
|
||||
create_cli_npm_resolver_for_lsp(if byonm {
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
root_node_modules_dir: initial_cwd.join("node_modules"),
|
||||
})
|
||||
} else {
|
||||
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
||||
http_client: http_client.clone(),
|
||||
snapshot: match config_data.and_then(|d| d.lockfile.as_ref()) {
|
||||
Some(lockfile) => {
|
||||
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
|
||||
lockfile.clone(),
|
||||
)
|
||||
}
|
||||
None => CliNpmResolverManagedSnapshotOption::Specified(None),
|
||||
},
|
||||
// Don't provide the lockfile. We don't want these resolvers
|
||||
// updating it. Only the cache request should update the lockfile.
|
||||
maybe_lockfile: None,
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
npm_global_cache_dir: deno_dir.npm_folder_path(),
|
||||
// Use an "only" cache setting in order to make the
|
||||
// user do an explicit "cache" command and prevent
|
||||
// the cache from being filled with lots of packages while
|
||||
// the user is typing.
|
||||
cache_setting: CacheSetting::Only,
|
||||
text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly),
|
||||
maybe_node_modules_path: config_data
|
||||
.and_then(|d| d.node_modules_dir.clone()),
|
||||
// do not install while resolving in the lsp—leave that to the cache command
|
||||
package_json_installer:
|
||||
CliNpmResolverManagedPackageJsonInstallerOption::NoInstall,
|
||||
npm_registry_url: crate::args::npm_registry_url().to_owned(),
|
||||
npm_system_info: NpmSystemInfo::default(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
|
||||
impl Inner {
|
||||
async fn initialize(
|
||||
|
@ -1004,7 +844,6 @@ impl Inner {
|
|||
self.client.show_message(MessageType::WARNING, err);
|
||||
}
|
||||
|
||||
self.recreate_npm_services_if_necessary().await;
|
||||
self.assets.initialize(self.snapshot()).await;
|
||||
|
||||
self.performance.measure(mark);
|
||||
|
@ -1178,13 +1017,20 @@ impl Inner {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.resolver = self
|
||||
.resolver
|
||||
.with_new_config(
|
||||
&self.config,
|
||||
self.maybe_global_cache_path.as_deref(),
|
||||
Some(&self.http_client),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn refresh_documents_config(&mut self) {
|
||||
self.documents.update_config(
|
||||
&self.config,
|
||||
self.npm.node_resolver.clone(),
|
||||
self.npm.resolver.clone(),
|
||||
&self.resolver,
|
||||
&self.workspace_files,
|
||||
);
|
||||
|
||||
|
@ -1262,17 +1108,10 @@ impl Inner {
|
|||
|
||||
async fn refresh_npm_specifiers(&mut self) {
|
||||
let package_reqs = self.documents.npm_package_reqs();
|
||||
let npm_resolver = self.npm.resolver.clone();
|
||||
let resolver = self.resolver.clone();
|
||||
// spawn to avoid the LSP's Send requirements
|
||||
let handle = spawn(async move {
|
||||
if let Some(npm_resolver) =
|
||||
npm_resolver.as_ref().and_then(|r| r.as_managed())
|
||||
{
|
||||
npm_resolver.set_package_reqs(&package_reqs).await
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
let handle =
|
||||
spawn(async move { resolver.set_npm_package_reqs(&package_reqs).await });
|
||||
if let Err(err) = handle.await.unwrap() {
|
||||
lsp_warn!("Could not set npm package requirements. {:#}", err);
|
||||
}
|
||||
|
@ -1331,7 +1170,6 @@ impl Inner {
|
|||
lsp_warn!("Error updating registries: {:#}", err);
|
||||
self.client.show_message(MessageType::WARNING, err);
|
||||
}
|
||||
self.recreate_npm_services_if_necessary().await;
|
||||
self.refresh_documents_config().await;
|
||||
self.diagnostics_server.invalidate_all();
|
||||
self.send_diagnostics_update();
|
||||
|
@ -1408,7 +1246,6 @@ impl Inner {
|
|||
},
|
||||
);
|
||||
}
|
||||
self.recreate_npm_services_if_necessary().await;
|
||||
self.refresh_documents_config().await;
|
||||
self.diagnostics_server.invalidate_all();
|
||||
self.project_changed(
|
||||
|
@ -2003,8 +1840,7 @@ impl Inner {
|
|||
TsResponseImportMapper::new(
|
||||
&self.documents,
|
||||
self.config.tree.root_import_map().map(|i| i.as_ref()),
|
||||
self.npm.node_resolver.as_deref(),
|
||||
self.npm.resolver.as_deref(),
|
||||
self.resolver.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2313,7 +2149,7 @@ impl Inner {
|
|||
&self.client,
|
||||
&self.module_registries,
|
||||
&self.jsr_search_api,
|
||||
&self.npm.search_api,
|
||||
&self.npm_search_api,
|
||||
&self.documents,
|
||||
self.config.tree.root_import_map().map(|i| i.as_ref()),
|
||||
)
|
||||
|
|
|
@ -32,6 +32,7 @@ mod performance;
|
|||
mod refactor;
|
||||
mod registries;
|
||||
mod repl;
|
||||
mod resolver;
|
||||
mod search;
|
||||
mod semantic_tokens;
|
||||
mod testing;
|
||||
|
|
328
cli/lsp/resolver.rs
Normal file
328
cli/lsp/resolver.rs
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::args::package_json;
|
||||
use crate::args::CacheSetting;
|
||||
use crate::cache::DenoDir;
|
||||
use crate::cache::FastInsecureHasher;
|
||||
use crate::http_util::HttpClient;
|
||||
use crate::lsp::config::Config;
|
||||
use crate::lsp::config::ConfigData;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::npm::create_cli_npm_resolver_for_lsp;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||
use crate::npm::CliNpmResolverCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedCreateOptions;
|
||||
use crate::npm::CliNpmResolverManagedPackageJsonInstallerOption;
|
||||
use crate::npm::CliNpmResolverManagedSnapshotOption;
|
||||
use crate::npm::ManagedCliNpmResolver;
|
||||
use crate::resolver::CliGraphResolver;
|
||||
use crate::resolver::CliGraphResolverOptions;
|
||||
use crate::resolver::CliNodeResolver;
|
||||
use crate::util::progress_bar::ProgressBar;
|
||||
use crate::util::progress_bar::ProgressBarStyle;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_graph::source::NpmResolver;
|
||||
use deno_graph::source::Resolver;
|
||||
use deno_graph::ModuleSpecifier;
|
||||
use deno_npm::NpmSystemInfo;
|
||||
use deno_runtime::deno_fs;
|
||||
use deno_runtime::deno_node::NodeResolution;
|
||||
use deno_runtime::deno_node::NodeResolutionMode;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_runtime::deno_node::PackageJson;
|
||||
use deno_runtime::fs_util::specifier_to_file_path;
|
||||
use deno_runtime::permissions::PermissionsContainer;
|
||||
use deno_semver::npm::NpmPackageReqReference;
|
||||
use deno_semver::package::PackageReq;
|
||||
use package_json::PackageJsonDepsProvider;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LspResolver {
|
||||
graph_resolver: Arc<CliGraphResolver>,
|
||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||
npm_config_hash: LspNpmConfigHash,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl Default for LspResolver {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
graph_resolver: create_graph_resolver(&Default::default(), None, None),
|
||||
npm_resolver: None,
|
||||
node_resolver: None,
|
||||
npm_config_hash: LspNpmConfigHash(0),
|
||||
config: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LspResolver {
|
||||
pub async fn with_new_config(
|
||||
&self,
|
||||
config: &Config,
|
||||
global_cache_path: Option<&Path>,
|
||||
http_client: Option<&Arc<HttpClient>>,
|
||||
) -> Arc<Self> {
|
||||
let npm_config_hash = LspNpmConfigHash::new(config, global_cache_path);
|
||||
let mut npm_resolver = None;
|
||||
let mut node_resolver = None;
|
||||
if npm_config_hash != self.npm_config_hash {
|
||||
if let (Some(http_client), Some(config_data)) =
|
||||
(http_client, config.tree.root_data())
|
||||
{
|
||||
npm_resolver =
|
||||
create_npm_resolver(config_data, global_cache_path, http_client)
|
||||
.await;
|
||||
node_resolver = create_node_resolver(npm_resolver.as_ref());
|
||||
}
|
||||
} else {
|
||||
npm_resolver = self.npm_resolver.clone();
|
||||
node_resolver = self.node_resolver.clone();
|
||||
}
|
||||
let graph_resolver = create_graph_resolver(
|
||||
config,
|
||||
npm_resolver.as_ref(),
|
||||
node_resolver.as_ref(),
|
||||
);
|
||||
Arc::new(Self {
|
||||
graph_resolver,
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
npm_config_hash,
|
||||
config: Arc::new(config.clone()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Arc<Self> {
|
||||
let npm_resolver =
|
||||
self.npm_resolver.as_ref().map(|r| r.clone_snapshotted());
|
||||
let node_resolver = create_node_resolver(npm_resolver.as_ref());
|
||||
let graph_resolver = create_graph_resolver(
|
||||
&self.config,
|
||||
npm_resolver.as_ref(),
|
||||
node_resolver.as_ref(),
|
||||
);
|
||||
Arc::new(Self {
|
||||
graph_resolver,
|
||||
npm_resolver,
|
||||
node_resolver,
|
||||
npm_config_hash: self.npm_config_hash.clone(),
|
||||
config: self.config.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn set_npm_package_reqs(
|
||||
&self,
|
||||
reqs: &[PackageReq],
|
||||
) -> Result<(), AnyError> {
|
||||
if let Some(npm_resolver) = self.npm_resolver.as_ref() {
|
||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||
return npm_resolver.set_package_reqs(reqs).await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_graph_resolver(&self) -> &dyn Resolver {
|
||||
self.graph_resolver.as_ref()
|
||||
}
|
||||
|
||||
pub fn as_graph_npm_resolver(&self) -> &dyn NpmResolver {
|
||||
self.graph_resolver.as_ref()
|
||||
}
|
||||
|
||||
pub fn maybe_managed_npm_resolver(&self) -> Option<&ManagedCliNpmResolver> {
|
||||
self.npm_resolver.as_ref().and_then(|r| r.as_managed())
|
||||
}
|
||||
|
||||
pub fn in_npm_package(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
if let Some(npm_resolver) = &self.npm_resolver {
|
||||
return npm_resolver.in_npm_package(specifier);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn node_resolve(
|
||||
&self,
|
||||
specifier: &str,
|
||||
referrer: &ModuleSpecifier,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Option<NodeResolution>, AnyError> {
|
||||
let Some(node_resolver) = self.node_resolver.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
node_resolver.resolve(
|
||||
specifier,
|
||||
referrer,
|
||||
mode,
|
||||
&PermissionsContainer::allow_all(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn resolve_npm_req_reference(
|
||||
&self,
|
||||
req_ref: &NpmPackageReqReference,
|
||||
referrer: &ModuleSpecifier,
|
||||
mode: NodeResolutionMode,
|
||||
) -> Result<Option<NodeResolution>, AnyError> {
|
||||
let Some(node_resolver) = self.node_resolver.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
node_resolver
|
||||
.resolve_req_reference(
|
||||
req_ref,
|
||||
&PermissionsContainer::allow_all(),
|
||||
referrer,
|
||||
mode,
|
||||
)
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
pub fn url_to_node_resolution(
|
||||
&self,
|
||||
specifier: ModuleSpecifier,
|
||||
) -> Result<Option<NodeResolution>, AnyError> {
|
||||
let Some(node_resolver) = self.node_resolver.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
node_resolver.url_to_node_resolution(specifier).map(Some)
|
||||
}
|
||||
|
||||
pub fn get_closest_package_json(
|
||||
&self,
|
||||
referrer: &ModuleSpecifier,
|
||||
) -> Result<Option<Rc<PackageJson>>, AnyError> {
|
||||
let Some(node_resolver) = self.node_resolver.as_ref() else {
|
||||
return Ok(None);
|
||||
};
|
||||
node_resolver
|
||||
.get_closest_package_json(referrer, &PermissionsContainer::allow_all())
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_npm_resolver(
|
||||
config_data: &ConfigData,
|
||||
global_cache_path: Option<&Path>,
|
||||
http_client: &Arc<HttpClient>,
|
||||
) -> Option<Arc<dyn CliNpmResolver>> {
|
||||
let deno_dir = DenoDir::new(global_cache_path.map(|p| p.to_owned()))
|
||||
.inspect_err(|err| {
|
||||
lsp_warn!("Error getting deno dir: {:#}", err);
|
||||
})
|
||||
.ok()?;
|
||||
let node_modules_dir = config_data
|
||||
.node_modules_dir
|
||||
.clone()
|
||||
.or_else(|| specifier_to_file_path(&config_data.scope).ok())?;
|
||||
let options = if config_data.byonm {
|
||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
root_node_modules_dir: node_modules_dir,
|
||||
})
|
||||
} else {
|
||||
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
||||
http_client: http_client.clone(),
|
||||
snapshot: match config_data.lockfile.as_ref() {
|
||||
Some(lockfile) => {
|
||||
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
|
||||
lockfile.clone(),
|
||||
)
|
||||
}
|
||||
None => CliNpmResolverManagedSnapshotOption::Specified(None),
|
||||
},
|
||||
// Don't provide the lockfile. We don't want these resolvers
|
||||
// updating it. Only the cache request should update the lockfile.
|
||||
maybe_lockfile: None,
|
||||
fs: Arc::new(deno_fs::RealFs),
|
||||
npm_global_cache_dir: deno_dir.npm_folder_path(),
|
||||
// Use an "only" cache setting in order to make the
|
||||
// user do an explicit "cache" command and prevent
|
||||
// the cache from being filled with lots of packages while
|
||||
// the user is typing.
|
||||
cache_setting: CacheSetting::Only,
|
||||
text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly),
|
||||
maybe_node_modules_path: config_data.node_modules_dir.clone(),
|
||||
// do not install while resolving in the lsp—leave that to the cache command
|
||||
package_json_installer:
|
||||
CliNpmResolverManagedPackageJsonInstallerOption::NoInstall,
|
||||
npm_registry_url: crate::args::npm_registry_url().to_owned(),
|
||||
npm_system_info: NpmSystemInfo::default(),
|
||||
})
|
||||
};
|
||||
Some(create_cli_npm_resolver_for_lsp(options).await)
|
||||
}
|
||||
|
||||
fn create_node_resolver(
|
||||
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
||||
) -> Option<Arc<CliNodeResolver>> {
|
||||
let npm_resolver = npm_resolver?;
|
||||
let fs = Arc::new(deno_fs::RealFs);
|
||||
let node_resolver_inner = Arc::new(NodeResolver::new(
|
||||
fs.clone(),
|
||||
npm_resolver.clone().into_npm_resolver(),
|
||||
));
|
||||
Some(Arc::new(CliNodeResolver::new(
|
||||
None,
|
||||
fs,
|
||||
node_resolver_inner,
|
||||
npm_resolver.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn create_graph_resolver(
|
||||
config: &Config,
|
||||
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
||||
node_resolver: Option<&Arc<CliNodeResolver>>,
|
||||
) -> Arc<CliGraphResolver> {
|
||||
let config_data = config.tree.root_data();
|
||||
let config_file = config_data.and_then(|d| d.config_file.as_deref());
|
||||
Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||
node_resolver: node_resolver.cloned(),
|
||||
npm_resolver: npm_resolver.cloned(),
|
||||
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::new(
|
||||
config_data
|
||||
.and_then(|d| d.package_json.as_ref())
|
||||
.map(|package_json| {
|
||||
package_json::get_local_package_json_version_reqs(package_json)
|
||||
}),
|
||||
)),
|
||||
maybe_jsx_import_source_config: config_file
|
||||
.and_then(|cf| cf.to_maybe_jsx_import_source_config().ok().flatten()),
|
||||
maybe_import_map: config_data.and_then(|d| d.import_map.clone()),
|
||||
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
|
||||
bare_node_builtins_enabled: config_file
|
||||
.map(|config| config.has_unstable("bare-node-builtins"))
|
||||
.unwrap_or(false),
|
||||
// Don't set this for the LSP because instead we'll use the OpenDocumentsLoader
|
||||
// because it's much easier and we get diagnostics/quick fixes about a redirected
|
||||
// specifier for free.
|
||||
sloppy_imports_resolver: None,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct LspNpmConfigHash(u64);
|
||||
|
||||
impl LspNpmConfigHash {
|
||||
pub fn new(config: &Config, global_cache_path: Option<&Path>) -> Self {
|
||||
let config_data = config.tree.root_data();
|
||||
let scope = config_data.map(|d| &d.scope);
|
||||
let node_modules_dir =
|
||||
config_data.and_then(|d| d.node_modules_dir.as_ref());
|
||||
let lockfile = config_data.and_then(|d| d.lockfile.as_ref());
|
||||
let mut hasher = FastInsecureHasher::new();
|
||||
hasher.write_hashable(scope);
|
||||
hasher.write_hashable(node_modules_dir);
|
||||
hasher.write_hashable(global_cache_path);
|
||||
if let Some(lockfile) = lockfile {
|
||||
hasher.write_hashable(&*lockfile.lock());
|
||||
}
|
||||
hasher.write_hashable(global_cache_path);
|
||||
Self(hasher.finish())
|
||||
}
|
||||
}
|
|
@ -3999,12 +3999,7 @@ fn op_is_node_file(state: &mut OpState, #[string] path: String) -> bool {
|
|||
let state = state.borrow::<State>();
|
||||
let mark = state.performance.mark("tsc.op.op_is_node_file");
|
||||
let r = match ModuleSpecifier::parse(&path) {
|
||||
Ok(specifier) => state
|
||||
.state_snapshot
|
||||
.npm
|
||||
.as_ref()
|
||||
.map(|n| n.npm_resolver.in_npm_package(&specifier))
|
||||
.unwrap_or(false),
|
||||
Ok(specifier) => state.state_snapshot.resolver.in_npm_package(&specifier),
|
||||
Err(_) => false,
|
||||
};
|
||||
state.performance.measure(mark);
|
||||
|
@ -4089,11 +4084,7 @@ fn op_resolve_inner(
|
|||
let specifiers = state
|
||||
.state_snapshot
|
||||
.documents
|
||||
.resolve(
|
||||
&args.specifiers,
|
||||
&referrer,
|
||||
state.state_snapshot.npm.as_ref(),
|
||||
)
|
||||
.resolve(&args.specifiers, &referrer)
|
||||
.into_iter()
|
||||
.map(|o| {
|
||||
o.map(|(s, mt)| {
|
||||
|
@ -4408,7 +4399,7 @@ deno_core::extension!(deno_tsc,
|
|||
cache_metadata: CacheMetadata::new(options.cache.clone()),
|
||||
config: Default::default(),
|
||||
documents: Documents::new(options.cache.clone()),
|
||||
npm: None,
|
||||
resolver: Default::default(),
|
||||
}),
|
||||
options.specifier_map,
|
||||
options.performance,
|
||||
|
@ -5052,17 +5043,17 @@ impl TscRequest {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::cache::GlobalHttpCache;
|
||||
use crate::cache::HttpCache;
|
||||
use crate::cache::RealDenoCacheEnv;
|
||||
use crate::http_util::HeadersMap;
|
||||
use crate::lsp::cache::CacheMetadata;
|
||||
use crate::lsp::config::ConfigSnapshot;
|
||||
use crate::lsp::config::Config;
|
||||
use crate::lsp::config::WorkspaceSettings;
|
||||
use crate::lsp::documents::Documents;
|
||||
use crate::lsp::documents::LanguageId;
|
||||
use crate::lsp::resolver::LspResolver;
|
||||
use crate::lsp::text::LineIndex;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::Path;
|
||||
|
@ -5088,7 +5079,7 @@ mod tests {
|
|||
(*source).into(),
|
||||
);
|
||||
}
|
||||
let mut config = ConfigSnapshot::default();
|
||||
let mut config = Config::default();
|
||||
config
|
||||
.tree
|
||||
.inject_config_file(
|
||||
|
@ -5103,13 +5094,16 @@ mod tests {
|
|||
.unwrap(),
|
||||
)
|
||||
.await;
|
||||
let resolver = LspResolver::default()
|
||||
.with_new_config(&config, None, None)
|
||||
.await;
|
||||
StateSnapshot {
|
||||
project_version: 0,
|
||||
documents,
|
||||
assets: Default::default(),
|
||||
cache_metadata: CacheMetadata::new(cache),
|
||||
config: Arc::new(config),
|
||||
npm: None,
|
||||
config: config.snapshot(),
|
||||
resolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue