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.rs130
1 files changed, 110 insertions, 20 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs
index 95e8df917..6687d2208 100644
--- a/cli/lsp/documents.rs
+++ b/cli/lsp/documents.rs
@@ -20,6 +20,9 @@ use crate::lsp::logging::lsp_warn;
use crate::npm::CliNpmResolver;
use crate::resolver::CliGraphResolver;
use crate::resolver::CliGraphResolverOptions;
+use crate::resolver::UnstableSloppyImportsFsEntry;
+use crate::resolver::UnstableSloppyImportsResolution;
+use crate::resolver::UnstableSloppyImportsResolver;
use crate::util::glob;
use crate::util::path::specifier_to_file_path;
use crate::util::text_encoding;
@@ -50,6 +53,7 @@ use indexmap::IndexMap;
use lsp::Url;
use once_cell::sync::Lazy;
use package_json::PackageJsonDepsProvider;
+use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
@@ -688,12 +692,12 @@ fn recurse_dependents(
}
#[derive(Debug)]
-struct SpecifierResolver {
+struct RedirectResolver {
cache: Arc<dyn HttpCache>,
redirects: Mutex<HashMap<ModuleSpecifier, ModuleSpecifier>>,
}
-impl SpecifierResolver {
+impl RedirectResolver {
pub fn new(cache: Arc<dyn HttpCache>) -> Self {
Self {
cache,
@@ -887,7 +891,9 @@ pub struct Documents {
/// should be injected.
has_injected_types_node_package: bool,
/// Resolves a specifier to its final redirected to specifier.
- specifier_resolver: Arc<SpecifierResolver>,
+ redirect_resolver: Arc<RedirectResolver>,
+ /// If --unstable-sloppy-imports is enabled.
+ unstable_sloppy_imports: bool,
}
impl Documents {
@@ -910,10 +916,12 @@ impl Documents {
maybe_import_map: None,
maybe_vendor_dir: None,
bare_node_builtins_enabled: false,
+ sloppy_imports_resolver: None,
})),
npm_specifier_reqs: Default::default(),
has_injected_types_node_package: false,
- specifier_resolver: Arc::new(SpecifierResolver::new(cache)),
+ redirect_resolver: Arc::new(RedirectResolver::new(cache)),
+ unstable_sloppy_imports: false,
}
}
@@ -1022,7 +1030,15 @@ impl Documents {
) -> bool {
let maybe_specifier = self
.get_resolver()
- .resolve(specifier, referrer, ResolutionMode::Types)
+ .resolve(
+ specifier,
+ &deno_graph::Range {
+ specifier: referrer.clone(),
+ start: deno_graph::Position::zeroed(),
+ end: deno_graph::Position::zeroed(),
+ },
+ ResolutionMode::Types,
+ )
.ok();
if let Some(import_specifier) = maybe_specifier {
self.exists(&import_specifier)
@@ -1031,16 +1047,48 @@ impl Documents {
}
}
- pub fn resolve_redirected(
+ pub fn resolve_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
- self.specifier_resolver.resolve(specifier)
+ if self.unstable_sloppy_imports && specifier.scheme() == "file" {
+ Some(
+ self
+ .resolve_unstable_sloppy_import(specifier)
+ .into_owned_specifier(),
+ )
+ } else {
+ self.redirect_resolver.resolve(specifier)
+ }
+ }
+
+ fn resolve_unstable_sloppy_import<'a>(
+ &self,
+ specifier: &'a ModuleSpecifier,
+ ) -> UnstableSloppyImportsResolution<'a> {
+ UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
+ if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
+ if self.open_docs.contains_key(&specifier)
+ || self.cache.contains(&specifier)
+ {
+ return Some(UnstableSloppyImportsFsEntry::File);
+ }
+ }
+ path.metadata().ok().and_then(|m| {
+ if m.is_file() {
+ Some(UnstableSloppyImportsFsEntry::File)
+ } else if m.is_dir() {
+ Some(UnstableSloppyImportsFsEntry::Dir)
+ } else {
+ None
+ }
+ })
+ })
}
/// Return `true` if the specifier can be resolved to a document.
pub fn exists(&self, specifier: &ModuleSpecifier) -> bool {
- let specifier = self.specifier_resolver.resolve(specifier);
+ let specifier = self.resolve_specifier(specifier);
if let Some(specifier) = specifier {
if self.open_docs.contains_key(&specifier) {
return true;
@@ -1069,7 +1117,7 @@ impl Documents {
) -> Vec<ModuleSpecifier> {
self.calculate_dependents_if_dirty();
let mut dependents = HashSet::new();
- if let Some(specifier) = self.specifier_resolver.resolve(specifier) {
+ if let Some(specifier) = self.resolve_specifier(specifier) {
recurse_dependents(&specifier, &self.dependents_map, &mut dependents);
dependents.into_iter().collect()
} else {
@@ -1091,7 +1139,7 @@ impl Documents {
/// Return a document for the specifier.
pub fn get(&self, original_specifier: &ModuleSpecifier) -> Option<Document> {
- let specifier = self.specifier_resolver.resolve(original_specifier)?;
+ let specifier = self.resolve_specifier(original_specifier)?;
if let Some(document) = self.open_docs.get(&specifier) {
Some(document.clone())
} else {
@@ -1221,7 +1269,7 @@ impl Documents {
pub fn set_cache(&mut self, cache: Arc<dyn HttpCache>) {
// TODO update resolved dependencies?
self.cache = cache.clone();
- self.specifier_resolver = Arc::new(SpecifierResolver::new(cache));
+ self.redirect_resolver = Arc::new(RedirectResolver::new(cache));
self.dirty = true;
}
@@ -1257,6 +1305,7 @@ impl Documents {
maybe_jsx_config: Option<&JsxImportSourceConfig>,
maybe_vendor_dir: Option<bool>,
maybe_package_json_deps: Option<&PackageJsonDeps>,
+ maybe_unstable_flags: Option<&Vec<String>>,
) -> u64 {
let mut hasher = FastInsecureHasher::default();
hasher.write_hashable(document_preload_limit);
@@ -1272,6 +1321,7 @@ impl Documents {
}
hasher.write_hashable(maybe_vendor_dir);
hasher.write_hashable(maybe_jsx_config);
+ hasher.write_hashable(maybe_unstable_flags);
if let Some(package_json_deps) = &maybe_package_json_deps {
// We need to ensure the hashing is deterministic so explicitly type
// this in order to catch if the type of package_json_deps ever changes
@@ -1307,11 +1357,13 @@ impl Documents {
maybe_jsx_config.as_ref(),
options.maybe_config_file.and_then(|c| c.vendor_dir_flag()),
maybe_package_json_deps.as_ref(),
+ options.maybe_config_file.map(|c| &c.json.unstable),
);
let deps_provider =
Arc::new(PackageJsonDepsProvider::new(maybe_package_json_deps));
+ let fs = Arc::new(RealFs);
self.resolver = Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
- fs: Arc::new(RealFs),
+ fs: fs.clone(),
node_resolver: options.node_resolver,
npm_resolver: options.npm_resolver,
cjs_resolutions: None, // only used for runtime
@@ -1324,14 +1376,15 @@ impl Documents {
.as_ref(),
bare_node_builtins_enabled: options
.maybe_config_file
- .map(|config| {
- config
- .json
- .unstable
- .contains(&"bare-node-builtins".to_string())
- })
+ .map(|config| config.has_unstable("bare-node-builtins"))
.unwrap_or(false),
+ // Don't set this for the LSP because instead we'll use the OpenDocumentsLoader
+ // because it's much easier and we get diagnostics/quick fixes about a redirected
+ // specifier for free.
+ sloppy_imports_resolver: None,
}));
+ self.redirect_resolver =
+ Arc::new(RedirectResolver::new(self.cache.clone()));
self.imports = Arc::new(
if let Some(Ok(imports)) =
options.maybe_config_file.map(|cf| cf.to_maybe_imports())
@@ -1352,6 +1405,10 @@ impl Documents {
IndexMap::new()
},
);
+ self.unstable_sloppy_imports = options
+ .maybe_config_file
+ .map(|c| c.has_unstable("sloppy-imports"))
+ .unwrap_or(false);
// only refresh the dependencies if the underlying configuration has changed
if self.resolver_config_hash != new_resolver_config_hash {
@@ -1649,6 +1706,7 @@ fn node_resolve_npm_req_ref(
pub struct OpenDocumentsGraphLoader<'a> {
pub inner_loader: &'a mut dyn deno_graph::source::Loader,
pub open_docs: &'a HashMap<ModuleSpecifier, Document>,
+ pub unstable_sloppy_imports: bool,
}
impl<'a> OpenDocumentsGraphLoader<'a> {
@@ -1670,6 +1728,28 @@ impl<'a> OpenDocumentsGraphLoader<'a> {
}
None
}
+
+ fn resolve_unstable_sloppy_import<'b>(
+ &self,
+ specifier: &'b ModuleSpecifier,
+ ) -> UnstableSloppyImportsResolution<'b> {
+ UnstableSloppyImportsResolver::resolve_with_stat_sync(specifier, |path| {
+ if let Ok(specifier) = ModuleSpecifier::from_file_path(path) {
+ if self.open_docs.contains_key(&specifier) {
+ return Some(UnstableSloppyImportsFsEntry::File);
+ }
+ }
+ path.metadata().ok().and_then(|m| {
+ if m.is_file() {
+ Some(UnstableSloppyImportsFsEntry::File)
+ } else if m.is_dir() {
+ Some(UnstableSloppyImportsFsEntry::Dir)
+ } else {
+ None
+ }
+ })
+ })
+ }
}
impl<'a> deno_graph::source::Loader for OpenDocumentsGraphLoader<'a> {
@@ -1683,9 +1763,19 @@ impl<'a> deno_graph::source::Loader for OpenDocumentsGraphLoader<'a> {
is_dynamic: bool,
cache_setting: deno_graph::source::CacheSetting,
) -> deno_graph::source::LoadFuture {
- match self.load_from_docs(specifier) {
+ let specifier = if self.unstable_sloppy_imports {
+ self
+ .resolve_unstable_sloppy_import(specifier)
+ .into_specifier()
+ } else {
+ Cow::Borrowed(specifier)
+ };
+
+ match self.load_from_docs(&specifier) {
Some(fut) => fut,
- None => self.inner_loader.load(specifier, is_dynamic, cache_setting),
+ None => self
+ .inner_loader
+ .load(&specifier, is_dynamic, cache_setting),
}
}