Repository: denoland/deno
Pull request: fix(lsp): lookup patched jsr packages for auto-import

Fixes #29362.

Changed files:
filename: cli/lsp/jsr.rs
patch: @@ -57,34 +57,27 @@ impl JsrCacheResolver {
     let info_by_name = DashMap::new();
     let mut workspace_packages_by_name = HashMap::new();
     if let Some(config_data) = config_data {
-      for jsr_pkg_config in config_data.member_dir.workspace.jsr_packages() {
-        let Some(exports) = &jsr_pkg_config.config_file.json.exports else {
-          continue;
-        };
+      for jsr_package in config_data.resolver.jsr_packages() {
+        let exports = deno_core::serde_json::json!(&jsr_package.exports);
         let version_info = Arc::new(JsrPackageVersionInfo {
           exports: exports.clone(),
           module_graph_1: None,
           module_graph_2: None,
           manifest: Default::default(),
         });
+        let name = StackString::from_str(&jsr_package.name);
         workspace_packages_by_name.insert(
-          StackString::from_str(&jsr_pkg_config.name),
+          name.clone(),
           WorkspacePackage {
-            dir_url: Url::from_directory_path(
-              jsr_pkg_config.config_file.dir_path(),
-            )
-            .unwrap(),
+            dir_url: jsr_package.base.clone(),
             version_info: version_info.clone(),
           },
         );
-        let Some(version) = &jsr_pkg_config.config_file.json.version else {
-          continue;
-        };
-        let Ok(version) = Version::parse_standard(version) else {
+        let Some(version) = &jsr_package.version else {
           continue;
         };
         let nv = PackageNv {
-          name: jsr_pkg_config.name.as_str().into(),
+          name,
           version: version.clone(),
         };
         info_by_name.insert(

filename: tests/integration/lsp_tests.rs
patch: @@ -5990,6 +5990,74 @@ fn lsp_jsr_auto_import_completion_workspace_member() {
   client.shutdown();
 }
 
+#[test]
+#[timeout(300_000)]
+fn lsp_jsr_auto_import_completion_patch() {
+  let context = TestContextBuilder::new()
+    .use_http_server()
+    .use_temp_cwd()
+    .build();
+  let temp_dir = context.temp_dir();
+  temp_dir.write(
+    "deno.json",
+    json!({
+      "imports": {
+        "@org/package": "jsr:@org/package"
+      },
+      "patch": ["package"],
+    })
+    .to_string(),
+  );
+  temp_dir.write(
+    "package/deno.json",
+    json!({
+      "name": "@org/package",
+      "exports": "./mod.ts",
+    })
+    .to_string(),
+  );
+  temp_dir.write("package/mod.ts", "export const someValue = 1;\n");
+  temp_dir.write("other.ts", "import \"@org/package\";\n");
+  let file = temp_dir.source_file("file.ts", "someValue;\n");
+  let mut client = context.new_lsp_command().build();
+  client.initialize_default();
+  client.did_open_file(&file);
+  let list = client.get_completion_list(
+    file.uri().as_str(),
+    (0, 9),
+    json!({ "triggerKind": 1 }),
+  );
+  let items = list
+    .items
+    .iter()
+    .filter(|i| i.label == "someValue")
+    .map(|i| client.write_request("completionItem/resolve", json!(i)))
+    .collect::<Vec<_>>();
+  assert_eq!(
+    json!(items),
+    json!([
+      {
+        "label": "someValue",
+        "labelDetails": { "description": "@org/package" },
+        "kind": 6,
+        "detail": "Add import from \"@org/package\"\n\nconst someValue: 1",
+        "documentation": { "kind": "markdown", "value": "" },
+        "sortText": "\u{ffff}16_0",
+        "additionalTextEdits": [
+          {
+            "range": {
+              "start": { "line": 0, "character": 0 },
+              "end": { "line": 0, "character": 0 },
+            },
+            "newText": "import { someValue } from \"@org/package\";\n\n",
+          },
+        ],
+      },
+    ]),
+  );
+  client.shutdown();
+}
+
 #[test]
 #[timeout(300_000)]
 fn lsp_jsr_code_action_missing_declaration() {