summaryrefslogtreecommitdiff
path: root/cli/lsp/resolver.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2024-06-17 21:54:23 +0100
committerGitHub <noreply@github.com>2024-06-17 21:54:23 +0100
commit5dec3fd4b75a59574e5aeed4e927d8e3e0c1c683 (patch)
treeecb324184813fd33a96028ec288ef4ac946f46ff /cli/lsp/resolver.rs
parent341913319c1167011d71d899a101824c8fae86c2 (diff)
feat(lsp): multi deno.json resolver scopes (#24206)
Diffstat (limited to 'cli/lsp/resolver.rs')
-rw-r--r--cli/lsp/resolver.rs254
1 files changed, 179 insertions, 75 deletions
diff --git a/cli/lsp/resolver.rs b/cli/lsp/resolver.rs
index 9790dfed7..c4c66f114 100644
--- a/cli/lsp/resolver.rs
+++ b/cli/lsp/resolver.rs
@@ -7,6 +7,7 @@ use crate::graph_util::CliJsrUrlProvider;
use crate::http_util::HttpClientProvider;
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;
@@ -54,17 +55,17 @@ use super::cache::LspCache;
use super::jsr::JsrCacheResolver;
#[derive(Debug, Clone)]
-pub struct LspResolver {
+struct LspScopeResolver {
graph_resolver: Arc<CliGraphResolver>,
jsr_resolver: Option<Arc<JsrCacheResolver>>,
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
node_resolver: Option<Arc<CliNodeResolver>>,
redirect_resolver: Option<Arc<RedirectResolver>>,
graph_imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>,
- config: Arc<Config>,
+ config_data: Option<Arc<ConfigData>>,
}
-impl Default for LspResolver {
+impl Default for LspScopeResolver {
fn default() -> Self {
Self {
graph_resolver: create_graph_resolver(None, None, None),
@@ -73,38 +74,41 @@ impl Default for LspResolver {
node_resolver: None,
redirect_resolver: None,
graph_imports: Default::default(),
- config: Default::default(),
+ config_data: None,
}
}
}
-impl LspResolver {
- pub async fn from_config(
+impl LspScopeResolver {
+ async fn from_config_data(
+ config_data: Option<&Arc<ConfigData>>,
config: &Config,
cache: &LspCache,
http_client_provider: Option<&Arc<HttpClientProvider>>,
) -> Self {
- let config_data = config.tree.root_data();
let mut npm_resolver = None;
let mut node_resolver = None;
- if let (Some(http_client), Some(config_data)) =
- (http_client_provider, config_data)
- {
- npm_resolver = create_npm_resolver(config_data, cache, http_client).await;
+ if let Some(http_client) = http_client_provider {
+ npm_resolver = create_npm_resolver(
+ config_data.map(|d| d.as_ref()),
+ cache,
+ http_client,
+ )
+ .await;
node_resolver = create_node_resolver(npm_resolver.as_ref());
}
let graph_resolver = create_graph_resolver(
- config_data,
+ config_data.map(|d| d.as_ref()),
npm_resolver.as_ref(),
node_resolver.as_ref(),
);
let jsr_resolver = Some(Arc::new(JsrCacheResolver::new(
- cache.root_vendor_or_global(),
- config_data,
+ cache.for_specifier(config_data.map(|d| &d.scope)),
+ config_data.map(|d| d.as_ref()),
config,
)));
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
- cache.root_vendor_or_global(),
+ cache.for_specifier(config_data.map(|d| &d.scope)),
)));
let npm_graph_resolver = graph_resolver.create_graph_npm_resolver();
let graph_imports = config_data
@@ -135,16 +139,16 @@ impl LspResolver {
node_resolver,
redirect_resolver,
graph_imports,
- config: Arc::new(config.clone()),
+ config_data: config_data.cloned(),
}
}
- pub fn snapshot(&self) -> Arc<Self> {
+ 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.tree.root_data(),
+ self.config_data.as_deref(),
npm_resolver.as_ref(),
node_resolver.as_ref(),
);
@@ -155,68 +159,133 @@ impl LspResolver {
node_resolver,
redirect_resolver: self.redirect_resolver.clone(),
graph_imports: self.graph_imports.clone(),
- config: self.config.clone(),
+ config_data: self.config_data.clone(),
+ })
+ }
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct LspResolver {
+ unscoped: Arc<LspScopeResolver>,
+ by_scope: BTreeMap<ModuleSpecifier, Arc<LspScopeResolver>>,
+}
+
+impl LspResolver {
+ pub async fn from_config(
+ config: &Config,
+ cache: &LspCache,
+ http_client_provider: Option<&Arc<HttpClientProvider>>,
+ ) -> Self {
+ let mut by_scope = BTreeMap::new();
+ for (scope, config_data) in config.tree.data_by_scope().as_ref() {
+ by_scope.insert(
+ scope.clone(),
+ Arc::new(
+ LspScopeResolver::from_config_data(
+ Some(config_data),
+ config,
+ cache,
+ http_client_provider,
+ )
+ .await,
+ ),
+ );
+ }
+ Self {
+ unscoped: Arc::new(
+ LspScopeResolver::from_config_data(
+ None,
+ config,
+ cache,
+ http_client_provider,
+ )
+ .await,
+ ),
+ by_scope,
+ }
+ }
+
+ pub fn snapshot(&self) -> Arc<Self> {
+ Arc::new(Self {
+ unscoped: self.unscoped.snapshot(),
+ by_scope: self
+ .by_scope
+ .iter()
+ .map(|(s, r)| (s.clone(), r.snapshot()))
+ .collect(),
})
}
pub fn did_cache(&self) {
- self.jsr_resolver.as_ref().inspect(|r| r.did_cache());
+ for resolver in
+ std::iter::once(&self.unscoped).chain(self.by_scope.values())
+ {
+ resolver.jsr_resolver.as_ref().inspect(|r| r.did_cache());
+ }
}
pub async fn set_npm_reqs(
&self,
reqs: &BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>,
- ) -> Result<(), AnyError> {
- let reqs = reqs
- .values()
- .flatten()
- .collect::<BTreeSet<_>>()
+ ) {
+ for (scope, resolver) in [(None, &self.unscoped)]
.into_iter()
- .cloned()
- .collect::<Vec<_>>();
- 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;
+ .chain(self.by_scope.iter().map(|(s, r)| (Some(s), r)))
+ {
+ if let Some(npm_resolver) = resolver.npm_resolver.as_ref() {
+ if let Some(npm_resolver) = npm_resolver.as_managed() {
+ let reqs = reqs
+ .get(&scope.cloned())
+ .map(|reqs| reqs.iter().cloned().collect::<Vec<_>>())
+ .unwrap_or_default();
+ if let Err(err) = npm_resolver.set_package_reqs(&reqs).await {
+ lsp_warn!("Could not set npm package requirements: {:#}", err);
+ }
+ }
}
}
- Ok(())
}
pub fn as_graph_resolver(
&self,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> &dyn Resolver {
- self.graph_resolver.as_ref()
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver.graph_resolver.as_ref()
}
pub fn create_graph_npm_resolver(
&self,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> WorkerCliNpmGraphResolver {
- self.graph_resolver.create_graph_npm_resolver()
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver.graph_resolver.create_graph_npm_resolver()
}
pub fn maybe_managed_npm_resolver(
&self,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<&ManagedCliNpmResolver> {
- self.npm_resolver.as_ref().and_then(|r| r.as_managed())
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver.npm_resolver.as_ref().and_then(|r| r.as_managed())
}
pub fn graph_imports_by_referrer(
&self,
) -> IndexMap<&ModuleSpecifier, Vec<&ModuleSpecifier>> {
self
- .graph_imports
+ .by_scope
.iter()
- .map(|(s, i)| {
- (
- s,
- i.dependencies
- .values()
- .flat_map(|d| d.get_type().or_else(|| d.get_code()))
- .collect(),
- )
+ .flat_map(|(_, r)| {
+ r.graph_imports.iter().map(|(s, i)| {
+ (
+ s,
+ i.dependencies
+ .values()
+ .flat_map(|d| d.get_type().or_else(|| d.get_code()))
+ .collect(),
+ )
+ })
})
.collect()
}
@@ -224,35 +293,42 @@ impl LspResolver {
pub fn jsr_to_resource_url(
&self,
req_ref: &JsrPackageReqReference,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
- self.jsr_resolver.as_ref()?.jsr_to_resource_url(req_ref)
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver.jsr_resolver.as_ref()?.jsr_to_resource_url(req_ref)
}
pub fn jsr_lookup_export_for_path(
&self,
nv: &PackageNv,
path: &str,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<String> {
- self.jsr_resolver.as_ref()?.lookup_export_for_path(nv, path)
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver
+ .jsr_resolver
+ .as_ref()?
+ .lookup_export_for_path(nv, path)
}
pub fn jsr_lookup_req_for_nv(
&self,
nv: &PackageNv,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<PackageReq> {
- self.jsr_resolver.as_ref()?.lookup_req_for_nv(nv)
+ let resolver = self.get_scope_resolver(file_referrer);
+ resolver.jsr_resolver.as_ref()?.lookup_req_for_nv(nv)
}
pub fn npm_to_file_url(
&self,
req_ref: &NpmPackageReqReference,
referrer: &ModuleSpecifier,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
- let node_resolver = self.node_resolver.as_ref()?;
+ let resolver = self.get_scope_resolver(file_referrer);
+ let node_resolver = resolver.node_resolver.as_ref()?;
Some(NodeResolution::into_specifier_and_media_type(
node_resolver
.resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
@@ -261,7 +337,8 @@ impl LspResolver {
}
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
- if let Some(npm_resolver) = &self.npm_resolver {
+ let resolver = self.get_scope_resolver(Some(specifier));
+ if let Some(npm_resolver) = &resolver.npm_resolver {
return npm_resolver.in_npm_package(specifier);
}
false
@@ -271,7 +348,8 @@ impl LspResolver {
&self,
specifier: &ModuleSpecifier,
) -> Option<MediaType> {
- let node_resolver = self.node_resolver.as_ref()?;
+ let resolver = self.get_scope_resolver(Some(specifier));
+ let node_resolver = resolver.node_resolver.as_ref()?;
let resolution = node_resolver
.url_to_node_resolution(specifier.clone())
.ok()?;
@@ -282,7 +360,8 @@ impl LspResolver {
&self,
referrer: &ModuleSpecifier,
) -> Result<Option<Rc<PackageJson>>, AnyError> {
- let Some(node_resolver) = self.node_resolver.as_ref() else {
+ let resolver = self.get_scope_resolver(Some(referrer));
+ let Some(node_resolver) = resolver.node_resolver.as_ref() else {
return Ok(None);
};
node_resolver.get_closest_package_json(
@@ -294,9 +373,10 @@ impl LspResolver {
pub fn resolve_redirects(
&self,
specifier: &ModuleSpecifier,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
- let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
+ let resolver = self.get_scope_resolver(file_referrer);
+ let Some(redirect_resolver) = resolver.redirect_resolver.as_ref() else {
return Some(specifier.clone());
};
redirect_resolver.resolve(specifier)
@@ -305,9 +385,10 @@ impl LspResolver {
pub fn redirect_chain_headers(
&self,
specifier: &ModuleSpecifier,
- _file_referrer: Option<&ModuleSpecifier>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
- let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
+ let resolver = self.get_scope_resolver(file_referrer);
+ let Some(redirect_resolver) = resolver.redirect_resolver.as_ref() else {
return vec![];
};
redirect_resolver
@@ -316,26 +397,47 @@ impl LspResolver {
.map(|(s, e)| (s, e.headers.clone()))
.collect()
}
+
+ fn get_scope_resolver(
+ &self,
+ file_referrer: Option<&ModuleSpecifier>,
+ ) -> &LspScopeResolver {
+ let Some(file_referrer) = file_referrer else {
+ return self.unscoped.as_ref();
+ };
+ self
+ .by_scope
+ .iter()
+ .rfind(|(s, _)| file_referrer.as_str().starts_with(s.as_str()))
+ .map(|(_, r)| r.as_ref())
+ .unwrap_or(self.unscoped.as_ref())
+ }
}
async fn create_npm_resolver(
- config_data: &ConfigData,
+ config_data: Option<&ConfigData>,
cache: &LspCache,
http_client_provider: &Arc<HttpClientProvider>,
) -> Option<Arc<dyn CliNpmResolver>> {
- 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 {
+ let mut byonm_dir = None;
+ if let Some(config_data) = config_data {
+ if config_data.byonm {
+ byonm_dir = Some(config_data.node_modules_dir.clone().or_else(|| {
+ specifier_to_file_path(&config_data.scope)
+ .ok()
+ .map(|p| p.join("node_modules/"))
+ })?)
+ }
+ }
+ let options = if let Some(byonm_dir) = byonm_dir {
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
fs: Arc::new(deno_fs::RealFs),
- root_node_modules_dir: node_modules_dir.clone(),
+ root_node_modules_dir: byonm_dir,
})
} else {
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
http_client_provider: http_client_provider.clone(),
- snapshot: match config_data.lockfile.as_ref() {
+ snapshot: match config_data.and_then(|d| d.lockfile.as_ref()) {
Some(lockfile) => {
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
lockfile.clone(),
@@ -354,15 +456,17 @@ async fn create_npm_resolver(
// 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(),
+ maybe_node_modules_path: config_data
+ .and_then(|d| d.node_modules_dir.clone()),
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::new(
- config_data.package_json.as_ref().map(|package_json| {
- package_json::get_local_package_json_version_reqs(package_json)
- }),
+ config_data
+ .and_then(|d| d.package_json.as_ref())
+ .map(|package_json| {
+ package_json::get_local_package_json_version_reqs(package_json)
+ }),
)),
npmrc: config_data
- .npmrc
- .clone()
+ .and_then(|d| d.npmrc.clone())
.unwrap_or_else(create_default_npmrc),
npm_system_info: NpmSystemInfo::default(),
})