mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(lsp): support npm workspaces and fix some resolution issues (#24627)
Makes the lsp use the same code as the rest of the cli.
This commit is contained in:
parent
1722e0aebf
commit
3bda8eb4fe
11 changed files with 1053 additions and 800 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1312,9 +1312,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno_config"
|
name = "deno_config"
|
||||||
version = "0.23.0"
|
version = "0.24.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90684d387a893a3318569b8bb548e2f9291f86f2909f5349dd9d2b97c83fdb18"
|
checksum = "d6b72d6f849f5640ed80dc458b529aec74a79bdabdebe291448d345f865faa99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"deno_semver",
|
"deno_semver",
|
||||||
|
|
|
@ -101,7 +101,7 @@ console_static_text = "=0.8.1"
|
||||||
data-encoding = "2.3.3"
|
data-encoding = "2.3.3"
|
||||||
data-url = "=0.3.0"
|
data-url = "=0.3.0"
|
||||||
deno_cache_dir = "=0.10.0"
|
deno_cache_dir = "=0.10.0"
|
||||||
deno_config = { version = "=0.23.0", default-features = false }
|
deno_config = { version = "=0.24.0", default-features = false }
|
||||||
dlopen2 = "0.6.1"
|
dlopen2 = "0.6.1"
|
||||||
ecb = "=0.1.2"
|
ecb = "=0.1.2"
|
||||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem"] }
|
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem"] }
|
||||||
|
|
|
@ -500,6 +500,22 @@ fn resolve_lint_rules_options(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn discover_npmrc_from_workspace(
|
||||||
|
workspace: &Workspace,
|
||||||
|
) -> Result<(Arc<ResolvedNpmRc>, Option<PathBuf>), AnyError> {
|
||||||
|
let root_folder = workspace.root_folder().1;
|
||||||
|
discover_npmrc(
|
||||||
|
root_folder.pkg_json.as_ref().map(|p| p.path.clone()),
|
||||||
|
root_folder.deno_json.as_ref().and_then(|cf| {
|
||||||
|
if cf.specifier.scheme() == "file" {
|
||||||
|
Some(cf.specifier.to_file_path().unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Discover `.npmrc` file - currently we only support it next to `package.json`
|
/// Discover `.npmrc` file - currently we only support it next to `package.json`
|
||||||
/// or next to `deno.json`.
|
/// or next to `deno.json`.
|
||||||
///
|
///
|
||||||
|
@ -846,6 +862,7 @@ impl CliOptions {
|
||||||
}
|
}
|
||||||
WorkspaceDiscoverOptions {
|
WorkspaceDiscoverOptions {
|
||||||
fs: &config_fs_adapter,
|
fs: &config_fs_adapter,
|
||||||
|
deno_json_cache: None,
|
||||||
pkg_json_cache: Some(
|
pkg_json_cache: Some(
|
||||||
&deno_runtime::deno_node::PackageJsonThreadLocalCache,
|
&deno_runtime::deno_node::PackageJsonThreadLocalCache,
|
||||||
),
|
),
|
||||||
|
@ -890,17 +907,7 @@ impl CliOptions {
|
||||||
log::warn!("{} {}", colors::yellow("Warning"), diagnostic);
|
log::warn!("{} {}", colors::yellow("Warning"), diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_folder = workspace.root_folder().1;
|
let (npmrc, _) = discover_npmrc_from_workspace(&workspace)?;
|
||||||
let (npmrc, _) = discover_npmrc(
|
|
||||||
root_folder.pkg_json.as_ref().map(|p| p.path.clone()),
|
|
||||||
root_folder.deno_json.as_ref().and_then(|cf| {
|
|
||||||
if cf.specifier.scheme() == "file" {
|
|
||||||
Some(cf.specifier.to_file_path().unwrap())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let maybe_lock_file = CliLockfile::discover(&flags, &workspace)?;
|
let maybe_lock_file = CliLockfile::discover(&flags, &workspace)?;
|
||||||
|
|
||||||
|
|
|
@ -804,7 +804,7 @@ mod tests {
|
||||||
fs_sources: &[(&str, &str)],
|
fs_sources: &[(&str, &str)],
|
||||||
) -> Documents {
|
) -> Documents {
|
||||||
let temp_dir = TempDir::new();
|
let temp_dir = TempDir::new();
|
||||||
let cache = LspCache::new(Some(temp_dir.uri()));
|
let cache = LspCache::new(Some(temp_dir.uri().join(".deno_dir").unwrap()));
|
||||||
let mut documents = Documents::default();
|
let mut documents = Documents::default();
|
||||||
documents.update_config(
|
documents.update_config(
|
||||||
&Default::default(),
|
&Default::default(),
|
||||||
|
|
1180
cli/lsp/config.rs
1180
cli/lsp/config.rs
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,6 @@ use super::tsc::TsServer;
|
||||||
use super::urls::LspClientUrl;
|
use super::urls::LspClientUrl;
|
||||||
use super::urls::LspUrlMap;
|
use super::urls::LspUrlMap;
|
||||||
|
|
||||||
use crate::args::LintOptions;
|
|
||||||
use crate::graph_util;
|
use crate::graph_util;
|
||||||
use crate::graph_util::enhanced_resolution_error_message;
|
use crate::graph_util::enhanced_resolution_error_message;
|
||||||
use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams;
|
use crate::lsp::lsp_custom::DiagnosticBatchNotificationParams;
|
||||||
|
@ -24,6 +23,7 @@ use crate::resolver::SloppyImportsResolver;
|
||||||
use crate::util::path::to_percent_decoded_str;
|
use crate::util::path::to_percent_decoded_str;
|
||||||
|
|
||||||
use deno_ast::MediaType;
|
use deno_ast::MediaType;
|
||||||
|
use deno_config::glob::FilePatterns;
|
||||||
use deno_core::anyhow::anyhow;
|
use deno_core::anyhow::anyhow;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::parking_lot::RwLock;
|
use deno_core::parking_lot::RwLock;
|
||||||
|
@ -39,7 +39,6 @@ use deno_graph::source::ResolutionMode;
|
||||||
use deno_graph::Resolution;
|
use deno_graph::Resolution;
|
||||||
use deno_graph::ResolutionError;
|
use deno_graph::ResolutionError;
|
||||||
use deno_graph::SpecifierError;
|
use deno_graph::SpecifierError;
|
||||||
use deno_lint::linter::LintConfig;
|
|
||||||
use deno_lint::rules::LintRule;
|
use deno_lint::rules::LintRule;
|
||||||
use deno_runtime::deno_fs;
|
use deno_runtime::deno_fs;
|
||||||
use deno_runtime::deno_node;
|
use deno_runtime::deno_node;
|
||||||
|
@ -51,6 +50,7 @@ use import_map::ImportMap;
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -814,21 +814,24 @@ fn generate_lint_diagnostics(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let version = document.maybe_lsp_version();
|
let version = document.maybe_lsp_version();
|
||||||
let (lint_options, lint_config, lint_rules) = config
|
let (lint_config, deno_lint_config, lint_rules) = config
|
||||||
.tree
|
.tree
|
||||||
.scope_for_specifier(specifier)
|
.scope_for_specifier(specifier)
|
||||||
.and_then(|s| config_data_by_scope.get(s))
|
.and_then(|s| config_data_by_scope.get(s))
|
||||||
.map(|d| {
|
.map(|d| {
|
||||||
(
|
(
|
||||||
d.lint_options.clone(),
|
|
||||||
d.lint_config.clone(),
|
d.lint_config.clone(),
|
||||||
|
d.deno_lint_config.clone(),
|
||||||
d.lint_rules.clone(),
|
d.lint_rules.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
(
|
(
|
||||||
Arc::default(),
|
Arc::new(deno_config::LintConfig {
|
||||||
LintConfig {
|
options: Default::default(),
|
||||||
|
files: FilePatterns::new_with_base(PathBuf::from("/")),
|
||||||
|
}),
|
||||||
|
deno_lint::linter::LintConfig {
|
||||||
default_jsx_factory: None,
|
default_jsx_factory: None,
|
||||||
default_jsx_fragment_factory: None,
|
default_jsx_fragment_factory: None,
|
||||||
},
|
},
|
||||||
|
@ -841,8 +844,8 @@ fn generate_lint_diagnostics(
|
||||||
version,
|
version,
|
||||||
diagnostics: generate_document_lint_diagnostics(
|
diagnostics: generate_document_lint_diagnostics(
|
||||||
&document,
|
&document,
|
||||||
&lint_options,
|
&lint_config,
|
||||||
lint_config,
|
deno_lint_config,
|
||||||
lint_rules.rules.clone(),
|
lint_rules.rules.clone(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -853,18 +856,20 @@ fn generate_lint_diagnostics(
|
||||||
|
|
||||||
fn generate_document_lint_diagnostics(
|
fn generate_document_lint_diagnostics(
|
||||||
document: &Document,
|
document: &Document,
|
||||||
lint_options: &LintOptions,
|
lint_config: &deno_config::LintConfig,
|
||||||
lint_config: LintConfig,
|
deno_lint_config: deno_lint::linter::LintConfig,
|
||||||
lint_rules: Vec<&'static dyn LintRule>,
|
lint_rules: Vec<&'static dyn LintRule>,
|
||||||
) -> Vec<lsp::Diagnostic> {
|
) -> Vec<lsp::Diagnostic> {
|
||||||
if !lint_options.files.matches_specifier(document.specifier()) {
|
if !lint_config.files.matches_specifier(document.specifier()) {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
match document.maybe_parsed_source() {
|
match document.maybe_parsed_source() {
|
||||||
Some(Ok(parsed_source)) => {
|
Some(Ok(parsed_source)) => {
|
||||||
if let Ok(references) =
|
if let Ok(references) = analysis::get_lint_references(
|
||||||
analysis::get_lint_references(parsed_source, lint_rules, lint_config)
|
parsed_source,
|
||||||
{
|
lint_rules,
|
||||||
|
deno_lint_config,
|
||||||
|
) {
|
||||||
references
|
references
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|r| r.to_diagnostic())
|
.map(|r| r.to_diagnostic())
|
||||||
|
@ -1479,7 +1484,7 @@ fn diagnose_dependency(
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.data_for_specifier(referrer_doc.file_referrer().unwrap_or(referrer))
|
.data_for_specifier(referrer_doc.file_referrer().unwrap_or(referrer))
|
||||||
.and_then(|d| d.import_map.as_ref());
|
.and_then(|d| d.resolver.maybe_import_map());
|
||||||
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) {
|
||||||
|
@ -1530,7 +1535,7 @@ fn diagnose_dependency(
|
||||||
dependency.is_dynamic,
|
dependency.is_dynamic,
|
||||||
dependency.maybe_attribute_type.as_deref(),
|
dependency.maybe_attribute_type.as_deref(),
|
||||||
referrer_doc,
|
referrer_doc,
|
||||||
import_map.map(|i| i.as_ref()),
|
import_map,
|
||||||
)
|
)
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|diag| {
|
.flat_map(|diag| {
|
||||||
|
@ -1554,7 +1559,7 @@ fn diagnose_dependency(
|
||||||
dependency.is_dynamic,
|
dependency.is_dynamic,
|
||||||
dependency.maybe_attribute_type.as_deref(),
|
dependency.maybe_attribute_type.as_deref(),
|
||||||
referrer_doc,
|
referrer_doc,
|
||||||
import_map.map(|i| i.as_ref()),
|
import_map,
|
||||||
)
|
)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|diag| diag.to_lsp_diagnostic(&range)),
|
.map(|diag| diag.to_lsp_diagnostic(&range)),
|
||||||
|
@ -1646,12 +1651,13 @@ mod tests {
|
||||||
async fn setup(
|
async fn setup(
|
||||||
sources: &[(&str, &str, i32, LanguageId)],
|
sources: &[(&str, &str, i32, LanguageId)],
|
||||||
maybe_import_map: Option<(&str, &str)>,
|
maybe_import_map: Option<(&str, &str)>,
|
||||||
) -> StateSnapshot {
|
) -> (TempDir, StateSnapshot) {
|
||||||
let temp_dir = TempDir::new();
|
let temp_dir = TempDir::new();
|
||||||
let cache = LspCache::new(Some(temp_dir.uri()));
|
let root_uri = temp_dir.uri();
|
||||||
let mut config = Config::new_with_roots([resolve_url("file:///").unwrap()]);
|
let cache = LspCache::new(Some(root_uri.join(".deno_dir").unwrap()));
|
||||||
if let Some((base_url, json_string)) = maybe_import_map {
|
let mut config = Config::new_with_roots([root_uri.clone()]);
|
||||||
let base_url = resolve_url(base_url).unwrap();
|
if let Some((relative_path, json_string)) = maybe_import_map {
|
||||||
|
let base_url = root_uri.join(relative_path).unwrap();
|
||||||
let config_file = ConfigFile::new(
|
let config_file = ConfigFile::new(
|
||||||
json_string,
|
json_string,
|
||||||
base_url,
|
base_url,
|
||||||
|
@ -1664,9 +1670,8 @@ mod tests {
|
||||||
Arc::new(LspResolver::from_config(&config, &cache, None).await);
|
Arc::new(LspResolver::from_config(&config, &cache, None).await);
|
||||||
let mut documents = Documents::default();
|
let mut documents = Documents::default();
|
||||||
documents.update_config(&config, &resolver, &cache, &Default::default());
|
documents.update_config(&config, &resolver, &cache, &Default::default());
|
||||||
for (specifier, source, version, language_id) in sources {
|
for (relative_path, source, version, language_id) in sources {
|
||||||
let specifier =
|
let specifier = root_uri.join(relative_path).unwrap();
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
|
||||||
documents.open(
|
documents.open(
|
||||||
specifier.clone(),
|
specifier.clone(),
|
||||||
*version,
|
*version,
|
||||||
|
@ -1675,20 +1680,23 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StateSnapshot {
|
(
|
||||||
project_version: 0,
|
temp_dir,
|
||||||
documents: Arc::new(documents),
|
StateSnapshot {
|
||||||
assets: Default::default(),
|
project_version: 0,
|
||||||
config: Arc::new(config),
|
documents: Arc::new(documents),
|
||||||
resolver,
|
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 snapshot = setup(
|
let (_, snapshot) = setup(
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"import * as b from "./b.ts";
|
r#"import * as b from "./b.ts";
|
||||||
let a: any = "a";
|
let a: any = "a";
|
||||||
let c: number = "a";
|
let c: number = "a";
|
||||||
|
@ -1781,23 +1789,23 @@ 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 snapshot = setup(
|
let (temp_dir, snapshot) = setup(
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
"file:///std/assert/mod.ts",
|
"std/assert/mod.ts",
|
||||||
"export function assert() {}",
|
"export function assert() {}",
|
||||||
1,
|
1,
|
||||||
LanguageId::TypeScript,
|
LanguageId::TypeScript,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"file:///a/file.ts",
|
"a/file.ts",
|
||||||
"import { assert } from \"../std/assert/mod.ts\";\n\nassert();\n",
|
"import { assert } from \"../std/assert/mod.ts\";\n\nassert();\n",
|
||||||
1,
|
1,
|
||||||
LanguageId::TypeScript,
|
LanguageId::TypeScript,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Some((
|
Some((
|
||||||
"file:///a/import-map.json",
|
"a/deno.json",
|
||||||
r#"{
|
r#"{
|
||||||
"imports": {
|
"imports": {
|
||||||
"/~/std/": "../std/"
|
"/~/std/": "../std/"
|
||||||
|
@ -1811,11 +1819,13 @@ let c: number = "a";
|
||||||
let actual = generate_deno_diagnostics(&snapshot, &config, token);
|
let actual = generate_deno_diagnostics(&snapshot, &config, token);
|
||||||
assert_eq!(actual.len(), 2);
|
assert_eq!(actual.len(), 2);
|
||||||
for record in actual {
|
for record in actual {
|
||||||
match record.specifier.as_str() {
|
let relative_specifier =
|
||||||
"file:///std/assert/mod.ts" => {
|
temp_dir.uri().make_relative(&record.specifier).unwrap();
|
||||||
|
match relative_specifier.as_str() {
|
||||||
|
"std/assert/mod.ts" => {
|
||||||
assert_eq!(json!(record.versioned.diagnostics), json!([]))
|
assert_eq!(json!(record.versioned.diagnostics), json!([]))
|
||||||
}
|
}
|
||||||
"file:///a/file.ts" => assert_eq!(
|
"a/file.ts" => assert_eq!(
|
||||||
json!(record.versioned.diagnostics),
|
json!(record.versioned.diagnostics),
|
||||||
json!([
|
json!([
|
||||||
{
|
{
|
||||||
|
@ -1917,9 +1927,9 @@ let c: number = "a";
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn duplicate_diagnostics_for_duplicate_imports() {
|
async fn duplicate_diagnostics_for_duplicate_imports() {
|
||||||
let snapshot = setup(
|
let (_, snapshot) = setup(
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
// @deno-types="bad.d.ts"
|
// @deno-types="bad.d.ts"
|
||||||
import "bad.js";
|
import "bad.js";
|
||||||
|
@ -1993,9 +2003,9 @@ 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 snapshot = setup(
|
let (temp_dir, snapshot) = setup(
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import { 東京 } from "./🦕.ts";
|
import { 東京 } from "./🦕.ts";
|
||||||
"#,
|
"#,
|
||||||
|
@ -2027,7 +2037,10 @@ let c: number = "a";
|
||||||
"severity": 1,
|
"severity": 1,
|
||||||
"code": "no-local",
|
"code": "no-local",
|
||||||
"source": "deno",
|
"source": "deno",
|
||||||
"message": "Unable to load a local module: file:///🦕.ts\nPlease check the file path.",
|
"message": format!(
|
||||||
|
"Unable to load a local module: {}🦕.ts\nPlease check the file path.",
|
||||||
|
temp_dir.uri(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,7 +24,6 @@ use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::config::Config;
|
|
||||||
use super::config::ConfigData;
|
use super::config::ConfigData;
|
||||||
use super::search::PackageSearchApi;
|
use super::search::PackageSearchApi;
|
||||||
|
|
||||||
|
@ -44,26 +43,31 @@ impl JsrCacheResolver {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
cache: Arc<dyn HttpCache>,
|
cache: Arc<dyn HttpCache>,
|
||||||
config_data: Option<&ConfigData>,
|
config_data: Option<&ConfigData>,
|
||||||
config: &Config,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let nv_by_req = DashMap::new();
|
let nv_by_req = DashMap::new();
|
||||||
let info_by_nv = DashMap::new();
|
let info_by_nv = DashMap::new();
|
||||||
let info_by_name = DashMap::new();
|
let info_by_name = DashMap::new();
|
||||||
let mut workspace_scope_by_name = HashMap::new();
|
let mut workspace_scope_by_name = HashMap::new();
|
||||||
if let Some(config_data) = config_data {
|
if let Some(config_data) = config_data {
|
||||||
let config_data_by_scope = config.tree.data_by_scope();
|
for jsr_pkg_config in config_data.workspace.jsr_packages() {
|
||||||
for member_scope in config_data.workspace_members.as_ref() {
|
let Some(exports) = &jsr_pkg_config.config_file.json.exports else {
|
||||||
let Some(member_data) = config_data_by_scope.get(member_scope) else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let Some(package_config) = member_data.package_config.as_ref() else {
|
let Some(version) = &jsr_pkg_config.config_file.json.version else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let Ok(version) = Version::parse_standard(version) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let nv = PackageNv {
|
||||||
|
name: jsr_pkg_config.name.clone(),
|
||||||
|
version: version.clone(),
|
||||||
|
};
|
||||||
info_by_name.insert(
|
info_by_name.insert(
|
||||||
package_config.nv.name.clone(),
|
nv.name.clone(),
|
||||||
Some(Arc::new(JsrPackageInfo {
|
Some(Arc::new(JsrPackageInfo {
|
||||||
versions: [(
|
versions: [(
|
||||||
package_config.nv.version.clone(),
|
nv.version.clone(),
|
||||||
JsrPackageInfoVersion { yanked: false },
|
JsrPackageInfoVersion { yanked: false },
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -71,16 +75,21 @@ impl JsrCacheResolver {
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
info_by_nv.insert(
|
info_by_nv.insert(
|
||||||
package_config.nv.clone(),
|
nv.clone(),
|
||||||
Some(Arc::new(JsrPackageVersionInfo {
|
Some(Arc::new(JsrPackageVersionInfo {
|
||||||
exports: package_config.exports.clone(),
|
exports: exports.clone(),
|
||||||
module_graph_1: None,
|
module_graph_1: None,
|
||||||
module_graph_2: None,
|
module_graph_2: None,
|
||||||
manifest: Default::default(),
|
manifest: Default::default(),
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
workspace_scope_by_name
|
workspace_scope_by_name.insert(
|
||||||
.insert(package_config.nv.name.clone(), member_scope.clone());
|
nv.name.clone(),
|
||||||
|
ModuleSpecifier::from_directory_path(
|
||||||
|
jsr_pkg_config.config_file.dir_path(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(lockfile) = config_data.and_then(|d| d.lockfile.as_ref()) {
|
if let Some(lockfile) = config_data.and_then(|d| d.lockfile.as_ref()) {
|
||||||
|
|
|
@ -89,6 +89,7 @@ use super::tsc::TsServer;
|
||||||
use super::urls;
|
use super::urls;
|
||||||
use crate::args::create_default_npmrc;
|
use crate::args::create_default_npmrc;
|
||||||
use crate::args::get_root_cert_store;
|
use crate::args::get_root_cert_store;
|
||||||
|
use crate::args::has_flag_env_var;
|
||||||
use crate::args::CaData;
|
use crate::args::CaData;
|
||||||
use crate::args::CacheSetting;
|
use crate::args::CacheSetting;
|
||||||
use crate::args::CliOptions;
|
use crate::args::CliOptions;
|
||||||
|
@ -1322,7 +1323,7 @@ impl Inner {
|
||||||
if !self
|
if !self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&specifier)
|
.fmt_config_for_specifier(&specifier)
|
||||||
.files
|
.files
|
||||||
.matches_specifier(&specifier)
|
.matches_specifier(&specifier)
|
||||||
{
|
{
|
||||||
|
@ -1352,7 +1353,7 @@ impl Inner {
|
||||||
let mut fmt_options = self
|
let mut fmt_options = self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&specifier)
|
.fmt_config_for_specifier(&specifier)
|
||||||
.options
|
.options
|
||||||
.clone();
|
.clone();
|
||||||
fmt_options.use_tabs = Some(!params.options.insert_spaces);
|
fmt_options.use_tabs = Some(!params.options.insert_spaces);
|
||||||
|
@ -1606,7 +1607,7 @@ impl Inner {
|
||||||
(&self
|
(&self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&specifier)
|
.fmt_config_for_specifier(&specifier)
|
||||||
.options)
|
.options)
|
||||||
.into(),
|
.into(),
|
||||||
tsc::UserPreferences::from_config_for_specifier(
|
tsc::UserPreferences::from_config_for_specifier(
|
||||||
|
@ -1771,7 +1772,7 @@ impl Inner {
|
||||||
(&self
|
(&self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&code_action_data.specifier)
|
.fmt_config_for_specifier(&code_action_data.specifier)
|
||||||
.options)
|
.options)
|
||||||
.into(),
|
.into(),
|
||||||
tsc::UserPreferences::from_config_for_specifier(
|
tsc::UserPreferences::from_config_for_specifier(
|
||||||
|
@ -1822,7 +1823,7 @@ impl Inner {
|
||||||
(&self
|
(&self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&action_data.specifier)
|
.fmt_config_for_specifier(&action_data.specifier)
|
||||||
.options)
|
.options)
|
||||||
.into(),
|
.into(),
|
||||||
line_index.offset_tsc(action_data.range.start)?
|
line_index.offset_tsc(action_data.range.start)?
|
||||||
|
@ -1857,7 +1858,9 @@ impl Inner {
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.data_for_specifier(file_referrer)
|
.data_for_specifier(file_referrer)
|
||||||
.and_then(|d| d.import_map.as_ref().map(|i| i.as_ref())),
|
// todo(dsherret): this should probably just take the resolver itself
|
||||||
|
// as the import map is an implementation detail
|
||||||
|
.and_then(|d| d.resolver.maybe_import_map()),
|
||||||
self.resolver.as_ref(),
|
self.resolver.as_ref(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2178,7 +2181,9 @@ impl Inner {
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.data_for_specifier(file_referrer)
|
.data_for_specifier(file_referrer)
|
||||||
.and_then(|d| d.import_map.as_ref().map(|i| i.as_ref())),
|
// todo(dsherret): this should probably just take the resolver itself
|
||||||
|
// as the import map is an implementation detail
|
||||||
|
.and_then(|d| d.resolver.maybe_import_map()),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -2213,7 +2218,7 @@ impl Inner {
|
||||||
(&self
|
(&self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&specifier)
|
.fmt_config_for_specifier(&specifier)
|
||||||
.options)
|
.options)
|
||||||
.into(),
|
.into(),
|
||||||
scope.cloned(),
|
scope.cloned(),
|
||||||
|
@ -2268,11 +2273,7 @@ impl Inner {
|
||||||
self.snapshot(),
|
self.snapshot(),
|
||||||
GetCompletionDetailsArgs {
|
GetCompletionDetailsArgs {
|
||||||
format_code_settings: Some(
|
format_code_settings: Some(
|
||||||
(&self
|
(&self.config.tree.fmt_config_for_specifier(specifier).options)
|
||||||
.config
|
|
||||||
.tree
|
|
||||||
.fmt_options_for_specifier(specifier)
|
|
||||||
.options)
|
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
preferences: Some(
|
preferences: Some(
|
||||||
|
@ -2846,7 +2847,7 @@ impl Inner {
|
||||||
let format_code_settings = (&self
|
let format_code_settings = (&self
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
.fmt_options_for_specifier(&old_specifier)
|
.fmt_config_for_specifier(&old_specifier)
|
||||||
.options)
|
.options)
|
||||||
.into();
|
.into();
|
||||||
changes.extend(
|
changes.extend(
|
||||||
|
@ -3056,7 +3057,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
|
|
||||||
let mut config_events = vec![];
|
let mut config_events = vec![];
|
||||||
for (scope_uri, config_data) in inner.config.tree.data_by_scope().iter() {
|
for (scope_uri, config_data) in inner.config.tree.data_by_scope().iter() {
|
||||||
if let Some(config_file) = &config_data.config_file {
|
if let Some(config_file) = config_data.maybe_deno_json() {
|
||||||
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri: scope_uri.clone(),
|
scope_uri: scope_uri.clone(),
|
||||||
file_uri: config_file.specifier.clone(),
|
file_uri: config_file.specifier.clone(),
|
||||||
|
@ -3064,7 +3065,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
configuration_type: lsp_custom::DenoConfigurationType::DenoJson,
|
configuration_type: lsp_custom::DenoConfigurationType::DenoJson,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(package_json) = &config_data.package_json {
|
if let Some(package_json) = config_data.maybe_pkg_json() {
|
||||||
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
config_events.push(lsp_custom::DenoConfigurationChangeEvent {
|
||||||
scope_uri: scope_uri.clone(),
|
scope_uri: scope_uri.clone(),
|
||||||
file_uri: package_json.specifier(),
|
file_uri: package_json.specifier(),
|
||||||
|
@ -3542,7 +3543,7 @@ impl Inner {
|
||||||
if let Some(npm_reqs) = self
|
if let Some(npm_reqs) = self
|
||||||
.documents
|
.documents
|
||||||
.npm_reqs_by_scope()
|
.npm_reqs_by_scope()
|
||||||
.get(&config_data.map(|d| d.scope.clone()))
|
.get(&config_data.map(|d| d.scope.as_ref().clone()))
|
||||||
{
|
{
|
||||||
roots.extend(
|
roots.extend(
|
||||||
npm_reqs
|
npm_reqs
|
||||||
|
@ -3562,12 +3563,13 @@ impl Inner {
|
||||||
]),
|
]),
|
||||||
&WorkspaceDiscoverOptions {
|
&WorkspaceDiscoverOptions {
|
||||||
fs: &DenoConfigFsAdapter::new(&deno_runtime::deno_fs::RealFs),
|
fs: &DenoConfigFsAdapter::new(&deno_runtime::deno_fs::RealFs),
|
||||||
|
deno_json_cache: None,
|
||||||
pkg_json_cache: None,
|
pkg_json_cache: None,
|
||||||
config_parse_options: deno_config::ConfigParseOptions {
|
config_parse_options: deno_config::ConfigParseOptions {
|
||||||
include_task_comments: false,
|
include_task_comments: false,
|
||||||
},
|
},
|
||||||
additional_config_file_names: &[],
|
additional_config_file_names: &[],
|
||||||
discover_pkg_json: true,
|
discover_pkg_json: !has_flag_env_var("DENO_NO_PACKAGE_JSON"),
|
||||||
maybe_vendor_override: if force_global_cache {
|
maybe_vendor_override: if force_global_cache {
|
||||||
Some(deno_config::workspace::VendorEnablement::Disable)
|
Some(deno_config::workspace::VendorEnablement::Disable)
|
||||||
} else {
|
} else {
|
||||||
|
@ -3584,10 +3586,9 @@ impl Inner {
|
||||||
.unsafely_ignore_certificate_errors
|
.unsafely_ignore_certificate_errors
|
||||||
.clone(),
|
.clone(),
|
||||||
import_map_path: config_data.and_then(|d| {
|
import_map_path: config_data.and_then(|d| {
|
||||||
if d.import_map_from_settings {
|
d.import_map_from_settings
|
||||||
return Some(d.import_map.as_ref()?.base_url().to_string());
|
.as_ref()
|
||||||
}
|
.map(|url| url.to_string())
|
||||||
None
|
|
||||||
}),
|
}),
|
||||||
node_modules_dir: Some(
|
node_modules_dir: Some(
|
||||||
config_data
|
config_data
|
||||||
|
|
|
@ -86,7 +86,6 @@ impl Default for LspScopeResolver {
|
||||||
impl LspScopeResolver {
|
impl LspScopeResolver {
|
||||||
async fn from_config_data(
|
async fn from_config_data(
|
||||||
config_data: Option<&Arc<ConfigData>>,
|
config_data: Option<&Arc<ConfigData>>,
|
||||||
config: &Config,
|
|
||||||
cache: &LspCache,
|
cache: &LspCache,
|
||||||
http_client_provider: Option<&Arc<HttpClientProvider>>,
|
http_client_provider: Option<&Arc<HttpClientProvider>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -107,18 +106,16 @@ impl LspScopeResolver {
|
||||||
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.for_specifier(config_data.map(|d| &d.scope)),
|
cache.for_specifier(config_data.map(|d| d.scope.as_ref())),
|
||||||
config_data.map(|d| d.as_ref()),
|
config_data.map(|d| d.as_ref()),
|
||||||
config,
|
|
||||||
)));
|
)));
|
||||||
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
|
let redirect_resolver = Some(Arc::new(RedirectResolver::new(
|
||||||
cache.for_specifier(config_data.map(|d| &d.scope)),
|
cache.for_specifier(config_data.map(|d| d.scope.as_ref())),
|
||||||
config_data.and_then(|d| d.lockfile.clone()),
|
config_data.and_then(|d| d.lockfile.clone()),
|
||||||
)));
|
)));
|
||||||
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
|
||||||
.and_then(|d| d.config_file.as_ref())
|
.and_then(|d| d.workspace.to_compiler_option_types().ok())
|
||||||
.and_then(|cf| cf.to_compiler_option_types().ok())
|
|
||||||
.map(|imports| {
|
.map(|imports| {
|
||||||
Arc::new(
|
Arc::new(
|
||||||
imports
|
imports
|
||||||
|
@ -188,7 +185,6 @@ impl LspResolver {
|
||||||
Arc::new(
|
Arc::new(
|
||||||
LspScopeResolver::from_config_data(
|
LspScopeResolver::from_config_data(
|
||||||
Some(config_data),
|
Some(config_data),
|
||||||
config,
|
|
||||||
cache,
|
cache,
|
||||||
http_client_provider,
|
http_client_provider,
|
||||||
)
|
)
|
||||||
|
@ -198,13 +194,8 @@ impl LspResolver {
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
unscoped: Arc::new(
|
unscoped: Arc::new(
|
||||||
LspScopeResolver::from_config_data(
|
LspScopeResolver::from_config_data(None, cache, http_client_provider)
|
||||||
None,
|
.await,
|
||||||
config,
|
|
||||||
cache,
|
|
||||||
http_client_provider,
|
|
||||||
)
|
|
||||||
.await,
|
|
||||||
),
|
),
|
||||||
by_scope,
|
by_scope,
|
||||||
}
|
}
|
||||||
|
@ -522,39 +513,28 @@ fn create_graph_resolver(
|
||||||
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
npm_resolver: Option<&Arc<dyn CliNpmResolver>>,
|
||||||
node_resolver: Option<&Arc<CliNodeResolver>>,
|
node_resolver: Option<&Arc<CliNodeResolver>>,
|
||||||
) -> Arc<CliGraphResolver> {
|
) -> Arc<CliGraphResolver> {
|
||||||
let config_file = config_data.and_then(|d| d.config_file.as_deref());
|
let workspace = config_data.map(|d| &d.workspace);
|
||||||
let unstable_sloppy_imports =
|
let unstable_sloppy_imports =
|
||||||
config_file.is_some_and(|cf| cf.has_unstable("sloppy-imports"));
|
workspace.is_some_and(|w| w.has_unstable("sloppy-imports"));
|
||||||
Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
Arc::new(CliGraphResolver::new(CliGraphResolverOptions {
|
||||||
node_resolver: node_resolver.cloned(),
|
node_resolver: node_resolver.cloned(),
|
||||||
npm_resolver: npm_resolver.cloned(),
|
npm_resolver: npm_resolver.cloned(),
|
||||||
workspace_resolver: Arc::new(WorkspaceResolver::new_raw(
|
workspace_resolver: config_data.map(|d| d.resolver.clone()).unwrap_or_else(
|
||||||
Arc::new(
|
|| {
|
||||||
config_data
|
Arc::new(WorkspaceResolver::new_raw(
|
||||||
.map(|d| d.workspace_root_dir.clone())
|
// this is fine because this is only used before initialization
|
||||||
// this is fine because this value is only used to filter bare
|
Arc::new(ModuleSpecifier::parse("file:///").unwrap()),
|
||||||
// specifier resolution to workspace npm packages when in a workspace
|
None,
|
||||||
.unwrap_or_else(|| ModuleSpecifier::parse("file:///").unwrap()),
|
Vec::new(),
|
||||||
),
|
PackageJsonDepResolution::Disabled,
|
||||||
config_data.and_then(|d| d.import_map.as_ref().map(|i| (**i).clone())),
|
))
|
||||||
config_data
|
|
||||||
.and_then(|d| d.package_json.clone())
|
|
||||||
.into_iter()
|
|
||||||
.collect(),
|
|
||||||
if config_data.map(|d| d.byonm).unwrap_or(false) {
|
|
||||||
PackageJsonDepResolution::Disabled
|
|
||||||
} else {
|
|
||||||
// todo(dsherret): this should also be disabled for when using
|
|
||||||
// auto-install with a node_modules directory
|
|
||||||
PackageJsonDepResolution::Enabled
|
|
||||||
},
|
},
|
||||||
)),
|
),
|
||||||
maybe_jsx_import_source_config: config_file
|
maybe_jsx_import_source_config: workspace
|
||||||
.and_then(|cf| cf.to_maybe_jsx_import_source_config().ok().flatten()),
|
.and_then(|cf| cf.to_maybe_jsx_import_source_config().ok().flatten()),
|
||||||
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
|
maybe_vendor_dir: config_data.and_then(|d| d.vendor_dir.as_ref()),
|
||||||
bare_node_builtins_enabled: config_file
|
bare_node_builtins_enabled: workspace
|
||||||
.map(|cf| cf.has_unstable("bare-node-builtins"))
|
.is_some_and(|cf| cf.has_unstable("bare-node-builtins")),
|
||||||
.unwrap_or(false),
|
|
||||||
sloppy_imports_resolver: unstable_sloppy_imports.then(|| {
|
sloppy_imports_resolver: unstable_sloppy_imports.then(|| {
|
||||||
SloppyImportsResolver::new_without_stat_cache(Arc::new(deno_fs::RealFs))
|
SloppyImportsResolver::new_without_stat_cache(Arc::new(deno_fs::RealFs))
|
||||||
}),
|
}),
|
||||||
|
|
182
cli/lsp/tsc.rs
182
cli/lsp/tsc.rs
|
@ -4905,7 +4905,7 @@ impl UserPreferences {
|
||||||
config: &config::Config,
|
config: &config::Config,
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let fmt_options = config.tree.fmt_options_for_specifier(specifier);
|
let fmt_options = config.tree.fmt_config_for_specifier(specifier);
|
||||||
let fmt_config = &fmt_options.options;
|
let fmt_config = &fmt_options.options;
|
||||||
let base_preferences = Self {
|
let base_preferences = Self {
|
||||||
allow_incomplete_completions: Some(true),
|
allow_incomplete_completions: Some(true),
|
||||||
|
@ -5012,8 +5012,8 @@ impl UserPreferences {
|
||||||
// Only use workspace settings for quote style if there's no `deno.json`.
|
// Only use workspace settings for quote style if there's no `deno.json`.
|
||||||
quote_preference: if config
|
quote_preference: if config
|
||||||
.tree
|
.tree
|
||||||
.config_file_for_specifier(specifier)
|
.workspace_member_ctx_for_specifier(specifier)
|
||||||
.is_some()
|
.is_some_and(|ctx| ctx.maybe_deno_json().is_some())
|
||||||
{
|
{
|
||||||
base_preferences.quote_preference
|
base_preferences.quote_preference
|
||||||
} else {
|
} else {
|
||||||
|
@ -5400,9 +5400,9 @@ mod tests {
|
||||||
async fn setup(
|
async fn setup(
|
||||||
ts_config: Value,
|
ts_config: Value,
|
||||||
sources: &[(&str, &str, i32, LanguageId)],
|
sources: &[(&str, &str, i32, LanguageId)],
|
||||||
) -> (TsServer, Arc<StateSnapshot>, LspCache) {
|
) -> (TempDir, TsServer, Arc<StateSnapshot>, LspCache) {
|
||||||
let temp_dir = TempDir::new();
|
let temp_dir = TempDir::new();
|
||||||
let cache = LspCache::new(Some(temp_dir.uri()));
|
let cache = LspCache::new(Some(temp_dir.uri().join(".deno_dir").unwrap()));
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
config
|
config
|
||||||
.tree
|
.tree
|
||||||
|
@ -5412,7 +5412,7 @@ mod tests {
|
||||||
"compilerOptions": ts_config,
|
"compilerOptions": ts_config,
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
resolve_url("file:///deno.json").unwrap(),
|
temp_dir.uri().join("deno.json").unwrap(),
|
||||||
&deno_config::ConfigParseOptions::default(),
|
&deno_config::ConfigParseOptions::default(),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -5422,16 +5422,9 @@ mod tests {
|
||||||
Arc::new(LspResolver::from_config(&config, &cache, None).await);
|
Arc::new(LspResolver::from_config(&config, &cache, None).await);
|
||||||
let mut documents = Documents::default();
|
let mut documents = Documents::default();
|
||||||
documents.update_config(&config, &resolver, &cache, &Default::default());
|
documents.update_config(&config, &resolver, &cache, &Default::default());
|
||||||
for (specifier, source, version, language_id) in sources {
|
for (relative_specifier, source, version, language_id) in sources {
|
||||||
let specifier =
|
let specifier = temp_dir.uri().join(relative_specifier).unwrap();
|
||||||
resolve_url(specifier).expect("failed to create specifier");
|
documents.open(specifier, *version, *language_id, (*source).into(), None);
|
||||||
documents.open(
|
|
||||||
specifier.clone(),
|
|
||||||
*version,
|
|
||||||
*language_id,
|
|
||||||
(*source).into(),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let snapshot = Arc::new(StateSnapshot {
|
let snapshot = Arc::new(StateSnapshot {
|
||||||
project_version: 0,
|
project_version: 0,
|
||||||
|
@ -5456,7 +5449,7 @@ mod tests {
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
(ts_server, snapshot, cache)
|
(temp_dir, ts_server, snapshot, cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_op_state(state_snapshot: Arc<StateSnapshot>) -> OpState {
|
fn setup_op_state(state_snapshot: Arc<StateSnapshot>) -> OpState {
|
||||||
|
@ -5485,7 +5478,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_diagnostics() {
|
async fn test_get_diagnostics() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5493,22 +5486,22 @@ mod tests {
|
||||||
"lib": [],
|
"lib": [],
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"console.log("hello deno");"#,
|
r#"console.log("hello deno");"#,
|
||||||
1,
|
1,
|
||||||
LanguageId::TypeScript,
|
LanguageId::TypeScript,
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": [
|
specifier.clone(): [
|
||||||
{
|
{
|
||||||
"start": {
|
"start": {
|
||||||
"line": 0,
|
"line": 0,
|
||||||
|
@ -5518,7 +5511,7 @@ mod tests {
|
||||||
"line": 0,
|
"line": 0,
|
||||||
"character": 7
|
"character": 7
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier,
|
||||||
"messageText": "Cannot find name 'console'. Do you need to change your target library? Try changing the \'lib\' compiler option to include 'dom'.",
|
"messageText": "Cannot find name 'console'. Do you need to change your target library? Try changing the \'lib\' compiler option to include 'dom'.",
|
||||||
"sourceLine": "console.log(\"hello deno\");",
|
"sourceLine": "console.log(\"hello deno\");",
|
||||||
"category": 1,
|
"category": 1,
|
||||||
|
@ -5531,7 +5524,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_diagnostics_lib() {
|
async fn test_get_diagnostics_lib() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5540,24 +5533,24 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"console.log(document.location);"#,
|
r#"console.log(document.location);"#,
|
||||||
1,
|
1,
|
||||||
LanguageId::TypeScript,
|
LanguageId::TypeScript,
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
|
assert_eq!(json!(diagnostics), json!({ specifier: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_module_resolution() {
|
async fn test_module_resolution() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5565,7 +5558,7 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import { B } from "https://deno.land/x/b/mod.ts";
|
import { B } from "https://deno.land/x/b/mod.ts";
|
||||||
|
|
||||||
|
@ -5578,17 +5571,17 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
|
assert_eq!(json!(diagnostics), json!({ specifier: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_bad_module_specifiers() {
|
async fn test_bad_module_specifiers() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5596,7 +5589,7 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import { A } from ".";
|
import { A } from ".";
|
||||||
"#,
|
"#,
|
||||||
|
@ -5605,15 +5598,15 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": [{
|
specifier.clone(): [{
|
||||||
"start": {
|
"start": {
|
||||||
"line": 1,
|
"line": 1,
|
||||||
"character": 8
|
"character": 8
|
||||||
|
@ -5622,7 +5615,7 @@ mod tests {
|
||||||
"line": 1,
|
"line": 1,
|
||||||
"character": 30
|
"character": 30
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier,
|
||||||
"messageText": "\'A\' is declared but its value is never read.",
|
"messageText": "\'A\' is declared but its value is never read.",
|
||||||
"sourceLine": " import { A } from \".\";",
|
"sourceLine": " import { A } from \".\";",
|
||||||
"category": 2,
|
"category": 2,
|
||||||
|
@ -5634,7 +5627,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_remote_modules() {
|
async fn test_remote_modules() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5642,7 +5635,7 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import { B } from "https://deno.land/x/b/mod.ts";
|
import { B } from "https://deno.land/x/b/mod.ts";
|
||||||
|
|
||||||
|
@ -5655,17 +5648,17 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] }));
|
assert_eq!(json!(diagnostics), json!({ specifier: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_partial_modules() {
|
async fn test_partial_modules() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5673,7 +5666,7 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import {
|
import {
|
||||||
Application,
|
Application,
|
||||||
|
@ -5689,15 +5682,15 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": [{
|
specifier.clone(): [{
|
||||||
"start": {
|
"start": {
|
||||||
"line": 1,
|
"line": 1,
|
||||||
"character": 8
|
"character": 8
|
||||||
|
@ -5706,7 +5699,7 @@ mod tests {
|
||||||
"line": 6,
|
"line": 6,
|
||||||
"character": 55,
|
"character": 55,
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier.clone(),
|
||||||
"messageText": "All imports in import declaration are unused.",
|
"messageText": "All imports in import declaration are unused.",
|
||||||
"sourceLine": " import {",
|
"sourceLine": " import {",
|
||||||
"category": 2,
|
"category": 2,
|
||||||
|
@ -5720,7 +5713,7 @@ mod tests {
|
||||||
"line": 8,
|
"line": 8,
|
||||||
"character": 29
|
"character": 29
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier,
|
||||||
"messageText": "Expression expected.",
|
"messageText": "Expression expected.",
|
||||||
"sourceLine": " import * as test from",
|
"sourceLine": " import * as test from",
|
||||||
"category": 1,
|
"category": 1,
|
||||||
|
@ -5732,7 +5725,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_no_debug_failure() {
|
async fn test_no_debug_failure() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5740,22 +5733,22 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"const url = new URL("b.js", import."#,
|
r#"const url = new URL("b.js", import."#,
|
||||||
1,
|
1,
|
||||||
LanguageId::TypeScript,
|
LanguageId::TypeScript,
|
||||||
)],
|
)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot, vec![specifier], Default::default())
|
.get_diagnostics(snapshot, vec![specifier.clone()], Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": [
|
specifier.clone(): [
|
||||||
{
|
{
|
||||||
"start": {
|
"start": {
|
||||||
"line": 0,
|
"line": 0,
|
||||||
|
@ -5765,7 +5758,7 @@ mod tests {
|
||||||
"line": 0,
|
"line": 0,
|
||||||
"character": 35
|
"character": 35
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier,
|
||||||
"messageText": "Identifier expected.",
|
"messageText": "Identifier expected.",
|
||||||
"sourceLine": "const url = new URL(\"b.js\", import.",
|
"sourceLine": "const url = new URL(\"b.js\", import.",
|
||||||
"category": 1,
|
"category": 1,
|
||||||
|
@ -5778,7 +5771,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_request_assets() {
|
async fn test_request_assets() {
|
||||||
let (ts_server, snapshot, _) = setup(json!({}), &[]).await;
|
let (_, ts_server, snapshot, _) = setup(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()
|
||||||
|
@ -5810,7 +5803,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_modify_sources() {
|
async fn test_modify_sources() {
|
||||||
let (ts_server, snapshot, cache) = setup(
|
let (temp_dir, ts_server, snapshot, cache) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -5818,7 +5811,7 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[(
|
&[(
|
||||||
"file:///a.ts",
|
"a.ts",
|
||||||
r#"
|
r#"
|
||||||
import * as a from "https://deno.land/x/example/a.ts";
|
import * as a from "https://deno.land/x/example/a.ts";
|
||||||
if (a.a === "b") {
|
if (a.a === "b") {
|
||||||
|
@ -5840,15 +5833,19 @@ mod tests {
|
||||||
b"export const b = \"b\";\n",
|
b"export const b = \"b\";\n",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let specifier = resolve_url("file:///a.ts").unwrap();
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot.clone(), vec![specifier], Default::default())
|
.get_diagnostics(
|
||||||
|
snapshot.clone(),
|
||||||
|
vec![specifier.clone()],
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": [
|
specifier.clone(): [
|
||||||
{
|
{
|
||||||
"start": {
|
"start": {
|
||||||
"line": 2,
|
"line": 2,
|
||||||
|
@ -5858,7 +5855,7 @@ mod tests {
|
||||||
"line": 2,
|
"line": 2,
|
||||||
"character": 17
|
"character": 17
|
||||||
},
|
},
|
||||||
"fileName": "file:///a.ts",
|
"fileName": specifier,
|
||||||
"messageText": "Property \'a\' does not exist on type \'typeof import(\"https://deno.land/x/example/a\")\'.",
|
"messageText": "Property \'a\' does not exist on type \'typeof import(\"https://deno.land/x/example/a\")\'.",
|
||||||
"sourceLine": " if (a.a === \"b\") {",
|
"sourceLine": " if (a.a === \"b\") {",
|
||||||
"code": 2339,
|
"code": 2339,
|
||||||
|
@ -5886,15 +5883,19 @@ mod tests {
|
||||||
[(&specifier_dep, ChangeKind::Opened)],
|
[(&specifier_dep, ChangeKind::Opened)],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let specifier = resolve_url("file:///a.ts").unwrap();
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let diagnostics = ts_server
|
let diagnostics = ts_server
|
||||||
.get_diagnostics(snapshot.clone(), vec![specifier], Default::default())
|
.get_diagnostics(
|
||||||
|
snapshot.clone(),
|
||||||
|
vec![specifier.clone()],
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json!(diagnostics),
|
json!(diagnostics),
|
||||||
json!({
|
json!({
|
||||||
"file:///a.ts": []
|
specifier: []
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5944,17 +5945,17 @@ mod tests {
|
||||||
character: 16,
|
character: 16,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"lib": ["deno.ns", "deno.window"],
|
"lib": ["deno.ns", "deno.window"],
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[("file:///a.ts", fixture, 1, LanguageId::TypeScript)],
|
&[("a.ts", fixture, 1, LanguageId::TypeScript)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let info = ts_server
|
let info = ts_server
|
||||||
.get_completions(
|
.get_completions(
|
||||||
snapshot.clone(),
|
snapshot.clone(),
|
||||||
|
@ -5969,7 +5970,7 @@ mod tests {
|
||||||
trigger_kind: None,
|
trigger_kind: None,
|
||||||
},
|
},
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Some(ModuleSpecifier::parse("file:///").unwrap()),
|
Some(temp_dir.uri()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -5986,7 +5987,7 @@ mod tests {
|
||||||
preferences: None,
|
preferences: None,
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
Some(ModuleSpecifier::parse("file:///").unwrap()),
|
Some(temp_dir.uri()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -6095,7 +6096,7 @@ mod tests {
|
||||||
character: 33,
|
character: 33,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -6103,12 +6104,12 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[
|
&[
|
||||||
("file:///a.ts", fixture_a, 1, LanguageId::TypeScript),
|
("a.ts", fixture_a, 1, LanguageId::TypeScript),
|
||||||
("file:///b.ts", fixture_b, 1, LanguageId::TypeScript),
|
("b.ts", fixture_b, 1, LanguageId::TypeScript),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
let specifier = temp_dir.uri().join("a.ts").unwrap();
|
||||||
let fmt_options_config = FmtOptionsConfig {
|
let fmt_options_config = FmtOptionsConfig {
|
||||||
semi_colons: Some(false),
|
semi_colons: Some(false),
|
||||||
single_quote: Some(true),
|
single_quote: Some(true),
|
||||||
|
@ -6129,7 +6130,7 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
FormatCodeSettings::from(&fmt_options_config),
|
FormatCodeSettings::from(&fmt_options_config),
|
||||||
Some(ModuleSpecifier::parse("file:///").unwrap()),
|
Some(temp_dir.uri()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -6155,7 +6156,7 @@ mod tests {
|
||||||
}),
|
}),
|
||||||
data: entry.data.clone(),
|
data: entry.data.clone(),
|
||||||
},
|
},
|
||||||
Some(ModuleSpecifier::parse("file:///").unwrap()),
|
Some(temp_dir.uri()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -6204,7 +6205,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_edits_for_file_rename() {
|
async fn test_get_edits_for_file_rename() {
|
||||||
let (ts_server, snapshot, _) = setup(
|
let (temp_dir, ts_server, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
@ -6212,21 +6213,16 @@ mod tests {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[
|
&[
|
||||||
(
|
("a.ts", r#"import "./b.ts";"#, 1, LanguageId::TypeScript),
|
||||||
"file:///a.ts",
|
("b.ts", r#""#, 1, LanguageId::TypeScript),
|
||||||
r#"import "./b.ts";"#,
|
|
||||||
1,
|
|
||||||
LanguageId::TypeScript,
|
|
||||||
),
|
|
||||||
("file:///b.ts", r#""#, 1, LanguageId::TypeScript),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let changes = ts_server
|
let changes = ts_server
|
||||||
.get_edits_for_file_rename(
|
.get_edits_for_file_rename(
|
||||||
snapshot,
|
snapshot,
|
||||||
resolve_url("file:///b.ts").unwrap(),
|
temp_dir.uri().join("b.ts").unwrap(),
|
||||||
resolve_url("file:///🦕.ts").unwrap(),
|
temp_dir.uri().join("🦕.ts").unwrap(),
|
||||||
FormatCodeSettings::default(),
|
FormatCodeSettings::default(),
|
||||||
UserPreferences::default(),
|
UserPreferences::default(),
|
||||||
)
|
)
|
||||||
|
@ -6235,7 +6231,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
changes,
|
changes,
|
||||||
vec![FileTextChanges {
|
vec![FileTextChanges {
|
||||||
file_name: "file:///a.ts".to_string(),
|
file_name: temp_dir.uri().join("a.ts").unwrap().to_string(),
|
||||||
text_changes: vec![TextChange {
|
text_changes: vec![TextChange {
|
||||||
span: TextSpan {
|
span: TextSpan {
|
||||||
start: 8,
|
start: 8,
|
||||||
|
@ -6280,21 +6276,21 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn resolve_unknown_dependency() {
|
async fn resolve_unknown_dependency() {
|
||||||
let (_, snapshot, _) = setup(
|
let (temp_dir, _, snapshot, _) = setup(
|
||||||
json!({
|
json!({
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"lib": ["deno.ns", "deno.window"],
|
"lib": ["deno.ns", "deno.window"],
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
}),
|
}),
|
||||||
&[("file:///a.ts", "", 1, LanguageId::TypeScript)],
|
&[("a.ts", "", 1, LanguageId::TypeScript)],
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let mut state = setup_op_state(snapshot);
|
let mut state = setup_op_state(snapshot);
|
||||||
let resolved = op_resolve_inner(
|
let resolved = op_resolve_inner(
|
||||||
&mut state,
|
&mut state,
|
||||||
ResolveArgs {
|
ResolveArgs {
|
||||||
base: "file:///a.ts".to_string(),
|
base: temp_dir.uri().join("a.ts").unwrap().to_string(),
|
||||||
is_base_cjs: false,
|
is_base_cjs: false,
|
||||||
specifiers: vec!["./b.ts".to_string()],
|
specifiers: vec!["./b.ts".to_string()],
|
||||||
},
|
},
|
||||||
|
@ -6303,7 +6299,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
vec![Some((
|
vec![Some((
|
||||||
"file:///b.ts".to_string(),
|
temp_dir.uri().join("b.ts").unwrap().to_string(),
|
||||||
MediaType::TypeScript.as_ts_extension().to_string()
|
MediaType::TypeScript.as_ts_extension().to_string()
|
||||||
))]
|
))]
|
||||||
);
|
);
|
||||||
|
|
|
@ -11917,6 +11917,11 @@ fn lsp_node_modules_dir() {
|
||||||
|
|
||||||
assert!(!temp_dir.path().join("node_modules").exists());
|
assert!(!temp_dir.path().join("node_modules").exists());
|
||||||
|
|
||||||
|
// a lockfile will be created here because someone did an explicit cache
|
||||||
|
let lockfile_path = temp_dir.path().join("deno.lock");
|
||||||
|
assert!(lockfile_path.exists());
|
||||||
|
lockfile_path.remove_file();
|
||||||
|
|
||||||
temp_dir.write(
|
temp_dir.write(
|
||||||
temp_dir.path().join("deno.json"),
|
temp_dir.path().join("deno.json"),
|
||||||
"{ \"nodeModulesDir\": true, \"lock\": false }\n",
|
"{ \"nodeModulesDir\": true, \"lock\": false }\n",
|
||||||
|
@ -11950,7 +11955,7 @@ fn lsp_node_modules_dir() {
|
||||||
|
|
||||||
assert!(temp_dir.path().join("node_modules/chalk").exists());
|
assert!(temp_dir.path().join("node_modules/chalk").exists());
|
||||||
assert!(temp_dir.path().join("node_modules/@types/node").exists());
|
assert!(temp_dir.path().join("node_modules/@types/node").exists());
|
||||||
assert!(!temp_dir.path().join("deno.lock").exists());
|
assert!(!lockfile_path.exists()); // was disabled
|
||||||
|
|
||||||
// now add a lockfile and cache
|
// now add a lockfile and cache
|
||||||
temp_dir.write(
|
temp_dir.write(
|
||||||
|
@ -11963,7 +11968,7 @@ fn lsp_node_modules_dir() {
|
||||||
let diagnostics = client.read_diagnostics();
|
let diagnostics = client.read_diagnostics();
|
||||||
assert_eq!(diagnostics.all().len(), 0, "{:#?}", diagnostics);
|
assert_eq!(diagnostics.all().len(), 0, "{:#?}", diagnostics);
|
||||||
|
|
||||||
assert!(temp_dir.path().join("deno.lock").exists());
|
assert!(lockfile_path.exists());
|
||||||
|
|
||||||
// the declaration should be found in the node_modules directory
|
// the declaration should be found in the node_modules directory
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
|
@ -13315,9 +13320,9 @@ fn lsp_deno_json_workspace_fmt_config() {
|
||||||
json!([{
|
json!([{
|
||||||
"range": {
|
"range": {
|
||||||
"start": { "line": 0, "character": 12 },
|
"start": { "line": 0, "character": 12 },
|
||||||
"end": { "line": 0, "character": 14 },
|
"end": { "line": 0, "character": 16 },
|
||||||
},
|
},
|
||||||
"newText": "''",
|
"newText": "'')",
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
// `project2/file.ts` should use the fmt settings from `deno.json`, since it
|
// `project2/file.ts` should use the fmt settings from `deno.json`, since it
|
||||||
|
@ -13449,6 +13454,15 @@ fn lsp_deno_json_workspace_lint_config() {
|
||||||
"code": "ban-untagged-todo",
|
"code": "ban-untagged-todo",
|
||||||
"source": "deno-lint",
|
"source": "deno-lint",
|
||||||
"message": "TODO should be tagged with (@username) or (#issue)\nAdd a user tag or issue reference to the TODO comment, e.g. TODO(@djones), TODO(djones), TODO(#123)",
|
"message": "TODO should be tagged with (@username) or (#issue)\nAdd a user tag or issue reference to the TODO comment, e.g. TODO(@djones), TODO(djones), TODO(#123)",
|
||||||
|
}, {
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 2, "character": 14 },
|
||||||
|
"end": { "line": 2, "character": 28 },
|
||||||
|
},
|
||||||
|
"severity": 2,
|
||||||
|
"code": "camelcase",
|
||||||
|
"source": "deno-lint",
|
||||||
|
"message": "Identifier 'snake_case_var' is not in camel case.\nConsider renaming `snake_case_var` to `snakeCaseVar`",
|
||||||
}],
|
}],
|
||||||
"version": 1,
|
"version": 1,
|
||||||
})
|
})
|
||||||
|
@ -13513,8 +13527,8 @@ fn lsp_deno_json_workspace_import_map() {
|
||||||
temp_dir.write("project1/foo1.ts", "");
|
temp_dir.write("project1/foo1.ts", "");
|
||||||
temp_dir.write(
|
temp_dir.write(
|
||||||
"project1/project2/deno.json",
|
"project1/project2/deno.json",
|
||||||
// Should ignore and inherit import map from `project1/deno.json`.
|
|
||||||
json!({
|
json!({
|
||||||
|
// should overwrite the "foo" entry in the parent for this scope
|
||||||
"imports": {
|
"imports": {
|
||||||
"foo": "./foo2.ts",
|
"foo": "./foo2.ts",
|
||||||
},
|
},
|
||||||
|
@ -13524,36 +13538,74 @@ fn lsp_deno_json_workspace_import_map() {
|
||||||
temp_dir.write("project1/project2/foo2.ts", "");
|
temp_dir.write("project1/project2/foo2.ts", "");
|
||||||
let mut client = context.new_lsp_command().build();
|
let mut client = context.new_lsp_command().build();
|
||||||
client.initialize_default();
|
client.initialize_default();
|
||||||
client.did_open(json!({
|
|
||||||
"textDocument": {
|
// project1 resolution
|
||||||
"uri": temp_dir.uri().join("project1/project2/file.ts").unwrap(),
|
{
|
||||||
"languageId": "typescript",
|
client.did_open(json!({
|
||||||
"version": 1,
|
"textDocument": {
|
||||||
"text": "import \"foo\";\n",
|
"uri": temp_dir.uri().join("project1/file.ts").unwrap(),
|
||||||
},
|
"languageId": "typescript",
|
||||||
}));
|
"version": 1,
|
||||||
let res = client.write_request(
|
"text": "import \"foo\";\n",
|
||||||
"textDocument/hover",
|
},
|
||||||
json!({
|
}));
|
||||||
|
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 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// project1/project2 resolution
|
||||||
|
{
|
||||||
|
client.did_open(json!({
|
||||||
"textDocument": {
|
"textDocument": {
|
||||||
"uri": temp_dir.uri().join("project1/project2/file.ts").unwrap(),
|
"uri": temp_dir.uri().join("project1/project2/file.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import \"foo\";\n",
|
||||||
},
|
},
|
||||||
"position": { "line": 0, "character": 7 },
|
}));
|
||||||
}),
|
let res = client.write_request(
|
||||||
);
|
"textDocument/hover",
|
||||||
assert_eq!(
|
json!({
|
||||||
res,
|
"textDocument": {
|
||||||
json!({
|
"uri": temp_dir.uri().join("project1/project2/file.ts").unwrap(),
|
||||||
"contents": {
|
},
|
||||||
"kind": "markdown",
|
"position": { "line": 0, "character": 7 },
|
||||||
"value": format!("**Resolved Dependency**\n\n**Code**: file​{}\n", temp_dir.uri().join("project1/foo1.ts").unwrap().as_str().trim_start_matches("file")),
|
}),
|
||||||
},
|
);
|
||||||
"range": {
|
assert_eq!(
|
||||||
"start": { "line": 0, "character": 7 },
|
res,
|
||||||
"end": { "line": 0, "character": 12 },
|
json!({
|
||||||
},
|
"contents": {
|
||||||
})
|
"kind": "markdown",
|
||||||
);
|
"value": format!("**Resolved Dependency**\n\n**Code**: file​{}\n", temp_dir.uri().join("project1/project2/foo2.ts").unwrap().as_str().trim_start_matches("file")),
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"start": { "line": 0, "character": 7 },
|
||||||
|
"end": { "line": 0, "character": 12 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13827,6 +13879,101 @@ fn lsp_deno_json_workspace_jsr_resolution() {
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_npm_workspace() {
|
||||||
|
let context = TestContextBuilder::new()
|
||||||
|
.use_http_server()
|
||||||
|
.use_temp_cwd()
|
||||||
|
.build();
|
||||||
|
let temp_dir = context.temp_dir();
|
||||||
|
temp_dir.write(
|
||||||
|
"package.json",
|
||||||
|
json!({
|
||||||
|
"workspaces": ["packages/*"]
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
{
|
||||||
|
temp_dir.create_dir_all("packages/add");
|
||||||
|
temp_dir.write(
|
||||||
|
"packages/add/package.json",
|
||||||
|
json!({
|
||||||
|
"name": "add",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"exports": "./index.ts"
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
temp_dir.write(
|
||||||
|
"packages/add/index.ts",
|
||||||
|
"export function add(a: number, b: number): number { return a + b; }",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
temp_dir.create_dir_all("packages/subtract");
|
||||||
|
temp_dir.write(
|
||||||
|
"packages/subtract/package.json",
|
||||||
|
json!({
|
||||||
|
"name": "add",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"exports": "./index.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"add": "^1.0.0"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
client.initialize_default();
|
||||||
|
let diagnostics = client.did_open(json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("packages/subtract/index.ts").unwrap(),
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import { add } from 'add';\nexport function subtract(a: number, b: number): number { return add(a, -b); }",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
assert_eq!(json!(diagnostics.all()), json!([]));
|
||||||
|
let res = client.write_request(
|
||||||
|
"textDocument/definition",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": temp_dir.uri().join("packages/subtract/index.ts").unwrap(),
|
||||||
|
},
|
||||||
|
"position": { "line": 0, "character": 9 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// The temp dir is symlinked on the CI
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
json!([{
|
||||||
|
"targetUri": temp_dir.uri().join("packages/add/index.ts").unwrap(),
|
||||||
|
"targetRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 0,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 67,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"targetSelectionRange": {
|
||||||
|
"start": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 16,
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 0,
|
||||||
|
"character": 19,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]),
|
||||||
|
);
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_import_unstable_bare_node_builtins_auto_discovered() {
|
fn lsp_import_unstable_bare_node_builtins_auto_discovered() {
|
||||||
let context = TestContextBuilder::new().use_temp_cwd().build();
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
|
Loading…
Reference in a new issue