mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
refactor(lsp): unify caching into LspCache (#23746)
This commit is contained in:
parent
f0e8ec0146
commit
439b3b8db9
10 changed files with 449 additions and 498 deletions
5
cli/cache/deno_dir.rs
vendored
5
cli/cache/deno_dir.rs
vendored
|
@ -33,11 +33,10 @@ impl DenoDirProvider {
|
||||||
|
|
||||||
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
|
/// `DenoDir` serves as coordinator for multiple `DiskCache`s containing them
|
||||||
/// in single directory that can be controlled with `$DENO_DIR` env variable.
|
/// in single directory that can be controlled with `$DENO_DIR` env variable.
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DenoDir {
|
pub struct DenoDir {
|
||||||
/// Example: /Users/rld/.deno/
|
/// Example: /Users/rld/.deno/
|
||||||
/// Note: This is not exposed in order to encourage using re-usable methods.
|
pub root: PathBuf,
|
||||||
root: PathBuf,
|
|
||||||
/// Used by TsCompiler to cache compiler output.
|
/// Used by TsCompiler to cache compiler output.
|
||||||
pub gen_cache: DiskCache,
|
pub gen_cache: DiskCache,
|
||||||
}
|
}
|
||||||
|
|
2
cli/cache/disk_cache.rs
vendored
2
cli/cache/disk_cache.rs
vendored
|
@ -14,7 +14,7 @@ use std::path::PathBuf;
|
||||||
use std::path::Prefix;
|
use std::path::Prefix;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DiskCache {
|
pub struct DiskCache {
|
||||||
pub location: PathBuf,
|
pub location: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
136
cli/lsp/cache.rs
136
cli/lsp/cache.rs
|
@ -1,11 +1,16 @@
|
||||||
// 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::DenoDir;
|
||||||
|
use crate::cache::GlobalHttpCache;
|
||||||
use crate::cache::HttpCache;
|
use crate::cache::HttpCache;
|
||||||
|
use crate::cache::LocalLspHttpCache;
|
||||||
|
use crate::lsp::config::Config;
|
||||||
|
use crate::lsp::logging::lsp_log;
|
||||||
|
use crate::lsp::logging::lsp_warn;
|
||||||
use deno_runtime::fs_util::specifier_to_file_path;
|
use deno_runtime::fs_util::specifier_to_file_path;
|
||||||
|
|
||||||
use deno_core::parking_lot::Mutex;
|
use deno_core::url::Url;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -22,7 +27,7 @@ pub const LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY: deno_cache_dir::GlobalToLocalCopy =
|
||||||
deno_cache_dir::GlobalToLocalCopy::Disallow;
|
deno_cache_dir::GlobalToLocalCopy::Disallow;
|
||||||
|
|
||||||
pub fn calculate_fs_version(
|
pub fn calculate_fs_version(
|
||||||
cache: &Arc<dyn HttpCache>,
|
cache: &LspCache,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
match specifier.scheme() {
|
match specifier.scheme() {
|
||||||
|
@ -49,13 +54,14 @@ pub fn calculate_fs_version_at_path(path: &Path) -> Option<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_fs_version_in_cache(
|
fn calculate_fs_version_in_cache(
|
||||||
cache: &Arc<dyn HttpCache>,
|
cache: &LspCache,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let Ok(cache_key) = cache.cache_item_key(specifier) else {
|
let http_cache = cache.root_vendor_or_global();
|
||||||
|
let Ok(cache_key) = http_cache.cache_item_key(specifier) else {
|
||||||
return Some("1".to_string());
|
return Some("1".to_string());
|
||||||
};
|
};
|
||||||
match cache.read_modified_time(&cache_key) {
|
match http_cache.read_modified_time(&cache_key) {
|
||||||
Ok(Some(modified)) => {
|
Ok(Some(modified)) => {
|
||||||
match modified.duration_since(SystemTime::UNIX_EPOCH) {
|
match modified.duration_since(SystemTime::UNIX_EPOCH) {
|
||||||
Ok(n) => Some(n.as_millis().to_string()),
|
Ok(n) => Some(n.as_millis().to_string()),
|
||||||
|
@ -67,83 +73,71 @@ fn calculate_fs_version_in_cache(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populate the metadata map based on the supplied headers
|
|
||||||
fn parse_metadata(
|
|
||||||
headers: &HashMap<String, String>,
|
|
||||||
) -> HashMap<MetadataKey, String> {
|
|
||||||
let mut metadata = HashMap::new();
|
|
||||||
if let Some(warning) = headers.get("x-deno-warning").cloned() {
|
|
||||||
metadata.insert(MetadataKey::Warning, warning);
|
|
||||||
}
|
|
||||||
metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub enum MetadataKey {
|
|
||||||
/// Represent the `x-deno-warning` header associated with the document
|
|
||||||
Warning,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Metadata {
|
pub struct LspCache {
|
||||||
values: Arc<HashMap<MetadataKey, String>>,
|
deno_dir: DenoDir,
|
||||||
version: Option<String>,
|
global: Arc<GlobalHttpCache>,
|
||||||
|
root_vendor: Option<Arc<LocalLspHttpCache>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
impl Default for LspCache {
|
||||||
pub struct CacheMetadata {
|
fn default() -> Self {
|
||||||
cache: Arc<dyn HttpCache>,
|
Self::new(None)
|
||||||
metadata: Arc<Mutex<HashMap<ModuleSpecifier, Metadata>>>,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheMetadata {
|
impl LspCache {
|
||||||
pub fn new(cache: Arc<dyn HttpCache>) -> Self {
|
pub fn new(global_cache_url: Option<Url>) -> Self {
|
||||||
|
let global_cache_path = global_cache_url.and_then(|s| {
|
||||||
|
specifier_to_file_path(&s)
|
||||||
|
.inspect(|p| {
|
||||||
|
lsp_log!("Resolved global cache path: \"{}\"", p.to_string_lossy());
|
||||||
|
})
|
||||||
|
.inspect_err(|err| {
|
||||||
|
lsp_warn!("Failed to resolve custom cache path: {err}");
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
|
let deno_dir = DenoDir::new(global_cache_path)
|
||||||
|
.expect("should be infallible with absolute custom root");
|
||||||
|
let global = Arc::new(GlobalHttpCache::new(
|
||||||
|
deno_dir.deps_folder_path(),
|
||||||
|
crate::cache::RealDenoCacheEnv,
|
||||||
|
));
|
||||||
Self {
|
Self {
|
||||||
cache,
|
deno_dir,
|
||||||
metadata: Default::default(),
|
global,
|
||||||
|
root_vendor: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the meta data associated with the specifier. Unlike the `get()`
|
pub fn update_config(&mut self, config: &Config) {
|
||||||
/// method, redirects of the supplied specifier will not be followed.
|
self.root_vendor = config.tree.root_data().and_then(|data| {
|
||||||
pub fn get(
|
let vendor_dir = data.vendor_dir.as_ref()?;
|
||||||
&self,
|
Some(Arc::new(LocalLspHttpCache::new(
|
||||||
specifier: &ModuleSpecifier,
|
vendor_dir.clone(),
|
||||||
) -> Option<Arc<HashMap<MetadataKey, String>>> {
|
self.global.clone(),
|
||||||
if matches!(
|
)))
|
||||||
specifier.scheme(),
|
});
|
||||||
"file" | "npm" | "node" | "data" | "blob"
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let version = calculate_fs_version_in_cache(&self.cache, specifier);
|
|
||||||
let metadata = self.metadata.lock().get(specifier).cloned();
|
|
||||||
if metadata.as_ref().and_then(|m| m.version.clone()) != version {
|
|
||||||
self.refresh(specifier).map(|m| m.values)
|
|
||||||
} else {
|
|
||||||
metadata.map(|m| m.values)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn refresh(&self, specifier: &ModuleSpecifier) -> Option<Metadata> {
|
pub fn deno_dir(&self) -> &DenoDir {
|
||||||
if matches!(
|
&self.deno_dir
|
||||||
specifier.scheme(),
|
|
||||||
"file" | "npm" | "node" | "data" | "blob"
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let cache_key = self.cache.cache_item_key(specifier).ok()?;
|
|
||||||
let headers = self.cache.read_headers(&cache_key).ok()??;
|
|
||||||
let values = Arc::new(parse_metadata(&headers));
|
|
||||||
let version = calculate_fs_version_in_cache(&self.cache, specifier);
|
|
||||||
let mut metadata_map = self.metadata.lock();
|
|
||||||
let metadata = Metadata { values, version };
|
|
||||||
metadata_map.insert(specifier.clone(), metadata.clone());
|
|
||||||
Some(metadata)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cache(&mut self, cache: Arc<dyn HttpCache>) {
|
pub fn global(&self) -> &Arc<GlobalHttpCache> {
|
||||||
self.cache = cache;
|
&self.global
|
||||||
self.metadata.lock().clear();
|
}
|
||||||
|
|
||||||
|
pub fn root_vendor(&self) -> Option<&Arc<LocalLspHttpCache>> {
|
||||||
|
self.root_vendor.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_vendor_or_global(&self) -> Arc<dyn HttpCache> {
|
||||||
|
self
|
||||||
|
.root_vendor
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| v.clone() as _)
|
||||||
|
.unwrap_or(self.global.clone() as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,41 +799,39 @@ fn get_workspace_completions(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cache::GlobalHttpCache;
|
|
||||||
use crate::cache::HttpCache;
|
use crate::cache::HttpCache;
|
||||||
|
use crate::lsp::cache::LspCache;
|
||||||
use crate::lsp::documents::Documents;
|
use crate::lsp::documents::Documents;
|
||||||
use crate::lsp::documents::LanguageId;
|
use crate::lsp::documents::LanguageId;
|
||||||
use crate::lsp::search::tests::TestPackageSearchApi;
|
use crate::lsp::search::tests::TestPackageSearchApi;
|
||||||
use deno_core::resolve_url;
|
use deno_core::resolve_url;
|
||||||
use deno_graph::Range;
|
use deno_graph::Range;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
|
|
||||||
fn mock_documents(
|
fn setup(
|
||||||
fixtures: &[(&str, &str, i32, LanguageId)],
|
open_sources: &[(&str, &str, i32, LanguageId)],
|
||||||
source_fixtures: &[(&str, &str)],
|
fs_sources: &[(&str, &str)],
|
||||||
location: &Path,
|
|
||||||
) -> Documents {
|
) -> Documents {
|
||||||
let cache = Arc::new(GlobalHttpCache::new(
|
let temp_dir = TempDir::new();
|
||||||
location.to_path_buf(),
|
let cache = LspCache::new(Some(temp_dir.uri()));
|
||||||
crate::cache::RealDenoCacheEnv,
|
let mut documents = Documents::default();
|
||||||
));
|
documents.update_config(
|
||||||
let mut documents = Documents::new(cache);
|
&Default::default(),
|
||||||
for (specifier, source, version, language_id) in fixtures {
|
&Default::default(),
|
||||||
|
&cache,
|
||||||
|
&Default::default(),
|
||||||
|
);
|
||||||
|
for (specifier, source, version, language_id) in open_sources {
|
||||||
let specifier =
|
let specifier =
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
resolve_url(specifier).expect("failed to create specifier");
|
||||||
documents.open(specifier, *version, *language_id, (*source).into());
|
documents.open(specifier, *version, *language_id, (*source).into());
|
||||||
}
|
}
|
||||||
let http_cache = GlobalHttpCache::new(
|
for (specifier, source) in fs_sources {
|
||||||
location.to_path_buf(),
|
|
||||||
crate::cache::RealDenoCacheEnv,
|
|
||||||
);
|
|
||||||
for (specifier, source) in source_fixtures {
|
|
||||||
let specifier =
|
let specifier =
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
resolve_url(specifier).expect("failed to create specifier");
|
||||||
http_cache
|
cache
|
||||||
|
.global()
|
||||||
.set(&specifier, HashMap::default(), source.as_bytes())
|
.set(&specifier, HashMap::default(), source.as_bytes())
|
||||||
.expect("could not cache file");
|
.expect("could not cache file");
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -844,15 +842,6 @@ mod tests {
|
||||||
documents
|
documents
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(
|
|
||||||
temp_dir: &TempDir,
|
|
||||||
documents: &[(&str, &str, i32, LanguageId)],
|
|
||||||
sources: &[(&str, &str)],
|
|
||||||
) -> Documents {
|
|
||||||
let location = temp_dir.path().join("deps");
|
|
||||||
mock_documents(documents, sources, location.as_path())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_relative_specifiers() {
|
fn test_get_relative_specifiers() {
|
||||||
let base = resolve_url("file:///a/b/c.ts").unwrap();
|
let base = resolve_url("file:///a/b/c.ts").unwrap();
|
||||||
|
@ -936,9 +925,7 @@ mod tests {
|
||||||
character: 21,
|
character: 21,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let documents = setup(
|
let documents = setup(
|
||||||
&temp_dir,
|
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
"file:///a/b/c.ts",
|
"file:///a/b/c.ts",
|
||||||
|
|
|
@ -1454,10 +1454,6 @@ impl ConfigTree {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root_vendor_dir(&self) -> Option<&PathBuf> {
|
|
||||||
self.root_data().and_then(|d| d.vendor_dir.as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_lockfile(&self) -> Option<&Arc<Mutex<Lockfile>>> {
|
pub fn root_lockfile(&self) -> Option<&Arc<Mutex<Lockfile>>> {
|
||||||
self.root_data().and_then(|d| d.lockfile.as_ref())
|
self.root_data().and_then(|d| d.lockfile.as_ref())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use super::analysis;
|
use super::analysis;
|
||||||
use super::cache;
|
|
||||||
use super::client::Client;
|
use super::client::Client;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
use super::documents;
|
use super::documents;
|
||||||
|
@ -1328,17 +1327,18 @@ fn diagnose_resolution(
|
||||||
match resolution {
|
match resolution {
|
||||||
Resolution::Ok(resolved) => {
|
Resolution::Ok(resolved) => {
|
||||||
let specifier = &resolved.specifier;
|
let specifier = &resolved.specifier;
|
||||||
// If the module is a remote module and has a `X-Deno-Warning` header, we
|
|
||||||
// want a warning diagnostic with that message.
|
|
||||||
if let Some(metadata) = snapshot.cache_metadata.get(specifier) {
|
|
||||||
if let Some(message) =
|
|
||||||
metadata.get(&cache::MetadataKey::Warning).cloned()
|
|
||||||
{
|
|
||||||
diagnostics.push(DenoDiagnostic::DenoWarn(message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let managed_npm_resolver = snapshot.resolver.maybe_managed_npm_resolver();
|
let managed_npm_resolver = snapshot.resolver.maybe_managed_npm_resolver();
|
||||||
|
for (_, headers) in snapshot.resolver.redirect_chain_headers(specifier) {
|
||||||
|
if let Some(message) = headers.get("x-deno-warning") {
|
||||||
|
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(doc) = snapshot.documents.get(specifier) {
|
if let Some(doc) = snapshot.documents.get(specifier) {
|
||||||
|
if let Some(headers) = doc.maybe_headers() {
|
||||||
|
if let Some(message) = headers.get("x-deno-warning") {
|
||||||
|
diagnostics.push(DenoDiagnostic::DenoWarn(message.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(diagnostic) = check_redirect_diagnostic(specifier, &doc) {
|
if let Some(diagnostic) = check_redirect_diagnostic(specifier, &doc) {
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
@ -1563,9 +1563,9 @@ fn generate_deno_diagnostics(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cache::GlobalHttpCache;
|
use crate::lsp::cache::LspCache;
|
||||||
use crate::cache::RealDenoCacheEnv;
|
|
||||||
use crate::lsp::config::Config;
|
use crate::lsp::config::Config;
|
||||||
use crate::lsp::config::Settings;
|
use crate::lsp::config::Settings;
|
||||||
use crate::lsp::config::WorkspaceSettings;
|
use crate::lsp::config::WorkspaceSettings;
|
||||||
|
@ -1575,57 +1575,9 @@ mod tests {
|
||||||
use crate::lsp::resolver::LspResolver;
|
use crate::lsp::resolver::LspResolver;
|
||||||
use deno_config::ConfigFile;
|
use deno_config::ConfigFile;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
|
|
||||||
async fn mock_state_snapshot(
|
|
||||||
fixtures: &[(&str, &str, i32, LanguageId)],
|
|
||||||
location: &Path,
|
|
||||||
maybe_import_map: Option<(&str, &str)>,
|
|
||||||
) -> StateSnapshot {
|
|
||||||
let cache = Arc::new(GlobalHttpCache::new(
|
|
||||||
location.to_path_buf(),
|
|
||||||
RealDenoCacheEnv,
|
|
||||||
));
|
|
||||||
let mut documents = Documents::new(cache.clone());
|
|
||||||
for (specifier, source, version, language_id) in fixtures {
|
|
||||||
let specifier =
|
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
|
||||||
documents.open(
|
|
||||||
specifier.clone(),
|
|
||||||
*version,
|
|
||||||
*language_id,
|
|
||||||
(*source).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut config = Config::new_with_roots([resolve_url("file:///").unwrap()]);
|
|
||||||
if let Some((base_url, json_string)) = maybe_import_map {
|
|
||||||
let base_url = resolve_url(base_url).unwrap();
|
|
||||||
let config_file = ConfigFile::new(
|
|
||||||
json_string,
|
|
||||||
base_url,
|
|
||||||
&deno_config::ParseOptions::default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
config.tree.inject_config_file(config_file).await;
|
|
||||||
}
|
|
||||||
let resolver = LspResolver::default()
|
|
||||||
.with_new_config(&config, cache, None, None)
|
|
||||||
.await;
|
|
||||||
StateSnapshot {
|
|
||||||
project_version: 0,
|
|
||||||
documents,
|
|
||||||
assets: Default::default(),
|
|
||||||
cache_metadata: cache::CacheMetadata::new(Arc::new(
|
|
||||||
GlobalHttpCache::new(location.to_path_buf(), RealDenoCacheEnv),
|
|
||||||
)),
|
|
||||||
config: Arc::new(config),
|
|
||||||
resolver,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mock_config() -> Config {
|
fn mock_config() -> Config {
|
||||||
let root_uri = resolve_url("file:///").unwrap();
|
let root_uri = resolve_url("file:///").unwrap();
|
||||||
Config {
|
Config {
|
||||||
|
@ -1649,21 +1601,49 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup(
|
async fn setup(
|
||||||
temp_dir: &TempDir,
|
|
||||||
sources: &[(&str, &str, i32, LanguageId)],
|
sources: &[(&str, &str, i32, LanguageId)],
|
||||||
maybe_import_map: Option<(&str, &str)>,
|
maybe_import_map: Option<(&str, &str)>,
|
||||||
) -> (StateSnapshot, PathBuf) {
|
) -> StateSnapshot {
|
||||||
let location = temp_dir.path().join("deps").to_path_buf();
|
let temp_dir = TempDir::new();
|
||||||
let state_snapshot =
|
let cache = LspCache::new(Some(temp_dir.uri()));
|
||||||
mock_state_snapshot(sources, &location, maybe_import_map).await;
|
let mut config = Config::new_with_roots([resolve_url("file:///").unwrap()]);
|
||||||
(state_snapshot, location)
|
if let Some((base_url, json_string)) = maybe_import_map {
|
||||||
|
let base_url = resolve_url(base_url).unwrap();
|
||||||
|
let config_file = ConfigFile::new(
|
||||||
|
json_string,
|
||||||
|
base_url,
|
||||||
|
&deno_config::ParseOptions::default(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
config.tree.inject_config_file(config_file).await;
|
||||||
|
}
|
||||||
|
let resolver = LspResolver::default()
|
||||||
|
.with_new_config(&config, &cache, None)
|
||||||
|
.await;
|
||||||
|
let mut documents = Documents::default();
|
||||||
|
documents.update_config(&config, &resolver, &cache, &Default::default());
|
||||||
|
for (specifier, source, version, language_id) in sources {
|
||||||
|
let specifier =
|
||||||
|
resolve_url(specifier).expect("failed to create specifier");
|
||||||
|
documents.open(
|
||||||
|
specifier.clone(),
|
||||||
|
*version,
|
||||||
|
*language_id,
|
||||||
|
(*source).into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
StateSnapshot {
|
||||||
|
project_version: 0,
|
||||||
|
documents,
|
||||||
|
assets: Default::default(),
|
||||||
|
config: Arc::new(config),
|
||||||
|
resolver,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_enabled_then_disabled_specifier() {
|
async fn test_enabled_then_disabled_specifier() {
|
||||||
let temp_dir = TempDir::new();
|
let snapshot = setup(
|
||||||
let (snapshot, cache_location) = setup(
|
|
||||||
&temp_dir,
|
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"file:///a.ts",
|
||||||
r#"import * as b from "./b.ts";
|
r#"import * as b from "./b.ts";
|
||||||
|
@ -1677,9 +1657,7 @@ let c: number = "a";
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let snapshot = Arc::new(snapshot);
|
let snapshot = Arc::new(snapshot);
|
||||||
let cache =
|
let ts_server = TsServer::new(Default::default());
|
||||||
Arc::new(GlobalHttpCache::new(cache_location, RealDenoCacheEnv));
|
|
||||||
let ts_server = TsServer::new(Default::default(), cache);
|
|
||||||
ts_server.start(None).unwrap();
|
ts_server.start(None).unwrap();
|
||||||
|
|
||||||
// test enabled
|
// test enabled
|
||||||
|
@ -1757,9 +1735,7 @@ let c: number = "a";
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_deno_diagnostics_with_import_map() {
|
async fn test_deno_diagnostics_with_import_map() {
|
||||||
let temp_dir = TempDir::new();
|
let snapshot = setup(
|
||||||
let (snapshot, _) = setup(
|
|
||||||
&temp_dir,
|
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
"file:///std/assert/mod.ts",
|
"file:///std/assert/mod.ts",
|
||||||
|
@ -1895,9 +1871,7 @@ let c: number = "a";
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn duplicate_diagnostics_for_duplicate_imports() {
|
async fn duplicate_diagnostics_for_duplicate_imports() {
|
||||||
let temp_dir = TempDir::new();
|
let snapshot = setup(
|
||||||
let (snapshot, _) = setup(
|
|
||||||
&temp_dir,
|
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"file:///a.ts",
|
||||||
r#"
|
r#"
|
||||||
|
@ -1973,9 +1947,7 @@ let c: number = "a";
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn unable_to_load_a_local_module() {
|
async fn unable_to_load_a_local_module() {
|
||||||
let temp_dir = TempDir::new();
|
let snapshot = setup(
|
||||||
let (snapshot, _) = setup(
|
|
||||||
&temp_dir,
|
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"file:///a.ts",
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use super::cache::calculate_fs_version;
|
use super::cache::calculate_fs_version;
|
||||||
|
use super::cache::LspCache;
|
||||||
use super::cache::LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY;
|
use super::cache::LSP_DISALLOW_GLOBAL_TO_LOCAL_COPY;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
use super::resolver::LspResolver;
|
use super::resolver::LspResolver;
|
||||||
|
@ -10,7 +11,6 @@ use super::text::LineIndex;
|
||||||
use super::tsc;
|
use super::tsc;
|
||||||
use super::tsc::AssetDocument;
|
use super::tsc::AssetDocument;
|
||||||
|
|
||||||
use crate::cache::HttpCache;
|
|
||||||
use crate::graph_util::CliJsrUrlProvider;
|
use crate::graph_util::CliJsrUrlProvider;
|
||||||
use crate::lsp::logging::lsp_warn;
|
use crate::lsp::logging::lsp_warn;
|
||||||
use deno_graph::source::Resolver;
|
use deno_graph::source::Resolver;
|
||||||
|
@ -287,7 +287,7 @@ impl Document {
|
||||||
maybe_headers: Option<HashMap<String, String>>,
|
maybe_headers: Option<HashMap<String, String>>,
|
||||||
resolver: Arc<LspResolver>,
|
resolver: Arc<LspResolver>,
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
cache: &Arc<dyn HttpCache>,
|
cache: &Arc<LspCache>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let text_info = SourceTextInfo::new(content);
|
let text_info = SourceTextInfo::new(content);
|
||||||
let media_type = resolve_media_type(
|
let media_type = resolve_media_type(
|
||||||
|
@ -507,7 +507,7 @@ impl Document {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn closed(&self, cache: &Arc<dyn HttpCache>) -> Arc<Self> {
|
pub fn closed(&self, cache: &Arc<LspCache>) -> Arc<Self> {
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
specifier: self.specifier.clone(),
|
specifier: self.specifier.clone(),
|
||||||
|
@ -528,7 +528,7 @@ impl Document {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn saved(&self, cache: &Arc<dyn HttpCache>) -> Arc<Self> {
|
pub fn saved(&self, cache: &Arc<LspCache>) -> Arc<Self> {
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
specifier: self.specifier.clone(),
|
specifier: self.specifier.clone(),
|
||||||
|
@ -565,6 +565,10 @@ impl Document {
|
||||||
self.line_index.clone()
|
self.line_index.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn maybe_headers(&self) -> Option<&HashMap<String, String>> {
|
||||||
|
self.maybe_headers.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
fn maybe_fs_version(&self) -> Option<&str> {
|
fn maybe_fs_version(&self) -> Option<&str> {
|
||||||
self.maybe_fs_version.as_deref()
|
self.maybe_fs_version.as_deref()
|
||||||
}
|
}
|
||||||
|
@ -712,7 +716,7 @@ impl FileSystemDocuments {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
resolver: &Arc<LspResolver>,
|
resolver: &Arc<LspResolver>,
|
||||||
config: &Arc<Config>,
|
config: &Arc<Config>,
|
||||||
cache: &Arc<dyn HttpCache>,
|
cache: &Arc<LspCache>,
|
||||||
) -> Option<Arc<Document>> {
|
) -> Option<Arc<Document>> {
|
||||||
let new_fs_version = calculate_fs_version(cache, specifier);
|
let new_fs_version = calculate_fs_version(cache, specifier);
|
||||||
let old_doc = self.docs.get(specifier).map(|v| v.value().clone());
|
let old_doc = self.docs.get(specifier).map(|v| v.value().clone());
|
||||||
|
@ -742,7 +746,7 @@ impl FileSystemDocuments {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
resolver: &Arc<LspResolver>,
|
resolver: &Arc<LspResolver>,
|
||||||
config: &Arc<Config>,
|
config: &Arc<Config>,
|
||||||
cache: &Arc<dyn HttpCache>,
|
cache: &Arc<LspCache>,
|
||||||
) -> Option<Arc<Document>> {
|
) -> Option<Arc<Document>> {
|
||||||
let doc = if specifier.scheme() == "file" {
|
let doc = if specifier.scheme() == "file" {
|
||||||
let path = specifier_to_file_path(specifier).ok()?;
|
let path = specifier_to_file_path(specifier).ok()?;
|
||||||
|
@ -775,11 +779,12 @@ impl FileSystemDocuments {
|
||||||
cache,
|
cache,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let cache_key = cache.cache_item_key(specifier).ok()?;
|
let http_cache = cache.root_vendor_or_global();
|
||||||
let bytes = cache
|
let cache_key = http_cache.cache_item_key(specifier).ok()?;
|
||||||
|
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)
|
||||||
.ok()??;
|
.ok()??;
|
||||||
let specifier_headers = cache.read_headers(&cache_key).ok()??;
|
let specifier_headers = http_cache.read_headers(&cache_key).ok()??;
|
||||||
let (_, maybe_charset) =
|
let (_, maybe_charset) =
|
||||||
deno_graph::source::resolve_media_type_and_charset_from_headers(
|
deno_graph::source::resolve_media_type_and_charset_from_headers(
|
||||||
specifier,
|
specifier,
|
||||||
|
@ -832,10 +837,10 @@ pub enum DocumentsFilter {
|
||||||
OpenDiagnosable,
|
OpenDiagnosable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct Documents {
|
pub struct Documents {
|
||||||
/// The DENO_DIR that the documents looks for non-file based modules.
|
/// The DENO_DIR that the documents looks for non-file based modules.
|
||||||
cache: Arc<dyn HttpCache>,
|
cache: Arc<LspCache>,
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
/// A flag that indicates that stated data is potentially invalid and needs to
|
/// A flag that indicates that stated data is potentially invalid and needs to
|
||||||
/// be recalculated before being considered valid.
|
/// be recalculated before being considered valid.
|
||||||
|
@ -855,19 +860,6 @@ pub struct Documents {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Documents {
|
impl Documents {
|
||||||
pub fn new(cache: Arc<dyn HttpCache>) -> Self {
|
|
||||||
Self {
|
|
||||||
cache: cache.clone(),
|
|
||||||
config: Default::default(),
|
|
||||||
dirty: true,
|
|
||||||
open_docs: HashMap::default(),
|
|
||||||
file_system_docs: Default::default(),
|
|
||||||
resolver: Default::default(),
|
|
||||||
npm_specifier_reqs: Default::default(),
|
|
||||||
has_injected_types_node_package: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// "Open" a document from the perspective of the editor, meaning that
|
/// "Open" a document from the perspective of the editor, meaning that
|
||||||
/// requests for information from the document will come from the in-memory
|
/// requests for information from the document will come from the in-memory
|
||||||
/// representation received from the language server client, versus reading
|
/// representation received from the language server client, versus reading
|
||||||
|
@ -1019,7 +1011,7 @@ impl Documents {
|
||||||
.map(|p| p.is_file())
|
.map(|p| p.is_file())
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
}
|
}
|
||||||
if self.cache.contains(&specifier) {
|
if self.cache.root_vendor_or_global().contains(&specifier) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1179,11 +1171,11 @@ impl Documents {
|
||||||
&mut self,
|
&mut self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
resolver: &Arc<LspResolver>,
|
resolver: &Arc<LspResolver>,
|
||||||
cache: Arc<dyn HttpCache>,
|
cache: &LspCache,
|
||||||
workspace_files: &BTreeSet<ModuleSpecifier>,
|
workspace_files: &BTreeSet<ModuleSpecifier>,
|
||||||
) {
|
) {
|
||||||
self.config = Arc::new(config.clone());
|
self.config = Arc::new(config.clone());
|
||||||
self.cache = cache;
|
self.cache = Arc::new(cache.clone());
|
||||||
self.resolver = resolver.clone();
|
self.resolver = resolver.clone();
|
||||||
{
|
{
|
||||||
let fs_docs = &self.file_system_docs;
|
let fs_docs = &self.file_system_docs;
|
||||||
|
@ -1461,31 +1453,29 @@ fn analyze_module(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::cache::GlobalHttpCache;
|
|
||||||
use crate::cache::RealDenoCacheEnv;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::lsp::cache::LspCache;
|
||||||
use deno_config::ConfigFile;
|
use deno_config::ConfigFile;
|
||||||
use deno_core::serde_json;
|
use deno_core::serde_json;
|
||||||
use deno_core::serde_json::json;
|
use deno_core::serde_json::json;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use test_util::PathRef;
|
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
|
|
||||||
fn setup(temp_dir: &TempDir) -> (Documents, PathRef, Arc<dyn HttpCache>) {
|
async fn setup() -> (Documents, LspCache, TempDir) {
|
||||||
let location = temp_dir.path().join("deps");
|
let temp_dir = TempDir::new();
|
||||||
let cache = Arc::new(GlobalHttpCache::new(
|
let cache = LspCache::new(Some(temp_dir.uri()));
|
||||||
location.to_path_buf(),
|
let config = Config::default();
|
||||||
RealDenoCacheEnv,
|
let resolver = LspResolver::default()
|
||||||
));
|
.with_new_config(&config, &cache, None)
|
||||||
let documents = Documents::new(cache.clone());
|
.await;
|
||||||
(documents, location, cache)
|
let mut documents = Documents::default();
|
||||||
|
documents.update_config(&config, &resolver, &cache, &Default::default());
|
||||||
|
(documents, cache, temp_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn test_documents_open_close() {
|
async fn test_documents_open_close() {
|
||||||
let temp_dir = TempDir::new();
|
let (mut documents, _, _) = setup().await;
|
||||||
let (mut documents, _, _) = setup(&temp_dir);
|
|
||||||
let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap();
|
let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap();
|
||||||
let content = r#"import * as b from "./b.ts";
|
let content = r#"import * as b from "./b.ts";
|
||||||
console.log(b);
|
console.log(b);
|
||||||
|
@ -1508,10 +1498,9 @@ console.log(b);
|
||||||
assert!(document.maybe_lsp_version().is_none());
|
assert!(document.maybe_lsp_version().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn test_documents_change() {
|
async fn test_documents_change() {
|
||||||
let temp_dir = TempDir::new();
|
let (mut documents, _, _) = setup().await;
|
||||||
let (mut documents, _, _) = setup(&temp_dir);
|
|
||||||
let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap();
|
let specifier = ModuleSpecifier::parse("file:///a.ts").unwrap();
|
||||||
let content = r#"import * as b from "./b.ts";
|
let content = r#"import * as b from "./b.ts";
|
||||||
console.log(b);
|
console.log(b);
|
||||||
|
@ -1550,15 +1539,13 @@ console.log(b, "hello deno");
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn test_documents_ensure_no_duplicates() {
|
async fn test_documents_ensure_no_duplicates() {
|
||||||
// it should never happen that a user of this API causes this to happen,
|
// it should never happen that a user of this API causes this to happen,
|
||||||
// but we'll guard against it anyway
|
// but we'll guard against it anyway
|
||||||
let temp_dir = TempDir::new();
|
let (mut documents, _, temp_dir) = setup().await;
|
||||||
let (mut documents, documents_path, _) = setup(&temp_dir);
|
let file_path = temp_dir.path().join("file.ts");
|
||||||
let file_path = documents_path.join("file.ts");
|
let file_specifier = temp_dir.uri().join("file.ts").unwrap();
|
||||||
let file_specifier = ModuleSpecifier::from_file_path(&file_path).unwrap();
|
|
||||||
documents_path.create_dir_all();
|
|
||||||
file_path.write("");
|
file_path.write("");
|
||||||
|
|
||||||
// open the document
|
// open the document
|
||||||
|
@ -1582,27 +1569,21 @@ console.log(b, "hello deno");
|
||||||
async fn test_documents_refresh_dependencies_config_change() {
|
async fn test_documents_refresh_dependencies_config_change() {
|
||||||
// it should never happen that a user of this API causes this to happen,
|
// it should never happen that a user of this API causes this to happen,
|
||||||
// but we'll guard against it anyway
|
// but we'll guard against it anyway
|
||||||
let temp_dir = TempDir::new();
|
let (mut documents, cache, temp_dir) = setup().await;
|
||||||
let (mut documents, documents_path, cache) = setup(&temp_dir);
|
|
||||||
fs::create_dir_all(&documents_path).unwrap();
|
|
||||||
|
|
||||||
let file1_path = documents_path.join("file1.ts");
|
let file1_path = temp_dir.path().join("file1.ts");
|
||||||
let file1_specifier = ModuleSpecifier::from_file_path(&file1_path).unwrap();
|
let file1_specifier = temp_dir.uri().join("file1.ts").unwrap();
|
||||||
fs::write(&file1_path, "").unwrap();
|
fs::write(&file1_path, "").unwrap();
|
||||||
|
|
||||||
let file2_path = documents_path.join("file2.ts");
|
let file2_path = temp_dir.path().join("file2.ts");
|
||||||
let file2_specifier = ModuleSpecifier::from_file_path(&file2_path).unwrap();
|
let file2_specifier = temp_dir.uri().join("file2.ts").unwrap();
|
||||||
fs::write(&file2_path, "").unwrap();
|
fs::write(&file2_path, "").unwrap();
|
||||||
|
|
||||||
let file3_path = documents_path.join("file3.ts");
|
let file3_path = temp_dir.path().join("file3.ts");
|
||||||
let file3_specifier = ModuleSpecifier::from_file_path(&file3_path).unwrap();
|
let file3_specifier = temp_dir.uri().join("file3.ts").unwrap();
|
||||||
fs::write(&file3_path, "").unwrap();
|
fs::write(&file3_path, "").unwrap();
|
||||||
|
|
||||||
let mut config =
|
let mut config = Config::new_with_roots([temp_dir.uri()]);
|
||||||
Config::new_with_roots(vec![ModuleSpecifier::from_directory_path(
|
|
||||||
&documents_path,
|
|
||||||
)
|
|
||||||
.unwrap()]);
|
|
||||||
let workspace_settings =
|
let workspace_settings =
|
||||||
serde_json::from_str(r#"{ "enable": true }"#).unwrap();
|
serde_json::from_str(r#"{ "enable": true }"#).unwrap();
|
||||||
config.set_workspace_settings(workspace_settings, vec![]);
|
config.set_workspace_settings(workspace_settings, vec![]);
|
||||||
|
@ -1632,14 +1613,9 @@ console.log(b, "hello deno");
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let resolver = LspResolver::default()
|
let resolver = LspResolver::default()
|
||||||
.with_new_config(&config, cache.clone(), None, None)
|
.with_new_config(&config, &cache, None)
|
||||||
.await;
|
.await;
|
||||||
documents.update_config(
|
documents.update_config(&config, &resolver, &cache, &workspace_files);
|
||||||
&config,
|
|
||||||
&resolver,
|
|
||||||
cache.clone(),
|
|
||||||
&workspace_files,
|
|
||||||
);
|
|
||||||
|
|
||||||
// open the document
|
// open the document
|
||||||
let document = documents.open(
|
let document = documents.open(
|
||||||
|
@ -1681,9 +1657,9 @@ console.log(b, "hello deno");
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let resolver = LspResolver::default()
|
let resolver = LspResolver::default()
|
||||||
.with_new_config(&config, cache.clone(), None, None)
|
.with_new_config(&config, &cache, None)
|
||||||
.await;
|
.await;
|
||||||
documents.update_config(&config, &resolver, cache, &workspace_files);
|
documents.update_config(&config, &resolver, &cache, &workspace_files);
|
||||||
|
|
||||||
// check the document's dependencies
|
// check the document's dependencies
|
||||||
let document = documents.get(&file1_specifier).unwrap();
|
let document = documents.get(&file1_specifier).unwrap();
|
||||||
|
|
|
@ -42,7 +42,7 @@ use super::analysis::ts_changes_to_edit;
|
||||||
use super::analysis::CodeActionCollection;
|
use super::analysis::CodeActionCollection;
|
||||||
use super::analysis::CodeActionData;
|
use super::analysis::CodeActionData;
|
||||||
use super::analysis::TsResponseImportMapper;
|
use super::analysis::TsResponseImportMapper;
|
||||||
use super::cache;
|
use super::cache::LspCache;
|
||||||
use super::capabilities;
|
use super::capabilities;
|
||||||
use super::client::Client;
|
use super::client::Client;
|
||||||
use super::code_lens;
|
use super::code_lens;
|
||||||
|
@ -88,10 +88,6 @@ use crate::args::CaData;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
use crate::args::Flags;
|
use crate::args::Flags;
|
||||||
use crate::cache::DenoDir;
|
|
||||||
use crate::cache::GlobalHttpCache;
|
|
||||||
use crate::cache::HttpCache;
|
|
||||||
use crate::cache::LocalLspHttpCache;
|
|
||||||
use crate::factory::CliFactory;
|
use crate::factory::CliFactory;
|
||||||
use crate::file_fetcher::FileFetcher;
|
use crate::file_fetcher::FileFetcher;
|
||||||
use crate::graph_util;
|
use crate::graph_util;
|
||||||
|
@ -121,11 +117,10 @@ impl RootCertStoreProvider for LspRootCertStoreProvider {
|
||||||
pub struct LanguageServer(Arc<tokio::sync::RwLock<Inner>>, CancellationToken);
|
pub struct LanguageServer(Arc<tokio::sync::RwLock<Inner>>, CancellationToken);
|
||||||
|
|
||||||
/// Snapshot of the state used by TSC.
|
/// Snapshot of the state used by TSC.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct StateSnapshot {
|
pub struct StateSnapshot {
|
||||||
pub project_version: usize,
|
pub project_version: usize,
|
||||||
pub assets: AssetsSnapshot,
|
pub assets: AssetsSnapshot,
|
||||||
pub cache_metadata: cache::CacheMetadata,
|
|
||||||
pub config: Arc<Config>,
|
pub config: Arc<Config>,
|
||||||
pub documents: Documents,
|
pub documents: Documents,
|
||||||
pub resolver: Arc<LspResolver>,
|
pub resolver: Arc<LspResolver>,
|
||||||
|
@ -174,12 +169,7 @@ pub struct Inner {
|
||||||
/// Cached versions of "fixed" assets that can either be inlined in Rust or
|
/// Cached versions of "fixed" assets that can either be inlined in Rust or
|
||||||
/// are part of the TypeScript snapshot and have to be fetched out.
|
/// are part of the TypeScript snapshot and have to be fetched out.
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
/// This may be a copy of `self.global_cache`, or a vendor dir if one is
|
cache: LspCache,
|
||||||
/// configured.
|
|
||||||
cache: Arc<dyn HttpCache>,
|
|
||||||
/// A representation of metadata associated with specifiers in the DENO_DIR
|
|
||||||
/// or vendor dir which is used by the language server.
|
|
||||||
cache_metadata: cache::CacheMetadata,
|
|
||||||
/// The LSP client that this LSP server is connected to.
|
/// The LSP client that this LSP server is connected to.
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
/// Configuration information.
|
/// Configuration information.
|
||||||
|
@ -189,16 +179,11 @@ pub struct Inner {
|
||||||
/// The collection of documents that the server is currently handling, either
|
/// The collection of documents that the server is currently handling, either
|
||||||
/// on disk or "open" within the client.
|
/// on disk or "open" within the client.
|
||||||
pub documents: Documents,
|
pub documents: Documents,
|
||||||
global_cache: Arc<GlobalHttpCache>,
|
http_client: Arc<HttpClient>,
|
||||||
initial_cwd: PathBuf,
|
initial_cwd: PathBuf,
|
||||||
jsr_search_api: CliJsrSearchApi,
|
jsr_search_api: CliJsrSearchApi,
|
||||||
http_client: Arc<HttpClient>,
|
|
||||||
task_queue: LanguageServerTaskQueue,
|
|
||||||
/// Handles module registries, which allow discovery of modules
|
/// Handles module registries, which allow discovery of modules
|
||||||
module_registry: ModuleRegistry,
|
module_registry: ModuleRegistry,
|
||||||
/// An optional path to the DENO_DIR which has been specified in the client
|
|
||||||
/// options.
|
|
||||||
maybe_global_cache_path: Option<PathBuf>,
|
|
||||||
/// A lazily create "server" for handling test run requests.
|
/// A lazily create "server" for handling test run requests.
|
||||||
maybe_testing_server: Option<testing::TestServer>,
|
maybe_testing_server: Option<testing::TestServer>,
|
||||||
npm_search_api: CliNpmSearchApi,
|
npm_search_api: CliNpmSearchApi,
|
||||||
|
@ -206,6 +191,7 @@ pub struct Inner {
|
||||||
/// A collection of measurements which instrument that performance of the LSP.
|
/// A collection of measurements which instrument that performance of the LSP.
|
||||||
performance: Arc<Performance>,
|
performance: Arc<Performance>,
|
||||||
resolver: Arc<LspResolver>,
|
resolver: Arc<LspResolver>,
|
||||||
|
task_queue: LanguageServerTaskQueue,
|
||||||
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
|
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
|
||||||
ts_fixable_diagnostics: Vec<String>,
|
ts_fixable_diagnostics: Vec<String>,
|
||||||
/// An abstraction that handles interactions with TypeScript.
|
/// An abstraction that handles interactions with TypeScript.
|
||||||
|
@ -450,24 +436,20 @@ impl LanguageServer {
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
fn new(client: Client) -> Self {
|
fn new(client: Client) -> Self {
|
||||||
let dir = DenoDir::new(None).expect("could not access DENO_DIR");
|
let cache = LspCache::default();
|
||||||
let http_client = Arc::new(HttpClient::new(None, None));
|
let http_client = Arc::new(HttpClient::new(None, None));
|
||||||
let module_registry =
|
let module_registry = ModuleRegistry::new(
|
||||||
ModuleRegistry::new(dir.registries_folder_path(), http_client.clone());
|
cache.deno_dir().registries_folder_path(),
|
||||||
|
http_client.clone(),
|
||||||
|
);
|
||||||
let jsr_search_api =
|
let jsr_search_api =
|
||||||
CliJsrSearchApi::new(module_registry.file_fetcher.clone());
|
CliJsrSearchApi::new(module_registry.file_fetcher.clone());
|
||||||
let npm_search_api =
|
let npm_search_api =
|
||||||
CliNpmSearchApi::new(module_registry.file_fetcher.clone());
|
CliNpmSearchApi::new(module_registry.file_fetcher.clone());
|
||||||
let global_cache = Arc::new(GlobalHttpCache::new(
|
let documents = Documents::default();
|
||||||
dir.deps_folder_path(),
|
|
||||||
crate::cache::RealDenoCacheEnv,
|
|
||||||
));
|
|
||||||
let cache = global_cache.clone();
|
|
||||||
let documents = Documents::new(cache.clone());
|
|
||||||
let cache_metadata = cache::CacheMetadata::new(cache.clone());
|
|
||||||
let performance = Arc::new(Performance::default());
|
let performance = Arc::new(Performance::default());
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let ts_server = Arc::new(TsServer::new(performance.clone(), cache.clone()));
|
let ts_server = Arc::new(TsServer::new(performance.clone()));
|
||||||
let diagnostics_state = Arc::new(DiagnosticsState::default());
|
let diagnostics_state = Arc::new(DiagnosticsState::default());
|
||||||
let diagnostics_server = DiagnosticsServer::new(
|
let diagnostics_server = DiagnosticsServer::new(
|
||||||
client.clone(),
|
client.clone(),
|
||||||
|
@ -483,17 +465,14 @@ impl Inner {
|
||||||
Self {
|
Self {
|
||||||
assets,
|
assets,
|
||||||
cache,
|
cache,
|
||||||
cache_metadata,
|
|
||||||
client,
|
client,
|
||||||
config,
|
config,
|
||||||
diagnostics_state,
|
diagnostics_state,
|
||||||
diagnostics_server,
|
diagnostics_server,
|
||||||
documents,
|
documents,
|
||||||
global_cache,
|
|
||||||
http_client,
|
http_client,
|
||||||
initial_cwd: initial_cwd.clone(),
|
initial_cwd: initial_cwd.clone(),
|
||||||
jsr_search_api,
|
jsr_search_api,
|
||||||
maybe_global_cache_path: None,
|
|
||||||
project_version: 0,
|
project_version: 0,
|
||||||
task_queue: Default::default(),
|
task_queue: Default::default(),
|
||||||
maybe_testing_server: None,
|
maybe_testing_server: None,
|
||||||
|
@ -598,7 +577,6 @@ impl Inner {
|
||||||
Arc::new(StateSnapshot {
|
Arc::new(StateSnapshot {
|
||||||
project_version: self.project_version,
|
project_version: self.project_version,
|
||||||
assets: self.assets.snapshot(),
|
assets: self.assets.snapshot(),
|
||||||
cache_metadata: self.cache_metadata.clone(),
|
|
||||||
config: Arc::new(self.config.clone()),
|
config: Arc::new(self.config.clone()),
|
||||||
documents: self.documents.clone(),
|
documents: self.documents.clone(),
|
||||||
resolver: self.resolver.snapshot(),
|
resolver: self.resolver.snapshot(),
|
||||||
|
@ -607,36 +585,21 @@ impl Inner {
|
||||||
|
|
||||||
pub async fn update_global_cache(&mut self) {
|
pub async fn update_global_cache(&mut self) {
|
||||||
let mark = self.performance.mark("lsp.update_global_cache");
|
let mark = self.performance.mark("lsp.update_global_cache");
|
||||||
let maybe_cache = &self.config.workspace_settings().cache;
|
let maybe_cache = self.config.workspace_settings().cache.as_ref();
|
||||||
self.maybe_global_cache_path = if let Some(cache_str) = maybe_cache {
|
let global_cache_url = maybe_cache.and_then(|cache_str| {
|
||||||
let cache_url = if let Ok(url) = Url::from_file_path(cache_str) {
|
if let Ok(url) = Url::from_file_path(cache_str) {
|
||||||
Ok(url)
|
Some(url)
|
||||||
} else if let Some(root_uri) = self.config.root_uri() {
|
} else if let Some(root_uri) = self.config.root_uri() {
|
||||||
root_uri.join(cache_str).map_err(|e| e.into())
|
root_uri.join(cache_str).inspect_err(|err| lsp_warn!("Failed to resolve custom cache path: {err}")).ok()
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!(
|
lsp_warn!(
|
||||||
"The configured cache path \"{cache_str}\" is not resolvable outside of a workspace.",
|
"The configured cache path \"{cache_str}\" is not resolvable outside of a workspace.",
|
||||||
))
|
);
|
||||||
};
|
|
||||||
cache_url
|
|
||||||
.and_then(|s| specifier_to_file_path(&s))
|
|
||||||
.inspect(|p| {
|
|
||||||
lsp_log!("Resolved global cache path: \"{}\"", p.to_string_lossy());
|
|
||||||
})
|
|
||||||
.inspect_err(|err| {
|
|
||||||
lsp_warn!("Failed to resolve custom cache path: {err}");
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
};
|
|
||||||
let deno_dir = match DenoDir::new(self.maybe_global_cache_path.clone()) {
|
|
||||||
Ok(d) => d,
|
|
||||||
Err(err) => {
|
|
||||||
lsp_warn!("Couldn't access DENO_DIR: {err}");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
self.cache = LspCache::new(global_cache_url);
|
||||||
|
let deno_dir = self.cache.deno_dir();
|
||||||
let workspace_settings = self.config.workspace_settings();
|
let workspace_settings = self.config.workspace_settings();
|
||||||
let maybe_root_path = self
|
let maybe_root_path = self
|
||||||
.config
|
.config
|
||||||
|
@ -674,28 +637,13 @@ impl Inner {
|
||||||
CliJsrSearchApi::new(self.module_registry.file_fetcher.clone());
|
CliJsrSearchApi::new(self.module_registry.file_fetcher.clone());
|
||||||
self.npm_search_api =
|
self.npm_search_api =
|
||||||
CliNpmSearchApi::new(self.module_registry.file_fetcher.clone());
|
CliNpmSearchApi::new(self.module_registry.file_fetcher.clone());
|
||||||
self.global_cache = Arc::new(GlobalHttpCache::new(
|
|
||||||
deno_dir.deps_folder_path(),
|
|
||||||
crate::cache::RealDenoCacheEnv,
|
|
||||||
));
|
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
let maybe_local_cache =
|
self.cache.update_config(&self.config);
|
||||||
self.config.tree.root_vendor_dir().map(|local_path| {
|
self.url_map.set_cache(self.cache.root_vendor().cloned());
|
||||||
Arc::new(LocalLspHttpCache::new(
|
|
||||||
local_path.clone(),
|
|
||||||
self.global_cache.clone(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
self.url_map.set_cache(maybe_local_cache.clone());
|
|
||||||
self.cache = maybe_local_cache
|
|
||||||
.clone()
|
|
||||||
.map(|c| c as Arc<dyn HttpCache>)
|
|
||||||
.unwrap_or(self.global_cache.clone());
|
|
||||||
self.cache_metadata.set_cache(self.cache.clone());
|
|
||||||
self.performance.measure(mark);
|
self.performance.measure(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,7 +898,7 @@ impl Inner {
|
||||||
|
|
||||||
async fn refresh_config_tree(&mut self) {
|
async fn refresh_config_tree(&mut self) {
|
||||||
let mut file_fetcher = FileFetcher::new(
|
let mut file_fetcher = FileFetcher::new(
|
||||||
self.global_cache.clone(),
|
self.cache.global().clone(),
|
||||||
CacheSetting::RespectHeaders,
|
CacheSetting::RespectHeaders,
|
||||||
true,
|
true,
|
||||||
self.http_client.clone(),
|
self.http_client.clone(),
|
||||||
|
@ -995,12 +943,7 @@ impl Inner {
|
||||||
async fn refresh_resolver(&mut self) {
|
async fn refresh_resolver(&mut self) {
|
||||||
self.resolver = self
|
self.resolver = self
|
||||||
.resolver
|
.resolver
|
||||||
.with_new_config(
|
.with_new_config(&self.config, &self.cache, Some(&self.http_client))
|
||||||
&self.config,
|
|
||||||
self.cache.clone(),
|
|
||||||
self.maybe_global_cache_path.as_deref(),
|
|
||||||
Some(&self.http_client),
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1008,7 +951,7 @@ impl Inner {
|
||||||
self.documents.update_config(
|
self.documents.update_config(
|
||||||
&self.config,
|
&self.config,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
self.cache.clone(),
|
&self.cache,
|
||||||
&self.workspace_files,
|
&self.workspace_files,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3304,7 +3247,7 @@ impl Inner {
|
||||||
let workspace_settings = self.config.workspace_settings();
|
let workspace_settings = self.config.workspace_settings();
|
||||||
let cli_options = CliOptions::new(
|
let cli_options = CliOptions::new(
|
||||||
Flags {
|
Flags {
|
||||||
cache_path: self.maybe_global_cache_path.clone(),
|
cache_path: Some(self.cache.deno_dir().root.clone()),
|
||||||
ca_stores: workspace_settings.certificate_stores.clone(),
|
ca_stores: workspace_settings.certificate_stores.clone(),
|
||||||
ca_data: workspace_settings.tls_certificate.clone().map(CaData::File),
|
ca_data: workspace_settings.tls_certificate.clone().map(CaData::File),
|
||||||
unsafely_ignore_certificate_errors: workspace_settings
|
unsafely_ignore_certificate_errors: workspace_settings
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
|
|
||||||
use crate::args::package_json;
|
use crate::args::package_json;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::cache::DenoDir;
|
|
||||||
use crate::cache::FastInsecureHasher;
|
use crate::cache::FastInsecureHasher;
|
||||||
use crate::graph_util::CliJsrUrlProvider;
|
use crate::graph_util::CliJsrUrlProvider;
|
||||||
use crate::http_util::HttpClient;
|
use crate::http_util::HttpClient;
|
||||||
use crate::jsr::JsrCacheResolver;
|
use crate::jsr::JsrCacheResolver;
|
||||||
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;
|
||||||
|
@ -25,9 +23,10 @@ use crate::resolver::SloppyImportsFsEntry;
|
||||||
use crate::resolver::SloppyImportsResolver;
|
use crate::resolver::SloppyImportsResolver;
|
||||||
use crate::util::progress_bar::ProgressBar;
|
use crate::util::progress_bar::ProgressBar;
|
||||||
use crate::util::progress_bar::ProgressBarStyle;
|
use crate::util::progress_bar::ProgressBarStyle;
|
||||||
|
use dashmap::DashMap;
|
||||||
use deno_cache_dir::HttpCache;
|
use deno_cache_dir::HttpCache;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::parking_lot::Mutex;
|
use deno_core::url::Url;
|
||||||
use deno_graph::source::NpmResolver;
|
use deno_graph::source::NpmResolver;
|
||||||
use deno_graph::source::Resolver;
|
use deno_graph::source::Resolver;
|
||||||
use deno_graph::GraphImport;
|
use deno_graph::GraphImport;
|
||||||
|
@ -47,11 +46,14 @@ use deno_semver::package::PackageNv;
|
||||||
use deno_semver::package::PackageReq;
|
use deno_semver::package::PackageReq;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use package_json::PackageJsonDepsProvider;
|
use package_json::PackageJsonDepsProvider;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::collections::HashSet;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::cache::LspCache;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LspResolver {
|
pub struct LspResolver {
|
||||||
graph_resolver: Arc<CliGraphResolver>,
|
graph_resolver: Arc<CliGraphResolver>,
|
||||||
|
@ -85,11 +87,10 @@ impl LspResolver {
|
||||||
pub async fn with_new_config(
|
pub async fn with_new_config(
|
||||||
&self,
|
&self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
cache: Arc<dyn HttpCache>,
|
cache: &LspCache,
|
||||||
global_cache_path: Option<&Path>,
|
|
||||||
http_client: Option<&Arc<HttpClient>>,
|
http_client: Option<&Arc<HttpClient>>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let npm_config_hash = LspNpmConfigHash::new(config, global_cache_path);
|
let npm_config_hash = LspNpmConfigHash::new(config, cache);
|
||||||
let config_data = config.tree.root_data();
|
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;
|
||||||
|
@ -97,8 +98,7 @@ impl LspResolver {
|
||||||
if let (Some(http_client), Some(config_data)) = (http_client, config_data)
|
if let (Some(http_client), Some(config_data)) = (http_client, config_data)
|
||||||
{
|
{
|
||||||
npm_resolver =
|
npm_resolver =
|
||||||
create_npm_resolver(config_data, global_cache_path, http_client)
|
create_npm_resolver(config_data, cache, http_client).await;
|
||||||
.await;
|
|
||||||
node_resolver = create_node_resolver(npm_resolver.as_ref());
|
node_resolver = create_node_resolver(npm_resolver.as_ref());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,10 +111,12 @@ impl LspResolver {
|
||||||
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.clone(),
|
cache.root_vendor_or_global(),
|
||||||
config_data.and_then(|d| d.lockfile.clone()),
|
config_data.and_then(|d| d.lockfile.clone()),
|
||||||
)));
|
)));
|
||||||
let redirect_resolver = Some(Arc::new(RedirectResolver::new(cache)));
|
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
|
||||||
|
cache.root_vendor_or_global(),
|
||||||
|
)));
|
||||||
let graph_imports = config_data
|
let graph_imports = config_data
|
||||||
.and_then(|d| d.config_file.as_ref())
|
.and_then(|d| d.config_file.as_ref())
|
||||||
.and_then(|cf| cf.to_maybe_imports().ok())
|
.and_then(|cf| cf.to_maybe_imports().ok())
|
||||||
|
@ -317,6 +319,20 @@ impl LspResolver {
|
||||||
};
|
};
|
||||||
redirect_resolver.resolve(specifier)
|
redirect_resolver.resolve(specifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn redirect_chain_headers(
|
||||||
|
&self,
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
) -> Vec<(ModuleSpecifier, Arc<HashMap<String, String>>)> {
|
||||||
|
let Some(redirect_resolver) = self.redirect_resolver.as_ref() else {
|
||||||
|
return vec![];
|
||||||
|
};
|
||||||
|
redirect_resolver
|
||||||
|
.chain(specifier)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(s, e)| (s, e.headers.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -383,14 +399,9 @@ impl<'a> Resolver for LspGraphResolver<'a> {
|
||||||
|
|
||||||
async fn create_npm_resolver(
|
async fn create_npm_resolver(
|
||||||
config_data: &ConfigData,
|
config_data: &ConfigData,
|
||||||
global_cache_path: Option<&Path>,
|
cache: &LspCache,
|
||||||
http_client: &Arc<HttpClient>,
|
http_client: &Arc<HttpClient>,
|
||||||
) -> Option<Arc<dyn CliNpmResolver>> {
|
) -> Option<Arc<dyn CliNpmResolver>> {
|
||||||
let deno_dir = DenoDir::new(global_cache_path.map(|p| p.to_owned()))
|
|
||||||
.inspect_err(|err| {
|
|
||||||
lsp_warn!("Error getting deno dir: {:#}", err);
|
|
||||||
})
|
|
||||||
.ok()?;
|
|
||||||
let node_modules_dir = config_data
|
let node_modules_dir = config_data
|
||||||
.node_modules_dir
|
.node_modules_dir
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -415,7 +426,7 @@ async fn create_npm_resolver(
|
||||||
// updating it. Only the cache request should update the lockfile.
|
// updating it. Only the cache request should update the lockfile.
|
||||||
maybe_lockfile: None,
|
maybe_lockfile: None,
|
||||||
fs: Arc::new(deno_fs::RealFs),
|
fs: Arc::new(deno_fs::RealFs),
|
||||||
npm_global_cache_dir: deno_dir.npm_folder_path(),
|
npm_global_cache_dir: cache.deno_dir().npm_folder_path(),
|
||||||
// Use an "only" cache setting in order to make the
|
// Use an "only" cache setting in order to make the
|
||||||
// user do an explicit "cache" command and prevent
|
// user do an explicit "cache" command and prevent
|
||||||
// the cache from being filled with lots of packages while
|
// the cache from being filled with lots of packages while
|
||||||
|
@ -482,7 +493,7 @@ fn create_graph_resolver(
|
||||||
struct LspNpmConfigHash(u64);
|
struct LspNpmConfigHash(u64);
|
||||||
|
|
||||||
impl LspNpmConfigHash {
|
impl LspNpmConfigHash {
|
||||||
pub fn new(config: &Config, global_cache_path: Option<&Path>) -> Self {
|
pub fn new(config: &Config, cache: &LspCache) -> Self {
|
||||||
let config_data = config.tree.root_data();
|
let config_data = config.tree.root_data();
|
||||||
let scope = config_data.map(|d| &d.scope);
|
let scope = config_data.map(|d| &d.scope);
|
||||||
let node_modules_dir =
|
let node_modules_dir =
|
||||||
|
@ -491,64 +502,195 @@ impl LspNpmConfigHash {
|
||||||
let mut hasher = FastInsecureHasher::new();
|
let mut hasher = FastInsecureHasher::new();
|
||||||
hasher.write_hashable(scope);
|
hasher.write_hashable(scope);
|
||||||
hasher.write_hashable(node_modules_dir);
|
hasher.write_hashable(node_modules_dir);
|
||||||
hasher.write_hashable(global_cache_path);
|
|
||||||
if let Some(lockfile) = lockfile {
|
if let Some(lockfile) = lockfile {
|
||||||
hasher.write_hashable(&*lockfile.lock());
|
hasher.write_hashable(&*lockfile.lock());
|
||||||
}
|
}
|
||||||
hasher.write_hashable(global_cache_path);
|
hasher.write_hashable(cache.deno_dir().npm_folder_path());
|
||||||
Self(hasher.finish())
|
Self(hasher.finish())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
struct RedirectEntry {
|
||||||
|
headers: Arc<HashMap<String, String>>,
|
||||||
|
target: Url,
|
||||||
|
destination: Option<Url>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetHeadersFn =
|
||||||
|
Box<dyn Fn(&Url) -> Option<HashMap<String, String>> + Send + Sync>;
|
||||||
|
|
||||||
struct RedirectResolver {
|
struct RedirectResolver {
|
||||||
cache: Arc<dyn HttpCache>,
|
get_headers: GetHeadersFn,
|
||||||
redirects: Mutex<HashMap<ModuleSpecifier, ModuleSpecifier>>,
|
entries: DashMap<Url, Option<Arc<RedirectEntry>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for RedirectResolver {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("RedirectResolver")
|
||||||
|
.field("get_headers", &"Box(|_| { ... })")
|
||||||
|
.field("entries", &self.entries)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RedirectResolver {
|
impl RedirectResolver {
|
||||||
pub fn new(cache: Arc<dyn HttpCache>) -> Self {
|
fn new(cache: Arc<dyn HttpCache>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cache,
|
get_headers: Box::new(move |specifier| {
|
||||||
redirects: Mutex::new(HashMap::new()),
|
let cache_key = cache.cache_item_key(specifier).ok()?;
|
||||||
|
cache.read_headers(&cache_key).ok().flatten()
|
||||||
|
}),
|
||||||
|
entries: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(
|
#[cfg(test)]
|
||||||
&self,
|
fn mock(get_headers: GetHeadersFn) -> Self {
|
||||||
specifier: &ModuleSpecifier,
|
Self {
|
||||||
) -> Option<ModuleSpecifier> {
|
get_headers,
|
||||||
if matches!(specifier.scheme(), "http" | "https") {
|
entries: Default::default(),
|
||||||
let mut redirects = self.redirects.lock();
|
|
||||||
if let Some(specifier) = redirects.get(specifier) {
|
|
||||||
Some(specifier.clone())
|
|
||||||
} else {
|
|
||||||
let redirect = self.resolve_remote(specifier, 10)?;
|
|
||||||
redirects.insert(specifier.clone(), redirect.clone());
|
|
||||||
Some(redirect)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Some(specifier.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_remote(
|
fn resolve(&self, specifier: &Url) -> Option<Url> {
|
||||||
&self,
|
if !matches!(specifier.scheme(), "http" | "https") {
|
||||||
specifier: &ModuleSpecifier,
|
return Some(specifier.clone());
|
||||||
redirect_limit: usize,
|
}
|
||||||
) -> Option<ModuleSpecifier> {
|
let mut current = specifier.clone();
|
||||||
if redirect_limit > 0 {
|
let mut chain = vec![];
|
||||||
let cache_key = self.cache.cache_item_key(specifier).ok()?;
|
let destination = loop {
|
||||||
let headers = self.cache.read_headers(&cache_key).ok().flatten()?;
|
if let Some(maybe_entry) = self.entries.get(¤t) {
|
||||||
|
break match maybe_entry.as_ref() {
|
||||||
|
Some(entry) => entry.destination.clone(),
|
||||||
|
None => Some(current),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let Some(headers) = (self.get_headers)(¤t) else {
|
||||||
|
break None;
|
||||||
|
};
|
||||||
|
let headers = Arc::new(headers);
|
||||||
if let Some(location) = headers.get("location") {
|
if let Some(location) = headers.get("location") {
|
||||||
let redirect =
|
if chain.len() > 10 {
|
||||||
deno_core::resolve_import(location, specifier.as_str()).ok()?;
|
break None;
|
||||||
self.resolve_remote(&redirect, redirect_limit - 1)
|
|
||||||
} else {
|
|
||||||
Some(specifier.clone())
|
|
||||||
}
|
}
|
||||||
|
let Ok(target) =
|
||||||
|
deno_core::resolve_import(location, specifier.as_str())
|
||||||
|
else {
|
||||||
|
break None;
|
||||||
|
};
|
||||||
|
chain.push((
|
||||||
|
current.clone(),
|
||||||
|
RedirectEntry {
|
||||||
|
headers,
|
||||||
|
target: target.clone(),
|
||||||
|
destination: None,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
current = target;
|
||||||
} else {
|
} else {
|
||||||
|
self.entries.insert(current.clone(), None);
|
||||||
|
break Some(current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (specifier, mut entry) in chain {
|
||||||
|
entry.destination = destination.clone();
|
||||||
|
self.entries.insert(specifier, Some(Arc::new(entry)));
|
||||||
|
}
|
||||||
|
destination
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chain(&self, specifier: &Url) -> Vec<(Url, Arc<RedirectEntry>)> {
|
||||||
|
self.resolve(specifier);
|
||||||
|
let mut result = vec![];
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
let mut current = Cow::Borrowed(specifier);
|
||||||
|
loop {
|
||||||
|
let Some(maybe_entry) = self.entries.get(¤t) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
let Some(entry) = maybe_entry.as_ref() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
result.push((current.as_ref().clone(), entry.clone()));
|
||||||
|
seen.insert(current.as_ref().clone());
|
||||||
|
if seen.contains(&entry.target) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = Cow::Owned(entry.target.clone())
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_redirect_resolver() {
|
||||||
|
let redirect_resolver =
|
||||||
|
RedirectResolver::mock(Box::new(|specifier| match specifier.as_str() {
|
||||||
|
"https://foo/redirect_2.js" => Some(
|
||||||
|
[("location".to_string(), "./redirect_1.js".to_string())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
"https://foo/redirect_1.js" => Some(
|
||||||
|
[("location".to_string(), "./file.js".to_string())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
"https://foo/file.js" => Some([].into_iter().collect()),
|
||||||
|
_ => None,
|
||||||
|
}));
|
||||||
|
assert_eq!(
|
||||||
|
redirect_resolver.resolve(&Url::parse("https://foo/file.js").unwrap()),
|
||||||
|
Some(Url::parse("https://foo/file.js").unwrap())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
redirect_resolver
|
||||||
|
.resolve(&Url::parse("https://foo/redirect_1.js").unwrap()),
|
||||||
|
Some(Url::parse("https://foo/file.js").unwrap())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
redirect_resolver
|
||||||
|
.resolve(&Url::parse("https://foo/redirect_2.js").unwrap()),
|
||||||
|
Some(Url::parse("https://foo/file.js").unwrap())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
redirect_resolver.resolve(&Url::parse("https://foo/unknown").unwrap()),
|
||||||
None
|
None
|
||||||
}
|
);
|
||||||
|
assert_eq!(
|
||||||
|
redirect_resolver
|
||||||
|
.chain(&Url::parse("https://foo/redirect_2.js").unwrap()),
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Url::parse("https://foo/redirect_2.js").unwrap(),
|
||||||
|
Arc::new(RedirectEntry {
|
||||||
|
headers: Arc::new(
|
||||||
|
[("location".to_string(), "./redirect_1.js".to_string())]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
target: Url::parse("https://foo/redirect_1.js").unwrap(),
|
||||||
|
destination: Some(Url::parse("https://foo/file.js").unwrap()),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Url::parse("https://foo/redirect_1.js").unwrap(),
|
||||||
|
Arc::new(RedirectEntry {
|
||||||
|
headers: Arc::new(
|
||||||
|
[("location".to_string(), "./file.js".to_string())]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
target: Url::parse("https://foo/file.js").unwrap(),
|
||||||
|
destination: Some(Url::parse("https://foo/file.js").unwrap()),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
114
cli/lsp/tsc.rs
114
cli/lsp/tsc.rs
|
@ -22,9 +22,6 @@ use super::urls::INVALID_SPECIFIER;
|
||||||
|
|
||||||
use crate::args::jsr_url;
|
use crate::args::jsr_url;
|
||||||
use crate::args::FmtOptionsConfig;
|
use crate::args::FmtOptionsConfig;
|
||||||
use crate::cache::HttpCache;
|
|
||||||
use crate::lsp::cache::CacheMetadata;
|
|
||||||
use crate::lsp::documents::Documents;
|
|
||||||
use crate::lsp::logging::lsp_warn;
|
use crate::lsp::logging::lsp_warn;
|
||||||
use crate::tsc;
|
use crate::tsc;
|
||||||
use crate::tsc::ResolveArgs;
|
use crate::tsc::ResolveArgs;
|
||||||
|
@ -220,7 +217,6 @@ fn normalize_diagnostic(
|
||||||
|
|
||||||
pub struct TsServer {
|
pub struct TsServer {
|
||||||
performance: Arc<Performance>,
|
performance: Arc<Performance>,
|
||||||
cache: Arc<dyn HttpCache>,
|
|
||||||
sender: mpsc::UnboundedSender<Request>,
|
sender: mpsc::UnboundedSender<Request>,
|
||||||
receiver: Mutex<Option<mpsc::UnboundedReceiver<Request>>>,
|
receiver: Mutex<Option<mpsc::UnboundedReceiver<Request>>>,
|
||||||
specifier_map: Arc<TscSpecifierMap>,
|
specifier_map: Arc<TscSpecifierMap>,
|
||||||
|
@ -232,7 +228,6 @@ impl std::fmt::Debug for TsServer {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("TsServer")
|
f.debug_struct("TsServer")
|
||||||
.field("performance", &self.performance)
|
.field("performance", &self.performance)
|
||||||
.field("cache", &self.cache)
|
|
||||||
.field("sender", &self.sender)
|
.field("sender", &self.sender)
|
||||||
.field("receiver", &self.receiver)
|
.field("receiver", &self.receiver)
|
||||||
.field("specifier_map", &self.specifier_map)
|
.field("specifier_map", &self.specifier_map)
|
||||||
|
@ -331,11 +326,10 @@ impl PendingChange {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TsServer {
|
impl TsServer {
|
||||||
pub fn new(performance: Arc<Performance>, cache: Arc<dyn HttpCache>) -> Self {
|
pub fn new(performance: Arc<Performance>) -> Self {
|
||||||
let (tx, request_rx) = mpsc::unbounded_channel::<Request>();
|
let (tx, request_rx) = mpsc::unbounded_channel::<Request>();
|
||||||
Self {
|
Self {
|
||||||
performance,
|
performance,
|
||||||
cache,
|
|
||||||
sender: tx,
|
sender: tx,
|
||||||
receiver: Mutex::new(Some(request_rx)),
|
receiver: Mutex::new(Some(request_rx)),
|
||||||
specifier_map: Arc::new(TscSpecifierMap::new()),
|
specifier_map: Arc::new(TscSpecifierMap::new()),
|
||||||
|
@ -363,13 +357,11 @@ impl TsServer {
|
||||||
// on the `TsServer` struct.
|
// on the `TsServer` struct.
|
||||||
let receiver = self.receiver.lock().take().unwrap();
|
let receiver = self.receiver.lock().take().unwrap();
|
||||||
let performance = self.performance.clone();
|
let performance = self.performance.clone();
|
||||||
let cache = self.cache.clone();
|
|
||||||
let specifier_map = self.specifier_map.clone();
|
let specifier_map = self.specifier_map.clone();
|
||||||
let _join_handle = thread::spawn(move || {
|
let _join_handle = thread::spawn(move || {
|
||||||
run_tsc_thread(
|
run_tsc_thread(
|
||||||
receiver,
|
receiver,
|
||||||
performance.clone(),
|
performance.clone(),
|
||||||
cache.clone(),
|
|
||||||
specifier_map.clone(),
|
specifier_map.clone(),
|
||||||
maybe_inspector_server,
|
maybe_inspector_server,
|
||||||
)
|
)
|
||||||
|
@ -4340,7 +4332,6 @@ impl TscRuntime {
|
||||||
fn run_tsc_thread(
|
fn run_tsc_thread(
|
||||||
mut request_rx: UnboundedReceiver<Request>,
|
mut request_rx: UnboundedReceiver<Request>,
|
||||||
performance: Arc<Performance>,
|
performance: Arc<Performance>,
|
||||||
cache: Arc<dyn HttpCache>,
|
|
||||||
specifier_map: Arc<TscSpecifierMap>,
|
specifier_map: Arc<TscSpecifierMap>,
|
||||||
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
maybe_inspector_server: Option<Arc<InspectorServer>>,
|
||||||
) {
|
) {
|
||||||
|
@ -4349,7 +4340,7 @@ fn run_tsc_thread(
|
||||||
// supplied snapshot is an isolate that contains the TypeScript language
|
// supplied snapshot is an isolate that contains the TypeScript language
|
||||||
// server.
|
// server.
|
||||||
let mut tsc_runtime = JsRuntime::new(RuntimeOptions {
|
let mut tsc_runtime = JsRuntime::new(RuntimeOptions {
|
||||||
extensions: vec![deno_tsc::init_ops(performance, cache, specifier_map)],
|
extensions: vec![deno_tsc::init_ops(performance, specifier_map)],
|
||||||
startup_snapshot: Some(tsc::compiler_snapshot()),
|
startup_snapshot: Some(tsc::compiler_snapshot()),
|
||||||
inspector: maybe_inspector_server.is_some(),
|
inspector: maybe_inspector_server.is_some(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -4422,19 +4413,11 @@ deno_core::extension!(deno_tsc,
|
||||||
],
|
],
|
||||||
options = {
|
options = {
|
||||||
performance: Arc<Performance>,
|
performance: Arc<Performance>,
|
||||||
cache: Arc<dyn HttpCache>,
|
|
||||||
specifier_map: Arc<TscSpecifierMap>,
|
specifier_map: Arc<TscSpecifierMap>,
|
||||||
},
|
},
|
||||||
state = |state, options| {
|
state = |state, options| {
|
||||||
state.put(State::new(
|
state.put(State::new(
|
||||||
Arc::new(StateSnapshot {
|
Default::default(),
|
||||||
project_version: 0,
|
|
||||||
assets: Default::default(),
|
|
||||||
cache_metadata: CacheMetadata::new(options.cache.clone()),
|
|
||||||
config: Default::default(),
|
|
||||||
documents: Documents::new(options.cache.clone()),
|
|
||||||
resolver: Default::default(),
|
|
||||||
}),
|
|
||||||
options.specifier_map,
|
options.specifier_map,
|
||||||
options.performance,
|
options.performance,
|
||||||
));
|
));
|
||||||
|
@ -5078,11 +5061,9 @@ impl TscRequest {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cache::GlobalHttpCache;
|
|
||||||
use crate::cache::HttpCache;
|
use crate::cache::HttpCache;
|
||||||
use crate::cache::RealDenoCacheEnv;
|
|
||||||
use crate::http_util::HeadersMap;
|
use crate::http_util::HeadersMap;
|
||||||
use crate::lsp::cache::CacheMetadata;
|
use crate::lsp::cache::LspCache;
|
||||||
use crate::lsp::config::Config;
|
use crate::lsp::config::Config;
|
||||||
use crate::lsp::config::WorkspaceSettings;
|
use crate::lsp::config::WorkspaceSettings;
|
||||||
use crate::lsp::documents::Documents;
|
use crate::lsp::documents::Documents;
|
||||||
|
@ -5090,29 +5071,14 @@ mod tests {
|
||||||
use crate::lsp::resolver::LspResolver;
|
use crate::lsp::resolver::LspResolver;
|
||||||
use crate::lsp::text::LineIndex;
|
use crate::lsp::text::LineIndex;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::path::Path;
|
|
||||||
use test_util::TempDir;
|
use test_util::TempDir;
|
||||||
|
|
||||||
async fn mock_state_snapshot(
|
async fn setup(
|
||||||
fixtures: &[(&str, &str, i32, LanguageId)],
|
|
||||||
location: &Path,
|
|
||||||
ts_config: Value,
|
ts_config: Value,
|
||||||
) -> StateSnapshot {
|
sources: &[(&str, &str, i32, LanguageId)],
|
||||||
let cache = Arc::new(GlobalHttpCache::new(
|
) -> (TsServer, Arc<StateSnapshot>, LspCache) {
|
||||||
location.to_path_buf(),
|
let temp_dir = TempDir::new();
|
||||||
RealDenoCacheEnv,
|
let cache = LspCache::new(Some(temp_dir.uri()));
|
||||||
));
|
|
||||||
let mut documents = Documents::new(cache.clone());
|
|
||||||
for (specifier, source, version, language_id) in fixtures {
|
|
||||||
let specifier =
|
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
|
||||||
documents.open(
|
|
||||||
specifier.clone(),
|
|
||||||
*version,
|
|
||||||
*language_id,
|
|
||||||
(*source).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config
|
config
|
||||||
.tree
|
.tree
|
||||||
|
@ -5129,30 +5095,29 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let resolver = LspResolver::default()
|
let resolver = LspResolver::default()
|
||||||
.with_new_config(&config, cache.clone(), None, None)
|
.with_new_config(&config, &cache, None)
|
||||||
.await;
|
.await;
|
||||||
StateSnapshot {
|
let mut documents = Documents::default();
|
||||||
|
documents.update_config(&config, &resolver, &cache, &Default::default());
|
||||||
|
for (specifier, source, version, language_id) in sources {
|
||||||
|
let specifier =
|
||||||
|
resolve_url(specifier).expect("failed to create specifier");
|
||||||
|
documents.open(
|
||||||
|
specifier.clone(),
|
||||||
|
*version,
|
||||||
|
*language_id,
|
||||||
|
(*source).into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let snapshot = Arc::new(StateSnapshot {
|
||||||
project_version: 0,
|
project_version: 0,
|
||||||
documents,
|
documents,
|
||||||
assets: Default::default(),
|
assets: Default::default(),
|
||||||
cache_metadata: CacheMetadata::new(cache),
|
|
||||||
config: Arc::new(config),
|
config: Arc::new(config),
|
||||||
resolver,
|
resolver,
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
async fn setup(
|
|
||||||
temp_dir: &TempDir,
|
|
||||||
config: Value,
|
|
||||||
sources: &[(&str, &str, i32, LanguageId)],
|
|
||||||
) -> (TsServer, Arc<StateSnapshot>, Arc<GlobalHttpCache>) {
|
|
||||||
let location = temp_dir.path().join("deps").to_path_buf();
|
|
||||||
let cache =
|
|
||||||
Arc::new(GlobalHttpCache::new(location.clone(), RealDenoCacheEnv));
|
|
||||||
let snapshot =
|
|
||||||
Arc::new(mock_state_snapshot(sources, &location, config).await);
|
|
||||||
let performance = Arc::new(Performance::default());
|
let performance = Arc::new(Performance::default());
|
||||||
let ts_server = TsServer::new(performance, cache.clone());
|
let ts_server = TsServer::new(performance);
|
||||||
ts_server.start(None).unwrap();
|
ts_server.start(None).unwrap();
|
||||||
(ts_server, snapshot, cache)
|
(ts_server, snapshot, cache)
|
||||||
}
|
}
|
||||||
|
@ -5182,9 +5147,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_diagnostics() {
|
async fn test_get_diagnostics() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5230,9 +5193,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_diagnostics_lib() {
|
async fn test_get_diagnostics_lib() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5258,9 +5219,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_module_resolution() {
|
async fn test_module_resolution() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5291,9 +5250,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_bad_module_specifiers() {
|
async fn test_bad_module_specifiers() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5339,9 +5296,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_remote_modules() {
|
async fn test_remote_modules() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5372,9 +5327,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_partial_modules() {
|
async fn test_partial_modules() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5441,9 +5394,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_no_debug_failure() {
|
async fn test_no_debug_failure() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5489,8 +5440,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_request_assets() {
|
async fn test_request_assets() {
|
||||||
let temp_dir = TempDir::new();
|
let (ts_server, snapshot, _) = setup(json!({}), &[]).await;
|
||||||
let (ts_server, snapshot, _) = setup(&temp_dir, json!({}), &[]).await;
|
|
||||||
let assets = get_isolate_assets(&ts_server, snapshot).await;
|
let assets = get_isolate_assets(&ts_server, snapshot).await;
|
||||||
let mut asset_names = assets
|
let mut asset_names = assets
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -5522,9 +5472,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_modify_sources() {
|
async fn test_modify_sources() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, cache) = setup(
|
let (ts_server, snapshot, cache) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5547,6 +5495,7 @@ mod tests {
|
||||||
let specifier_dep =
|
let specifier_dep =
|
||||||
resolve_url("https://deno.land/x/example/a.ts").unwrap();
|
resolve_url("https://deno.land/x/example/a.ts").unwrap();
|
||||||
cache
|
cache
|
||||||
|
.global()
|
||||||
.set(
|
.set(
|
||||||
&specifier_dep,
|
&specifier_dep,
|
||||||
HeadersMap::default(),
|
HeadersMap::default(),
|
||||||
|
@ -5581,6 +5530,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
cache
|
cache
|
||||||
|
.global()
|
||||||
.set(
|
.set(
|
||||||
&specifier_dep,
|
&specifier_dep,
|
||||||
HeadersMap::default(),
|
HeadersMap::default(),
|
||||||
|
@ -5656,9 +5606,7 @@ mod tests {
|
||||||
character: 16,
|
character: 16,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5807,9 +5755,7 @@ mod tests {
|
||||||
character: 33,
|
character: 33,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5916,9 +5862,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_edits_for_file_rename() {
|
async fn test_get_edits_for_file_rename() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (ts_server, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5994,9 +5938,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn resolve_unknown_dependency() {
|
async fn resolve_unknown_dependency() {
|
||||||
let temp_dir = TempDir::new();
|
|
||||||
let (_, snapshot, _) = setup(
|
let (_, snapshot, _) = setup(
|
||||||
&temp_dir,
|
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue