summaryrefslogtreecommitdiff
path: root/cli/lsp/documents.rs
diff options
context:
space:
mode:
authorNayeem Rahman <nayeemrmn99@gmail.com>2024-05-23 17:31:56 +0100
committerGitHub <noreply@github.com>2024-05-23 17:31:56 +0100
commit0a30897925fd8940884231b97474f4ea76e5ed28 (patch)
treeca0081c4eb455e6ac1ebe71b24853b2262f4c63a /cli/lsp/documents.rs
parent143ea4759fa32bcd32ff983caeaec08929a52e80 (diff)
refactor(lsp): determine file referrer for each document (#23867)
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r--cli/lsp/documents.rs170
1 files changed, 138 insertions, 32 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index df15bff2a..ab053336f 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -266,6 +266,9 @@ pub struct Document {
/// Contains the last-known-good set of dependencies from parsing the module.
config: Arc<Config>,
dependencies: Arc<IndexMap<String, deno_graph::Dependency>>,
+ // TODO(nayeemrmn): This is unused, use it for scope attribution for remote
+ // modules.
+ file_referrer: Option<ModuleSpecifier>,
maybe_types_dependency: Option<Arc<deno_graph::TypesDependency>>,
maybe_fs_version: Option<String>,
line_index: Arc<LineIndex>,
@@ -295,6 +298,7 @@ impl Document {
resolver: Arc<LspResolver>,
config: Arc<Config>,
cache: &Arc<LspCache>,
+ file_referrer: Option<ModuleSpecifier>,
) -> Arc<Self> {
let text_info = SourceTextInfo::new(content);
let media_type = resolve_media_type(
@@ -310,6 +314,7 @@ impl Document {
text_info.clone(),
maybe_headers.as_ref(),
media_type,
+ file_referrer.as_ref(),
&resolver,
)
} else {
@@ -329,6 +334,7 @@ impl Document {
Arc::new(Self {
config,
dependencies,
+ file_referrer: file_referrer.filter(|_| specifier.scheme() != "file"),
maybe_types_dependency,
maybe_fs_version: calculate_fs_version(cache, &specifier),
line_index,
@@ -370,6 +376,7 @@ impl Document {
&self.specifier,
&parsed_source_result,
self.maybe_headers.as_ref(),
+ self.file_referrer.as_ref(),
&resolver,
)
.ok();
@@ -384,8 +391,10 @@ 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();
+ let graph_resolver =
+ resolver.as_graph_resolver(self.file_referrer.as_ref());
+ let npm_resolver =
+ resolver.as_graph_npm_resolver(self.file_referrer.as_ref());
dependencies = Arc::new(
self
.dependencies
@@ -420,6 +429,7 @@ impl Document {
config,
// updated properties
dependencies,
+ file_referrer: self.file_referrer.clone(),
maybe_types_dependency,
maybe_navigation_tree: Mutex::new(None),
// maintain - this should all be copies/clones
@@ -475,6 +485,7 @@ impl Document {
text_info.clone(),
self.maybe_headers.as_ref(),
media_type,
+ self.file_referrer.as_ref(),
self.resolver.as_ref(),
)
} else {
@@ -499,6 +510,7 @@ impl Document {
Ok(Arc::new(Self {
config: self.config.clone(),
specifier: self.specifier.clone(),
+ file_referrer: self.file_referrer.clone(),
maybe_fs_version: self.maybe_fs_version.clone(),
maybe_language_id: self.maybe_language_id,
dependencies,
@@ -522,6 +534,7 @@ impl Document {
Arc::new(Self {
config: self.config.clone(),
specifier: self.specifier.clone(),
+ file_referrer: self.file_referrer.clone(),
maybe_fs_version: calculate_fs_version(cache, &self.specifier),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
@@ -543,6 +556,7 @@ impl Document {
Arc::new(Self {
config: self.config.clone(),
specifier: self.specifier.clone(),
+ file_referrer: self.file_referrer.clone(),
maybe_fs_version: calculate_fs_version(cache, &self.specifier),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
@@ -564,6 +578,10 @@ impl Document {
&self.specifier
}
+ pub fn file_referrer(&self) -> Option<&ModuleSpecifier> {
+ self.file_referrer.as_ref()
+ }
+
pub fn content(&self) -> Arc<str> {
self.text_info.text()
}
@@ -729,6 +747,7 @@ impl FileSystemDocuments {
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<Arc<Document>> {
let new_fs_version = calculate_fs_version(cache, specifier);
let old_doc = self.docs.get(specifier).map(|v| v.value().clone());
@@ -745,7 +764,7 @@ impl FileSystemDocuments {
};
if dirty {
// attempt to update the file on the file system
- self.refresh_document(specifier, resolver, config, cache)
+ self.refresh_document(specifier, resolver, config, cache, file_referrer)
} else {
old_doc
}
@@ -759,6 +778,7 @@ impl FileSystemDocuments {
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<Arc<Document>> {
let doc = if specifier.scheme() == "file" {
let path = specifier_to_file_path(specifier).ok()?;
@@ -774,6 +794,7 @@ impl FileSystemDocuments {
resolver.clone(),
config.clone(),
cache,
+ file_referrer.cloned(),
)
} else if specifier.scheme() == "data" {
let source = deno_graph::source::RawDataUrl::parse(specifier)
@@ -789,6 +810,7 @@ impl FileSystemDocuments {
resolver.clone(),
config.clone(),
cache,
+ file_referrer.cloned(),
)
} else {
let http_cache = cache.root_vendor_or_global();
@@ -818,6 +840,7 @@ impl FileSystemDocuments {
resolver.clone(),
config.clone(),
cache,
+ file_referrer.cloned(),
)
};
self.docs.insert(specifier.clone(), doc.clone());
@@ -882,6 +905,7 @@ impl Documents {
version: i32,
language_id: LanguageId,
content: Arc<str>,
+ file_referrer: Option<ModuleSpecifier>,
) -> Arc<Document> {
let document = Document::new(
specifier.clone(),
@@ -895,6 +919,7 @@ impl Documents {
self.resolver.clone(),
self.config.clone(),
&self.cache,
+ file_referrer,
);
self.file_system_docs.remove_document(&specifier);
@@ -964,6 +989,19 @@ impl Documents {
self.file_system_docs.set_dirty(true);
}
+ pub fn get_file_referrer<'a>(
+ &self,
+ specifier: &'a ModuleSpecifier,
+ ) -> Option<Cow<'a, ModuleSpecifier>> {
+ if specifier.scheme() == "file" {
+ Some(Cow::Borrowed(specifier))
+ } else {
+ self
+ .get(specifier)
+ .and_then(|d| d.file_referrer().cloned().map(Cow::Owned))
+ }
+ }
+
/// Return `true` if the provided specifier can be resolved to a document,
/// otherwise `false`.
pub fn contains_import(
@@ -971,9 +1009,10 @@ impl Documents {
specifier: &str,
referrer: &ModuleSpecifier,
) -> bool {
+ let file_referrer = self.get_file_referrer(referrer);
let maybe_specifier = self
.resolver
- .as_graph_resolver()
+ .as_graph_resolver(file_referrer.as_deref())
.resolve(
specifier,
&deno_graph::Range {
@@ -985,7 +1024,7 @@ impl Documents {
)
.ok();
if let Some(import_specifier) = maybe_specifier {
- self.exists(&import_specifier)
+ self.exists(&import_specifier, file_referrer.as_deref())
} else {
false
}
@@ -994,23 +1033,32 @@ impl Documents {
pub fn resolve_document_specifier(
&self,
specifier: &ModuleSpecifier,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<ModuleSpecifier> {
let specifier = if let Ok(jsr_req_ref) =
JsrPackageReqReference::from_specifier(specifier)
{
- Cow::Owned(self.resolver.jsr_to_registry_url(&jsr_req_ref)?)
+ Cow::Owned(
+ self
+ .resolver
+ .jsr_to_registry_url(&jsr_req_ref, file_referrer)?,
+ )
} else {
Cow::Borrowed(specifier)
};
if !DOCUMENT_SCHEMES.contains(&specifier.scheme()) {
return None;
}
- self.resolver.resolve_redirects(&specifier)
+ self.resolver.resolve_redirects(&specifier, file_referrer)
}
/// Return `true` if the specifier can be resolved to a document.
- pub fn exists(&self, specifier: &ModuleSpecifier) -> bool {
- let specifier = self.resolve_document_specifier(specifier);
+ pub fn exists(
+ &self,
+ specifier: &ModuleSpecifier,
+ file_referrer: Option<&ModuleSpecifier>,
+ ) -> bool {
+ let specifier = self.resolve_document_specifier(specifier, file_referrer);
if let Some(specifier) = specifier {
if self.open_docs.contains_key(&specifier) {
return true;
@@ -1043,11 +1091,38 @@ impl Documents {
}
/// Return a document for the specifier.
- pub fn get(
+ pub fn get(&self, specifier: &ModuleSpecifier) -> Option<Arc<Document>> {
+ if let Some(document) = self.open_docs.get(specifier) {
+ Some(document.clone())
+ } else {
+ let old_doc = self
+ .file_system_docs
+ .docs
+ .get(specifier)
+ .map(|d| d.value().clone());
+ if let Some(old_doc) = old_doc {
+ self.file_system_docs.get(
+ specifier,
+ &self.resolver,
+ &self.config,
+ &self.cache,
+ old_doc.file_referrer(),
+ )
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Return a document for the specifier.
+ pub fn get_or_load(
&self,
- original_specifier: &ModuleSpecifier,
+ specifier: &ModuleSpecifier,
+ referrer: &ModuleSpecifier,
) -> Option<Arc<Document>> {
- let specifier = self.resolve_document_specifier(original_specifier)?;
+ let file_referrer = self.get_file_referrer(referrer);
+ let specifier =
+ self.resolve_document_specifier(specifier, file_referrer.as_deref())?;
if let Some(document) = self.open_docs.get(&specifier) {
Some(document.clone())
} else {
@@ -1056,6 +1131,7 @@ impl Documents {
&self.resolver,
&self.config,
&self.cache,
+ file_referrer.as_deref(),
)
}
}
@@ -1110,6 +1186,7 @@ impl Documents {
referrer: &ModuleSpecifier,
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
let document = self.get(referrer);
+ let file_referrer = document.as_ref().and_then(|d| d.file_referrer());
let dependencies = document.as_ref().map(|d| d.dependencies());
let mut results = Vec::new();
for specifier in specifiers {
@@ -1124,22 +1201,36 @@ 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, referrer));
+ results.push(self.resolve_dependency(
+ specifier,
+ referrer,
+ file_referrer,
+ ));
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
- results.push(self.resolve_dependency(specifier, referrer));
+ results.push(self.resolve_dependency(
+ specifier,
+ referrer,
+ file_referrer,
+ ));
} else {
results.push(None);
}
- } else if let Ok(specifier) = self.resolver.as_graph_resolver().resolve(
- specifier,
- &deno_graph::Range {
- specifier: referrer.clone(),
- start: deno_graph::Position::zeroed(),
- end: deno_graph::Position::zeroed(),
- },
- ResolutionMode::Types,
- ) {
- results.push(self.resolve_dependency(&specifier, referrer));
+ } else if let Ok(specifier) =
+ self.resolver.as_graph_resolver(file_referrer).resolve(
+ specifier,
+ &deno_graph::Range {
+ specifier: referrer.clone(),
+ start: deno_graph::Position::zeroed(),
+ end: deno_graph::Position::zeroed(),
+ },
+ ResolutionMode::Types,
+ )
+ {
+ results.push(self.resolve_dependency(
+ &specifier,
+ referrer,
+ file_referrer,
+ ));
} else {
results.push(None);
}
@@ -1203,6 +1294,7 @@ impl Documents {
&self.resolver,
&self.config,
&self.cache,
+ None,
);
}
}
@@ -1283,6 +1375,7 @@ impl Documents {
&self,
specifier: &ModuleSpecifier,
referrer: &ModuleSpecifier,
+ file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
if let Some(module_name) = specifier.as_str().strip_prefix("node:") {
if deno_node::is_builtin_node_module(module_name) {
@@ -1294,13 +1387,15 @@ impl Documents {
}
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(specifier) {
- return self.resolver.npm_to_file_url(&npm_ref, referrer);
+ return self
+ .resolver
+ .npm_to_file_url(&npm_ref, referrer, file_referrer);
}
- let Some(doc) = self.get(specifier) else {
+ let Some(doc) = self.get_or_load(specifier, referrer) else {
return Some((specifier.clone(), MediaType::from_specifier(specifier)));
};
- if let Some(specifier) = doc.maybe_types_dependency().maybe_specifier() {
- self.resolve_dependency(specifier, referrer)
+ if let Some(types) = doc.maybe_types_dependency().maybe_specifier() {
+ self.resolve_dependency(types, specifier, file_referrer)
} else {
let media_type = doc.media_type();
Some((doc.specifier().clone(), media_type))
@@ -1364,11 +1459,17 @@ fn parse_and_analyze_module(
text_info: SourceTextInfo,
maybe_headers: Option<&HashMap<String, String>>,
media_type: MediaType,
+ file_referrer: Option<&ModuleSpecifier>,
resolver: &LspResolver,
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) {
let parsed_source_result = parse_source(specifier, text_info, media_type);
- let module_result =
- analyze_module(specifier, &parsed_source_result, maybe_headers, resolver);
+ let module_result = analyze_module(
+ specifier,
+ &parsed_source_result,
+ maybe_headers,
+ file_referrer,
+ resolver,
+ );
(Some(parsed_source_result), Some(module_result))
}
@@ -1391,6 +1492,7 @@ fn analyze_module(
specifier: &ModuleSpecifier,
parsed_source_result: &ParsedSourceResult,
maybe_headers: Option<&HashMap<String, String>>,
+ file_referrer: Option<&ModuleSpecifier>,
resolver: &LspResolver,
) -> ModuleResult {
match parsed_source_result {
@@ -1404,8 +1506,8 @@ fn analyze_module(
// dynamic imports like import(`./dir/${something}`) in the LSP
file_system: &deno_graph::source::NullFileSystem,
jsr_url_provider: &CliJsrUrlProvider,
- maybe_resolver: Some(resolver.as_graph_resolver()),
- maybe_npm_resolver: Some(resolver.as_graph_npm_resolver()),
+ maybe_resolver: Some(resolver.as_graph_resolver(file_referrer)),
+ maybe_npm_resolver: Some(resolver.as_graph_npm_resolver(file_referrer)),
},
)),
Err(err) => Err(deno_graph::ModuleGraphError::ModuleError(
@@ -1448,6 +1550,7 @@ console.log(b);
1,
"javascript".parse().unwrap(),
content.into(),
+ None,
);
assert!(document.is_diagnosable());
assert!(document.is_open());
@@ -1473,6 +1576,7 @@ console.log(b);
1,
"javascript".parse().unwrap(),
content.into(),
+ None,
);
documents
.change(
@@ -1517,6 +1621,7 @@ console.log(b, "hello deno");
1,
LanguageId::TypeScript,
"".into(),
+ None,
);
// make a clone of the document store and close the document in that one
@@ -1586,6 +1691,7 @@ console.log(b, "hello deno");
1,
LanguageId::TypeScript,
"import {} from 'test';".into(),
+ None,
);
assert_eq!(