diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-07-18 18:16:35 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-18 18:16:35 -0400 |
commit | 3bda8eb4fe059fd79a522c9277a5a872f75dc270 (patch) | |
tree | 172d04d91223694c494b754d39c44ac5851575ac /cli/lsp/tsc.rs | |
parent | 1722e0aebfd830b7cbc0824ace5de0517072d0dc (diff) |
fix(lsp): support npm workspaces and fix some resolution issues (#24627)
Makes the lsp use the same code as the rest of the cli.
Diffstat (limited to 'cli/lsp/tsc.rs')
-rw-r--r-- | cli/lsp/tsc.rs | 182 |
1 files changed, 89 insertions, 93 deletions
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 6759f75f4..9dabb6ca5 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -4905,7 +4905,7 @@ impl UserPreferences { config: &config::Config, specifier: &ModuleSpecifier, ) -> 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 base_preferences = Self { allow_incomplete_completions: Some(true), @@ -5012,8 +5012,8 @@ impl UserPreferences { // Only use workspace settings for quote style if there's no `deno.json`. quote_preference: if config .tree - .config_file_for_specifier(specifier) - .is_some() + .workspace_member_ctx_for_specifier(specifier) + .is_some_and(|ctx| ctx.maybe_deno_json().is_some()) { base_preferences.quote_preference } else { @@ -5400,9 +5400,9 @@ mod tests { async fn setup( ts_config: Value, sources: &[(&str, &str, i32, LanguageId)], - ) -> (TsServer, Arc<StateSnapshot>, LspCache) { + ) -> (TempDir, TsServer, Arc<StateSnapshot>, LspCache) { 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(); config .tree @@ -5412,7 +5412,7 @@ mod tests { "compilerOptions": ts_config, }) .to_string(), - resolve_url("file:///deno.json").unwrap(), + temp_dir.uri().join("deno.json").unwrap(), &deno_config::ConfigParseOptions::default(), ) .unwrap(), @@ -5422,16 +5422,9 @@ mod tests { Arc::new(LspResolver::from_config(&config, &cache, None).await); let mut documents = Documents::default(); documents.update_config(&config, &resolver, &cache, &Default::default()); - for (specifier, source, version, language_id) in sources { - let specifier = - resolve_url(specifier).expect("failed to create specifier"); - documents.open( - specifier.clone(), - *version, - *language_id, - (*source).into(), - None, - ); + for (relative_specifier, source, version, language_id) in sources { + let specifier = temp_dir.uri().join(relative_specifier).unwrap(); + documents.open(specifier, *version, *language_id, (*source).into(), None); } let snapshot = Arc::new(StateSnapshot { project_version: 0, @@ -5456,7 +5449,7 @@ mod tests { .collect(), ), ); - (ts_server, snapshot, cache) + (temp_dir, ts_server, snapshot, cache) } fn setup_op_state(state_snapshot: Arc<StateSnapshot>) -> OpState { @@ -5485,7 +5478,7 @@ mod tests { #[tokio::test] async fn test_get_diagnostics() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5493,22 +5486,22 @@ mod tests { "lib": [], }), &[( - "file:///a.ts", + "a.ts", r#"console.log("hello deno");"#, 1, LanguageId::TypeScript, )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [ + specifier.clone(): [ { "start": { "line": 0, @@ -5518,7 +5511,7 @@ mod tests { "line": 0, "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'.", "sourceLine": "console.log(\"hello deno\");", "category": 1, @@ -5531,7 +5524,7 @@ mod tests { #[tokio::test] async fn test_get_diagnostics_lib() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5540,24 +5533,24 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#"console.log(document.location);"#, 1, LanguageId::TypeScript, )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); - assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); + assert_eq!(json!(diagnostics), json!({ specifier: [] })); } #[tokio::test] async fn test_module_resolution() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5565,7 +5558,7 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#" import { B } from "https://deno.land/x/b/mod.ts"; @@ -5578,17 +5571,17 @@ mod tests { )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); - assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); + assert_eq!(json!(diagnostics), json!({ specifier: [] })); } #[tokio::test] async fn test_bad_module_specifiers() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5596,7 +5589,7 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#" import { A } from "."; "#, @@ -5605,15 +5598,15 @@ mod tests { )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [{ + specifier.clone(): [{ "start": { "line": 1, "character": 8 @@ -5622,7 +5615,7 @@ mod tests { "line": 1, "character": 30 }, - "fileName": "file:///a.ts", + "fileName": specifier, "messageText": "\'A\' is declared but its value is never read.", "sourceLine": " import { A } from \".\";", "category": 2, @@ -5634,7 +5627,7 @@ mod tests { #[tokio::test] async fn test_remote_modules() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5642,7 +5635,7 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#" import { B } from "https://deno.land/x/b/mod.ts"; @@ -5655,17 +5648,17 @@ mod tests { )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); - assert_eq!(json!(diagnostics), json!({ "file:///a.ts": [] })); + assert_eq!(json!(diagnostics), json!({ specifier: [] })); } #[tokio::test] async fn test_partial_modules() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5673,7 +5666,7 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#" import { Application, @@ -5689,15 +5682,15 @@ mod tests { )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [{ + specifier.clone(): [{ "start": { "line": 1, "character": 8 @@ -5706,7 +5699,7 @@ mod tests { "line": 6, "character": 55, }, - "fileName": "file:///a.ts", + "fileName": specifier.clone(), "messageText": "All imports in import declaration are unused.", "sourceLine": " import {", "category": 2, @@ -5720,7 +5713,7 @@ mod tests { "line": 8, "character": 29 }, - "fileName": "file:///a.ts", + "fileName": specifier, "messageText": "Expression expected.", "sourceLine": " import * as test from", "category": 1, @@ -5732,7 +5725,7 @@ mod tests { #[tokio::test] async fn test_no_debug_failure() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5740,22 +5733,22 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#"const url = new URL("b.js", import."#, 1, LanguageId::TypeScript, )], ) .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 - .get_diagnostics(snapshot, vec![specifier], Default::default()) + .get_diagnostics(snapshot, vec![specifier.clone()], Default::default()) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [ + specifier.clone(): [ { "start": { "line": 0, @@ -5765,7 +5758,7 @@ mod tests { "line": 0, "character": 35 }, - "fileName": "file:///a.ts", + "fileName": specifier, "messageText": "Identifier expected.", "sourceLine": "const url = new URL(\"b.js\", import.", "category": 1, @@ -5778,7 +5771,7 @@ mod tests { #[tokio::test] 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 mut asset_names = assets .iter() @@ -5810,7 +5803,7 @@ mod tests { #[tokio::test] async fn test_modify_sources() { - let (ts_server, snapshot, cache) = setup( + let (temp_dir, ts_server, snapshot, cache) = setup( json!({ "target": "esnext", "module": "esnext", @@ -5818,7 +5811,7 @@ mod tests { "noEmit": true, }), &[( - "file:///a.ts", + "a.ts", r#" import * as a from "https://deno.land/x/example/a.ts"; if (a.a === "b") { @@ -5840,15 +5833,19 @@ mod tests { b"export const b = \"b\";\n", ) .unwrap(); - let specifier = resolve_url("file:///a.ts").unwrap(); + let specifier = temp_dir.uri().join("a.ts").unwrap(); let diagnostics = ts_server - .get_diagnostics(snapshot.clone(), vec![specifier], Default::default()) + .get_diagnostics( + snapshot.clone(), + vec![specifier.clone()], + Default::default(), + ) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [ + specifier.clone(): [ { "start": { "line": 2, @@ -5858,7 +5855,7 @@ mod tests { "line": 2, "character": 17 }, - "fileName": "file:///a.ts", + "fileName": specifier, "messageText": "Property \'a\' does not exist on type \'typeof import(\"https://deno.land/x/example/a\")\'.", "sourceLine": " if (a.a === \"b\") {", "code": 2339, @@ -5886,15 +5883,19 @@ mod tests { [(&specifier_dep, ChangeKind::Opened)], None, ); - let specifier = resolve_url("file:///a.ts").unwrap(); + let specifier = temp_dir.uri().join("a.ts").unwrap(); let diagnostics = ts_server - .get_diagnostics(snapshot.clone(), vec![specifier], Default::default()) + .get_diagnostics( + snapshot.clone(), + vec![specifier.clone()], + Default::default(), + ) .await .unwrap(); assert_eq!( json!(diagnostics), json!({ - "file:///a.ts": [] + specifier: [] }) ); } @@ -5944,17 +5945,17 @@ mod tests { character: 16, }) .unwrap(); - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", "lib": ["deno.ns", "deno.window"], "noEmit": true, }), - &[("file:///a.ts", fixture, 1, LanguageId::TypeScript)], + &[("a.ts", fixture, 1, LanguageId::TypeScript)], ) .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 .get_completions( snapshot.clone(), @@ -5969,7 +5970,7 @@ mod tests { trigger_kind: None, }, Default::default(), - Some(ModuleSpecifier::parse("file:///").unwrap()), + Some(temp_dir.uri()), ) .await .unwrap(); @@ -5986,7 +5987,7 @@ mod tests { preferences: None, data: None, }, - Some(ModuleSpecifier::parse("file:///").unwrap()), + Some(temp_dir.uri()), ) .await .unwrap() @@ -6095,7 +6096,7 @@ mod tests { character: 33, }) .unwrap(); - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -6103,12 +6104,12 @@ mod tests { "noEmit": true, }), &[ - ("file:///a.ts", fixture_a, 1, LanguageId::TypeScript), - ("file:///b.ts", fixture_b, 1, LanguageId::TypeScript), + ("a.ts", fixture_a, 1, LanguageId::TypeScript), + ("b.ts", fixture_b, 1, LanguageId::TypeScript), ], ) .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 { semi_colons: Some(false), single_quote: Some(true), @@ -6129,7 +6130,7 @@ mod tests { ..Default::default() }, FormatCodeSettings::from(&fmt_options_config), - Some(ModuleSpecifier::parse("file:///").unwrap()), + Some(temp_dir.uri()), ) .await .unwrap(); @@ -6155,7 +6156,7 @@ mod tests { }), data: entry.data.clone(), }, - Some(ModuleSpecifier::parse("file:///").unwrap()), + Some(temp_dir.uri()), ) .await .unwrap() @@ -6204,7 +6205,7 @@ mod tests { #[tokio::test] async fn test_get_edits_for_file_rename() { - let (ts_server, snapshot, _) = setup( + let (temp_dir, ts_server, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", @@ -6212,21 +6213,16 @@ mod tests { "noEmit": true, }), &[ - ( - "file:///a.ts", - r#"import "./b.ts";"#, - 1, - LanguageId::TypeScript, - ), - ("file:///b.ts", r#""#, 1, LanguageId::TypeScript), + ("a.ts", r#"import "./b.ts";"#, 1, LanguageId::TypeScript), + ("b.ts", r#""#, 1, LanguageId::TypeScript), ], ) .await; let changes = ts_server .get_edits_for_file_rename( snapshot, - resolve_url("file:///b.ts").unwrap(), - resolve_url("file:///🦕.ts").unwrap(), + temp_dir.uri().join("b.ts").unwrap(), + temp_dir.uri().join("🦕.ts").unwrap(), FormatCodeSettings::default(), UserPreferences::default(), ) @@ -6235,7 +6231,7 @@ mod tests { assert_eq!( changes, vec![FileTextChanges { - file_name: "file:///a.ts".to_string(), + file_name: temp_dir.uri().join("a.ts").unwrap().to_string(), text_changes: vec![TextChange { span: TextSpan { start: 8, @@ -6280,21 +6276,21 @@ mod tests { #[tokio::test] async fn resolve_unknown_dependency() { - let (_, snapshot, _) = setup( + let (temp_dir, _, snapshot, _) = setup( json!({ "target": "esnext", "module": "esnext", "lib": ["deno.ns", "deno.window"], "noEmit": true, }), - &[("file:///a.ts", "", 1, LanguageId::TypeScript)], + &[("a.ts", "", 1, LanguageId::TypeScript)], ) .await; let mut state = setup_op_state(snapshot); let resolved = op_resolve_inner( &mut state, ResolveArgs { - base: "file:///a.ts".to_string(), + base: temp_dir.uri().join("a.ts").unwrap().to_string(), is_base_cjs: false, specifiers: vec!["./b.ts".to_string()], }, @@ -6303,7 +6299,7 @@ mod tests { assert_eq!( resolved, vec![Some(( - "file:///b.ts".to_string(), + temp_dir.uri().join("b.ts").unwrap().to_string(), MediaType::TypeScript.as_ts_extension().to_string() ))] ); |