refactor(lsp): internally expose and use LspScopedResolver (#28755)

Reduces some repeat hashmap lookups by exposing the `LspScopedResolver`.
This commit is contained in:
David Sherret 2025-04-04 17:48:04 -04:00 committed by GitHub
parent 37b760e3c6
commit 9d841987ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 240 additions and 294 deletions

View file

@ -280,6 +280,9 @@ impl<'a> TsResponseImportMapper<'a> {
return Some(specifier.to_string()); return Some(specifier.to_string());
} }
let scoped_resolver =
self.resolver.get_scoped_resolver(self.scope.as_deref());
if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str()) if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str())
{ {
let mut segments = jsr_path.split('/'); let mut segments = jsr_path.split('/');
@ -298,11 +301,7 @@ impl<'a> TsResponseImportMapper<'a> {
let version = Version::parse_standard(segments.next()?).ok()?; let version = Version::parse_standard(segments.next()?).ok()?;
let nv = PackageNv { name, version }; let nv = PackageNv { name, version };
let path = segments.collect::<Vec<_>>().join("/"); let path = segments.collect::<Vec<_>>().join("/");
let export = self.resolver.jsr_lookup_export_for_path( let export = scoped_resolver.jsr_lookup_export_for_path(&nv, &path)?;
&nv,
&path,
self.scope.as_deref(),
)?;
let sub_path = (export != ".") let sub_path = (export != ".")
.then_some(export) .then_some(export)
.map(SmallStackString::from_string); .map(SmallStackString::from_string);
@ -326,11 +325,7 @@ impl<'a> TsResponseImportMapper<'a> {
} }
None None
}); });
req = req.or_else(|| { req = req.or_else(|| scoped_resolver.jsr_lookup_req_for_nv(&nv));
self
.resolver
.jsr_lookup_req_for_nv(&nv, self.scope.as_deref())
});
let spec_str = if let Some(req) = req { let spec_str = if let Some(req) = req {
let req_ref = PackageReqReference { req, sub_path }; let req_ref = PackageReqReference { req, sub_path };
JsrPackageReqReference::new(req_ref).to_string() JsrPackageReqReference::new(req_ref).to_string()
@ -357,13 +352,10 @@ impl<'a> TsResponseImportMapper<'a> {
return Some(spec_str); return Some(spec_str);
} }
if let Some(npm_resolver) = self if let Some(npm_resolver) = scoped_resolver.as_maybe_managed_npm_resolver()
.resolver
.maybe_managed_npm_resolver(self.scope.as_deref())
{ {
let in_npm_pkg = self let in_npm_pkg = scoped_resolver
.resolver .as_in_npm_pkg_checker()
.in_npm_pkg_checker(self.scope.as_deref())
.in_npm_package(specifier); .in_npm_package(specifier);
if in_npm_pkg { if in_npm_pkg {
if let Ok(Some(pkg_id)) = if let Ok(Some(pkg_id)) =
@ -428,9 +420,8 @@ impl<'a> TsResponseImportMapper<'a> {
} }
} }
} }
} else if let Some(dep_name) = self } else if let Some(dep_name) =
.resolver scoped_resolver.file_url_to_package_json_dep(specifier)
.file_url_to_package_json_dep(specifier, self.scope.as_deref())
{ {
return Some(dep_name); return Some(dep_name);
} }
@ -450,9 +441,9 @@ impl<'a> TsResponseImportMapper<'a> {
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
package_root_folder: &Path, package_root_folder: &Path,
) -> Option<String> { ) -> Option<String> {
let package_json = self let scoped_resolver = self.resolver.get_scoped_resolver(Some(specifier));
.resolver let package_json = scoped_resolver
.pkg_json_resolver(specifier) .as_pkg_json_resolver()
// the specifier might have a closer package.json, but we // the specifier might have a closer package.json, but we
// want the root of the package's package.json // want the root of the package's package.json
.get_closest_package_json(&package_root_folder.join("package.json")) .get_closest_package_json(&package_root_folder.join("package.json"))
@ -514,10 +505,11 @@ impl<'a> TsResponseImportMapper<'a> {
.iter() .iter()
.map(|ext| Cow::Owned(format!("{specifier_stem}{ext}"))), .map(|ext| Cow::Owned(format!("{specifier_stem}{ext}"))),
); );
let scoped_resolver =
self.resolver.get_scoped_resolver(self.scope.as_deref());
for specifier in specifiers { for specifier in specifiers {
if let Some(specifier) = self if let Some(specifier) = scoped_resolver
.resolver .as_cli_resolver()
.as_cli_resolver(self.scope.as_deref())
.resolve( .resolve(
&specifier, &specifier,
referrer, referrer,
@ -553,7 +545,8 @@ impl<'a> TsResponseImportMapper<'a> {
) -> bool { ) -> bool {
self self
.resolver .resolver
.as_cli_resolver(self.scope.as_deref()) .get_scoped_resolver(self.scope.as_deref())
.as_cli_resolver()
.resolve( .resolve(
specifier_text, specifier_text,
referrer, referrer,

View file

@ -170,8 +170,9 @@ pub async fn get_import_completions(
.map(to_node_resolution_mode) .map(to_node_resolution_mode)
.unwrap_or_else(|| module.resolution_mode); .unwrap_or_else(|| module.resolution_mode);
let range = to_narrow_lsp_range(module.text_info(), graph_range.range); let range = to_narrow_lsp_range(module.text_info(), graph_range.range);
let resolved = resolver let scoped_resolver = resolver.get_scoped_resolver(module.scope.as_deref());
.as_cli_resolver(module.scope.as_deref()) let resolved = scoped_resolver
.as_cli_resolver()
.resolve( .resolve(
text, text,
&module.specifier, &module.specifier,
@ -377,8 +378,9 @@ fn get_local_completions(
return None; return None;
} }
let parent = &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1]; let parent = &text[..text.char_indices().rfind(|(_, c)| *c == '/')?.0 + 1];
let resolved_parent = resolver let scoped_resolver = resolver.get_scoped_resolver(Some(referrer));
.as_cli_resolver(Some(referrer)) let resolved_parent = scoped_resolver
.as_cli_resolver()
.resolve( .resolve(
parent, parent,
referrer, referrer,

View file

@ -1596,13 +1596,12 @@ fn diagnose_resolution(
match resolution { match resolution {
Resolution::Ok(resolved) => { Resolution::Ok(resolved) => {
let specifier = &resolved.specifier; let specifier = &resolved.specifier;
let managed_npm_resolver = snapshot let scoped_resolver = snapshot
.resolver .resolver
.maybe_managed_npm_resolver(referrer_module.scope.as_deref()); .get_scoped_resolver(referrer_module.scope.as_deref());
for (_, headers) in snapshot let managed_npm_resolver =
.resolver scoped_resolver.as_maybe_managed_npm_resolver();
.redirect_chain_headers(specifier, referrer_module.scope.as_deref()) for (_, headers) in scoped_resolver.redirect_chain_headers(specifier) {
{
if let Some(message) = headers.get("x-deno-warning") { if let Some(message) = headers.get("x-deno-warning") {
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone())); diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
} }

View file

@ -1041,14 +1041,15 @@ impl DocumentModules {
specifier: &Url, specifier: &Url,
scope: Option<&Url>, scope: Option<&Url>,
) -> Option<Arc<DocumentModule>> { ) -> Option<Arc<DocumentModule>> {
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
let specifier = if let Ok(jsr_req_ref) = let specifier = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier) JsrPackageReqReference::from_specifier(specifier)
{ {
Cow::Owned(self.resolver.jsr_to_resource_url(&jsr_req_ref, scope)?) Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
} else { } else {
Cow::Borrowed(specifier) Cow::Borrowed(specifier)
}; };
let specifier = self.resolver.resolve_redirects(&specifier, scope)?; let specifier = scoped_resolver.resolve_redirects(&specifier)?;
let document = let document =
self self
.documents .documents
@ -1137,14 +1138,15 @@ impl DocumentModules {
specifier: &Url, specifier: &Url,
scope: Option<&Url>, scope: Option<&Url>,
) -> Option<Arc<DocumentModule>> { ) -> Option<Arc<DocumentModule>> {
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
let specifier = if let Ok(jsr_req_ref) = let specifier = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier) JsrPackageReqReference::from_specifier(specifier)
{ {
Cow::Owned(self.resolver.jsr_to_resource_url(&jsr_req_ref, scope)?) Cow::Owned(scoped_resolver.jsr_to_resource_url(&jsr_req_ref)?)
} else { } else {
Cow::Borrowed(specifier) Cow::Borrowed(specifier)
}; };
let specifier = self.resolver.resolve_redirects(&specifier, scope)?; let specifier = scoped_resolver.resolve_redirects(&specifier)?;
let modules = self.modules_for_scope(scope)?; let modules = self.modules_for_scope(scope)?;
modules.get_for_specifier(&specifier) modules.get_for_specifier(&specifier)
} }
@ -1332,8 +1334,9 @@ impl DocumentModules {
member_dir.to_maybe_jsx_import_source_config().ok()??; member_dir.to_maybe_jsx_import_source_config().ok()??;
let import_source_types = jsx_config.import_source_types.as_ref()?; let import_source_types = jsx_config.import_source_types.as_ref()?;
let import_source = jsx_config.import_source.as_ref()?; let import_source = jsx_config.import_source.as_ref()?;
let cli_resolver = let scoped_resolver =
self.resolver.as_cli_resolver(scope.map(|s| s.as_ref())); self.resolver.get_scoped_resolver(scope.map(|s| s.as_ref()));
let cli_resolver = scoped_resolver.as_cli_resolver();
let type_specifier = cli_resolver let type_specifier = cli_resolver
.resolve( .resolve(
&import_source_types.specifier, &import_source_types.specifier,
@ -1417,6 +1420,7 @@ impl DocumentModules {
let referrer_module = self.module_for_specifier(referrer, scope); let referrer_module = self.module_for_specifier(referrer, scope);
let dependencies = referrer_module.as_ref().map(|d| &d.dependencies); let dependencies = referrer_module.as_ref().map(|d| &d.dependencies);
let mut results = Vec::new(); let mut results = Vec::new();
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
for (is_cjs, raw_specifier) in raw_specifiers { for (is_cjs, raw_specifier) in raw_specifiers {
let resolution_mode = match is_cjs { let resolution_mode = match is_cjs {
true => ResolutionMode::Require, true => ResolutionMode::Require,
@ -1449,15 +1453,13 @@ impl DocumentModules {
} else { } else {
results.push(None); results.push(None);
} }
} else if let Ok(specifier) = } else if let Ok(specifier) = scoped_resolver.as_cli_resolver().resolve(
self.resolver.as_cli_resolver(scope).resolve(
raw_specifier, raw_specifier,
referrer, referrer,
deno_graph::Position::zeroed(), deno_graph::Position::zeroed(),
resolution_mode, resolution_mode,
NodeResolutionKind::Types, NodeResolutionKind::Types,
) ) {
{
results.push(self.resolve_dependency( results.push(self.resolve_dependency(
&specifier, &specifier,
referrer, referrer,
@ -1490,12 +1492,9 @@ impl DocumentModules {
let mut specifier = specifier.clone(); let mut specifier = specifier.clone();
let mut media_type = None; let mut media_type = None;
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) { if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) {
let (s, mt) = self.resolver.npm_to_file_url( let scoped_resolver = self.resolver.get_scoped_resolver(scope);
&npm_ref, let (s, mt) =
referrer, scoped_resolver.npm_to_file_url(&npm_ref, referrer, resolution_mode)?;
resolution_mode,
scope,
)?;
specifier = s; specifier = s;
media_type = Some(mt); media_type = Some(mt);
} }
@ -1823,10 +1822,11 @@ fn analyze_module(
) -> (ModuleResult, ResolutionMode) { ) -> (ModuleResult, ResolutionMode) {
match parsed_source_result { match parsed_source_result {
Ok(parsed_source) => { Ok(parsed_source) => {
let npm_resolver = resolver.as_graph_npm_resolver(file_referrer); let scoped_resolver = resolver.get_scoped_resolver(file_referrer);
let cli_resolver = resolver.as_cli_resolver(file_referrer); let npm_resolver = scoped_resolver.as_graph_npm_resolver();
let is_cjs_resolver = resolver.as_is_cjs_resolver(file_referrer); let cli_resolver = scoped_resolver.as_cli_resolver();
let config_data = resolver.as_config_data(file_referrer); let is_cjs_resolver = scoped_resolver.as_is_cjs_resolver();
let config_data = scoped_resolver.as_config_data();
let valid_referrer = specifier.clone(); let valid_referrer = specifier.clone();
let jsx_import_source_config = let jsx_import_source_config =
config_data.and_then(|d| d.maybe_jsx_import_source_config()); config_data.and_then(|d| d.maybe_jsx_import_source_config());

View file

@ -1135,7 +1135,9 @@ impl Inner {
spawn(async move { spawn(async move {
let specifier = { let specifier = {
let inner = ls.inner.read().await; let inner = ls.inner.read().await;
let resolver = inner.resolver.as_cli_resolver(Some(&referrer)); let scoped_resolver =
inner.resolver.get_scoped_resolver(Some(&referrer));
let resolver = scoped_resolver.as_cli_resolver();
let Ok(specifier) = resolver.resolve( let Ok(specifier) = resolver.resolve(
&specifier, &specifier,
&referrer, &referrer,
@ -1783,8 +1785,9 @@ impl Inner {
if let Ok(jsr_req_ref) = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier) JsrPackageReqReference::from_specifier(specifier)
{ {
let scoped_resolver = self.resolver.get_scoped_resolver(scope);
if let Some(url) = if let Some(url) =
self.resolver.jsr_to_resource_url(&jsr_req_ref, scope) scoped_resolver.jsr_to_resource_url(&jsr_req_ref)
{ {
result = format!("{result} (<{url}>)"); result = format!("{result} (<{url}>)");
} }

View file

@ -88,7 +88,7 @@ use crate::util::progress_bar::ProgressBar;
use crate::util::progress_bar::ProgressBarStyle; use crate::util::progress_bar::ProgressBarStyle;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct LspScopeResolver { pub struct LspScopedResolver {
resolver: Arc<CliResolver>, resolver: Arc<CliResolver>,
in_npm_pkg_checker: DenoInNpmPackageChecker, in_npm_pkg_checker: DenoInNpmPackageChecker,
is_cjs_resolver: Arc<CliIsCjsResolver>, is_cjs_resolver: Arc<CliIsCjsResolver>,
@ -108,7 +108,7 @@ struct LspScopeResolver {
config_data: Option<Arc<ConfigData>>, config_data: Option<Arc<ConfigData>>,
} }
impl Default for LspScopeResolver { impl Default for LspScopedResolver {
fn default() -> Self { fn default() -> Self {
let factory = ResolverFactory::new(None); let factory = ResolverFactory::new(None);
Self { Self {
@ -133,7 +133,7 @@ impl Default for LspScopeResolver {
} }
} }
impl LspScopeResolver { impl LspScopedResolver {
async fn from_config_data( async fn from_config_data(
config_data: Option<&Arc<ConfigData>>, config_data: Option<&Arc<ConfigData>>,
cache: &LspCache, cache: &LspCache,
@ -294,12 +294,170 @@ impl LspScopeResolver {
config_data: self.config_data.clone(), config_data: self.config_data.clone(),
}) })
} }
pub fn as_in_npm_pkg_checker(&self) -> &DenoInNpmPackageChecker {
&self.in_npm_pkg_checker
}
pub fn as_cli_resolver(&self) -> &CliResolver {
self.resolver.as_ref()
}
pub fn as_graph_npm_resolver(&self) -> &Arc<CliNpmGraphResolver> {
&self.npm_graph_resolver
}
pub fn as_is_cjs_resolver(&self) -> &CliIsCjsResolver {
self.is_cjs_resolver.as_ref()
}
pub fn as_config_data(&self) -> Option<&Arc<ConfigData>> {
self.config_data.as_ref()
}
pub fn as_maybe_managed_npm_resolver(
&self,
) -> Option<&CliManagedNpmResolver> {
self.npm_resolver.as_ref().and_then(|r| r.as_managed())
}
pub fn as_pkg_json_resolver(&self) -> &Arc<CliPackageJsonResolver> {
&self.pkg_json_resolver
}
pub fn graph_imports_by_referrer(
&self,
) -> IndexMap<&ModuleSpecifier, Vec<&ModuleSpecifier>> {
self
.graph_imports
.iter()
.map(|(s, i)| {
(
s,
i.dependencies
.values()
.flat_map(|d| d.get_type().or_else(|| d.get_code()))
.collect(),
)
})
.collect()
}
pub fn jsr_to_resource_url(
&self,
req_ref: &JsrPackageReqReference,
) -> Option<ModuleSpecifier> {
self.jsr_resolver.as_ref()?.jsr_to_resource_url(req_ref)
}
pub fn jsr_lookup_export_for_path(
&self,
nv: &PackageNv,
path: &str,
) -> Option<String> {
self.jsr_resolver.as_ref()?.lookup_export_for_path(nv, path)
}
pub fn jsr_lookup_req_for_nv(&self, nv: &PackageNv) -> Option<PackageReq> {
self.jsr_resolver.as_ref()?.lookup_req_for_nv(nv)
}
pub fn npm_to_file_url(
&self,
req_ref: &NpmPackageReqReference,
referrer: &ModuleSpecifier,
resolution_mode: ResolutionMode,
) -> Option<(ModuleSpecifier, MediaType)> {
let npm_pkg_req_resolver = self.npm_pkg_req_resolver.as_ref()?;
Some(into_specifier_and_media_type(Some(
npm_pkg_req_resolver
.resolve_req_reference(
req_ref,
referrer,
resolution_mode,
NodeResolutionKind::Types,
)
.ok()?
.into_url()
.ok()?,
)))
}
pub fn file_url_to_package_json_dep(
&self,
specifier: &ModuleSpecifier,
) -> Option<String> {
self
.package_json_dep_resolutions
.package_ref_from_resolution(specifier)
.or_else(|| {
self
.node_resolver
.as_ref()?
.lookup_package_specifier_for_resolution(specifier)
})
}
pub fn deno_types_to_code_resolution(
&self,
specifier: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
let dep_info = self.dep_info.lock();
dep_info
.deno_types_to_code_resolutions
.get(specifier)
.cloned()
}
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
fn has_node_modules_dir(specifier: &ModuleSpecifier) -> bool {
// consider any /node_modules/ directory as being in the node_modules
// folder for the LSP because it's pretty complicated to deal with multiple scopes
specifier.scheme() == "file"
&& specifier
.path()
.to_ascii_lowercase()
.contains("/node_modules/")
}
if let Some(node_resolver) = &self.node_resolver {
if node_resolver.in_npm_package(specifier) {
return true;
}
}
has_node_modules_dir(specifier)
}
pub fn resolve_redirects(
&self,
specifier: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
return Some(specifier.clone());
};
redirect_resolver.resolve(specifier)
}
pub fn redirect_chain_headers(
&self,
specifier: &ModuleSpecifier,
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
return vec![];
};
redirect_resolver
.chain(specifier)
.into_iter()
.map(|(s, e)| (s, e.headers.clone()))
.collect()
}
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct LspResolver { pub struct LspResolver {
unscoped: Arc<LspScopeResolver>, unscoped: Arc<LspScopedResolver>,
by_scope: BTreeMap<Arc<Url>, Arc<LspScopeResolver>>, by_scope: BTreeMap<Arc<Url>, Arc<LspScopedResolver>>,
} }
impl LspResolver { impl LspResolver {
@ -313,7 +471,7 @@ impl LspResolver {
by_scope.insert( by_scope.insert(
scope.clone(), scope.clone(),
Arc::new( Arc::new(
LspScopeResolver::from_config_data( LspScopedResolver::from_config_data(
Some(config_data), Some(config_data),
cache, cache,
http_client_provider, http_client_provider,
@ -324,7 +482,7 @@ impl LspResolver {
} }
Self { Self {
unscoped: Arc::new( unscoped: Arc::new(
LspScopeResolver::from_config_data(None, cache, http_client_provider) LspScopedResolver::from_config_data(None, cache, http_client_provider)
.await, .await,
), ),
by_scope, by_scope,
@ -388,220 +546,16 @@ impl LspResolver {
} }
} }
pub fn as_cli_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &CliResolver {
let resolver = self.get_scope_resolver(file_referrer);
resolver.resolver.as_ref()
}
pub fn as_graph_npm_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &Arc<CliNpmGraphResolver> {
let resolver = self.get_scope_resolver(file_referrer);
&resolver.npm_graph_resolver
}
pub fn as_is_cjs_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &CliIsCjsResolver {
let resolver = self.get_scope_resolver(file_referrer);
resolver.is_cjs_resolver.as_ref()
}
pub fn as_config_data(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<&Arc<ConfigData>> {
let resolver = self.get_scope_resolver(file_referrer);
resolver.config_data.as_ref()
}
pub fn in_npm_pkg_checker(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> &DenoInNpmPackageChecker {
let resolver = self.get_scope_resolver(file_referrer);
&resolver.in_npm_pkg_checker
}
pub fn maybe_managed_npm_resolver(
&self,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<&CliManagedNpmResolver> {
let resolver = self.get_scope_resolver(file_referrer);
resolver.npm_resolver.as_ref().and_then(|r| r.as_managed())
}
pub fn pkg_json_resolver(
&self,
referrer: &ModuleSpecifier,
) -> &Arc<CliPackageJsonResolver> {
let resolver = self.get_scope_resolver(Some(referrer));
&resolver.pkg_json_resolver
}
pub fn graph_imports_by_referrer(
&self,
file_referrer: &ModuleSpecifier,
) -> IndexMap<&ModuleSpecifier, Vec<&ModuleSpecifier>> {
let resolver = self.get_scope_resolver(Some(file_referrer));
resolver
.graph_imports
.iter()
.map(|(s, i)| {
(
s,
i.dependencies
.values()
.flat_map(|d| d.get_type().or_else(|| d.get_code()))
.collect(),
)
})
.collect()
}
pub fn jsr_to_resource_url(
&self,
req_ref: &JsrPackageReqReference,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
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>,
) -> Option<String> {
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>,
) -> Option<PackageReq> {
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,
resolution_mode: ResolutionMode,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
let resolver = self.get_scope_resolver(file_referrer);
let npm_pkg_req_resolver = resolver.npm_pkg_req_resolver.as_ref()?;
Some(into_specifier_and_media_type(Some(
npm_pkg_req_resolver
.resolve_req_reference(
req_ref,
referrer,
resolution_mode,
NodeResolutionKind::Types,
)
.ok()?
.into_url()
.ok()?,
)))
}
pub fn file_url_to_package_json_dep(
&self,
specifier: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<String> {
let resolver = self.get_scope_resolver(file_referrer);
resolver
.package_json_dep_resolutions
.package_ref_from_resolution(specifier)
.or_else(|| {
resolver
.node_resolver
.as_ref()?
.lookup_package_specifier_for_resolution(specifier)
})
}
pub fn deno_types_to_code_resolution(
&self,
specifier: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
let resolver = self.get_scope_resolver(file_referrer);
let dep_info = resolver.dep_info.lock().clone();
dep_info
.deno_types_to_code_resolutions
.get(specifier)
.cloned()
}
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool { pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
fn has_node_modules_dir(specifier: &ModuleSpecifier) -> bool { self
// consider any /node_modules/ directory as being in the node_modules .get_scoped_resolver(Some(specifier))
// folder for the LSP because it's pretty complicated to deal with multiple scopes .in_node_modules(specifier)
specifier.scheme() == "file"
&& specifier
.path()
.to_ascii_lowercase()
.contains("/node_modules/")
} }
if let Some(node_resolver) = pub fn get_scoped_resolver(
&self.get_scope_resolver(Some(specifier)).node_resolver
{
if node_resolver.in_npm_package(specifier) {
return true;
}
}
has_node_modules_dir(specifier)
}
pub fn resolve_redirects(
&self,
specifier: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
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)
}
pub fn redirect_chain_headers(
&self,
specifier: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
let resolver = self.get_scope_resolver(file_referrer);
let Some(redirect_resolver) = resolver.redirect_resolver.as_ref() else {
return vec![];
};
redirect_resolver
.chain(specifier)
.into_iter()
.map(|(s, e)| (s, e.headers.clone()))
.collect()
}
fn get_scope_resolver(
&self, &self,
file_referrer: Option<&ModuleSpecifier>, file_referrer: Option<&ModuleSpecifier>,
) -> &LspScopeResolver { ) -> &LspScopedResolver {
let Some(file_referrer) = file_referrer else { let Some(file_referrer) = file_referrer else {
return self.unscoped.as_ref(); return self.unscoped.as_ref();
}; };

View file

@ -3881,10 +3881,8 @@ impl CompletionEntry {
let mut new_deno_types_specifier = None; let mut new_deno_types_specifier = None;
if let Some(code_specifier) = language_server if let Some(code_specifier) = language_server
.resolver .resolver
.deno_types_to_code_resolution( .get_scoped_resolver(module.scope.as_deref())
&import_data.normalized, .deno_types_to_code_resolution(&import_data.normalized)
module.scope.as_deref(),
)
.and_then(|s| { .and_then(|s| {
import_mapper import_mapper
.check_specifier(&s, &module.specifier) .check_specifier(&s, &module.specifier)
@ -4684,23 +4682,20 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
// inject these next because they're global // inject these next because they're global
for (scope, script_names) in &mut result.by_scope { for (scope, script_names) in &mut result.by_scope {
for (_, specifiers) in state let scoped_resolver = state
.state_snapshot .state_snapshot
.resolver .resolver
.graph_imports_by_referrer(scope) .get_scoped_resolver(Some(scope));
{ for (_, specifiers) in scoped_resolver.graph_imports_by_referrer() {
for specifier in specifiers { for specifier in specifiers {
if let Ok(req_ref) = if let Ok(req_ref) =
deno_semver::npm::NpmPackageReqReference::from_specifier(specifier) deno_semver::npm::NpmPackageReqReference::from_specifier(specifier)
{ {
let Some((resolved, _)) = let Some((resolved, _)) = scoped_resolver.npm_to_file_url(
state.state_snapshot.resolver.npm_to_file_url(
&req_ref, &req_ref,
scope, scope,
ResolutionMode::Import, ResolutionMode::Import,
Some(scope), ) else {
)
else {
lsp_log!("failed to resolve {req_ref} to file URL"); lsp_log!("failed to resolve {req_ref} to file URL");
continue; continue;
}; };