summaryrefslogtreecommitdiff
path: root/cli/lsp/documents.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r--cli/lsp/documents.rs178
1 files changed, 124 insertions, 54 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index 61db899e5..57216eecb 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -12,6 +12,13 @@ use crate::file_fetcher::SUPPORTED_SCHEMES;
use crate::fs_util::specifier_to_file_path;
use crate::http_cache;
use crate::http_cache::HttpCache;
+use crate::node;
+use crate::node::node_resolve_npm_reference;
+use crate::node::NodeResolution;
+use crate::node::NodeResolutionMode;
+use crate::npm::NpmPackageReference;
+use crate::npm::NpmPackageReq;
+use crate::npm::NpmPackageResolver;
use crate::resolver::ImportMapResolver;
use crate::resolver::JsxResolver;
use crate::text_encoding;
@@ -209,6 +216,29 @@ impl AssetOrDocument {
}
}
+#[derive(Debug, Default)]
+struct DocumentDependencies {
+ deps: BTreeMap<String, deno_graph::Dependency>,
+ maybe_types_dependency: Option<(String, Resolved)>,
+}
+
+impl DocumentDependencies {
+ pub fn from_maybe_module(maybe_module: &MaybeModuleResult) -> Self {
+ if let Some(Ok(module)) = &maybe_module {
+ Self::from_module(module)
+ } else {
+ Self::default()
+ }
+ }
+
+ pub fn from_module(module: &deno_graph::Module) -> Self {
+ Self {
+ deps: module.dependencies.clone(),
+ maybe_types_dependency: module.maybe_types_dependency.clone(),
+ }
+ }
+}
+
type MaybeModuleResult =
Option<Result<deno_graph::Module, deno_graph::ModuleGraphError>>;
type MaybeParsedSourceResult =
@@ -217,7 +247,7 @@ type MaybeParsedSourceResult =
#[derive(Debug, Clone)]
struct DocumentInner {
/// contains the last-known-good set of dependencies from parsing the module
- dependencies: Arc<BTreeMap<String, deno_graph::Dependency>>,
+ dependencies: Arc<DocumentDependencies>,
fs_version: String,
line_index: Arc<LineIndex>,
maybe_language_id: Option<LanguageId>,
@@ -249,12 +279,9 @@ impl Document {
maybe_headers,
maybe_resolver,
);
- let dependencies = if let Some(Ok(module)) = &maybe_module {
- Arc::new(module.dependencies.clone())
- } else {
- Arc::new(BTreeMap::new())
- };
- // todo(dsherret): retrieve this from the parsed source if it
+ let dependencies =
+ Arc::new(DocumentDependencies::from_maybe_module(&maybe_module));
+ // todo(dsherret): retrieve this from the parsed source if it exists
let text_info = SourceTextInfo::new(content);
let line_index = Arc::new(LineIndex::new(text_info.text_str()));
Self(Arc::new(DocumentInner {
@@ -289,11 +316,8 @@ impl Document {
} else {
(None, None)
};
- let dependencies = if let Some(Ok(module)) = &maybe_module {
- Arc::new(module.dependencies.clone())
- } else {
- Arc::new(BTreeMap::new())
- };
+ let dependencies =
+ Arc::new(DocumentDependencies::from_maybe_module(&maybe_module));
let source = SourceTextInfo::new(content);
let line_index = Arc::new(LineIndex::new(source.text_str()));
Self(Arc::new(DocumentInner {
@@ -355,9 +379,9 @@ impl Document {
(None, None)
};
let dependencies = if let Some(Ok(module)) = &maybe_module {
- Arc::new(module.dependencies.clone())
+ Arc::new(DocumentDependencies::from_module(module))
} else {
- self.0.dependencies.clone()
+ self.0.dependencies.clone() // use the last known good
};
let text_info = SourceTextInfo::new(content);
let line_index = if index_valid == IndexValid::All {
@@ -435,15 +459,9 @@ impl Document {
}
pub fn maybe_types_dependency(&self) -> deno_graph::Resolved {
- let module_result = match self.0.maybe_module.as_ref() {
- Some(module_result) => module_result,
- _ => return deno_graph::Resolved::None,
- };
- let module = match module_result.as_ref() {
- Ok(module) => module,
- Err(_) => return deno_graph::Resolved::None,
- };
- if let Some((_, maybe_dep)) = module.maybe_types_dependency.as_ref() {
+ if let Some((_, maybe_dep)) =
+ self.0.dependencies.maybe_types_dependency.as_ref()
+ {
maybe_dep.clone()
} else {
deno_graph::Resolved::None
@@ -479,13 +497,8 @@ impl Document {
self.0.maybe_navigation_tree.clone()
}
- pub fn dependencies(&self) -> Vec<(String, deno_graph::Dependency)> {
- self
- .0
- .dependencies
- .iter()
- .map(|(s, d)| (s.clone(), d.clone()))
- .collect()
+ pub fn dependencies(&self) -> &BTreeMap<String, deno_graph::Dependency> {
+ &self.0.dependencies.deps
}
/// If the supplied position is within a dependency range, return the resolved
@@ -698,6 +711,8 @@ pub struct Documents {
maybe_import_map: Option<ImportMapResolver>,
/// The optional JSX resolver, which is used when JSX imports are configured.
maybe_jsx_resolver: Option<JsxResolver>,
+ /// The npm package requirements.
+ npm_reqs: HashSet<NpmPackageReq>,
/// Resolves a specifier to its final redirected to specifier.
specifier_resolver: Arc<SpecifierResolver>,
}
@@ -713,6 +728,7 @@ impl Documents {
imports: Default::default(),
maybe_import_map: None,
maybe_jsx_resolver: None,
+ npm_reqs: HashSet::new(),
specifier_resolver: Arc::new(SpecifierResolver::new(location)),
}
}
@@ -847,6 +863,12 @@ impl Documents {
}
}
+ /// Returns a collection of npm package requirements.
+ pub fn npm_package_reqs(&mut self) -> HashSet<NpmPackageReq> {
+ self.calculate_dependents_if_dirty();
+ self.npm_reqs.clone()
+ }
+
/// Return a document for the specifier.
pub fn get(&self, original_specifier: &ModuleSpecifier) -> Option<Document> {
let specifier = self.specifier_resolver.resolve(original_specifier)?;
@@ -921,10 +943,28 @@ impl Documents {
&self,
specifiers: Vec<String>,
referrer: &ModuleSpecifier,
+ maybe_npm_resolver: Option<&NpmPackageResolver>,
) -> Option<Vec<Option<(ModuleSpecifier, MediaType)>>> {
let dependencies = self.get(referrer)?.0.dependencies.clone();
let mut results = Vec::new();
for specifier in specifiers {
+ if let Some(npm_resolver) = maybe_npm_resolver {
+ if npm_resolver.in_npm_package(referrer) {
+ // we're in an npm package, so use node resolution
+ results.push(Some(NodeResolution::into_specifier_and_media_type(
+ node::node_resolve(
+ &specifier,
+ referrer,
+ node::NodeResolutionMode::Types,
+ npm_resolver,
+ )
+ .ok()
+ .flatten(),
+ )));
+ continue;
+ }
+ }
+ // handle npm:<package> urls
if specifier.starts_with("asset:") {
if let Ok(specifier) = ModuleSpecifier::parse(&specifier) {
let media_type = MediaType::from(&specifier);
@@ -932,11 +972,11 @@ impl Documents {
} else {
results.push(None);
}
- } else if let Some(dep) = dependencies.get(&specifier) {
+ } else if let Some(dep) = dependencies.deps.get(&specifier) {
if let Resolved::Ok { specifier, .. } = &dep.maybe_type {
- results.push(self.resolve_dependency(specifier));
+ results.push(self.resolve_dependency(specifier, maybe_npm_resolver));
} else if let Resolved::Ok { specifier, .. } = &dep.maybe_code {
- results.push(self.resolve_dependency(specifier));
+ results.push(self.resolve_dependency(specifier, maybe_npm_resolver));
} else {
results.push(None);
}
@@ -945,7 +985,19 @@ impl Documents {
{
// clone here to avoid double borrow of self
let specifier = specifier.clone();
- results.push(self.resolve_dependency(&specifier));
+ results.push(self.resolve_dependency(&specifier, maybe_npm_resolver));
+ } else if let Ok(npm_ref) = NpmPackageReference::from_str(&specifier) {
+ results.push(maybe_npm_resolver.map(|npm_resolver| {
+ NodeResolution::into_specifier_and_media_type(
+ node_resolve_npm_reference(
+ &npm_ref,
+ NodeResolutionMode::Types,
+ npm_resolver,
+ )
+ .ok()
+ .flatten(),
+ )
+ }));
} else {
results.push(None);
}
@@ -1038,32 +1090,36 @@ impl Documents {
// favour documents that are open in case a document exists in both collections
let documents = file_system_docs.docs.iter().chain(self.open_docs.iter());
for (specifier, doc) in documents {
- if let Some(Ok(module)) = doc.maybe_module() {
- for dependency in module.dependencies.values() {
- if let Some(dep) = dependency.get_code() {
- dependents_map
- .entry(dep.clone())
- .or_default()
- .insert(specifier.clone());
- }
- if let Some(dep) = dependency.get_type() {
- dependents_map
- .entry(dep.clone())
- .or_default()
- .insert(specifier.clone());
- }
+ for dependency in doc.dependencies().values() {
+ if let Some(dep) = dependency.get_code() {
+ dependents_map
+ .entry(dep.clone())
+ .or_default()
+ .insert(specifier.clone());
}
- if let Some((_, Resolved::Ok { specifier: dep, .. })) =
- &module.maybe_types_dependency
- {
+ if let Some(dep) = dependency.get_type() {
dependents_map
.entry(dep.clone())
.or_default()
.insert(specifier.clone());
}
}
+ if let Resolved::Ok { specifier: dep, .. } = doc.maybe_types_dependency()
+ {
+ dependents_map
+ .entry(dep.clone())
+ .or_default()
+ .insert(specifier.clone());
+ }
+ }
+ let mut npm_reqs = HashSet::new();
+ for specifier in dependents_map.keys() {
+ if let Ok(reference) = NpmPackageReference::from_specifier(specifier) {
+ npm_reqs.insert(reference.req);
+ }
}
self.dependents_map = Arc::new(dependents_map);
+ self.npm_reqs = npm_reqs;
self.dirty = false;
file_system_docs.dirty = false;
}
@@ -1079,7 +1135,21 @@ impl Documents {
fn resolve_dependency(
&self,
specifier: &ModuleSpecifier,
+ maybe_npm_resolver: Option<&NpmPackageResolver>,
) -> Option<(ModuleSpecifier, MediaType)> {
+ if let Ok(npm_ref) = NpmPackageReference::from_specifier(specifier) {
+ return maybe_npm_resolver.map(|npm_resolver| {
+ NodeResolution::into_specifier_and_media_type(
+ node_resolve_npm_reference(
+ &npm_ref,
+ NodeResolutionMode::Types,
+ npm_resolver,
+ )
+ .ok()
+ .flatten(),
+ )
+ });
+ }
let doc = self.get(specifier)?;
let maybe_module = doc.maybe_module().and_then(|r| r.as_ref().ok());
let maybe_types_dependency = maybe_module.and_then(|m| {
@@ -1088,7 +1158,7 @@ impl Documents {
.map(|(_, resolved)| resolved.clone())
});
if let Some(Resolved::Ok { specifier, .. }) = maybe_types_dependency {
- self.resolve_dependency(&specifier)
+ self.resolve_dependency(&specifier, maybe_npm_resolver)
} else {
let media_type = doc.media_type();
Some((specifier.clone(), media_type))
@@ -1113,12 +1183,12 @@ impl Documents {
}
/// Loader that will look at the open documents.
-pub struct DocumentsDenoGraphLoader<'a> {
+pub struct OpenDocumentsGraphLoader<'a> {
pub inner_loader: &'a mut dyn deno_graph::source::Loader,
pub open_docs: &'a HashMap<ModuleSpecifier, Document>,
}
-impl<'a> deno_graph::source::Loader for DocumentsDenoGraphLoader<'a> {
+impl<'a> deno_graph::source::Loader for OpenDocumentsGraphLoader<'a> {
fn load(
&mut self,
specifier: &ModuleSpecifier,