diff options
Diffstat (limited to 'cli/lsp')
-rw-r--r-- | cli/lsp/config.rs | 34 | ||||
-rw-r--r-- | cli/lsp/tsc.rs | 70 |
2 files changed, 79 insertions, 25 deletions
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 362b029e9..3e5460a1d 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -1112,19 +1112,29 @@ impl Default for LspTsConfig { } impl LspTsConfig { - pub fn new(config_file: Option<&ConfigFile>) -> Self { + pub fn new( + config_file: Option<&ConfigFile>, + import_map: Option<&ImportMap>, + ) -> Self { let mut ts_config = Self::default(); - if let Some(config_file) = config_file { - match config_file.to_compiler_options() { - Ok((value, maybe_ignored_options)) => { - ts_config.inner.merge(&value); - if let Some(ignored_options) = maybe_ignored_options { - lsp_warn!("{}", ignored_options); - } - } - Err(err) => lsp_warn!("{}", err), - } + match ts_config.inner.merge_tsconfig_from_config_file(config_file) { + Ok(Some(ignored_options)) => lsp_warn!("{}", ignored_options), + Err(err) => lsp_warn!("{}", err), + _ => {} } + let mut maybe_map_jsx_import_source = || { + let import_map = import_map?; + let referrer = &config_file?.specifier; + let compiler_options = ts_config.inner.0.as_object_mut()?; + let jsx_import_source = + compiler_options.get("jsxImportSource")?.as_str()?; + let jsx_import_source = + import_map.resolve(jsx_import_source, referrer).ok()?; + compiler_options + .insert("jsxImportSource".to_string(), json!(jsx_import_source)); + Some(()) + }; + maybe_map_jsx_import_source(); ts_config } } @@ -1267,7 +1277,6 @@ impl ConfigData { .unwrap_or_default(); let lint_rules = get_configured_rules(lint_options.rules.clone(), config_file.as_ref()); - let ts_config = LspTsConfig::new(config_file.as_ref()); let vendor_dir = config_file.as_ref().and_then(|c| c.vendor_dir_path()); // Load lockfile @@ -1436,6 +1445,7 @@ impl ConfigData { } } } + let ts_config = LspTsConfig::new(config_file.as_ref(), import_map.as_ref()); ConfigData { config_file: config_file.map(Arc::new), diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index d62744e03..48ca7355a 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -28,6 +28,7 @@ use crate::lsp::documents::Documents; use crate::lsp::logging::lsp_warn; use crate::tsc; use crate::tsc::ResolveArgs; +use crate::tsc::MISSING_DEPENDENCY_SPECIFIER; use crate::util::path::relative_specifier; use crate::util::path::specifier_to_file_path; use crate::util::path::to_percent_decoded_str; @@ -4008,7 +4009,7 @@ fn op_load<'s>( .mark_with_args("tsc.op.op_load", specifier); let specifier = state.specifier_map.normalize(specifier)?; let maybe_load_response = - if specifier.as_str() == "internal:///missing_dependency.d.ts" { + if specifier.as_str() == MISSING_DEPENDENCY_SPECIFIER { None } else { let asset_or_document = state.get_asset_or_document(&specifier); @@ -4026,11 +4027,11 @@ fn op_load<'s>( } #[op2] -fn op_resolve<'s>( - scope: &'s mut v8::HandleScope, +#[serde] +fn op_resolve( state: &mut OpState, #[serde] args: ResolveArgs, -) -> Result<v8::Local<'s, v8::Value>, AnyError> { +) -> Result<Vec<Option<(String, String)>>, AnyError> { let state = state.borrow_mut::<State>(); let mark = state.performance.mark_with_args("tsc.op.op_resolve", &args); let referrer = state.specifier_map.normalize(&args.base)?; @@ -4043,13 +4044,17 @@ fn op_resolve<'s>( ); resolved .into_iter() - .map(|o| { - o.map(|(s, mt)| { - ( - state.specifier_map.denormalize(&s), - mt.as_ts_extension().to_string(), - ) - }) + // Resolved `node:` specifier means the user doesn't have @types/node, + // resolve to stub. + .map(|o| match o.filter(|(s, _)| s.scheme() != "node") { + Some((s, mt)) => Some(( + state.specifier_map.denormalize(&s), + mt.as_ts_extension().to_string(), + )), + None => Some(( + MISSING_DEPENDENCY_SPECIFIER.to_string(), + MediaType::Dts.as_ts_extension().to_string(), + )), }) .collect() } @@ -4062,9 +4067,8 @@ fn op_resolve<'s>( } }; - let response = serde_v8::to_v8(scope, specifiers)?; state.performance.measure(mark); - Ok(response) + Ok(specifiers) } #[op2] @@ -4750,6 +4754,14 @@ mod tests { (ts_server, snapshot, cache) } + fn setup_op_state(state_snapshot: Arc<StateSnapshot>) -> OpState { + let state = + State::new(state_snapshot, Default::default(), Default::default()); + let mut op_state = OpState::new(None); + op_state.put(state); + op_state + } + #[test] fn test_replace_links() { let actual = replace_links(r"test {@link http://deno.land/x/mod.ts} test"); @@ -5552,4 +5564,36 @@ mod tests { Some(false) ); } + + #[tokio::test] + async fn resolve_unknown_dependency_to_stub_module() { + let temp_dir = TempDir::new(); + let (_, snapshot, _) = setup( + &temp_dir, + json!({ + "target": "esnext", + "module": "esnext", + "lib": ["deno.ns", "deno.window"], + "noEmit": true, + }), + &[("file:///a.ts", "", 1, LanguageId::TypeScript)], + ) + .await; + let mut state = setup_op_state(snapshot); + let resolved = op_resolve::call( + &mut state, + ResolveArgs { + base: "file:///a.ts".to_string(), + specifiers: vec!["./b.ts".to_string()], + }, + ) + .unwrap(); + assert_eq!( + resolved, + vec![Some(( + MISSING_DEPENDENCY_SPECIFIER.to_string(), + MediaType::Dts.as_ts_extension().to_string() + ))] + ); + } } |