summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-05-03 16:44:41 -0400
committerGitHub <noreply@github.com>2024-05-03 16:44:41 -0400
commit121769844d4456b296e42d60794813da1b1472eb (patch)
treec8eeb93abfb0642f4d4ef17977b7039f10561dd5
parent1fce59281c38c83c937c01ff92f8656da44ccada (diff)
fix(lsp): always cache all npm packages (#23679)
Closes #23659
-rw-r--r--cli/lsp/language_server.rs22
-rw-r--r--tests/integration/lsp_tests.rs71
-rwxr-xr-xtools/lint.js2
3 files changed, 87 insertions, 8 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index ff0fa296e..01c9ac02f 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -279,9 +279,9 @@ impl LanguageServer {
Ok(())
}
- // do as much as possible in a read, then do a write outside
+ // prepare the cache inside the lock
let maybe_prepare_cache_result = {
- let inner = self.0.read().await; // ensure dropped
+ let mut inner = self.0.write().await; // ensure dropped
match inner.prepare_cache(specifiers, referrer, force_global_cache) {
Ok(maybe_cache_result) => maybe_cache_result,
Err(err) => {
@@ -297,6 +297,7 @@ impl LanguageServer {
}
};
if let Some(result) = maybe_prepare_cache_result {
+ // cache outside the lock
let cli_options = result.cli_options;
let roots = result.roots;
let open_docs = result.open_docs;
@@ -312,6 +313,8 @@ impl LanguageServer {
.client
.show_message(MessageType::WARNING, err);
}
+
+ // now get the lock back to update with the new information
let mut inner = self.0.write().await;
let lockfile = inner.config.tree.root_lockfile().cloned();
inner.documents.refresh_lockfile(lockfile);
@@ -3280,7 +3283,7 @@ struct PrepareCacheResult {
// These are implementations of custom commands supported by the LSP
impl Inner {
fn prepare_cache(
- &self,
+ &mut self,
specifiers: Vec<ModuleSpecifier>,
referrer: ModuleSpecifier,
force_global_cache: bool,
@@ -3289,11 +3292,22 @@ impl Inner {
.performance
.mark_with_args("lsp.cache", (&specifiers, &referrer));
let config_data = self.config.tree.root_data();
- let roots = if !specifiers.is_empty() {
+ let mut roots = if !specifiers.is_empty() {
specifiers
} else {
vec![referrer.clone()]
};
+
+ // always include the npm packages since resolution of one npm package
+ // might affect the resolution of other npm packages
+ roots.extend(
+ self
+ .documents
+ .npm_package_reqs()
+ .iter()
+ .map(|req| ModuleSpecifier::parse(&format!("npm:{}", req)).unwrap()),
+ );
+
let workspace_settings = self.config.workspace_settings();
let cli_options = CliOptions::new(
Flags {
diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs
index faec27e1c..7bac0192d 100644
--- a/tests/integration/lsp_tests.rs
+++ b/tests/integration/lsp_tests.rs
@@ -5391,7 +5391,8 @@ fn lsp_code_actions_deno_cache_all() {
let res =
client
- .write_request( "textDocument/codeAction",
+ .write_request(
+ "textDocument/codeAction",
json!({
"textDocument": {
"uri": "file:///a/file.ts",
@@ -5417,8 +5418,7 @@ fn lsp_code_actions_deno_cache_all() {
"only": ["quickfix"],
}
}),
- )
- ;
+ );
assert_eq!(
res,
json!([
@@ -7079,6 +7079,71 @@ fn lsp_npm_completions_auto_import_and_quick_fix_no_import_map() {
}
#[test]
+fn lsp_npm_always_caches() {
+ // npm specifiers should always be cached even when not specified
+ // because they affect the resolution of each other
+ let context = TestContextBuilder::new()
+ .use_http_server()
+ .use_temp_cwd()
+ .build();
+ let temp_dir_path = context.temp_dir().path();
+
+ // this file should be auto-discovered by the lsp
+ let not_opened_file = temp_dir_path.join("not_opened.ts");
+ not_opened_file.write("import chalk from 'npm:chalk@5.0';\n");
+
+ // create the lsp and cache a different npm specifier
+ let mut client = context.new_lsp_command().build();
+ client.initialize_default();
+ let opened_file_uri = temp_dir_path.join("file.ts").uri_file();
+ client.did_open(
+ json!({
+ "textDocument": {
+ "uri": opened_file_uri,
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import {getClient} from 'npm:@denotest/types-exports-subpaths@1/client';\n",
+ }
+ }),
+ );
+ client.write_request(
+ "workspace/executeCommand",
+ json!({
+ "command": "deno.cache",
+ "arguments": [
+ ["npm:@denotest/types-exports-subpaths@1/client"],
+ opened_file_uri,
+ ],
+ }),
+ );
+
+ // now open a new file and chalk should be working
+ let new_file_uri = temp_dir_path.join("new_file.ts").uri_file();
+ client.did_open(json!({
+ "textDocument": {
+ "uri": new_file_uri,
+ "languageId": "typescript",
+ "version": 1,
+ "text": "import chalk from 'npm:chalk@5.0';\nchalk.",
+ }
+ }));
+
+ let list = client.get_completion_list(
+ new_file_uri,
+ (1, 6),
+ json!({
+ "triggerKind": 2,
+ "triggerCharacter": "."
+ }),
+ );
+ assert!(!list.is_incomplete);
+ assert!(list.items.iter().any(|i| i.label == "green"));
+ assert!(list.items.iter().any(|i| i.label == "red"));
+
+ client.shutdown();
+}
+
+#[test]
fn lsp_semantic_tokens_for_disabled_module() {
let context = TestContextBuilder::new()
.use_http_server()
diff --git a/tools/lint.js b/tools/lint.js
index 38077273c..36e79b45b 100755
--- a/tools/lint.js
+++ b/tools/lint.js
@@ -51,7 +51,7 @@ async function dlint() {
":!:cli/bench/testdata/react-dom.js",
":!:cli/compilers/wasm_wrap.js",
":!:cli/tsc/dts/**",
- ":!:target/**",
+ ":!:target/",
":!:tests/specs/**",
":!:tests/testdata/encoding/**",
":!:tests/testdata/error_syntax.js",