mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
feat(lsp): multi deno.json resolver scopes (#24206)
This commit is contained in:
parent
10828cd62c
commit
b318d51822
10 changed files with 762 additions and 255 deletions
|
@ -11,6 +11,7 @@ use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
|
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -29,13 +30,14 @@ pub const LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY: deno_cache_dir::GlobalToLocalCopy =
|
||||||
pub fn calculate_fs_version(
|
pub fn calculate_fs_version(
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
match specifier.scheme() {
|
match specifier.scheme() {
|
||||||
"npm" | "node" | "data" | "blob" => None,
|
"npm" | "node" | "data" | "blob" => None,
|
||||||
"file" => specifier_to_file_path(specifier)
|
"file" => specifier_to_file_path(specifier)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|path| calculate_fs_version_at_path(&path)),
|
.and_then(|path| calculate_fs_version_at_path(&path)),
|
||||||
_ => calculate_fs_version_in_cache(cache, specifier),
|
_ => calculate_fs_version_in_cache(cache, specifier, file_referrer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +58,9 @@ pub fn calculate_fs_version_at_path(path: &Path) -> Option<String> {
|
||||||
fn calculate_fs_version_in_cache(
|
fn calculate_fs_version_in_cache(
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let http_cache = cache.root_vendor_or_global();
|
let http_cache = cache.for_specifier(file_referrer);
|
||||||
let Ok(cache_key) = http_cache.cache_item_key(specifier) else {
|
let Ok(cache_key) = http_cache.cache_item_key(specifier) else {
|
||||||
return Some("1".to_string());
|
return Some("1".to_string());
|
||||||
};
|
};
|
||||||
|
@ -77,7 +80,7 @@ fn calculate_fs_version_in_cache(
|
||||||
pub struct LspCache {
|
pub struct LspCache {
|
||||||
deno_dir: DenoDir,
|
deno_dir: DenoDir,
|
||||||
global: Arc<GlobalHttpCache>,
|
global: Arc<GlobalHttpCache>,
|
||||||
root_vendor: Option<Arc<LocalLspHttpCache>>,
|
vendors_by_scope: BTreeMap<ModuleSpecifier, Option<Arc<LocalLspHttpCache>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LspCache {
|
impl Default for LspCache {
|
||||||
|
@ -107,18 +110,24 @@ impl LspCache {
|
||||||
Self {
|
Self {
|
||||||
deno_dir,
|
deno_dir,
|
||||||
global,
|
global,
|
||||||
root_vendor: None,
|
vendors_by_scope: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_config(&mut self, config: &Config) {
|
pub fn update_config(&mut self, config: &Config) {
|
||||||
self.root_vendor = config.tree.root_data().and_then(|data| {
|
self.vendors_by_scope = config
|
||||||
let vendor_dir = data.vendor_dir.as_ref()?;
|
.tree
|
||||||
Some(Arc::new(LocalLspHttpCache::new(
|
.data_by_scope()
|
||||||
vendor_dir.clone(),
|
.iter()
|
||||||
self.global.clone(),
|
.map(|(scope, config_data)| {
|
||||||
)))
|
(
|
||||||
});
|
scope.clone(),
|
||||||
|
config_data.vendor_dir.as_ref().map(|v| {
|
||||||
|
Arc::new(LocalLspHttpCache::new(v.clone(), self.global.clone()))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deno_dir(&self) -> &DenoDir {
|
pub fn deno_dir(&self) -> &DenoDir {
|
||||||
|
@ -129,15 +138,50 @@ impl LspCache {
|
||||||
&self.global
|
&self.global
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_vendor(&self) -> Option<&Arc<LocalLspHttpCache>> {
|
pub fn for_specifier(
|
||||||
self.root_vendor.as_ref()
|
&self,
|
||||||
}
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
|
) -> Arc<dyn HttpCache> {
|
||||||
pub fn root_vendor_or_global(&self) -> Arc<dyn HttpCache> {
|
let Some(file_referrer) = file_referrer else {
|
||||||
|
return self.global.clone();
|
||||||
|
};
|
||||||
self
|
self
|
||||||
.root_vendor
|
.vendors_by_scope
|
||||||
.as_ref()
|
.iter()
|
||||||
.map(|v| v.clone() as _)
|
.rfind(|(s, _)| file_referrer.as_str().starts_with(s.as_str()))
|
||||||
|
.and_then(|(_, v)| v.clone().map(|v| v as _))
|
||||||
.unwrap_or(self.global.clone() as _)
|
.unwrap_or(self.global.clone() as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vendored_specifier(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
|
) -> Option<ModuleSpecifier> {
|
||||||
|
let file_referrer = file_referrer?;
|
||||||
|
if !matches!(specifier.scheme(), "http" | "https") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let vendor = self
|
||||||
|
.vendors_by_scope
|
||||||
|
.iter()
|
||||||
|
.rfind(|(s, _)| file_referrer.as_str().starts_with(s.as_str()))?
|
||||||
|
.1
|
||||||
|
.as_ref()?;
|
||||||
|
vendor.get_file_url(specifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unvendored_specifier(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
) -> Option<ModuleSpecifier> {
|
||||||
|
let path = specifier_to_file_path(specifier).ok()?;
|
||||||
|
let vendor = self
|
||||||
|
.vendors_by_scope
|
||||||
|
.iter()
|
||||||
|
.rfind(|(s, _)| specifier.as_str().starts_with(s.as_str()))?
|
||||||
|
.1
|
||||||
|
.as_ref()?;
|
||||||
|
vendor.get_remote_url(&path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ async fn resolve_references_code_lens(
|
||||||
locations.push(
|
locations.push(
|
||||||
reference
|
reference
|
||||||
.entry
|
.entry
|
||||||
.to_location(asset_or_doc.line_index(), &language_server.url_map),
|
.to_location(asset_or_doc.line_index(), language_server),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(locations)
|
Ok(locations)
|
||||||
|
|
|
@ -1568,27 +1568,13 @@ impl ConfigData {
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct ConfigTree {
|
pub struct ConfigTree {
|
||||||
first_folder: Option<ModuleSpecifier>,
|
first_folder: Option<ModuleSpecifier>,
|
||||||
scopes: Arc<BTreeMap<ModuleSpecifier, ConfigData>>,
|
scopes: Arc<BTreeMap<ModuleSpecifier, Arc<ConfigData>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigTree {
|
impl ConfigTree {
|
||||||
pub fn root_scope(&self) -> Option<&ModuleSpecifier> {
|
|
||||||
self.first_folder.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_data(&self) -> Option<&ConfigData> {
|
|
||||||
self.first_folder.as_ref().and_then(|s| self.scopes.get(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_ts_config(&self) -> Arc<LspTsConfig> {
|
pub fn root_ts_config(&self) -> Arc<LspTsConfig> {
|
||||||
self
|
let root_data = self.first_folder.as_ref().and_then(|s| self.scopes.get(s));
|
||||||
.root_data()
|
root_data.map(|d| d.ts_config.clone()).unwrap_or_default()
|
||||||
.map(|d| d.ts_config.clone())
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_import_map(&self) -> Option<&Arc<ImportMap>> {
|
|
||||||
self.root_data().and_then(|d| d.import_map.as_ref())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope_for_specifier(
|
pub fn scope_for_specifier(
|
||||||
|
@ -1599,19 +1585,20 @@ impl ConfigTree {
|
||||||
.scopes
|
.scopes
|
||||||
.keys()
|
.keys()
|
||||||
.rfind(|s| specifier.as_str().starts_with(s.as_str()))
|
.rfind(|s| specifier.as_str().starts_with(s.as_str()))
|
||||||
.or(self.first_folder.as_ref())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_for_specifier(
|
pub fn data_for_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<&ConfigData> {
|
) -> Option<&Arc<ConfigData>> {
|
||||||
self
|
self
|
||||||
.scope_for_specifier(specifier)
|
.scope_for_specifier(specifier)
|
||||||
.and_then(|s| self.scopes.get(s))
|
.and_then(|s| self.scopes.get(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_by_scope(&self) -> &Arc<BTreeMap<ModuleSpecifier, ConfigData>> {
|
pub fn data_by_scope(
|
||||||
|
&self,
|
||||||
|
) -> &Arc<BTreeMap<ModuleSpecifier, Arc<ConfigData>>> {
|
||||||
&self.scopes
|
&self.scopes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1694,14 +1681,16 @@ impl ConfigTree {
|
||||||
if let Ok(config_uri) = folder_uri.join(config_path) {
|
if let Ok(config_uri) = folder_uri.join(config_path) {
|
||||||
scopes.insert(
|
scopes.insert(
|
||||||
folder_uri.clone(),
|
folder_uri.clone(),
|
||||||
ConfigData::load(
|
Arc::new(
|
||||||
Some(&config_uri),
|
ConfigData::load(
|
||||||
folder_uri,
|
Some(&config_uri),
|
||||||
None,
|
folder_uri,
|
||||||
settings,
|
None,
|
||||||
Some(file_fetcher),
|
settings,
|
||||||
)
|
Some(file_fetcher),
|
||||||
.await,
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1756,10 +1745,10 @@ impl ConfigTree {
|
||||||
Some(file_fetcher),
|
Some(file_fetcher),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
scopes.insert(member_scope.clone(), member_data);
|
scopes.insert(member_scope.clone(), Arc::new(member_data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scopes.insert(scope, data);
|
scopes.insert(scope, Arc::new(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
for folder_uri in settings.by_workspace_folder.keys() {
|
for folder_uri in settings.by_workspace_folder.keys() {
|
||||||
|
@ -1769,14 +1758,16 @@ impl ConfigTree {
|
||||||
{
|
{
|
||||||
scopes.insert(
|
scopes.insert(
|
||||||
folder_uri.clone(),
|
folder_uri.clone(),
|
||||||
ConfigData::load(
|
Arc::new(
|
||||||
None,
|
ConfigData::load(
|
||||||
folder_uri,
|
None,
|
||||||
None,
|
folder_uri,
|
||||||
settings,
|
None,
|
||||||
Some(file_fetcher),
|
settings,
|
||||||
)
|
Some(file_fetcher),
|
||||||
.await,
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1787,14 +1778,16 @@ impl ConfigTree {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub async fn inject_config_file(&mut self, config_file: ConfigFile) {
|
pub async fn inject_config_file(&mut self, config_file: ConfigFile) {
|
||||||
let scope = config_file.specifier.join(".").unwrap();
|
let scope = config_file.specifier.join(".").unwrap();
|
||||||
let data = ConfigData::load_inner(
|
let data = Arc::new(
|
||||||
Some(config_file),
|
ConfigData::load_inner(
|
||||||
&scope,
|
Some(config_file),
|
||||||
None,
|
&scope,
|
||||||
&Default::default(),
|
None,
|
||||||
None,
|
&Default::default(),
|
||||||
)
|
None,
|
||||||
.await;
|
)
|
||||||
|
.await,
|
||||||
|
);
|
||||||
self.first_folder = Some(scope.clone());
|
self.first_folder = Some(scope.clone());
|
||||||
self.scopes = Arc::new([(scope, data)].into_iter().collect());
|
self.scopes = Arc::new([(scope, data)].into_iter().collect());
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use super::client::Client;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
use super::documents;
|
use super::documents;
|
||||||
use super::documents::Document;
|
use super::documents::Document;
|
||||||
|
use super::documents::Documents;
|
||||||
use super::documents::DocumentsFilter;
|
use super::documents::DocumentsFilter;
|
||||||
use super::language_server;
|
use super::language_server;
|
||||||
use super::language_server::StateSnapshot;
|
use super::language_server::StateSnapshot;
|
||||||
|
@ -120,6 +121,7 @@ impl DiagnosticsPublisher {
|
||||||
source: DiagnosticSource,
|
source: DiagnosticSource,
|
||||||
diagnostics: DiagnosticVec,
|
diagnostics: DiagnosticVec,
|
||||||
url_map: &LspUrlMap,
|
url_map: &LspUrlMap,
|
||||||
|
documents: &Documents,
|
||||||
token: &CancellationToken,
|
token: &CancellationToken,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let mut diagnostics_by_specifier =
|
let mut diagnostics_by_specifier =
|
||||||
|
@ -153,11 +155,12 @@ impl DiagnosticsPublisher {
|
||||||
self
|
self
|
||||||
.state
|
.state
|
||||||
.update(&record.specifier, version, &all_specifier_diagnostics);
|
.update(&record.specifier, version, &all_specifier_diagnostics);
|
||||||
|
let file_referrer = documents.get_file_referrer(&record.specifier);
|
||||||
self
|
self
|
||||||
.client
|
.client
|
||||||
.publish_diagnostics(
|
.publish_diagnostics(
|
||||||
url_map
|
url_map
|
||||||
.normalize_specifier(&record.specifier)
|
.normalize_specifier(&record.specifier, file_referrer.as_deref())
|
||||||
.unwrap_or(LspClientUrl::new(record.specifier)),
|
.unwrap_or(LspClientUrl::new(record.specifier)),
|
||||||
all_specifier_diagnostics,
|
all_specifier_diagnostics,
|
||||||
version,
|
version,
|
||||||
|
@ -183,11 +186,12 @@ impl DiagnosticsPublisher {
|
||||||
if let Some(removed_value) = maybe_removed_value {
|
if let Some(removed_value) = maybe_removed_value {
|
||||||
// clear out any diagnostics for this specifier
|
// clear out any diagnostics for this specifier
|
||||||
self.state.update(specifier, removed_value.version, &[]);
|
self.state.update(specifier, removed_value.version, &[]);
|
||||||
|
let file_referrer = documents.get_file_referrer(specifier);
|
||||||
self
|
self
|
||||||
.client
|
.client
|
||||||
.publish_diagnostics(
|
.publish_diagnostics(
|
||||||
url_map
|
url_map
|
||||||
.normalize_specifier(specifier)
|
.normalize_specifier(specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(specifier.clone())),
|
.unwrap_or_else(|_| LspClientUrl::new(specifier.clone())),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
removed_value.version,
|
removed_value.version,
|
||||||
|
@ -519,6 +523,7 @@ impl DiagnosticsServer {
|
||||||
DiagnosticSource::Ts,
|
DiagnosticSource::Ts,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
&url_map,
|
&url_map,
|
||||||
|
snapshot.documents.as_ref(),
|
||||||
&token,
|
&token,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -556,6 +561,7 @@ impl DiagnosticsServer {
|
||||||
let mark = performance.mark("lsp.update_diagnostics_deps");
|
let mark = performance.mark("lsp.update_diagnostics_deps");
|
||||||
let diagnostics = spawn_blocking({
|
let diagnostics = spawn_blocking({
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
|
let snapshot = snapshot.clone();
|
||||||
move || generate_deno_diagnostics(&snapshot, &config, token)
|
move || generate_deno_diagnostics(&snapshot, &config, token)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -568,6 +574,7 @@ impl DiagnosticsServer {
|
||||||
DiagnosticSource::Deno,
|
DiagnosticSource::Deno,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
&url_map,
|
&url_map,
|
||||||
|
snapshot.documents.as_ref(),
|
||||||
&token,
|
&token,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -605,6 +612,7 @@ impl DiagnosticsServer {
|
||||||
let mark = performance.mark("lsp.update_diagnostics_lint");
|
let mark = performance.mark("lsp.update_diagnostics_lint");
|
||||||
let diagnostics = spawn_blocking({
|
let diagnostics = spawn_blocking({
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
|
let snapshot = snapshot.clone();
|
||||||
move || generate_lint_diagnostics(&snapshot, &config, token)
|
move || generate_lint_diagnostics(&snapshot, &config, token)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -617,6 +625,7 @@ impl DiagnosticsServer {
|
||||||
DiagnosticSource::Lint,
|
DiagnosticSource::Lint,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
&url_map,
|
&url_map,
|
||||||
|
snapshot.documents.as_ref(),
|
||||||
&token,
|
&token,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -1466,7 +1475,11 @@ fn diagnose_dependency(
|
||||||
return; // ignore, surface typescript errors instead
|
return; // ignore, surface typescript errors instead
|
||||||
}
|
}
|
||||||
|
|
||||||
let import_map = snapshot.config.tree.root_import_map();
|
let import_map = snapshot
|
||||||
|
.config
|
||||||
|
.tree
|
||||||
|
.data_for_specifier(referrer_doc.file_referrer().unwrap_or(referrer))
|
||||||
|
.and_then(|d| d.import_map.as_ref());
|
||||||
if let Some(import_map) = import_map {
|
if let Some(import_map) = import_map {
|
||||||
if let Resolution::Ok(resolved) = &dependency.maybe_code {
|
if let Resolution::Ok(resolved) = &dependency.maybe_code {
|
||||||
if let Some(to) = import_map.lookup(&resolved.specifier, referrer) {
|
if let Some(to) = import_map.lookup(&resolved.specifier, referrer) {
|
||||||
|
|
|
@ -303,6 +303,10 @@ impl Document {
|
||||||
cache: &Arc<LspCache>,
|
cache: &Arc<LspCache>,
|
||||||
file_referrer: Option<ModuleSpecifier>,
|
file_referrer: Option<ModuleSpecifier>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
|
let file_referrer = Some(&specifier)
|
||||||
|
.filter(|s| s.scheme() == "file")
|
||||||
|
.cloned()
|
||||||
|
.or(file_referrer);
|
||||||
let media_type = resolve_media_type(
|
let media_type = resolve_media_type(
|
||||||
&specifier,
|
&specifier,
|
||||||
maybe_headers.as_ref(),
|
maybe_headers.as_ref(),
|
||||||
|
@ -336,9 +340,13 @@ impl Document {
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
config,
|
config,
|
||||||
dependencies,
|
dependencies,
|
||||||
file_referrer: file_referrer.filter(|_| specifier.scheme() != "file"),
|
maybe_fs_version: calculate_fs_version(
|
||||||
|
cache,
|
||||||
|
&specifier,
|
||||||
|
file_referrer.as_ref(),
|
||||||
|
),
|
||||||
|
file_referrer,
|
||||||
maybe_types_dependency,
|
maybe_types_dependency,
|
||||||
maybe_fs_version: calculate_fs_version(cache, &specifier),
|
|
||||||
line_index,
|
line_index,
|
||||||
maybe_language_id,
|
maybe_language_id,
|
||||||
maybe_headers,
|
maybe_headers,
|
||||||
|
@ -540,7 +548,11 @@ impl Document {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
specifier: self.specifier.clone(),
|
specifier: self.specifier.clone(),
|
||||||
file_referrer: self.file_referrer.clone(),
|
file_referrer: self.file_referrer.clone(),
|
||||||
maybe_fs_version: calculate_fs_version(cache, &self.specifier),
|
maybe_fs_version: calculate_fs_version(
|
||||||
|
cache,
|
||||||
|
&self.specifier,
|
||||||
|
self.file_referrer.as_ref(),
|
||||||
|
),
|
||||||
maybe_language_id: self.maybe_language_id,
|
maybe_language_id: self.maybe_language_id,
|
||||||
dependencies: self.dependencies.clone(),
|
dependencies: self.dependencies.clone(),
|
||||||
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
||||||
|
@ -563,7 +575,11 @@ impl Document {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
specifier: self.specifier.clone(),
|
specifier: self.specifier.clone(),
|
||||||
file_referrer: self.file_referrer.clone(),
|
file_referrer: self.file_referrer.clone(),
|
||||||
maybe_fs_version: calculate_fs_version(cache, &self.specifier),
|
maybe_fs_version: calculate_fs_version(
|
||||||
|
cache,
|
||||||
|
&self.specifier,
|
||||||
|
self.file_referrer.as_ref(),
|
||||||
|
),
|
||||||
maybe_language_id: self.maybe_language_id,
|
maybe_language_id: self.maybe_language_id,
|
||||||
dependencies: self.dependencies.clone(),
|
dependencies: self.dependencies.clone(),
|
||||||
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
maybe_types_dependency: self.maybe_types_dependency.clone(),
|
||||||
|
@ -766,7 +782,10 @@ impl FileSystemDocuments {
|
||||||
cache: &Arc<LspCache>,
|
cache: &Arc<LspCache>,
|
||||||
file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<Arc<Document>> {
|
) -> Option<Arc<Document>> {
|
||||||
let new_fs_version = calculate_fs_version(cache, specifier);
|
let file_referrer = Some(specifier)
|
||||||
|
.filter(|s| s.scheme() == "file")
|
||||||
|
.or(file_referrer);
|
||||||
|
let new_fs_version = calculate_fs_version(cache, specifier, file_referrer);
|
||||||
let old_doc = self.docs.get(specifier).map(|v| v.value().clone());
|
let old_doc = self.docs.get(specifier).map(|v| v.value().clone());
|
||||||
let dirty = match &old_doc {
|
let dirty = match &old_doc {
|
||||||
None => true,
|
None => true,
|
||||||
|
@ -830,7 +849,7 @@ impl FileSystemDocuments {
|
||||||
file_referrer.cloned(),
|
file_referrer.cloned(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let http_cache = cache.root_vendor_or_global();
|
let http_cache = cache.for_specifier(file_referrer);
|
||||||
let cache_key = http_cache.cache_item_key(specifier).ok()?;
|
let cache_key = http_cache.cache_item_key(specifier).ok()?;
|
||||||
let bytes = http_cache
|
let bytes = http_cache
|
||||||
.read_file_bytes(&cache_key, None, LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY)
|
.read_file_bytes(&cache_key, None, LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY)
|
||||||
|
@ -1089,7 +1108,7 @@ impl Documents {
|
||||||
.map(|p| p.is_file())
|
.map(|p| p.is_file())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
}
|
}
|
||||||
if self.cache.root_vendor_or_global().contains(&specifier) {
|
if self.cache.for_specifier(file_referrer).contains(&specifier) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1335,8 +1354,7 @@ impl Documents {
|
||||||
let mut visit_doc = |doc: &Arc<Document>| {
|
let mut visit_doc = |doc: &Arc<Document>| {
|
||||||
let scope = doc
|
let scope = doc
|
||||||
.file_referrer()
|
.file_referrer()
|
||||||
.and_then(|r| self.config.tree.scope_for_specifier(r))
|
.and_then(|r| self.config.tree.scope_for_specifier(r));
|
||||||
.or(self.config.tree.root_scope());
|
|
||||||
let reqs = npm_reqs_by_scope.entry(scope.cloned()).or_default();
|
let reqs = npm_reqs_by_scope.entry(scope.cloned()).or_default();
|
||||||
for dependency in doc.dependencies().values() {
|
for dependency in doc.dependencies().values() {
|
||||||
if let Some(dep) = dependency.get_code() {
|
if let Some(dep) = dependency.get_code() {
|
||||||
|
@ -1367,21 +1385,15 @@ impl Documents {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the reqs from the lockfile
|
// fill the reqs from the lockfile
|
||||||
// TODO(nayeemrmn): Iterate every lockfile here for multi-deno.json.
|
for (scope, config_data) in self.config.tree.data_by_scope().as_ref() {
|
||||||
if let Some(lockfile) = self
|
if let Some(lockfile) = config_data.lockfile.as_ref() {
|
||||||
.config
|
let reqs = npm_reqs_by_scope.entry(Some(scope.clone())).or_default();
|
||||||
.tree
|
let lockfile = lockfile.lock();
|
||||||
.root_data()
|
for key in lockfile.content.packages.specifiers.keys() {
|
||||||
.and_then(|d| d.lockfile.as_ref())
|
if let Some(key) = key.strip_prefix("npm:") {
|
||||||
{
|
if let Ok(req) = PackageReq::from_str(key) {
|
||||||
let reqs = npm_reqs_by_scope
|
reqs.insert(req);
|
||||||
.entry(self.config.tree.root_scope().cloned())
|
}
|
||||||
.or_default();
|
|
||||||
let lockfile = lockfile.lock();
|
|
||||||
for key in lockfile.content.packages.specifiers.keys() {
|
|
||||||
if let Some(key) = key.strip_prefix("npm:") {
|
|
||||||
if let Ok(req) = PackageReq::from_str(key) {
|
|
||||||
reqs.insert(req);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,7 +682,7 @@ impl Inner {
|
||||||
pub fn update_cache(&mut self) {
|
pub fn update_cache(&mut self) {
|
||||||
let mark = self.performance.mark("lsp.update_cache");
|
let mark = self.performance.mark("lsp.update_cache");
|
||||||
self.cache.update_config(&self.config);
|
self.cache.update_config(&self.config);
|
||||||
self.url_map.set_cache(self.cache.root_vendor().cloned());
|
self.url_map.set_cache(&self.cache);
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,11 +1134,9 @@ impl Inner {
|
||||||
let package_reqs = self.documents.npm_reqs_by_scope();
|
let package_reqs = self.documents.npm_reqs_by_scope();
|
||||||
let resolver = self.resolver.clone();
|
let resolver = self.resolver.clone();
|
||||||
// spawn due to the lsp's `Send` requirement
|
// spawn due to the lsp's `Send` requirement
|
||||||
let handle =
|
spawn(async move { resolver.set_npm_reqs(&package_reqs).await })
|
||||||
spawn(async move { resolver.set_npm_reqs(&package_reqs).await });
|
.await
|
||||||
if let Err(err) = handle.await.unwrap() {
|
.ok();
|
||||||
lsp_warn!("Could not set npm package requirements. {:#}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn did_close(&mut self, params: DidCloseTextDocumentParams) {
|
async fn did_close(&mut self, params: DidCloseTextDocumentParams) {
|
||||||
|
@ -1818,11 +1816,15 @@ impl Inner {
|
||||||
|
|
||||||
pub fn get_ts_response_import_mapper(
|
pub fn get_ts_response_import_mapper(
|
||||||
&self,
|
&self,
|
||||||
_referrer: &ModuleSpecifier,
|
file_referrer: &ModuleSpecifier,
|
||||||
) -> TsResponseImportMapper {
|
) -> TsResponseImportMapper {
|
||||||
TsResponseImportMapper::new(
|
TsResponseImportMapper::new(
|
||||||
&self.documents,
|
&self.documents,
|
||||||
self.config.tree.root_import_map().map(|i| i.as_ref()),
|
self
|
||||||
|
.config
|
||||||
|
.tree
|
||||||
|
.data_for_specifier(file_referrer)
|
||||||
|
.and_then(|d| d.import_map.as_ref().map(|i| i.as_ref())),
|
||||||
self.resolver.as_ref(),
|
self.resolver.as_ref(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1999,11 +2001,7 @@ impl Inner {
|
||||||
self.get_asset_or_document(&reference_specifier)?;
|
self.get_asset_or_document(&reference_specifier)?;
|
||||||
asset_or_doc.line_index()
|
asset_or_doc.line_index()
|
||||||
};
|
};
|
||||||
results.push(
|
results.push(reference.entry.to_location(reference_line_index, self));
|
||||||
reference
|
|
||||||
.entry
|
|
||||||
.to_location(reference_line_index, &self.url_map),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
|
@ -2125,6 +2123,10 @@ impl Inner {
|
||||||
.map(|s| s.suggest.include_completions_for_import_statements)
|
.map(|s| s.suggest.include_completions_for_import_statements)
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
|
let file_referrer = asset_or_doc
|
||||||
|
.document()
|
||||||
|
.and_then(|d| d.file_referrer())
|
||||||
|
.unwrap_or(&specifier);
|
||||||
response = completions::get_import_completions(
|
response = completions::get_import_completions(
|
||||||
&specifier,
|
&specifier,
|
||||||
¶ms.text_document_position.position,
|
¶ms.text_document_position.position,
|
||||||
|
@ -2135,7 +2137,11 @@ impl Inner {
|
||||||
&self.npm_search_api,
|
&self.npm_search_api,
|
||||||
&self.documents,
|
&self.documents,
|
||||||
self.resolver.as_ref(),
|
self.resolver.as_ref(),
|
||||||
self.config.tree.root_import_map().map(|i| i.as_ref()),
|
self
|
||||||
|
.config
|
||||||
|
.tree
|
||||||
|
.data_for_specifier(file_referrer)
|
||||||
|
.and_then(|d| d.import_map.as_ref().map(|i| i.as_ref())),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -3442,7 +3448,7 @@ impl Inner {
|
||||||
let mark = self
|
let mark = self
|
||||||
.performance
|
.performance
|
||||||
.mark_with_args("lsp.cache", (&specifiers, &referrer));
|
.mark_with_args("lsp.cache", (&specifiers, &referrer));
|
||||||
let config_data = self.config.tree.root_data();
|
let config_data = self.config.tree.data_for_specifier(&referrer);
|
||||||
let mut roots = if !specifiers.is_empty() {
|
let mut roots = if !specifiers.is_empty() {
|
||||||
specifiers
|
specifiers
|
||||||
} else {
|
} else {
|
||||||
|
@ -3451,16 +3457,17 @@ impl Inner {
|
||||||
|
|
||||||
// always include the npm packages since resolution of one npm package
|
// always include the npm packages since resolution of one npm package
|
||||||
// might affect the resolution of other npm packages
|
// might affect the resolution of other npm packages
|
||||||
roots.extend(
|
if let Some(npm_reqs) = self
|
||||||
self
|
.documents
|
||||||
.documents
|
.npm_reqs_by_scope()
|
||||||
.npm_reqs_by_scope()
|
.get(&config_data.map(|d| d.scope.clone()))
|
||||||
.values()
|
{
|
||||||
.flatten()
|
roots.extend(
|
||||||
.collect::<BTreeSet<_>>()
|
npm_reqs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|req| ModuleSpecifier::parse(&format!("npm:{}", req)).unwrap()),
|
.map(|req| ModuleSpecifier::parse(&format!("npm:{}", req)).unwrap()),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let workspace_settings = self.config.workspace_settings();
|
let workspace_settings = self.config.workspace_settings();
|
||||||
let cli_options = CliOptions::new(
|
let cli_options = CliOptions::new(
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::graph_util::CliJsrUrlProvider;
|
||||||
use crate::http_util::HttpClientProvider;
|
use crate::http_util::HttpClientProvider;
|
||||||
use crate::lsp::config::Config;
|
use crate::lsp::config::Config;
|
||||||
use crate::lsp::config::ConfigData;
|
use crate::lsp::config::ConfigData;
|
||||||
|
use crate::lsp::logging::lsp_warn;
|
||||||
use crate::npm::create_cli_npm_resolver_for_lsp;
|
use crate::npm::create_cli_npm_resolver_for_lsp;
|
||||||
use crate::npm::CliNpmResolver;
|
use crate::npm::CliNpmResolver;
|
||||||
use crate::npm::CliNpmResolverByonmCreateOptions;
|
use crate::npm::CliNpmResolverByonmCreateOptions;
|
||||||
|
@ -54,17 +55,17 @@ use super::cache::LspCache;
|
||||||
use super::jsr::JsrCacheResolver;
|
use super::jsr::JsrCacheResolver;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LspResolver {
|
struct LspScopeResolver {
|
||||||
graph_resolver: Arc<CliGraphResolver>,
|
graph_resolver: Arc<CliGraphResolver>,
|
||||||
jsr_resolver: Option<Arc<JsrCacheResolver>>,
|
jsr_resolver: Option<Arc<JsrCacheResolver>>,
|
||||||
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
npm_resolver: Option<Arc<dyn CliNpmResolver>>,
|
||||||
node_resolver: Option<Arc<CliNodeResolver>>,
|
node_resolver: Option<Arc<CliNodeResolver>>,
|
||||||
redirect_resolver: Option<Arc<RedirectResolver>>,
|
redirect_resolver: Option<Arc<RedirectResolver>>,
|
||||||
graph_imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>,
|
graph_imports: Arc<IndexMap<ModuleSpecifier, GraphImport>>,
|
||||||
config: Arc<Config>,
|
config_data: Option<Arc<ConfigData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LspResolver {
|
impl Default for LspScopeResolver {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
graph_resolver: create_graph_resolver(None, None, None),
|
graph_resolver: create_graph_resolver(None, None, None),
|
||||||
|
@ -73,38 +74,41 @@ impl Default for LspResolver {
|
||||||
node_resolver: None,
|
node_resolver: None,
|
||||||
redirect_resolver: None,
|
redirect_resolver: None,
|
||||||
graph_imports: Default::default(),
|
graph_imports: Default::default(),
|
||||||
config: Default::default(),
|
config_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LspResolver {
|
impl LspScopeResolver {
|
||||||
pub async fn from_config(
|
async fn from_config_data(
|
||||||
|
config_data: Option<&Arc<ConfigData>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
http_client_provider: Option<&Arc<HttpClientProvider>>,
|
http_client_provider: Option<&Arc<HttpClientProvider>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let config_data = config.tree.root_data();
|
|
||||||
let mut npm_resolver = None;
|
let mut npm_resolver = None;
|
||||||
let mut node_resolver = None;
|
let mut node_resolver = None;
|
||||||
if let (Some(http_client), Some(config_data)) =
|
if let Some(http_client) = http_client_provider {
|
||||||
(http_client_provider, config_data)
|
npm_resolver = create_npm_resolver(
|
||||||
{
|
config_data.map(|d| d.as_ref()),
|
||||||
npm_resolver = create_npm_resolver(config_data, cache, http_client).await;
|
cache,
|
||||||
|
http_client,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
node_resolver = create_node_resolver(npm_resolver.as_ref());
|
node_resolver = create_node_resolver(npm_resolver.as_ref());
|
||||||
}
|
}
|
||||||
let graph_resolver = create_graph_resolver(
|
let graph_resolver = create_graph_resolver(
|
||||||
config_data,
|
config_data.map(|d| d.as_ref()),
|
||||||
npm_resolver.as_ref(),
|
npm_resolver.as_ref(),
|
||||||
node_resolver.as_ref(),
|
node_resolver.as_ref(),
|
||||||
);
|
);
|
||||||
let jsr_resolver = Some(Arc::new(JsrCacheResolver::new(
|
let jsr_resolver = Some(Arc::new(JsrCacheResolver::new(
|
||||||
cache.root_vendor_or_global(),
|
cache.for_specifier(config_data.map(|d| &d.scope)),
|
||||||
config_data,
|
config_data.map(|d| d.as_ref()),
|
||||||
config,
|
config,
|
||||||
)));
|
)));
|
||||||
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
|
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
|
||||||
cache.root_vendor_or_global(),
|
cache.for_specifier(config_data.map(|d| &d.scope)),
|
||||||
)));
|
)));
|
||||||
let npm_graph_resolver = graph_resolver.create_graph_npm_resolver();
|
let npm_graph_resolver = graph_resolver.create_graph_npm_resolver();
|
||||||
let graph_imports = config_data
|
let graph_imports = config_data
|
||||||
|
@ -135,16 +139,16 @@ impl LspResolver {
|
||||||
node_resolver,
|
node_resolver,
|
||||||
redirect_resolver,
|
redirect_resolver,
|
||||||
graph_imports,
|
graph_imports,
|
||||||
config: Arc::new(config.clone()),
|
config_data: config_data.cloned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self) -> Arc<Self> {
|
fn snapshot(&self) -> Arc<Self> {
|
||||||
let npm_resolver =
|
let npm_resolver =
|
||||||
self.npm_resolver.as_ref().map(|r| r.clone_snapshotted());
|
self.npm_resolver.as_ref().map(|r| r.clone_snapshotted());
|
||||||
let node_resolver = create_node_resolver(npm_resolver.as_ref());
|
let node_resolver = create_node_resolver(npm_resolver.as_ref());
|
||||||
let graph_resolver = create_graph_resolver(
|
let graph_resolver = create_graph_resolver(
|
||||||
self.config.tree.root_data(),
|
self.config_data.as_deref(),
|
||||||
npm_resolver.as_ref(),
|
npm_resolver.as_ref(),
|
||||||
node_resolver.as_ref(),
|
node_resolver.as_ref(),
|
||||||
);
|
);
|
||||||
|
@ -155,68 +159,133 @@ impl LspResolver {
|
||||||
node_resolver,
|
node_resolver,
|
||||||
redirect_resolver: self.redirect_resolver.clone(),
|
redirect_resolver: self.redirect_resolver.clone(),
|
||||||
graph_imports: self.graph_imports.clone(),
|
graph_imports: self.graph_imports.clone(),
|
||||||
config: self.config.clone(),
|
config_data: self.config_data.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct LspResolver {
|
||||||
|
unscoped: Arc<LspScopeResolver>,
|
||||||
|
by_scope: BTreeMap<ModuleSpecifier, Arc<LspScopeResolver>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LspResolver {
|
||||||
|
pub async fn from_config(
|
||||||
|
config: &Config,
|
||||||
|
cache: &LspCache,
|
||||||
|
http_client_provider: Option<&Arc<HttpClientProvider>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut by_scope = BTreeMap::new();
|
||||||
|
for (scope, config_data) in config.tree.data_by_scope().as_ref() {
|
||||||
|
by_scope.insert(
|
||||||
|
scope.clone(),
|
||||||
|
Arc::new(
|
||||||
|
LspScopeResolver::from_config_data(
|
||||||
|
Some(config_data),
|
||||||
|
config,
|
||||||
|
cache,
|
||||||
|
http_client_provider,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
unscoped: Arc::new(
|
||||||
|
LspScopeResolver::from_config_data(
|
||||||
|
None,
|
||||||
|
config,
|
||||||
|
cache,
|
||||||
|
http_client_provider,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
),
|
||||||
|
by_scope,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn snapshot(&self) -> Arc<Self> {
|
||||||
|
Arc::new(Self {
|
||||||
|
unscoped: self.unscoped.snapshot(),
|
||||||
|
by_scope: self
|
||||||
|
.by_scope
|
||||||
|
.iter()
|
||||||
|
.map(|(s, r)| (s.clone(), r.snapshot()))
|
||||||
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn did_cache(&self) {
|
pub fn did_cache(&self) {
|
||||||
self.jsr_resolver.as_ref().inspect(|r| r.did_cache());
|
for resolver in
|
||||||
|
std::iter::once(&self.unscoped).chain(self.by_scope.values())
|
||||||
|
{
|
||||||
|
resolver.jsr_resolver.as_ref().inspect(|r| r.did_cache());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_npm_reqs(
|
pub async fn set_npm_reqs(
|
||||||
&self,
|
&self,
|
||||||
reqs: &BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>,
|
reqs: &BTreeMap<Option<ModuleSpecifier>, BTreeSet<PackageReq>>,
|
||||||
) -> Result<(), AnyError> {
|
) {
|
||||||
let reqs = reqs
|
for (scope, resolver) in [(None, &self.unscoped)]
|
||||||
.values()
|
|
||||||
.flatten()
|
|
||||||
.collect::<BTreeSet<_>>()
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.cloned()
|
.chain(self.by_scope.iter().map(|(s, r)| (Some(s), r)))
|
||||||
.collect::<Vec<_>>();
|
{
|
||||||
if let Some(npm_resolver) = self.npm_resolver.as_ref() {
|
if let Some(npm_resolver) = resolver.npm_resolver.as_ref() {
|
||||||
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
if let Some(npm_resolver) = npm_resolver.as_managed() {
|
||||||
return npm_resolver.set_package_reqs(&reqs).await;
|
let reqs = reqs
|
||||||
|
.get(&scope.cloned())
|
||||||
|
.map(|reqs| reqs.iter().cloned().collect::<Vec<_>>())
|
||||||
|
.unwrap_or_default();
|
||||||
|
if let Err(err) = npm_resolver.set_package_reqs(&reqs).await {
|
||||||
|
lsp_warn!("Could not set npm package requirements: {:#}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_graph_resolver(
|
pub fn as_graph_resolver(
|
||||||
&self,
|
&self,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> &dyn Resolver {
|
) -> &dyn Resolver {
|
||||||
self.graph_resolver.as_ref()
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
resolver.graph_resolver.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_graph_npm_resolver(
|
pub fn create_graph_npm_resolver(
|
||||||
&self,
|
&self,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> WorkerCliNpmGraphResolver {
|
) -> WorkerCliNpmGraphResolver {
|
||||||
self.graph_resolver.create_graph_npm_resolver()
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
resolver.graph_resolver.create_graph_npm_resolver()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_managed_npm_resolver(
|
pub fn maybe_managed_npm_resolver(
|
||||||
&self,
|
&self,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<&ManagedCliNpmResolver> {
|
) -> Option<&ManagedCliNpmResolver> {
|
||||||
self.npm_resolver.as_ref().and_then(|r| r.as_managed())
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
resolver.npm_resolver.as_ref().and_then(|r| r.as_managed())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn graph_imports_by_referrer(
|
pub fn graph_imports_by_referrer(
|
||||||
&self,
|
&self,
|
||||||
) -> IndexMap<&ModuleSpecifier, Vec<&ModuleSpecifier>> {
|
) -> IndexMap<&ModuleSpecifier, Vec<&ModuleSpecifier>> {
|
||||||
self
|
self
|
||||||
.graph_imports
|
.by_scope
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(s, i)| {
|
.flat_map(|(_, r)| {
|
||||||
(
|
r.graph_imports.iter().map(|(s, i)| {
|
||||||
s,
|
(
|
||||||
i.dependencies
|
s,
|
||||||
.values()
|
i.dependencies
|
||||||
.flat_map(|d| d.get_type().or_else(|| d.get_code()))
|
.values()
|
||||||
.collect(),
|
.flat_map(|d| d.get_type().or_else(|| d.get_code()))
|
||||||
)
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -224,35 +293,42 @@ impl LspResolver {
|
||||||
pub fn jsr_to_resource_url(
|
pub fn jsr_to_resource_url(
|
||||||
&self,
|
&self,
|
||||||
req_ref: &JsrPackageReqReference,
|
req_ref: &JsrPackageReqReference,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<ModuleSpecifier> {
|
) -> Option<ModuleSpecifier> {
|
||||||
self.jsr_resolver.as_ref()?.jsr_to_resource_url(req_ref)
|
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(
|
pub fn jsr_lookup_export_for_path(
|
||||||
&self,
|
&self,
|
||||||
nv: &PackageNv,
|
nv: &PackageNv,
|
||||||
path: &str,
|
path: &str,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
self.jsr_resolver.as_ref()?.lookup_export_for_path(nv, path)
|
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(
|
pub fn jsr_lookup_req_for_nv(
|
||||||
&self,
|
&self,
|
||||||
nv: &PackageNv,
|
nv: &PackageNv,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<PackageReq> {
|
) -> Option<PackageReq> {
|
||||||
self.jsr_resolver.as_ref()?.lookup_req_for_nv(nv)
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
resolver.jsr_resolver.as_ref()?.lookup_req_for_nv(nv)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn npm_to_file_url(
|
pub fn npm_to_file_url(
|
||||||
&self,
|
&self,
|
||||||
req_ref: &NpmPackageReqReference,
|
req_ref: &NpmPackageReqReference,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<(ModuleSpecifier, MediaType)> {
|
) -> Option<(ModuleSpecifier, MediaType)> {
|
||||||
let node_resolver = self.node_resolver.as_ref()?;
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
let node_resolver = resolver.node_resolver.as_ref()?;
|
||||||
Some(NodeResolution::into_specifier_and_media_type(
|
Some(NodeResolution::into_specifier_and_media_type(
|
||||||
node_resolver
|
node_resolver
|
||||||
.resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
|
.resolve_req_reference(req_ref, referrer, NodeResolutionMode::Types)
|
||||||
|
@ -261,7 +337,8 @@ impl LspResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
|
pub fn in_node_modules(&self, specifier: &ModuleSpecifier) -> bool {
|
||||||
if let Some(npm_resolver) = &self.npm_resolver {
|
let resolver = self.get_scope_resolver(Some(specifier));
|
||||||
|
if let Some(npm_resolver) = &resolver.npm_resolver {
|
||||||
return npm_resolver.in_npm_package(specifier);
|
return npm_resolver.in_npm_package(specifier);
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -271,7 +348,8 @@ impl LspResolver {
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<MediaType> {
|
) -> Option<MediaType> {
|
||||||
let node_resolver = self.node_resolver.as_ref()?;
|
let resolver = self.get_scope_resolver(Some(specifier));
|
||||||
|
let node_resolver = resolver.node_resolver.as_ref()?;
|
||||||
let resolution = node_resolver
|
let resolution = node_resolver
|
||||||
.url_to_node_resolution(specifier.clone())
|
.url_to_node_resolution(specifier.clone())
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
@ -282,7 +360,8 @@ impl LspResolver {
|
||||||
&self,
|
&self,
|
||||||
referrer: &ModuleSpecifier,
|
referrer: &ModuleSpecifier,
|
||||||
) -> Result<Option<Rc<PackageJson>>, AnyError> {
|
) -> Result<Option<Rc<PackageJson>>, AnyError> {
|
||||||
let Some(node_resolver) = self.node_resolver.as_ref() else {
|
let resolver = self.get_scope_resolver(Some(referrer));
|
||||||
|
let Some(node_resolver) = resolver.node_resolver.as_ref() else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
node_resolver.get_closest_package_json(
|
node_resolver.get_closest_package_json(
|
||||||
|
@ -294,9 +373,10 @@ impl LspResolver {
|
||||||
pub fn resolve_redirects(
|
pub fn resolve_redirects(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Option<ModuleSpecifier> {
|
) -> Option<ModuleSpecifier> {
|
||||||
let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
let Some(redirect_resolver) = resolver.redirect_resolver.as_ref() else {
|
||||||
return Some(specifier.clone());
|
return Some(specifier.clone());
|
||||||
};
|
};
|
||||||
redirect_resolver.resolve(specifier)
|
redirect_resolver.resolve(specifier)
|
||||||
|
@ -305,9 +385,10 @@ impl LspResolver {
|
||||||
pub fn redirect_chain_headers(
|
pub fn redirect_chain_headers(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
_file_referrer: Option<&ModuleSpecifier>,
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
|
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
|
||||||
let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
|
let resolver = self.get_scope_resolver(file_referrer);
|
||||||
|
let Some(redirect_resolver) = resolver.redirect_resolver.as_ref() else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
redirect_resolver
|
redirect_resolver
|
||||||
|
@ -316,26 +397,47 @@ impl LspResolver {
|
||||||
.map(|(s, e)| (s, e.headers.clone()))
|
.map(|(s, e)| (s, e.headers.clone()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_scope_resolver(
|
||||||
|
&self,
|
||||||
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
|
) -> &LspScopeResolver {
|
||||||
|
let Some(file_referrer) = file_referrer else {
|
||||||
|
return self.unscoped.as_ref();
|
||||||
|
};
|
||||||
|
self
|
||||||
|
.by_scope
|
||||||
|
.iter()
|
||||||
|
.rfind(|(s, _)| file_referrer.as_str().starts_with(s.as_str()))
|
||||||
|
.map(|(_, r)| r.as_ref())
|
||||||
|
.unwrap_or(self.unscoped.as_ref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_npm_resolver(
|
async fn create_npm_resolver(
|
||||||
config_data: &ConfigData,
|
config_data: Option<&ConfigData>,
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
http_client_provider: &Arc<HttpClientProvider>,
|
http_client_provider: &Arc<HttpClientProvider>,
|
||||||
) -> Option<Arc<dyn CliNpmResolver>> {
|
) -> Option<Arc<dyn CliNpmResolver>> {
|
||||||
let node_modules_dir = config_data
|
let mut byonm_dir = None;
|
||||||
.node_modules_dir
|
if let Some(config_data) = config_data {
|
||||||
.clone()
|
if config_data.byonm {
|
||||||
.or_else(|| specifier_to_file_path(&config_data.scope).ok())?;
|
byonm_dir = Some(config_data.node_modules_dir.clone().or_else(|| {
|
||||||
let options = if config_data.byonm {
|
specifier_to_file_path(&config_data.scope)
|
||||||
|
.ok()
|
||||||
|
.map(|p| p.join("node_modules/"))
|
||||||
|
})?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let options = if let Some(byonm_dir) = byonm_dir {
|
||||||
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
CliNpmResolverCreateOptions::Byonm(CliNpmResolverByonmCreateOptions {
|
||||||
fs: Arc::new(deno_fs::RealFs),
|
fs: Arc::new(deno_fs::RealFs),
|
||||||
root_node_modules_dir: node_modules_dir.clone(),
|
root_node_modules_dir: byonm_dir,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
CliNpmResolverCreateOptions::Managed(CliNpmResolverManagedCreateOptions {
|
||||||
http_client_provider: http_client_provider.clone(),
|
http_client_provider: http_client_provider.clone(),
|
||||||
snapshot: match config_data.lockfile.as_ref() {
|
snapshot: match config_data.and_then(|d| d.lockfile.as_ref()) {
|
||||||
Some(lockfile) => {
|
Some(lockfile) => {
|
||||||
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
|
CliNpmResolverManagedSnapshotOption::ResolveFromLockfile(
|
||||||
lockfile.clone(),
|
lockfile.clone(),
|
||||||
|
@ -354,15 +456,17 @@ async fn create_npm_resolver(
|
||||||
// the user is typing.
|
// the user is typing.
|
||||||
cache_setting: CacheSetting::Only,
|
cache_setting: CacheSetting::Only,
|
||||||
text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly),
|
text_only_progress_bar: ProgressBar::new(ProgressBarStyle::TextOnly),
|
||||||
maybe_node_modules_path: config_data.node_modules_dir.clone(),
|
maybe_node_modules_path: config_data
|
||||||
|
.and_then(|d| d.node_modules_dir.clone()),
|
||||||
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::new(
|
package_json_deps_provider: Arc::new(PackageJsonDepsProvider::new(
|
||||||
config_data.package_json.as_ref().map(|package_json| {
|
config_data
|
||||||
package_json::get_local_package_json_version_reqs(package_json)
|
.and_then(|d| d.package_json.as_ref())
|
||||||
}),
|
.map(|package_json| {
|
||||||
|
package_json::get_local_package_json_version_reqs(package_json)
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
npmrc: config_data
|
npmrc: config_data
|
||||||
.npmrc
|
.and_then(|d| d.npmrc.clone())
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(create_default_npmrc),
|
.unwrap_or_else(create_default_npmrc),
|
||||||
npm_system_info: NpmSystemInfo::default(),
|
npm_system_info: NpmSystemInfo::default(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,7 +19,6 @@ use super::semantic_tokens;
|
||||||
use super::semantic_tokens::SemanticTokensBuilder;
|
use super::semantic_tokens::SemanticTokensBuilder;
|
||||||
use super::text::LineIndex;
|
use super::text::LineIndex;
|
||||||
use super::urls::LspClientUrl;
|
use super::urls::LspClientUrl;
|
||||||
use super::urls::LspUrlMap;
|
|
||||||
use super::urls::INVALID_SPECIFIER;
|
use super::urls::INVALID_SPECIFIER;
|
||||||
|
|
||||||
use crate::args::jsr_url;
|
use crate::args::jsr_url;
|
||||||
|
@ -1844,9 +1843,12 @@ impl DocumentSpan {
|
||||||
let target_asset_or_doc =
|
let target_asset_or_doc =
|
||||||
language_server.get_maybe_asset_or_document(&target_specifier)?;
|
language_server.get_maybe_asset_or_document(&target_specifier)?;
|
||||||
let target_line_index = target_asset_or_doc.line_index();
|
let target_line_index = target_asset_or_doc.line_index();
|
||||||
|
let file_referrer = language_server
|
||||||
|
.documents
|
||||||
|
.get_file_referrer(&target_specifier);
|
||||||
let target_uri = language_server
|
let target_uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&target_specifier)
|
.normalize_specifier(&target_specifier, file_referrer.as_deref())
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let (target_range, target_selection_range) =
|
let (target_range, target_selection_range) =
|
||||||
if let Some(context_span) = &self.context_span {
|
if let Some(context_span) = &self.context_span {
|
||||||
|
@ -1890,9 +1892,10 @@ impl DocumentSpan {
|
||||||
language_server.get_maybe_asset_or_document(&specifier)?;
|
language_server.get_maybe_asset_or_document(&specifier)?;
|
||||||
let line_index = asset_or_doc.line_index();
|
let line_index = asset_or_doc.line_index();
|
||||||
let range = self.text_span.to_range(line_index);
|
let range = self.text_span.to_range(line_index);
|
||||||
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
let mut target = language_server
|
let mut target = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier)
|
.normalize_specifier(&specifier, file_referrer.as_deref())
|
||||||
.ok()?
|
.ok()?
|
||||||
.into_url();
|
.into_url();
|
||||||
target.set_fragment(Some(&format!(
|
target.set_fragment(Some(&format!(
|
||||||
|
@ -1950,9 +1953,10 @@ impl NavigateToItem {
|
||||||
let asset_or_doc =
|
let asset_or_doc =
|
||||||
language_server.get_asset_or_document(&specifier).ok()?;
|
language_server.get_asset_or_document(&specifier).ok()?;
|
||||||
let line_index = asset_or_doc.line_index();
|
let line_index = asset_or_doc.line_index();
|
||||||
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier)
|
.normalize_specifier(&specifier, file_referrer.as_deref())
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let range = self.text_span.to_range(line_index);
|
let range = self.text_span.to_range(line_index);
|
||||||
let location = lsp::Location {
|
let location = lsp::Location {
|
||||||
|
@ -2208,9 +2212,10 @@ impl ImplementationLocation {
|
||||||
) -> lsp::Location {
|
) -> lsp::Location {
|
||||||
let specifier = resolve_url(&self.document_span.file_name)
|
let specifier = resolve_url(&self.document_span.file_name)
|
||||||
.unwrap_or_else(|_| ModuleSpecifier::parse("deno://invalid").unwrap());
|
.unwrap_or_else(|_| ModuleSpecifier::parse("deno://invalid").unwrap());
|
||||||
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&specifier)
|
.normalize_specifier(&specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
LspClientUrl::new(ModuleSpecifier::parse("deno://invalid").unwrap())
|
LspClientUrl::new(ModuleSpecifier::parse("deno://invalid").unwrap())
|
||||||
});
|
});
|
||||||
|
@ -2270,7 +2275,11 @@ impl RenameLocations {
|
||||||
includes_non_files = true;
|
includes_non_files = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let uri = language_server.url_map.normalize_specifier(&specifier)?;
|
let file_referrer =
|
||||||
|
language_server.documents.get_file_referrer(&specifier);
|
||||||
|
let uri = language_server
|
||||||
|
.url_map
|
||||||
|
.normalize_specifier(&specifier, file_referrer.as_deref())?;
|
||||||
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
|
let asset_or_doc = language_server.get_asset_or_document(&specifier)?;
|
||||||
|
|
||||||
// ensure TextDocumentEdit for `location.file_name`.
|
// ensure TextDocumentEdit for `location.file_name`.
|
||||||
|
@ -2916,12 +2925,14 @@ impl ReferenceEntry {
|
||||||
pub fn to_location(
|
pub fn to_location(
|
||||||
&self,
|
&self,
|
||||||
line_index: Arc<LineIndex>,
|
line_index: Arc<LineIndex>,
|
||||||
url_map: &LspUrlMap,
|
language_server: &language_server::Inner,
|
||||||
) -> lsp::Location {
|
) -> lsp::Location {
|
||||||
let specifier = resolve_url(&self.document_span.file_name)
|
let specifier = resolve_url(&self.document_span.file_name)
|
||||||
.unwrap_or_else(|_| INVALID_SPECIFIER.clone());
|
.unwrap_or_else(|_| INVALID_SPECIFIER.clone());
|
||||||
let uri = url_map
|
let file_referrer = language_server.documents.get_file_referrer(&specifier);
|
||||||
.normalize_specifier(&specifier)
|
let uri = language_server
|
||||||
|
.url_map
|
||||||
|
.normalize_specifier(&specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
||||||
lsp::Location {
|
lsp::Location {
|
||||||
uri: uri.into_url(),
|
uri: uri.into_url(),
|
||||||
|
@ -2977,9 +2988,12 @@ impl CallHierarchyItem {
|
||||||
) -> lsp::CallHierarchyItem {
|
) -> lsp::CallHierarchyItem {
|
||||||
let target_specifier =
|
let target_specifier =
|
||||||
resolve_url(&self.file).unwrap_or_else(|_| INVALID_SPECIFIER.clone());
|
resolve_url(&self.file).unwrap_or_else(|_| INVALID_SPECIFIER.clone());
|
||||||
|
let file_referrer = language_server
|
||||||
|
.documents
|
||||||
|
.get_file_referrer(&target_specifier);
|
||||||
let uri = language_server
|
let uri = language_server
|
||||||
.url_map
|
.url_map
|
||||||
.normalize_specifier(&target_specifier)
|
.normalize_specifier(&target_specifier, file_referrer.as_deref())
|
||||||
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
.unwrap_or_else(|_| LspClientUrl::new(INVALID_SPECIFIER.clone()));
|
||||||
|
|
||||||
let use_file_name = self.is_source_file_item();
|
let use_file_name = self.is_source_file_item();
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::cache::LocalLspHttpCache;
|
|
||||||
|
|
||||||
use deno_ast::MediaType;
|
use deno_ast::MediaType;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::parking_lot::Mutex;
|
use deno_core::parking_lot::Mutex;
|
||||||
|
@ -12,6 +10,8 @@ use once_cell::sync::Lazy;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::cache::LspCache;
|
||||||
|
|
||||||
/// Used in situations where a default URL needs to be used where otherwise a
|
/// Used in situations where a default URL needs to be used where otherwise a
|
||||||
/// panic is undesired.
|
/// panic is undesired.
|
||||||
pub static INVALID_SPECIFIER: Lazy<ModuleSpecifier> =
|
pub static INVALID_SPECIFIER: Lazy<ModuleSpecifier> =
|
||||||
|
@ -156,13 +156,13 @@ pub enum LspUrlKind {
|
||||||
/// to allow the Deno language server to manage these as virtual documents.
|
/// to allow the Deno language server to manage these as virtual documents.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct LspUrlMap {
|
pub struct LspUrlMap {
|
||||||
local_http_cache: Option<Arc<LocalLspHttpCache>>,
|
cache: LspCache,
|
||||||
inner: Arc<Mutex<LspUrlMapInner>>,
|
inner: Arc<Mutex<LspUrlMapInner>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LspUrlMap {
|
impl LspUrlMap {
|
||||||
pub fn set_cache(&mut self, http_cache: Option<Arc<LocalLspHttpCache>>) {
|
pub fn set_cache(&mut self, cache: &LspCache) {
|
||||||
self.local_http_cache = http_cache;
|
self.cache = cache.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalize a specifier that is used internally within Deno (or tsc) to a
|
/// Normalize a specifier that is used internally within Deno (or tsc) to a
|
||||||
|
@ -170,13 +170,12 @@ impl LspUrlMap {
|
||||||
pub fn normalize_specifier(
|
pub fn normalize_specifier(
|
||||||
&self,
|
&self,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
|
file_referrer: Option<&ModuleSpecifier>,
|
||||||
) -> Result<LspClientUrl, AnyError> {
|
) -> Result<LspClientUrl, AnyError> {
|
||||||
if let Some(cache) = &self.local_http_cache {
|
if let Some(file_url) =
|
||||||
if matches!(specifier.scheme(), "http" | "https") {
|
self.cache.vendored_specifier(specifier, file_referrer)
|
||||||
if let Some(file_url) = cache.get_file_url(specifier) {
|
{
|
||||||
return Ok(LspClientUrl(file_url));
|
return Ok(LspClientUrl(file_url));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(url) = inner.get_url(specifier).cloned() {
|
if let Some(url) = inner.get_url(specifier).cloned() {
|
||||||
|
@ -220,14 +219,8 @@ impl LspUrlMap {
|
||||||
/// so we need to force it to in the mapping and nee to explicitly state whether
|
/// so we need to force it to in the mapping and nee to explicitly state whether
|
||||||
/// this is a file or directory url.
|
/// this is a file or directory url.
|
||||||
pub fn normalize_url(&self, url: &Url, kind: LspUrlKind) -> ModuleSpecifier {
|
pub fn normalize_url(&self, url: &Url, kind: LspUrlKind) -> ModuleSpecifier {
|
||||||
if let Some(cache) = &self.local_http_cache {
|
if let Some(remote_url) = self.cache.unvendored_specifier(url) {
|
||||||
if url.scheme() == "file" {
|
return remote_url;
|
||||||
if let Ok(path) = url.to_file_path() {
|
|
||||||
if let Some(remote_url) = cache.get_remote_url(&path) {
|
|
||||||
return remote_url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
if let Some(specifier) = inner.get_specifier(url).cloned() {
|
if let Some(specifier) = inner.get_specifier(url).cloned() {
|
||||||
|
@ -296,7 +289,7 @@ mod tests {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
let fixture = resolve_url("https://deno.land/x/pkg@1.0.0/mod.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_url = map
|
||||||
.normalize_specifier(&fixture)
|
.normalize_specifier(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url =
|
let expected_url =
|
||||||
Url::parse("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
|
Url::parse("deno:/https/deno.land/x/pkg%401.0.0/mod.ts").unwrap();
|
||||||
|
@ -318,7 +311,7 @@ mod tests {
|
||||||
assert_eq!(&actual_specifier, &expected_specifier);
|
assert_eq!(&actual_specifier, &expected_specifier);
|
||||||
|
|
||||||
let actual_url = map
|
let actual_url = map
|
||||||
.normalize_specifier(&actual_specifier)
|
.normalize_specifier(&actual_specifier, None)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_url()
|
.as_url()
|
||||||
.clone();
|
.clone();
|
||||||
|
@ -331,7 +324,7 @@ mod tests {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("https://cdn.skypack.dev/-/postcss@v8.2.9-E4SktPp9c0AtxrJHp8iV/dist=es2020,mode=types/lib/postcss.d.ts").unwrap();
|
let fixture = resolve_url("https://cdn.skypack.dev/-/postcss@v8.2.9-E4SktPp9c0AtxrJHp8iV/dist=es2020,mode=types/lib/postcss.d.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_url = map
|
||||||
.normalize_specifier(&fixture)
|
.normalize_specifier(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url = Url::parse("deno:/https/cdn.skypack.dev/-/postcss%40v8.2.9-E4SktPp9c0AtxrJHp8iV/dist%3Des2020%2Cmode%3Dtypes/lib/postcss.d.ts").unwrap();
|
let expected_url = Url::parse("deno:/https/cdn.skypack.dev/-/postcss%40v8.2.9-E4SktPp9c0AtxrJHp8iV/dist%3Des2020%2Cmode%3Dtypes/lib/postcss.d.ts").unwrap();
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
assert_eq!(actual_url.as_url(), &expected_url);
|
||||||
|
@ -346,7 +339,7 @@ mod tests {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
let fixture = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||||
let actual_url = map
|
let actual_url = map
|
||||||
.normalize_specifier(&fixture)
|
.normalize_specifier(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url = Url::parse("deno:/c21c7fc382b2b0553dc0864aa81a3acacfb7b3d1285ab5ae76da6abec213fb37/data_url.ts").unwrap();
|
let expected_url = Url::parse("deno:/c21c7fc382b2b0553dc0864aa81a3acacfb7b3d1285ab5ae76da6abec213fb37/data_url.ts").unwrap();
|
||||||
assert_eq!(actual_url.as_url(), &expected_url);
|
assert_eq!(actual_url.as_url(), &expected_url);
|
||||||
|
@ -361,7 +354,7 @@ mod tests {
|
||||||
let map = LspUrlMap::default();
|
let map = LspUrlMap::default();
|
||||||
let fixture = resolve_url("http://localhost:8000/mod.ts").unwrap();
|
let fixture = resolve_url("http://localhost:8000/mod.ts").unwrap();
|
||||||
let actual_url = map
|
let actual_url = map
|
||||||
.normalize_specifier(&fixture)
|
.normalize_specifier(&fixture, None)
|
||||||
.expect("could not handle specifier");
|
.expect("could not handle specifier");
|
||||||
let expected_url =
|
let expected_url =
|
||||||
Url::parse("deno:/http/localhost%3A8000/mod.ts").unwrap();
|
Url::parse("deno:/http/localhost%3A8000/mod.ts").unwrap();
|
||||||
|
|
|
@ -280,13 +280,14 @@ fn lsp_import_map_remote() {
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_import_map_data_url() {
|
fn lsp_import_map_data_url() {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
let mut client = context.new_lsp_command().build();
|
let mut client = context.new_lsp_command().build();
|
||||||
client.initialize(|builder| {
|
client.initialize(|builder| {
|
||||||
builder.set_import_map("data:application/json;utf8,{\"imports\": { \"example\": \"https://deno.land/x/example/mod.ts\" }}");
|
builder.set_import_map("data:application/json;utf8,{\"imports\": { \"example\": \"https://deno.land/x/example/mod.ts\" }}");
|
||||||
});
|
});
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/file.ts",
|
"uri": temp_dir.uri().join("file.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "import example from \"example\";\n"
|
"text": "import example from \"example\";\n"
|
||||||
|
@ -780,7 +781,7 @@ fn lsp_format_vendor_path() {
|
||||||
client.initialize_default();
|
client.initialize_default();
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/file.ts",
|
"uri": temp_dir.uri().join("file.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": r#"import "http://localhost:4545/run/002_hello.ts";"#,
|
"text": r#"import "http://localhost:4545/run/002_hello.ts";"#,
|
||||||
|
@ -802,7 +803,7 @@ fn lsp_format_vendor_path() {
|
||||||
"workspace/executeCommand",
|
"workspace/executeCommand",
|
||||||
json!({
|
json!({
|
||||||
"command": "deno.cache",
|
"command": "deno.cache",
|
||||||
"arguments": [[], "file:///a/file.ts"],
|
"arguments": [[], temp_dir.uri().join("file.ts").unwrap()],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
assert!(temp_dir
|
assert!(temp_dir
|
||||||
|
@ -2622,7 +2623,7 @@ fn lsp_import_map_setting_with_deno_json() {
|
||||||
});
|
});
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/file.ts",
|
"uri": temp_dir.uri().join("file.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "import \"file2\";\n",
|
"text": "import \"file2\";\n",
|
||||||
|
@ -7585,7 +7586,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
client.did_open(
|
client.did_open(
|
||||||
json!({
|
json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/file.ts",
|
"uri": temp_dir.uri().join("file.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": concat!(
|
"text": concat!(
|
||||||
|
@ -7612,7 +7613,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
"npm:chalk@~5",
|
"npm:chalk@~5",
|
||||||
"http://localhost:4545/subdir/print_hello.ts",
|
"http://localhost:4545/subdir/print_hello.ts",
|
||||||
],
|
],
|
||||||
"file:///a/file.ts",
|
temp_dir.uri().join("file.ts").unwrap(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -7620,14 +7621,14 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try auto-import with path
|
// try auto-import with path
|
||||||
client.did_open(json!({
|
client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/a.ts",
|
"uri": temp_dir.uri().join("a.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "getClie",
|
"text": "getClie",
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let list = client.get_completion_list(
|
let list = client.get_completion_list(
|
||||||
"file:///a/a.ts",
|
temp_dir.uri().join("a.ts").unwrap(),
|
||||||
(0, 7),
|
(0, 7),
|
||||||
json!({ "triggerKind": 1 }),
|
json!({ "triggerKind": 1 }),
|
||||||
);
|
);
|
||||||
|
@ -7668,20 +7669,23 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try quick fix with path
|
// try quick fix with path
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/b.ts",
|
"uri": temp_dir.uri().join("b.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "getClient",
|
"text": "getClient",
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let diagnostics = diagnostics
|
let diagnostics = diagnostics
|
||||||
.messages_with_file_and_source("file:///a/b.ts", "deno-ts")
|
.messages_with_file_and_source(
|
||||||
|
temp_dir.uri().join("b.ts").unwrap().as_str(),
|
||||||
|
"deno-ts",
|
||||||
|
)
|
||||||
.diagnostics;
|
.diagnostics;
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
"textDocument/codeAction",
|
"textDocument/codeAction",
|
||||||
json!(json!({
|
json!(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/b.ts"
|
"uri": temp_dir.uri().join("b.ts").unwrap()
|
||||||
},
|
},
|
||||||
"range": {
|
"range": {
|
||||||
"start": { "line": 0, "character": 0 },
|
"start": { "line": 0, "character": 0 },
|
||||||
|
@ -7713,7 +7717,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
"edit": {
|
"edit": {
|
||||||
"documentChanges": [{
|
"documentChanges": [{
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/b.ts",
|
"uri": temp_dir.uri().join("b.ts").unwrap(),
|
||||||
"version": 1,
|
"version": 1,
|
||||||
},
|
},
|
||||||
"edits": [{
|
"edits": [{
|
||||||
|
@ -7731,7 +7735,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try auto-import without path
|
// try auto-import without path
|
||||||
client.did_open(json!({
|
client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/c.ts",
|
"uri": temp_dir.uri().join("c.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "chal",
|
"text": "chal",
|
||||||
|
@ -7739,7 +7743,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let list = client.get_completion_list(
|
let list = client.get_completion_list(
|
||||||
"file:///a/c.ts",
|
temp_dir.uri().join("c.ts").unwrap(),
|
||||||
(0, 4),
|
(0, 4),
|
||||||
json!({ "triggerKind": 1 }),
|
json!({ "triggerKind": 1 }),
|
||||||
);
|
);
|
||||||
|
@ -7778,20 +7782,23 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try quick fix without path
|
// try quick fix without path
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/d.ts",
|
"uri": temp_dir.uri().join("d.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "chalk",
|
"text": "chalk",
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let diagnostics = diagnostics
|
let diagnostics = diagnostics
|
||||||
.messages_with_file_and_source("file:///a/d.ts", "deno-ts")
|
.messages_with_file_and_source(
|
||||||
|
temp_dir.uri().join("d.ts").unwrap().as_str(),
|
||||||
|
"deno-ts",
|
||||||
|
)
|
||||||
.diagnostics;
|
.diagnostics;
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
"textDocument/codeAction",
|
"textDocument/codeAction",
|
||||||
json!(json!({
|
json!(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/d.ts"
|
"uri": temp_dir.uri().join("d.ts").unwrap()
|
||||||
},
|
},
|
||||||
"range": {
|
"range": {
|
||||||
"start": { "line": 0, "character": 0 },
|
"start": { "line": 0, "character": 0 },
|
||||||
|
@ -7823,7 +7830,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
"edit": {
|
"edit": {
|
||||||
"documentChanges": [{
|
"documentChanges": [{
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/d.ts",
|
"uri": temp_dir.uri().join("d.ts").unwrap(),
|
||||||
"version": 1,
|
"version": 1,
|
||||||
},
|
},
|
||||||
"edits": [{
|
"edits": [{
|
||||||
|
@ -7841,7 +7848,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try auto-import with http import map
|
// try auto-import with http import map
|
||||||
client.did_open(json!({
|
client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/e.ts",
|
"uri": temp_dir.uri().join("e.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "printH",
|
"text": "printH",
|
||||||
|
@ -7849,7 +7856,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let list = client.get_completion_list(
|
let list = client.get_completion_list(
|
||||||
"file:///a/e.ts",
|
temp_dir.uri().join("e.ts").unwrap(),
|
||||||
(0, 6),
|
(0, 6),
|
||||||
json!({ "triggerKind": 1 }),
|
json!({ "triggerKind": 1 }),
|
||||||
);
|
);
|
||||||
|
@ -7888,20 +7895,23 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try quick fix with http import
|
// try quick fix with http import
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/f.ts",
|
"uri": temp_dir.uri().join("f.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "printHello",
|
"text": "printHello",
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let diagnostics = diagnostics
|
let diagnostics = diagnostics
|
||||||
.messages_with_file_and_source("file:///a/f.ts", "deno-ts")
|
.messages_with_file_and_source(
|
||||||
|
temp_dir.uri().join("f.ts").unwrap().as_str(),
|
||||||
|
"deno-ts",
|
||||||
|
)
|
||||||
.diagnostics;
|
.diagnostics;
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
"textDocument/codeAction",
|
"textDocument/codeAction",
|
||||||
json!(json!({
|
json!(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/f.ts"
|
"uri": temp_dir.uri().join("f.ts").unwrap()
|
||||||
},
|
},
|
||||||
"range": {
|
"range": {
|
||||||
"start": { "line": 0, "character": 0 },
|
"start": { "line": 0, "character": 0 },
|
||||||
|
@ -7933,7 +7943,7 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
"edit": {
|
"edit": {
|
||||||
"documentChanges": [{
|
"documentChanges": [{
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/f.ts",
|
"uri": temp_dir.uri().join("f.ts").unwrap(),
|
||||||
"version": 1,
|
"version": 1,
|
||||||
},
|
},
|
||||||
"edits": [{
|
"edits": [{
|
||||||
|
@ -7951,14 +7961,14 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() {
|
||||||
// try auto-import with npm package with sub-path on value side of import map
|
// try auto-import with npm package with sub-path on value side of import map
|
||||||
client.did_open(json!({
|
client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/nested_path.ts",
|
"uri": temp_dir.uri().join("nested_path.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "entry",
|
"text": "entry",
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
let list = client.get_completion_list(
|
let list = client.get_completion_list(
|
||||||
"file:///a/nested_path.ts",
|
temp_dir.uri().join("nested_path.ts").unwrap(),
|
||||||
(0, 5),
|
(0, 5),
|
||||||
json!({ "triggerKind": 1 }),
|
json!({ "triggerKind": 1 }),
|
||||||
);
|
);
|
||||||
|
@ -11001,7 +11011,7 @@ fn lsp_lint_with_config() {
|
||||||
|
|
||||||
let diagnostics = client.did_open(json!({
|
let diagnostics = client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": "file:///a/file.ts",
|
"uri": temp_dir.uri().join("file.ts").unwrap(),
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "// TODO: fixme\nexport async function non_camel_case() {\nconsole.log(\"finished!\")\n}"
|
"text": "// TODO: fixme\nexport async function non_camel_case() {\nconsole.log(\"finished!\")\n}"
|
||||||
|
@ -12104,6 +12114,323 @@ fn lsp_vendor_dir() {
|
||||||
|
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_deno_json_scopes_import_map() {
|
||||||
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
temp_dir.create_dir_all("project1");
|
||||||
|
temp_dir.create_dir_all("project2/project3");
|
||||||
|
temp_dir.write(
|
||||||
|
"project1/deno.json",
|
||||||
|
json!({
|
||||||
|
"imports": {
|
||||||
|
"foo": "./foo1.ts",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write("project1/foo1.ts", "");
|
||||||
|
temp_dir.write(
|
||||||
|
"project2/deno.json",
|
||||||
|
json!({
|
||||||
|
"imports": {
|
||||||
|
"foo": "./foo2.ts",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write("project2/foo2.ts", "");
|
||||||
|
temp_dir.write(
|
||||||
|
"project2/project3/deno.json",
|
||||||
|
json!({
|
||||||
|
"imports": {
|
||||||
|
"foo": "./foo3.ts",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write("project2/project3/foo3.ts", "");
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
client.initialize_default();
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project1/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"foo\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/hover",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project1/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!({
|
||||||
|
"contents": {
|
||||||
|
"kind": "markdown",
|
||||||
|
"value": format!("**Resolved Dependency**\n\n**Code**: file​{}\n", temp_dir.uri().join("project1/foo1.ts").unwrap().as_str().trim_start_matches("file")),
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 0, "character": 7 },
|
||||||
|
"end": { "line": 0, "character": 12 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"foo\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/hover",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!({
|
||||||
|
"contents": {
|
||||||
|
"kind": "markdown",
|
||||||
|
"value": format!("**Resolved Dependency**\n\n**Code**: file​{}\n", temp_dir.uri().join("project2/foo2.ts").unwrap().as_str().trim_start_matches("file")),
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 0, "character": 7 },
|
||||||
|
"end": { "line": 0, "character": 12 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/project3/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"foo\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/hover",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/project3/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!({
|
||||||
|
"contents": {
|
||||||
|
"kind": "markdown",
|
||||||
|
"value": format!("**Resolved Dependency**\n\n**Code**: file​{}\n", temp_dir.uri().join("project2/project3/foo3.ts").unwrap().as_str().trim_start_matches("file")),
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 0, "character": 7 },
|
||||||
|
"end": { "line": 0, "character": 12 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_deno_json_scopes_vendor_dirs() {
|
||||||
|
let context = TestContextBuilder::new()
|
||||||
|
.use_http_server()
|
||||||
|
.use_temp_cwd()
|
||||||
|
.build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
temp_dir.create_dir_all("project1");
|
||||||
|
temp_dir.create_dir_all("project2/project3");
|
||||||
|
temp_dir.write(
|
||||||
|
"project1/deno.json",
|
||||||
|
json!({
|
||||||
|
"vendor": true,
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write(
|
||||||
|
"project2/deno.json",
|
||||||
|
json!({
|
||||||
|
"vendor": true,
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write(
|
||||||
|
"project2/project3/deno.json",
|
||||||
|
json!({
|
||||||
|
"vendor": true,
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
client.initialize_default();
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project1/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"http://localhost:4545/subdir/mod1.ts\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
client.write_request(
|
||||||
|
"workspace/executeCommand",
|
||||||
|
json!({
|
||||||
|
"command": "deno.cache",
|
||||||
|
"arguments": [[], temp_dir.uri().join("project1/file.ts").unwrap()],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/definition",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project1/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!([{
|
||||||
|
"targetUri": temp_dir.uri().join("project1/vendor/http_localhost_4545/subdir/mod1.ts").unwrap(),
|
||||||
|
"targetRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 17,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"targetSelectionRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 17,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
);
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"http://localhost:4545/subdir/mod2.ts\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
client.write_request(
|
||||||
|
"workspace/executeCommand",
|
||||||
|
json!({
|
||||||
|
"command": "deno.cache",
|
||||||
|
"arguments": [[], temp_dir.uri().join("project2/file.ts").unwrap()],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/definition",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!([{
|
||||||
|
"targetUri": temp_dir.uri().join("project2/vendor/http_localhost_4545/subdir/mod2.ts").unwrap(),
|
||||||
|
"targetRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"targetSelectionRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
);
|
||||||
|
client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/project3/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"http://localhost:4545/subdir/mod3.js\";\n",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
client.write_request(
|
||||||
|
"workspace/executeCommand",
|
||||||
|
json!({
|
||||||
|
"command": "deno.cache",
|
||||||
|
"arguments": [[], temp_dir.uri().join("project2/project3/file.ts").unwrap()],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/definition",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("project2/project3/file.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 7 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!([{
|
||||||
|
"targetUri": temp_dir.uri().join("project2/project3/vendor/http_localhost_4545/subdir/mod3.js").unwrap(),
|
||||||
|
"targetRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"targetSelectionRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
);
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_deno_json_workspace_fmt_config() {
|
fn lsp_deno_json_workspace_fmt_config() {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
@ -13005,7 +13332,7 @@ fn lsp_uses_lockfile_for_npm_initialization() {
|
||||||
assert!(!line.contains("Running npm resolution."), "Line: {}", line);
|
assert!(!line.contains("Running npm resolution."), "Line: {}", line);
|
||||||
line.contains("Server ready.")
|
line.contains("Server ready.")
|
||||||
});
|
});
|
||||||
assert_eq!(skipping_count, 1);
|
assert_eq!(skipping_count, 2);
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue