diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2024-02-29 03:54:16 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-29 03:54:16 +0000 |
commit | 3a43568481108545178f5dd2f928d40736dc987a (patch) | |
tree | 5c9deec7135b5c9ace35aa2c13b238b3fdb53bb1 /cli/lsp/completions.rs | |
parent | 814eb420608b21d3d79d3580317d2e803d240589 (diff) |
feat(lsp): jsr specifier completions (#22612)
Diffstat (limited to 'cli/lsp/completions.rs')
-rw-r--r-- | cli/lsp/completions.rs | 639 |
1 files changed, 524 insertions, 115 deletions
diff --git a/cli/lsp/completions.rs b/cli/lsp/completions.rs index 7fe161039..074d913c5 100644 --- a/cli/lsp/completions.rs +++ b/cli/lsp/completions.rs @@ -5,10 +5,12 @@ use super::config::ConfigSnapshot; use super::config::WorkspaceSettings; use super::documents::Documents; use super::documents::DocumentsFilter; +use super::jsr::CliJsrSearchApi; +use super::jsr::JsrResolver; use super::lsp_custom; use super::npm::CliNpmSearchApi; -use super::npm::NpmSearchApi; use super::registries::ModuleRegistry; +use super::search::PackageSearchApi; use super::tsc; use crate::util::path::is_importable_ext; @@ -25,6 +27,8 @@ use deno_core::serde::Serialize; use deno_core::serde_json::json; use deno_core::url::Position; use deno_core::ModuleSpecifier; +use deno_semver::jsr::JsrPackageReqReference; +use deno_semver::package::PackageNv; use import_map::ImportMap; use once_cell::sync::Lazy; use regex::Regex; @@ -148,6 +152,7 @@ pub async fn get_import_completions( config: &ConfigSnapshot, client: &Client, module_registries: &ModuleRegistry, + jsr_search_api: &CliJsrSearchApi, npm_search_api: &CliNpmSearchApi, documents: &Documents, maybe_import_map: Option<Arc<ImportMap>>, @@ -170,6 +175,19 @@ pub async fn get_import_completions( is_incomplete: false, items: get_local_completions(specifier, &text, &range)?, })) + } else if text.starts_with("jsr:") { + let items = get_jsr_completions( + specifier, + &text, + &range, + jsr_search_api, + jsr_search_api.get_resolver(), + ) + .await?; + Some(lsp::CompletionResponse::List(lsp::CompletionList { + is_incomplete: !items.is_empty(), + items, + })) } else if text.starts_with("npm:") { let items = get_npm_completions(specifier, &text, &range, npm_search_api).await?; @@ -475,8 +493,7 @@ fn get_relative_specifiers( } /// Find the index of the '@' delimiting the package name and version, if any. -fn parse_npm_specifier_version_index(specifier: &str) -> Option<usize> { - let bare_specifier = specifier.strip_prefix("npm:")?; +fn parse_bare_specifier_version_index(bare_specifier: &str) -> Option<usize> { if bare_specifier.starts_with('@') { bare_specifier .find('/') @@ -486,49 +503,188 @@ fn parse_npm_specifier_version_index(specifier: &str) -> Option<usize> { .find('@') .filter(|idx2| !bare_specifier[idx..][1..*idx2].is_empty()) .filter(|idx2| !bare_specifier[idx..][1..*idx2].contains('/')) - .map(|idx2| 4 + idx + idx2) + .map(|idx2| idx + idx2) }) } else { bare_specifier .find('@') .filter(|idx| !bare_specifier[1..*idx].is_empty()) .filter(|idx| !bare_specifier[1..*idx].contains('/')) - .map(|idx| 4 + idx) } } +async fn get_jsr_completions( + referrer: &ModuleSpecifier, + specifier: &str, + range: &lsp::Range, + jsr_search_api: &impl PackageSearchApi, + jsr_resolver: &JsrResolver, +) -> Option<Vec<lsp::CompletionItem>> { + // First try to match `jsr:some-package@some-version/<export-to-complete>`. + if let Ok(req_ref) = JsrPackageReqReference::from_str(specifier) { + let sub_path = req_ref.sub_path(); + if sub_path.is_some() || specifier.ends_with('/') { + let export_prefix = sub_path.unwrap_or(""); + let req = req_ref.req(); + let nv = jsr_resolver.req_to_nv(req); + let nv = nv.or_else(|| PackageNv::from_str(&req.to_string()).ok())?; + let exports = jsr_search_api.exports(&nv).await.ok()?; + let items = exports + .iter() + .enumerate() + .filter_map(|(idx, export)| { + if export == "." { + return None; + } + let export = export.strip_prefix("./").unwrap_or(export.as_str()); + if !export.starts_with(export_prefix) { + return None; + } + let specifier = format!("jsr:{}/{}", req_ref.req(), export); + let command = Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!([&specifier]), + json!(referrer), + json!({ "forceGlobalCache": true }), + ]), + }); + let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range: *range, + new_text: specifier.clone(), + })); + Some(lsp::CompletionItem { + label: specifier, + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some(format!("{:0>10}", idx + 1)), + text_edit, + command, + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(), + ), + ..Default::default() + }) + }) + .collect(); + return Some(items); + } + } + + // Then try to match `jsr:some-package@<version-to-complete>`. + let bare_specifier = specifier.strip_prefix("jsr:")?; + if let Some(v_index) = parse_bare_specifier_version_index(bare_specifier) { + let package_name = &bare_specifier[..v_index]; + let v_prefix = &bare_specifier[(v_index + 1)..]; + + let versions = jsr_search_api.versions(package_name).await.ok()?; + let items = versions + .iter() + .enumerate() + .filter_map(|(idx, version)| { + let version = version.to_string(); + if !version.starts_with(v_prefix) { + return None; + } + let specifier = format!("jsr:{}@{}", package_name, version); + let command = Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!([&specifier]), + json!(referrer), + json!({ "forceGlobalCache": true }), + ]), + }); + let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range: *range, + new_text: specifier.clone(), + })); + Some(lsp::CompletionItem { + label: specifier, + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some(format!("{:0>10}", idx + 1)), + text_edit, + command, + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(), + ), + ..Default::default() + }) + }) + .collect(); + return Some(items); + } + + // Otherwise match `jsr:<package-to-complete>`. + let names = jsr_search_api.search(bare_specifier).await.ok()?; + let items = names + .iter() + .enumerate() + .map(|(idx, name)| { + let specifier = format!("jsr:{}", name); + let command = Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!([&specifier]), + json!(referrer), + json!({ "forceGlobalCache": true }), + ]), + }); + let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range: *range, + new_text: specifier.clone(), + })); + lsp::CompletionItem { + label: specifier, + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some(format!("{:0>10}", idx + 1)), + text_edit, + command, + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect(), + ), + ..Default::default() + } + }) + .collect(); + Some(items) +} + /// Get completions for `npm:` specifiers. async fn get_npm_completions( referrer: &ModuleSpecifier, specifier: &str, range: &lsp::Range, - npm_search_api: &impl NpmSearchApi, + npm_search_api: &impl PackageSearchApi, ) -> Option<Vec<lsp::CompletionItem>> { // First try to match `npm:some-package@<version-to-complete>`. - if let Some(v_index) = parse_npm_specifier_version_index(specifier) { - let package_name = &specifier[..v_index].strip_prefix("npm:")?; - let v_prefix = &specifier[(v_index + 1)..]; - let versions = &npm_search_api - .package_info(package_name) - .await - .ok()? - .versions; - let mut versions = versions.keys().collect::<Vec<_>>(); - versions.sort(); + let bare_specifier = specifier.strip_prefix("npm:")?; + if let Some(v_index) = parse_bare_specifier_version_index(bare_specifier) { + let package_name = &bare_specifier[..v_index]; + let v_prefix = &bare_specifier[(v_index + 1)..]; + let versions = npm_search_api.versions(package_name).await.ok()?; let items = versions - .into_iter() - .rev() + .iter() .enumerate() .filter_map(|(idx, version)| { let version = version.to_string(); if !version.starts_with(v_prefix) { return None; } - let specifier = format!("npm:{}@{}", package_name, &version); + let specifier = format!("npm:{}@{}", package_name, version); let command = Some(lsp::Command { title: "".to_string(), command: "deno.cache".to_string(), - arguments: Some(vec![json!([&specifier]), json!(referrer)]), + arguments: Some(vec![ + json!([&specifier]), + json!(referrer), + json!({ "forceGlobalCache": true }), + ]), }); let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { range: *range, @@ -552,8 +708,7 @@ async fn get_npm_completions( } // Otherwise match `npm:<package-to-complete>`. - let package_name_prefix = specifier.strip_prefix("npm:")?; - let names = npm_search_api.search(package_name_prefix).await.ok()?; + let names = npm_search_api.search(bare_specifier).await.ok()?; let items = names .iter() .enumerate() @@ -562,7 +717,11 @@ async fn get_npm_completions( let command = Some(lsp::Command { title: "".to_string(), command: "deno.cache".to_string(), - arguments: Some(vec![json!([&specifier]), json!(referrer)]), + arguments: Some(vec![ + json!([&specifier]), + json!(referrer), + json!({ "forceGlobalCache": true }), + ]), }); let text_edit = Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { range: *range, @@ -640,43 +799,16 @@ mod tests { use super::*; use crate::cache::GlobalHttpCache; use crate::cache::HttpCache; + use crate::cache::RealDenoCacheEnv; use crate::lsp::documents::Documents; use crate::lsp::documents::LanguageId; - use crate::lsp::npm::NpmSearchApi; - use crate::AnyError; - use async_trait::async_trait; + use crate::lsp::search::tests::TestPackageSearchApi; use deno_core::resolve_url; use deno_graph::Range; - use deno_npm::registry::NpmPackageInfo; - use deno_npm::registry::NpmRegistryApi; - use deno_npm::registry::TestNpmRegistryApi; use std::collections::HashMap; use std::path::Path; use test_util::TempDir; - #[derive(Default)] - struct TestNpmSearchApi( - HashMap<String, Arc<Vec<String>>>, - TestNpmRegistryApi, - ); - - #[async_trait] - impl NpmSearchApi for TestNpmSearchApi { - async fn search(&self, query: &str) -> Result<Arc<Vec<String>>, AnyError> { - match self.0.get(query) { - Some(names) => Ok(names.clone()), - None => Ok(Arc::new(vec![])), - } - } - - async fn package_info( - &self, - name: &str, - ) -> Result<Arc<NpmPackageInfo>, AnyError> { - self.1.package_info(name).await.map_err(|e| e.into()) - } - } - fn mock_documents( fixtures: &[(&str, &str, i32, LanguageId)], source_fixtures: &[(&str, &str)], @@ -846,52 +978,326 @@ mod tests { } #[test] - fn test_parse_npm_specifier_version_index() { - assert_eq!(parse_npm_specifier_version_index("npm:"), None); - assert_eq!(parse_npm_specifier_version_index("npm:/"), None); - assert_eq!(parse_npm_specifier_version_index("npm:/@"), None); - assert_eq!(parse_npm_specifier_version_index("npm:@"), None); - assert_eq!(parse_npm_specifier_version_index("npm:@/"), None); - assert_eq!(parse_npm_specifier_version_index("npm:@/@"), None); - assert_eq!(parse_npm_specifier_version_index("npm:foo"), None); - assert_eq!(parse_npm_specifier_version_index("npm:foo/bar"), None); - assert_eq!(parse_npm_specifier_version_index("npm:foo/bar@"), None); - assert_eq!(parse_npm_specifier_version_index("npm:@org/foo/bar"), None); - assert_eq!(parse_npm_specifier_version_index("npm:@org/foo/bar@"), None); + fn test_parse_bare_specifier_version_index() { + assert_eq!(parse_bare_specifier_version_index(""), None); + assert_eq!(parse_bare_specifier_version_index("/"), None); + assert_eq!(parse_bare_specifier_version_index("/@"), None); + assert_eq!(parse_bare_specifier_version_index("@"), None); + assert_eq!(parse_bare_specifier_version_index("@/"), None); + assert_eq!(parse_bare_specifier_version_index("@/@"), None); + assert_eq!(parse_bare_specifier_version_index("foo"), None); + assert_eq!(parse_bare_specifier_version_index("foo/bar"), None); + assert_eq!(parse_bare_specifier_version_index("foo/bar@"), None); + assert_eq!(parse_bare_specifier_version_index("@org/foo/bar"), None); + assert_eq!(parse_bare_specifier_version_index("@org/foo/bar@"), None); - assert_eq!(parse_npm_specifier_version_index("npm:foo@"), Some(7)); - assert_eq!(parse_npm_specifier_version_index("npm:foo@1."), Some(7)); - assert_eq!(parse_npm_specifier_version_index("npm:@org/foo@"), Some(12)); - assert_eq!( - parse_npm_specifier_version_index("npm:@org/foo@1."), - Some(12) - ); + assert_eq!(parse_bare_specifier_version_index("foo@"), Some(3)); + assert_eq!(parse_bare_specifier_version_index("foo@1."), Some(3)); + assert_eq!(parse_bare_specifier_version_index("@org/foo@"), Some(8)); + assert_eq!(parse_bare_specifier_version_index("@org/foo@1."), Some(8)); // Regression test for https://github.com/denoland/deno/issues/22325. assert_eq!( - parse_npm_specifier_version_index( - "npm:@longer_than_right_one/arbitrary_string@" + parse_bare_specifier_version_index( + "@longer_than_right_one/arbitrary_string@" ), - Some(43) + Some(39) ); } #[tokio::test] - async fn test_get_npm_completions() { - let npm_search_api = TestNpmSearchApi( - vec![( - "puppe".to_string(), - Arc::new(vec![ - "puppeteer".to_string(), - "puppeteer-core".to_string(), - "puppeteer-extra-plugin-stealth".to_string(), - "puppeteer-extra-plugin".to_string(), - ]), - )] - .into_iter() - .collect(), - Default::default(), + async fn test_get_jsr_completions() { + let temp_dir = TempDir::default(); + let jsr_resolver = JsrResolver::from_cache_and_lockfile( + Arc::new(GlobalHttpCache::new( + temp_dir.path().to_path_buf(), + RealDenoCacheEnv, + )), + None, ); + let jsr_search_api = TestPackageSearchApi::default() + .with_package_version("@std/archive", "1.0.0", &[]) + .with_package_version("@std/assert", "1.0.0", &[]) + .with_package_version("@std/async", "1.0.0", &[]) + .with_package_version("@std/bytes", "1.0.0", &[]); + let range = lsp::Range { + start: lsp::Position { + line: 0, + character: 23, + }, + end: lsp::Position { + line: 0, + character: 29, + }, + }; + let referrer = ModuleSpecifier::parse("file:///referrer.ts").unwrap(); + let actual = get_jsr_completions( + &referrer, + "jsr:as", + &range, + &jsr_search_api, + &jsr_resolver, + ) + .await + .unwrap(); + assert_eq!( + actual, + vec![ + lsp::CompletionItem { + label: "jsr:@std/assert".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000001".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/assert".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/assert"]), + json!(&referrer), + json!({ "forceGlobalCache": true }) + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + lsp::CompletionItem { + label: "jsr:@std/async".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000002".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/async".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/async"]), + json!(&referrer), + json!({ "forceGlobalCache": true }) + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + ] + ); + } + + #[tokio::test] + async fn test_get_jsr_completions_for_versions() { + let temp_dir = TempDir::default(); + let jsr_resolver = JsrResolver::from_cache_and_lockfile( + Arc::new(GlobalHttpCache::new( + temp_dir.path().to_path_buf(), + RealDenoCacheEnv, + )), + None, + ); + let jsr_search_api = TestPackageSearchApi::default() + .with_package_version("@std/assert", "0.3.0", &[]) + .with_package_version("@std/assert", "0.4.0", &[]) + .with_package_version("@std/assert", "0.5.0", &[]); + let range = lsp::Range { + start: lsp::Position { + line: 0, + character: 23, + }, + end: lsp::Position { + line: 0, + character: 39, + }, + }; + let referrer = ModuleSpecifier::parse("file:///referrer.ts").unwrap(); + let actual = get_jsr_completions( + &referrer, + "jsr:@std/assert@", + &range, + &jsr_search_api, + &jsr_resolver, + ) + .await + .unwrap(); + assert_eq!( + actual, + vec![ + lsp::CompletionItem { + label: "jsr:@std/assert@0.5.0".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000001".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/assert@0.5.0".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/assert@0.5.0"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + lsp::CompletionItem { + label: "jsr:@std/assert@0.4.0".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000002".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/assert@0.4.0".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/assert@0.4.0"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + lsp::CompletionItem { + label: "jsr:@std/assert@0.3.0".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000003".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/assert@0.3.0".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/assert@0.3.0"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + ] + ); + } + + #[tokio::test] + async fn test_get_jsr_completions_for_exports() { + let temp_dir = TempDir::default(); + let jsr_resolver = JsrResolver::from_cache_and_lockfile( + Arc::new(GlobalHttpCache::new( + temp_dir.path().to_path_buf(), + RealDenoCacheEnv, + )), + None, + ); + let jsr_search_api = TestPackageSearchApi::default().with_package_version( + "@std/path", + "0.1.0", + &[".", "./basename", "./common", "./constants", "./dirname"], + ); + let range = lsp::Range { + start: lsp::Position { + line: 0, + character: 23, + }, + end: lsp::Position { + line: 0, + character: 45, + }, + }; + let referrer = ModuleSpecifier::parse("file:///referrer.ts").unwrap(); + let actual = get_jsr_completions( + &referrer, + "jsr:@std/path@0.1.0/co", + &range, + &jsr_search_api, + &jsr_resolver, + ) + .await + .unwrap(); + assert_eq!( + actual, + vec![ + lsp::CompletionItem { + label: "jsr:@std/path@0.1.0/common".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000003".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/path@0.1.0/common".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/path@0.1.0/common"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + lsp::CompletionItem { + label: "jsr:@std/path@0.1.0/constants".to_string(), + kind: Some(lsp::CompletionItemKind::FILE), + detail: Some("(jsr)".to_string()), + sort_text: Some("0000000004".to_string()), + text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { + range, + new_text: "jsr:@std/path@0.1.0/constants".to_string(), + })), + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![ + json!(["jsr:@std/path@0.1.0/constants"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) + }), + commit_characters: Some( + IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() + ), + ..Default::default() + }, + ] + ); + } + + #[tokio::test] + async fn test_get_npm_completions() { + let npm_search_api = TestPackageSearchApi::default() + .with_package_version("puppeteer", "1.0.0", &[]) + .with_package_version("puppeteer-core", "1.0.0", &[]) + .with_package_version("puppeteer-extra-plugin", "1.0.0", &[]) + .with_package_version("puppeteer-extra-plugin-stealth", "1.0.0", &[]); let range = lsp::Range { start: lsp::Position { line: 0, @@ -922,7 +1328,11 @@ mod tests { command: Some(lsp::Command { title: "".to_string(), command: "deno.cache".to_string(), - arguments: Some(vec![json!(["npm:puppeteer"]), json!(&referrer)]) + arguments: Some(vec![ + json!(["npm:puppeteer"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), + ]) }), commit_characters: Some( IMPORT_COMMIT_CHARS.iter().map(|&c| c.into()).collect() @@ -943,7 +1353,8 @@ mod tests { command: "deno.cache".to_string(), arguments: Some(vec![ json!(["npm:puppeteer-core"]), - json!(&referrer) + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -952,20 +1363,21 @@ mod tests { ..Default::default() }, lsp::CompletionItem { - label: "npm:puppeteer-extra-plugin-stealth".to_string(), + label: "npm:puppeteer-extra-plugin".to_string(), kind: Some(lsp::CompletionItemKind::FILE), detail: Some("(npm)".to_string()), sort_text: Some("0000000003".to_string()), text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { range, - new_text: "npm:puppeteer-extra-plugin-stealth".to_string(), + new_text: "npm:puppeteer-extra-plugin".to_string(), })), command: Some(lsp::Command { title: "".to_string(), command: "deno.cache".to_string(), arguments: Some(vec![ - json!(["npm:puppeteer-extra-plugin-stealth"]), - json!(&referrer) + json!(["npm:puppeteer-extra-plugin"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -974,20 +1386,21 @@ mod tests { ..Default::default() }, lsp::CompletionItem { - label: "npm:puppeteer-extra-plugin".to_string(), + label: "npm:puppeteer-extra-plugin-stealth".to_string(), kind: Some(lsp::CompletionItemKind::FILE), detail: Some("(npm)".to_string()), sort_text: Some("0000000004".to_string()), text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { range, - new_text: "npm:puppeteer-extra-plugin".to_string(), + new_text: "npm:puppeteer-extra-plugin-stealth".to_string(), })), command: Some(lsp::Command { title: "".to_string(), command: "deno.cache".to_string(), arguments: Some(vec![ - json!(["npm:puppeteer-extra-plugin"]), - json!(&referrer) + json!(["npm:puppeteer-extra-plugin-stealth"]), + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -1001,19 +1414,11 @@ mod tests { #[tokio::test] async fn test_get_npm_completions_for_versions() { - let npm_search_api = TestNpmSearchApi::default(); - npm_search_api - .1 - .ensure_package_version("puppeteer", "20.9.0"); - npm_search_api - .1 - .ensure_package_version("puppeteer", "21.0.0"); - npm_search_api - .1 - .ensure_package_version("puppeteer", "21.0.1"); - npm_search_api - .1 - .ensure_package_version("puppeteer", "21.0.2"); + let npm_search_api = TestPackageSearchApi::default() + .with_package_version("puppeteer", "20.9.0", &[]) + .with_package_version("puppeteer", "21.0.0", &[]) + .with_package_version("puppeteer", "21.0.1", &[]) + .with_package_version("puppeteer", "21.0.2", &[]); let range = lsp::Range { start: lsp::Position { line: 0, @@ -1046,7 +1451,8 @@ mod tests { command: "deno.cache".to_string(), arguments: Some(vec![ json!(["npm:puppeteer@21.0.2"]), - json!(&referrer) + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -1068,7 +1474,8 @@ mod tests { command: "deno.cache".to_string(), arguments: Some(vec![ json!(["npm:puppeteer@21.0.1"]), - json!(&referrer) + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -1090,7 +1497,8 @@ mod tests { command: "deno.cache".to_string(), arguments: Some(vec![ json!(["npm:puppeteer@21.0.0"]), - json!(&referrer) + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( @@ -1112,7 +1520,8 @@ mod tests { command: "deno.cache".to_string(), arguments: Some(vec![ json!(["npm:puppeteer@20.9.0"]), - json!(&referrer) + json!(&referrer), + json!({ "forceGlobalCache": true }), ]) }), commit_characters: Some( |