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.rs136
1 files changed, 114 insertions, 22 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index ce13c3215..b62fa8553 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -3,7 +3,9 @@
use super::cache::calculate_fs_version;
use super::cache::LspCache;
use super::config::Config;
+use super::resolver::LspIsCjsResolver;
use super::resolver::LspResolver;
+use super::resolver::SingleReferrerGraphResolver;
use super::testing::TestCollector;
use super::testing::TestModule;
use super::text::LineIndex;
@@ -33,6 +35,7 @@ use deno_semver::npm::NpmPackageReqReference;
use deno_semver::package::PackageReq;
use indexmap::IndexMap;
use indexmap::IndexSet;
+use node_resolver::NodeModuleKind;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
@@ -293,6 +296,8 @@ 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>>,
+ /// If this is maybe a CJS script and maybe not an ES module.
+ is_script: Option<bool>,
// TODO(nayeemrmn): This is unused, use it for scope attribution for remote
// modules.
file_referrer: Option<ModuleSpecifier>,
@@ -323,6 +328,7 @@ impl Document {
maybe_lsp_version: Option<i32>,
maybe_language_id: Option<LanguageId>,
maybe_headers: Option<HashMap<String, String>>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>,
config: Arc<Config>,
cache: &Arc<LspCache>,
@@ -342,6 +348,7 @@ impl Document {
maybe_headers.as_ref(),
media_type,
file_referrer.as_ref(),
+ is_cjs_resolver,
&resolver,
)
} else {
@@ -367,6 +374,7 @@ impl Document {
file_referrer.as_ref(),
),
file_referrer,
+ is_script: maybe_module.as_ref().map(|m| m.is_script),
maybe_types_dependency,
line_index,
maybe_language_id,
@@ -388,6 +396,7 @@ impl Document {
fn with_new_config(
&self,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: Arc<LspResolver>,
config: Arc<Config>,
) -> Arc<Self> {
@@ -399,6 +408,7 @@ impl Document {
let dependencies;
let maybe_types_dependency;
let maybe_parsed_source;
+ let is_script;
let maybe_test_module_fut;
if media_type != self.media_type {
let parsed_source_result =
@@ -408,6 +418,7 @@ impl Document {
&parsed_source_result,
self.maybe_headers.as_ref(),
self.file_referrer.as_ref(),
+ is_cjs_resolver,
&resolver,
)
.ok();
@@ -415,6 +426,7 @@ impl Document {
.as_ref()
.map(|m| Arc::new(m.dependencies.clone()))
.unwrap_or_default();
+ is_script = maybe_module.as_ref().map(|m| m.is_script);
maybe_types_dependency = maybe_module
.as_ref()
.and_then(|m| Some(Arc::new(m.maybe_types_dependency.clone()?)));
@@ -422,10 +434,19 @@ 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(self.file_referrer.as_ref());
+ let cli_resolver = resolver.as_cli_resolver(self.file_referrer.as_ref());
let npm_resolver =
resolver.create_graph_npm_resolver(self.file_referrer.as_ref());
+ let config_data = resolver.as_config_data(self.file_referrer.as_ref());
+ let jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &self.specifier,
+ referrer_kind: is_cjs_resolver
+ .get_lsp_referrer_kind(&self.specifier, self.is_script),
+ cli_resolver,
+ jsx_import_source_config: jsx_import_source_config.as_ref(),
+ };
dependencies = Arc::new(
self
.dependencies
@@ -436,7 +457,7 @@ impl Document {
d.with_new_resolver(
s,
&CliJsrUrlProvider,
- Some(graph_resolver),
+ Some(&resolver),
Some(&npm_resolver),
),
)
@@ -446,10 +467,11 @@ impl Document {
maybe_types_dependency = self.maybe_types_dependency.as_ref().map(|d| {
Arc::new(d.with_new_resolver(
&CliJsrUrlProvider,
- Some(graph_resolver),
+ Some(&resolver),
Some(&npm_resolver),
))
});
+ is_script = self.is_script;
maybe_parsed_source = self.maybe_parsed_source().cloned();
maybe_test_module_fut = self
.maybe_test_module_fut
@@ -461,6 +483,7 @@ impl Document {
// updated properties
dependencies,
file_referrer: self.file_referrer.clone(),
+ is_script,
maybe_types_dependency,
maybe_navigation_tree: Mutex::new(None),
// maintain - this should all be copies/clones
@@ -485,6 +508,7 @@ impl Document {
fn with_change(
&self,
+ is_cjs_resolver: &LspIsCjsResolver,
version: i32,
changes: Vec<lsp::TextDocumentContentChangeEvent>,
) -> Result<Arc<Self>, AnyError> {
@@ -518,6 +542,7 @@ impl Document {
self.maybe_headers.as_ref(),
media_type,
self.file_referrer.as_ref(),
+ is_cjs_resolver,
self.resolver.as_ref(),
)
} else {
@@ -541,6 +566,7 @@ impl Document {
get_maybe_test_module_fut(maybe_parsed_source.as_ref(), &self.config);
Ok(Arc::new(Self {
config: self.config.clone(),
+ is_script: maybe_module.as_ref().map(|m| m.is_script),
specifier: self.specifier.clone(),
file_referrer: self.file_referrer.clone(),
maybe_fs_version: self.maybe_fs_version.clone(),
@@ -575,6 +601,7 @@ impl Document {
),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
+ is_script: self.is_script,
maybe_types_dependency: self.maybe_types_dependency.clone(),
text: self.text.clone(),
text_info_cell: once_cell::sync::OnceCell::new(),
@@ -602,6 +629,7 @@ impl Document {
),
maybe_language_id: self.maybe_language_id,
dependencies: self.dependencies.clone(),
+ is_script: self.is_script,
maybe_types_dependency: self.maybe_types_dependency.clone(),
text: self.text.clone(),
text_info_cell: once_cell::sync::OnceCell::new(),
@@ -650,6 +678,13 @@ impl Document {
})
}
+ /// If this is maybe a CJS script and maybe not an ES module.
+ ///
+ /// Use `LspIsCjsResolver` to determine for sure.
+ pub fn is_script(&self) -> Option<bool> {
+ self.is_script
+ }
+
pub fn line_index(&self) -> Arc<LineIndex> {
self.line_index.clone()
}
@@ -797,6 +832,7 @@ impl FileSystemDocuments {
pub fn get(
&self,
specifier: &ModuleSpecifier,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
@@ -820,7 +856,14 @@ impl FileSystemDocuments {
};
if dirty {
// attempt to update the file on the file system
- self.refresh_document(specifier, resolver, config, cache, file_referrer)
+ self.refresh_document(
+ specifier,
+ is_cjs_resolver,
+ resolver,
+ config,
+ cache,
+ file_referrer,
+ )
} else {
old_doc
}
@@ -831,6 +874,7 @@ impl FileSystemDocuments {
fn refresh_document(
&self,
specifier: &ModuleSpecifier,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &Arc<LspResolver>,
config: &Arc<Config>,
cache: &Arc<LspCache>,
@@ -847,6 +891,7 @@ impl FileSystemDocuments {
None,
None,
None,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -863,6 +908,7 @@ impl FileSystemDocuments {
None,
None,
None,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -890,6 +936,7 @@ impl FileSystemDocuments {
None,
None,
maybe_headers,
+ is_cjs_resolver,
resolver.clone(),
config.clone(),
cache,
@@ -930,6 +977,11 @@ pub struct Documents {
/// The DENO_DIR that the documents looks for non-file based modules.
cache: Arc<LspCache>,
config: Arc<Config>,
+ /// Resolver for detecting if a document is CJS or ESM.
+ is_cjs_resolver: Arc<LspIsCjsResolver>,
+ /// A resolver that takes into account currently loaded import map and JSX
+ /// settings.
+ resolver: Arc<LspResolver>,
/// A flag that indicates that stated data is potentially invalid and needs to
/// be recalculated before being considered valid.
dirty: bool,
@@ -937,9 +989,6 @@ pub struct Documents {
open_docs: HashMap<ModuleSpecifier, Arc<Document>>,
/// Documents stored on the file system.
file_system_docs: Arc<FileSystemDocuments>,
- /// A resolver that takes into account currently loaded import map and JSX
- /// settings.
- resolver: Arc<LspResolver>,
/// The npm package requirements found in npm specifiers.
npm_reqs_by_scope:
Arc<BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>>,
@@ -970,6 +1019,7 @@ impl Documents {
// the cache for remote modules here in order to get the
// x-typescript-types?
None,
+ &self.is_cjs_resolver,
self.resolver.clone(),
self.config.clone(),
&self.cache,
@@ -1004,7 +1054,7 @@ impl Documents {
))
})?;
self.dirty = true;
- let doc = doc.with_change(version, changes)?;
+ let doc = doc.with_change(&self.is_cjs_resolver, version, changes)?;
self.open_docs.insert(doc.specifier().clone(), doc.clone());
Ok(doc)
}
@@ -1133,6 +1183,7 @@ impl Documents {
if let Some(old_doc) = old_doc {
self.file_system_docs.get(
specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1157,6 +1208,7 @@ impl Documents {
} else {
self.file_system_docs.get(
&specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1215,12 +1267,15 @@ impl Documents {
referrer: &ModuleSpecifier,
file_referrer: Option<&ModuleSpecifier>,
) -> Vec<Option<(ModuleSpecifier, MediaType)>> {
- let document = self.get(referrer);
- let file_referrer = document
+ let referrer_doc = self.get(referrer);
+ let file_referrer = referrer_doc
.as_ref()
.and_then(|d| d.file_referrer())
.or(file_referrer);
- let dependencies = document.as_ref().map(|d| d.dependencies());
+ let dependencies = referrer_doc.as_ref().map(|d| d.dependencies());
+ let referrer_kind = self
+ .is_cjs_resolver
+ .get_maybe_doc_module_kind(referrer, referrer_doc.as_deref());
let mut results = Vec::new();
for raw_specifier in raw_specifiers {
if raw_specifier.starts_with("asset:") {
@@ -1237,31 +1292,35 @@ impl Documents {
results.push(self.resolve_dependency(
specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else if let Some(specifier) = dep.maybe_code.maybe_specifier() {
results.push(self.resolve_dependency(
specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else {
results.push(None);
}
} else if let Ok(specifier) =
- self.resolver.as_graph_resolver(file_referrer).resolve(
+ self.resolver.as_cli_resolver(file_referrer).resolve(
raw_specifier,
&deno_graph::Range {
specifier: referrer.clone(),
start: deno_graph::Position::zeroed(),
end: deno_graph::Position::zeroed(),
},
+ referrer_kind,
ResolutionMode::Types,
)
{
results.push(self.resolve_dependency(
&specifier,
referrer,
+ referrer_kind,
file_referrer,
));
} else {
@@ -1280,7 +1339,11 @@ impl Documents {
) {
self.config = Arc::new(config.clone());
self.cache = Arc::new(cache.clone());
+ self.is_cjs_resolver = Arc::new(LspIsCjsResolver::new(cache));
self.resolver = resolver.clone();
+
+ node_resolver::PackageJsonThreadLocalCache::clear();
+
{
let fs_docs = &self.file_system_docs;
// Clean up non-existent documents.
@@ -1300,14 +1363,21 @@ impl Documents {
if !config.specifier_enabled(doc.specifier()) {
continue;
}
- *doc = doc.with_new_config(self.resolver.clone(), self.config.clone());
+ *doc = doc.with_new_config(
+ &self.is_cjs_resolver,
+ 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.config.clone());
+ *doc.value_mut() = doc.with_new_config(
+ &self.is_cjs_resolver,
+ self.resolver.clone(),
+ self.config.clone(),
+ );
}
self.open_docs = open_docs;
let mut preload_count = 0;
@@ -1324,6 +1394,7 @@ impl Documents {
{
fs_docs.refresh_document(
specifier,
+ &self.is_cjs_resolver,
&self.resolver,
&self.config,
&self.cache,
@@ -1409,6 +1480,7 @@ impl Documents {
&self,
specifier: &ModuleSpecifier,
referrer: &ModuleSpecifier,
+ referrer_kind: NodeModuleKind,
file_referrer: Option<&ModuleSpecifier>,
) -> Option<(ModuleSpecifier, MediaType)> {
if let Some(module_name) = specifier.as_str().strip_prefix("node:") {
@@ -1422,10 +1494,12 @@ impl Documents {
let mut specifier = specifier.clone();
let mut media_type = None;
if let Ok(npm_ref) = NpmPackageReqReference::from_specifier(&specifier) {
- let (s, mt) =
- self
- .resolver
- .npm_to_file_url(&npm_ref, referrer, file_referrer)?;
+ let (s, mt) = self.resolver.npm_to_file_url(
+ &npm_ref,
+ referrer,
+ referrer_kind,
+ file_referrer,
+ )?;
specifier = s;
media_type = Some(mt);
}
@@ -1435,7 +1509,8 @@ impl Documents {
return Some((specifier, media_type));
};
if let Some(types) = doc.maybe_types_dependency().maybe_specifier() {
- self.resolve_dependency(types, &specifier, file_referrer)
+ let specifier_kind = self.is_cjs_resolver.get_doc_module_kind(&doc);
+ self.resolve_dependency(types, &specifier, specifier_kind, file_referrer)
} else {
Some((doc.specifier().clone(), doc.media_type()))
}
@@ -1503,6 +1578,7 @@ fn parse_and_analyze_module(
maybe_headers: Option<&HashMap<String, String>>,
media_type: MediaType,
file_referrer: Option<&ModuleSpecifier>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver,
) -> (Option<ParsedSourceResult>, Option<ModuleResult>) {
let parsed_source_result = parse_source(specifier.clone(), text, media_type);
@@ -1511,6 +1587,7 @@ fn parse_and_analyze_module(
&parsed_source_result,
maybe_headers,
file_referrer,
+ is_cjs_resolver,
resolver,
);
(Some(parsed_source_result), Some(module_result))
@@ -1536,11 +1613,26 @@ fn analyze_module(
parsed_source_result: &ParsedSourceResult,
maybe_headers: Option<&HashMap<String, String>>,
file_referrer: Option<&ModuleSpecifier>,
+ is_cjs_resolver: &LspIsCjsResolver,
resolver: &LspResolver,
) -> ModuleResult {
match parsed_source_result {
Ok(parsed_source) => {
let npm_resolver = resolver.create_graph_npm_resolver(file_referrer);
+ let cli_resolver = resolver.as_cli_resolver(file_referrer);
+ let config_data = resolver.as_config_data(file_referrer);
+ let valid_referrer = specifier.clone();
+ let jsx_import_source_config =
+ config_data.and_then(|d| d.maybe_jsx_import_source_config());
+ let resolver = SingleReferrerGraphResolver {
+ valid_referrer: &valid_referrer,
+ referrer_kind: is_cjs_resolver.get_lsp_referrer_kind(
+ &specifier,
+ Some(parsed_source.compute_is_script()),
+ ),
+ cli_resolver,
+ jsx_import_source_config: jsx_import_source_config.as_ref(),
+ };
Ok(deno_graph::parse_module_from_ast(
deno_graph::ParseModuleFromAstOptions {
graph_kind: deno_graph::GraphKind::TypesOnly,
@@ -1551,7 +1643,7 @@ 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(file_referrer)),
+ maybe_resolver: Some(&resolver),
maybe_npm_resolver: Some(&npm_resolver),
},
))