diff options
Diffstat (limited to 'cli/lsp/tsc.rs')
-rw-r--r-- | cli/lsp/tsc.rs | 632 |
1 files changed, 507 insertions, 125 deletions
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index 7999cb1df..e45d6d52b 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -3,6 +3,7 @@ use super::analysis::CodeActionData; use super::code_lens; use super::config; +use super::documents::cell_to_file_specifier; use super::documents::AssetOrDocument; use super::documents::DocumentsFilter; use super::language_server; @@ -31,6 +32,7 @@ use crate::tsc::ResolveArgs; use crate::util::path::relative_specifier; use crate::util::path::specifier_to_file_path; +use dashmap::DashMap; use deno_ast::MediaType; use deno_core::anyhow::anyhow; use deno_core::error::custom_error; @@ -126,14 +128,32 @@ pub enum SemicolonPreference { Remove, } +fn normalize_diagnostic( + diagnostic: &mut crate::tsc::Diagnostic, + specifier_map: &TscSpecifierMap, +) -> Result<(), AnyError> { + if let Some(file_name) = &mut diagnostic.file_name { + *file_name = specifier_map.normalize(&file_name)?.to_string(); + } + for ri in diagnostic.related_information.iter_mut().flatten() { + normalize_diagnostic(ri, specifier_map)?; + } + Ok(()) +} + #[derive(Clone, Debug)] -pub struct TsServer(mpsc::UnboundedSender<Request>); +pub struct TsServer { + sender: mpsc::UnboundedSender<Request>, + specifier_map: Arc<TscSpecifierMap>, +} impl TsServer { pub fn new(performance: Arc<Performance>, cache: Arc<dyn HttpCache>) -> Self { + let specifier_map = Arc::new(TscSpecifierMap::default()); + let specifier_map_ = specifier_map.clone(); let (tx, mut rx) = mpsc::unbounded_channel::<Request>(); let _join_handle = thread::spawn(move || { - let mut ts_runtime = js_runtime(performance, cache); + let mut ts_runtime = js_runtime(performance, cache, specifier_map_); let runtime = create_basic_runtime(); runtime.block_on(async { @@ -152,7 +172,10 @@ impl TsServer { }) }); - Self(tx) + Self { + sender: tx, + specifier_map, + } } pub async fn get_diagnostics( @@ -162,7 +185,16 @@ impl TsServer { token: CancellationToken, ) -> Result<HashMap<String, Vec<crate::tsc::Diagnostic>>, AnyError> { let req = RequestMethod::GetDiagnostics(specifiers); - self.request_with_cancellation(snapshot, req, token).await + let diagnostics_map_ = self.request_with_cancellation::<HashMap<String, Vec<crate::tsc::Diagnostic>>>(snapshot, req, token).await?; + let mut diagnostics_map = HashMap::new(); + for (mut specifier, mut diagnostics) in diagnostics_map_ { + specifier = self.specifier_map.normalize(&specifier)?.to_string(); + for diagnostic in &mut diagnostics { + normalize_diagnostic(diagnostic, &self.specifier_map)?; + } + diagnostics_map.insert(specifier, diagnostics); + } + Ok(diagnostics_map) } pub async fn find_references( @@ -175,10 +207,19 @@ impl TsServer { specifier, position, }; - self.request(snapshot, req).await.map_err(|err| { - log::error!("Unable to get references from TypeScript: {}", err); - LspError::internal_error() - }) + self + .request::<Option<Vec<ReferencedSymbol>>>(snapshot, req) + .await + .and_then(|mut symbols| { + for symbol in symbols.iter_mut().flatten() { + symbol.normalize(&self.specifier_map)?; + } + Ok(symbols) + }) + .map_err(|err| { + log::error!("Unable to get references from TypeScript: {}", err); + LspError::internal_error() + }) } pub async fn get_navigation_tree( @@ -244,7 +285,16 @@ impl TsServer { format_code_settings, preferences, )); - match self.request(snapshot, req).await { + let result = self + .request::<Vec<CodeFixAction>>(snapshot, req) + .await + .and_then(|mut actions| { + for action in &mut actions { + action.normalize(&self.specifier_map)?; + } + Ok(actions) + }); + match result { Ok(items) => items, Err(err) => { // sometimes tsc reports errors when retrieving code actions @@ -293,10 +343,17 @@ impl TsServer { format_code_settings, preferences, )); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Unable to get combined fix from TypeScript: {}", err); - LspError::internal_error() - }) + self + .request::<CombinedCodeActions>(snapshot, req) + .await + .and_then(|mut actions| { + actions.normalize(&self.specifier_map)?; + Ok(actions) + }) + .map_err(|err| { + log::error!("Unable to get combined fix from TypeScript: {}", err); + LspError::internal_error() + }) } #[allow(clippy::too_many_arguments)] @@ -321,10 +378,17 @@ impl TsServer { action_name, preferences, )); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<RefactorEditInfo>(snapshot, req) + .await + .and_then(|mut info| { + info.normalize(&self.specifier_map)?; + Ok(info) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn get_edits_for_file_rename( @@ -341,10 +405,19 @@ impl TsServer { format_code_settings, user_preferences, )); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Vec<FileTextChanges>>(snapshot, req) + .await + .and_then(|mut changes| { + for changes in &mut changes { + changes.normalize(&self.specifier_map)?; + } + Ok(changes) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn get_document_highlights( @@ -372,10 +445,19 @@ impl TsServer { position: u32, ) -> Result<Option<DefinitionInfoAndBoundSpan>, LspError> { let req = RequestMethod::GetDefinition((specifier, position)); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Unable to get definition from TypeScript: {}", err); - LspError::internal_error() - }) + self + .request::<Option<DefinitionInfoAndBoundSpan>>(snapshot, req) + .await + .and_then(|mut info| { + if let Some(info) = &mut info { + info.normalize(&self.specifier_map)?; + } + Ok(info) + }) + .map_err(|err| { + log::error!("Unable to get definition from TypeScript: {}", err); + LspError::internal_error() + }) } pub async fn get_type_definition( @@ -388,10 +470,19 @@ impl TsServer { specifier, position, }; - self.request(snapshot, req).await.map_err(|err| { - log::error!("Unable to get type definition from TypeScript: {}", err); - LspError::internal_error() - }) + self + .request::<Option<Vec<DefinitionInfo>>>(snapshot, req) + .await + .and_then(|mut infos| { + for info in infos.iter_mut().flatten() { + info.normalize(&self.specifier_map)?; + } + Ok(infos) + }) + .map_err(|err| { + log::error!("Unable to get type definition from TypeScript: {}", err); + LspError::internal_error() + }) } pub async fn get_completions( @@ -423,7 +514,15 @@ impl TsServer { args: GetCompletionDetailsArgs, ) -> Result<Option<CompletionEntryDetails>, AnyError> { let req = RequestMethod::GetCompletionDetails(args); - self.request(snapshot, req).await + self + .request::<Option<CompletionEntryDetails>>(snapshot, req) + .await + .and_then(|mut details| { + if let Some(details) = &mut details { + details.normalize(&self.specifier_map)?; + } + Ok(details) + }) } pub async fn get_implementations( @@ -433,10 +532,19 @@ impl TsServer { position: u32, ) -> Result<Option<Vec<ImplementationLocation>>, LspError> { let req = RequestMethod::GetImplementation((specifier, position)); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Option<Vec<ImplementationLocation>>>(snapshot, req) + .await + .and_then(|mut locations| { + for location in locations.iter_mut().flatten() { + location.normalize(&self.specifier_map)?; + } + Ok(locations) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn get_outlining_spans( @@ -459,10 +567,19 @@ impl TsServer { ) -> Result<Vec<CallHierarchyIncomingCall>, LspError> { let req = RequestMethod::ProvideCallHierarchyIncomingCalls((specifier, position)); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Vec<CallHierarchyIncomingCall>>(snapshot, req) + .await + .and_then(|mut calls| { + for call in &mut calls { + call.normalize(&self.specifier_map)?; + } + Ok(calls) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn provide_call_hierarchy_outgoing_calls( @@ -473,10 +590,19 @@ impl TsServer { ) -> Result<Vec<CallHierarchyOutgoingCall>, LspError> { let req = RequestMethod::ProvideCallHierarchyOutgoingCalls((specifier, position)); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Vec<CallHierarchyOutgoingCall>>(snapshot, req) + .await + .and_then(|mut calls| { + for call in &mut calls { + call.normalize(&self.specifier_map)?; + } + Ok(calls) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn prepare_call_hierarchy( @@ -486,10 +612,27 @@ impl TsServer { position: u32, ) -> Result<Option<OneOrMany<CallHierarchyItem>>, LspError> { let req = RequestMethod::PrepareCallHierarchy((specifier, position)); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Option<OneOrMany<CallHierarchyItem>>>(snapshot, req) + .await + .and_then(|mut items| { + match &mut items { + Some(OneOrMany::One(item)) => { + item.normalize(&self.specifier_map)?; + } + Some(OneOrMany::Many(items)) => { + for item in items { + item.normalize(&self.specifier_map)?; + } + } + None => {} + } + Ok(items) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn find_rename_locations( @@ -505,10 +648,19 @@ impl TsServer { find_in_comments: false, provide_prefix_and_suffix_text_for_rename: false, }; - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed to request to tsserver {}", err); - LspError::invalid_request() - }) + self + .request::<Option<Vec<RenameLocation>>>(snapshot, req) + .await + .and_then(|mut locations| { + for location in locations.iter_mut().flatten() { + location.normalize(&self.specifier_map)?; + } + Ok(locations) + }) + .map_err(|err| { + log::error!("Failed to request to tsserver {}", err); + LspError::invalid_request() + }) } pub async fn get_smart_selection_range( @@ -565,10 +717,19 @@ impl TsServer { args: GetNavigateToItemsArgs, ) -> Result<Vec<NavigateToItem>, LspError> { let req = RequestMethod::GetNavigateToItems(args); - self.request(snapshot, req).await.map_err(|err| { - log::error!("Failed request to tsserver: {}", err); - LspError::invalid_request() - }) + self + .request::<Vec<NavigateToItem>>(snapshot, req) + .await + .and_then(|mut items| { + for items in &mut items { + items.normalize(&self.specifier_map)?; + } + Ok(items) + }) + .map_err(|err| { + log::error!("Failed request to tsserver: {}", err); + LspError::invalid_request() + }) } pub async fn provide_inlay_hints( @@ -619,7 +780,7 @@ impl TsServer { R: de::DeserializeOwned, { let (tx, rx) = oneshot::channel::<Result<Value, AnyError>>(); - if self.0.send((req, snapshot, tx, token)).is_err() { + if self.sender.send((req, snapshot, tx, token)).is_err() { return Err(anyhow!("failed to send request to tsc thread")); } let value = rx.await??; @@ -1281,6 +1442,16 @@ pub struct DocumentSpan { } impl DocumentSpan { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.file_name = specifier_map.normalize(&self.file_name)?.to_string(); + Ok(()) + } +} + +impl DocumentSpan { pub fn to_link( &self, line_index: Arc<LineIndex>, @@ -1378,6 +1549,16 @@ pub struct NavigateToItem { } impl NavigateToItem { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.file_name = specifier_map.normalize(&self.file_name)?.to_string(); + Ok(()) + } +} + +impl NavigateToItem { pub fn to_symbol_information( &self, language_server: &language_server::Inner, @@ -1629,6 +1810,14 @@ pub struct ImplementationLocation { } impl ImplementationLocation { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.document_span.normalize(specifier_map)?; + Ok(()) + } + pub fn to_location( &self, line_index: Arc<LineIndex>, @@ -1667,6 +1856,16 @@ pub struct RenameLocation { // suffix_text: Option<String>, } +impl RenameLocation { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.document_span.normalize(specifier_map)?; + Ok(()) + } +} + pub struct RenameLocations { pub locations: Vec<RenameLocation>, } @@ -1744,7 +1943,7 @@ pub struct HighlightSpan { kind: HighlightSpanKind, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct DefinitionInfo { // kind: ScriptElementKind, @@ -1755,6 +1954,16 @@ pub struct DefinitionInfo { pub document_span: DocumentSpan, } +impl DefinitionInfo { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.document_span.normalize(specifier_map)?; + Ok(()) + } +} + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct DefinitionInfoAndBoundSpan { @@ -1763,6 +1972,16 @@ pub struct DefinitionInfoAndBoundSpan { } impl DefinitionInfoAndBoundSpan { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for definition in self.definitions.iter_mut().flatten() { + definition.normalize(specifier_map)?; + } + Ok(()) + } + pub async fn to_definition( &self, line_index: Arc<LineIndex>, @@ -1849,6 +2068,14 @@ pub struct FileTextChanges { } impl FileTextChanges { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.file_name = specifier_map.normalize(&self.file_name)?.to_string(); + Ok(()) + } + pub fn to_text_document_edit( &self, language_server: &language_server::Inner, @@ -2119,7 +2346,7 @@ pub fn file_text_changes_to_workspace_edit( })) } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RefactorEditInfo { edits: Vec<FileTextChanges>, @@ -2128,6 +2355,16 @@ pub struct RefactorEditInfo { } impl RefactorEditInfo { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for changes in &mut self.edits { + changes.normalize(specifier_map)?; + } + Ok(()) + } + pub async fn to_workspace_edit( &self, language_server: &language_server::Inner, @@ -2145,6 +2382,18 @@ pub struct CodeAction { commands: Option<Vec<Value>>, } +impl CodeAction { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for changes in &mut self.changes { + changes.normalize(specifier_map)?; + } + Ok(()) + } +} + #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct CodeFixAction { @@ -2166,6 +2415,18 @@ pub struct CodeFixAction { pub fix_all_description: Option<String>, } +impl CodeFixAction { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for changes in &mut self.changes { + changes.normalize(specifier_map)?; + } + Ok(()) + } +} + #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CombinedCodeActions { @@ -2173,21 +2434,56 @@ pub struct CombinedCodeActions { pub commands: Option<Vec<Value>>, } -#[derive(Debug, Deserialize)] +impl CombinedCodeActions { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for changes in &mut self.changes { + changes.normalize(specifier_map)?; + } + Ok(()) + } +} + +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ReferencedSymbol { pub definition: ReferencedSymbolDefinitionInfo, pub references: Vec<ReferencedSymbolEntry>, } -#[derive(Debug, Deserialize)] +impl ReferencedSymbol { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.definition.normalize(specifier_map)?; + for reference in &mut self.references { + reference.normalize(specifier_map)?; + } + Ok(()) + } +} + +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ReferencedSymbolDefinitionInfo { #[serde(flatten)] pub definition_info: DefinitionInfo, } -#[derive(Debug, Deserialize)] +impl ReferencedSymbolDefinitionInfo { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.definition_info.normalize(specifier_map)?; + Ok(()) + } +} + +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ReferencedSymbolEntry { #[serde(default)] @@ -2196,7 +2492,17 @@ pub struct ReferencedSymbolEntry { pub entry: ReferenceEntry, } -#[derive(Debug, Deserialize)] +impl ReferencedSymbolEntry { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.entry.normalize(specifier_map)?; + Ok(()) + } +} + +#[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ReferenceEntry { // is_write_access: bool, @@ -2206,6 +2512,16 @@ pub struct ReferenceEntry { } impl ReferenceEntry { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.document_span.normalize(specifier_map)?; + Ok(()) + } +} + +impl ReferenceEntry { pub fn to_location( &self, line_index: Arc<LineIndex>, @@ -2238,6 +2554,14 @@ pub struct CallHierarchyItem { } impl CallHierarchyItem { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.file = specifier_map.normalize(&self.file)?.to_string(); + Ok(()) + } + pub fn try_resolve_call_hierarchy_item( &self, language_server: &language_server::Inner, @@ -2337,6 +2661,14 @@ pub struct CallHierarchyIncomingCall { } impl CallHierarchyIncomingCall { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.from.normalize(specifier_map)?; + Ok(()) + } + pub fn try_resolve_call_hierarchy_incoming_call( &self, language_server: &language_server::Inner, @@ -2369,6 +2701,14 @@ pub struct CallHierarchyOutgoingCall { } impl CallHierarchyOutgoingCall { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + self.to.normalize(specifier_map)?; + Ok(()) + } + pub fn try_resolve_call_hierarchy_outgoing_call( &self, line_index: Arc<LineIndex>, @@ -2524,6 +2864,16 @@ pub struct CompletionEntryDetails { } impl CompletionEntryDetails { + pub fn normalize( + &mut self, + specifier_map: &TscSpecifierMap, + ) -> Result<(), AnyError> { + for action in self.code_actions.iter_mut().flatten() { + action.normalize(specifier_map)?; + } + Ok(()) + } + pub fn as_completion_item( &self, original_item: &lsp::CompletionItem, @@ -3164,41 +3514,30 @@ struct Response { data: Value, } -struct State { - last_id: usize, - performance: Arc<Performance>, - response: Option<Response>, - state_snapshot: Arc<StateSnapshot>, - normalized_specifiers: HashMap<String, ModuleSpecifier>, - denormalized_specifiers: HashMap<ModuleSpecifier, String>, - token: CancellationToken, +#[derive(Debug, Default)] +pub struct TscSpecifierMap { + normalized_specifiers: DashMap<String, ModuleSpecifier>, + denormalized_specifiers: DashMap<ModuleSpecifier, String>, } -impl State { - fn new( - state_snapshot: Arc<StateSnapshot>, - performance: Arc<Performance>, - ) -> Self { - Self { - last_id: 1, - performance, - response: None, - state_snapshot, - normalized_specifiers: HashMap::default(), - denormalized_specifiers: HashMap::default(), - token: Default::default(), - } - } - +impl TscSpecifierMap { /// Convert the specifier to one compatible with tsc. Cache the resulting /// mapping in case it needs to be reversed. - fn denormalize_specifier(&mut self, specifier: &ModuleSpecifier) -> String { + // TODO(nayeemrmn): Factor in out-of-band media type here. + pub fn denormalize(&self, specifier: &ModuleSpecifier) -> String { let original = specifier; if let Some(specifier) = self.denormalized_specifiers.get(original) { return specifier.to_string(); } let mut specifier = original.to_string(); - let media_type = MediaType::from_specifier(original); + let media_type = if original.scheme() == "deno-notebook-cell" { + if let Some(s) = cell_to_file_specifier(original) { + specifier = s.to_string(); + } + MediaType::TypeScript + } else { + MediaType::from_specifier(original) + }; // If the URL-inferred media type doesn't correspond to tsc's path-inferred // media type, force it to be the same by appending an extension. if MediaType::from_path(Path::new(specifier.as_str())) != media_type { @@ -3214,8 +3553,8 @@ impl State { /// Convert the specifier from one compatible with tsc. Cache the resulting /// mapping in case it needs to be reversed. - fn normalize_specifier<S: AsRef<str>>( - &mut self, + pub fn normalize<S: AsRef<str>>( + &self, specifier: S, ) -> Result<ModuleSpecifier, AnyError> { let original = specifier.as_ref(); @@ -3234,6 +3573,32 @@ impl State { } Ok(specifier) } +} + +struct State { + last_id: usize, + performance: Arc<Performance>, + response: Option<Response>, + state_snapshot: Arc<StateSnapshot>, + specifier_map: Arc<TscSpecifierMap>, + token: CancellationToken, +} + +impl State { + fn new( + state_snapshot: Arc<StateSnapshot>, + specifier_map: Arc<TscSpecifierMap>, + performance: Arc<Performance>, + ) -> Self { + Self { + last_id: 1, + performance, + response: None, + state_snapshot, + specifier_map, + token: Default::default(), + } + } fn get_asset_or_document( &self, @@ -3316,7 +3681,7 @@ fn op_load( ) -> Result<Option<LoadResponse>, AnyError> { let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_load", Some(&args)); - let specifier = state.normalize_specifier(args.specifier)?; + let specifier = state.specifier_map.normalize(args.specifier)?; let asset_or_document = state.get_asset_or_document(&specifier); state.performance.measure(mark); Ok(asset_or_document.map(|doc| LoadResponse { @@ -3334,7 +3699,7 @@ fn op_resolve( ) -> Result<Vec<Option<(String, String)>>, AnyError> { let state = state.borrow_mut::<State>(); let mark = state.performance.mark("op_resolve", Some(&args)); - let referrer = state.normalize_specifier(&args.base)?; + let referrer = state.specifier_map.normalize(&args.base)?; let result = match state.get_asset_or_document(&referrer) { Some(referrer_doc) => { let resolved = state.state_snapshot.documents.resolve( @@ -3348,7 +3713,7 @@ fn op_resolve( .map(|o| { o.map(|(s, mt)| { ( - state.denormalize_specifier(&s), + state.specifier_map.denormalize(&s), mt.as_ts_extension().to_string(), ) }) @@ -3419,6 +3784,12 @@ fn op_script_names(state: &mut OpState) -> Vec<String> { } result + .into_iter() + .map(|s| match ModuleSpecifier::parse(&s) { + Ok(s) => state.specifier_map.denormalize(&s), + Err(_) => s, + }) + .collect() } #[derive(Debug, Deserialize, Serialize)] @@ -3436,7 +3807,7 @@ fn op_script_version( let state = state.borrow_mut::<State>(); // this op is very "noisy" and measuring its performance is not useful, so we // don't measure it uniquely anymore. - let specifier = state.normalize_specifier(args.specifier)?; + let specifier = state.specifier_map.normalize(args.specifier)?; Ok(state.script_version(&specifier)) } @@ -3446,9 +3817,10 @@ fn op_script_version( fn js_runtime( performance: Arc<Performance>, cache: Arc<dyn HttpCache>, + specifier_map: Arc<TscSpecifierMap>, ) -> JsRuntime { JsRuntime::new(RuntimeOptions { - extensions: vec![deno_tsc::init_ops(performance, cache)], + extensions: vec![deno_tsc::init_ops(performance, cache, specifier_map)], startup_snapshot: Some(tsc::compiler_snapshot()), ..Default::default() }) @@ -3467,6 +3839,7 @@ deno_core::extension!(deno_tsc, options = { performance: Arc<Performance>, cache: Arc<dyn HttpCache>, + specifier_map: Arc<TscSpecifierMap>, }, state = |state, options| { state.put(State::new( @@ -3478,6 +3851,7 @@ deno_core::extension!(deno_tsc, maybe_import_map: None, npm: None, }), + options.specifier_map, options.performance, )); }, @@ -3969,7 +4343,7 @@ impl RequestMethod { json!({ "id": id, "method": "findRenameLocations", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, "findInStrings": find_in_strings, "findInComments": find_in_comments, @@ -3988,7 +4362,7 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getApplicableRefactors", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "range": { "pos": span.start, "end": span.start + span.length }, "preferences": preferences, "kind": kind, @@ -4003,7 +4377,7 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getEditsForRefactor", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "formatCodeSettings": format_code_settings, "range": { "pos": span.start, "end": span.start + span.length}, "refactorName": refactor_name, @@ -4018,8 +4392,8 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getEditsForFileRename", - "oldSpecifier": state.denormalize_specifier(old_specifier), - "newSpecifier": state.denormalize_specifier(new_specifier), + "oldSpecifier": state.specifier_map.denormalize(old_specifier), + "newSpecifier": state.specifier_map.denormalize(new_specifier), "formatCodeSettings": format_code_settings, "preferences": preferences, }), @@ -4033,7 +4407,7 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getCodeFixes", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "startPosition": start_pos, "endPosition": end_pos, "errorCodes": error_codes, @@ -4048,16 +4422,24 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getCombinedCodeFix", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "fixId": fix_id, "formatCodeSettings": format_code_settings, "preferences": preferences, }), - RequestMethod::GetCompletionDetails(args) => json!({ - "id": id, - "method": "getCompletionDetails", - "args": args - }), + RequestMethod::GetCompletionDetails(args) => { + let mut args = json!(args); + let specifier = + args.as_object_mut().unwrap().get_mut("specifier").unwrap(); + if let Ok(s) = ModuleSpecifier::parse(specifier.as_str().unwrap()) { + *specifier = json!(state.specifier_map.denormalize(&s)); + } + json!({ + "id": id, + "method": "getCompletionDetails", + "args": args + }) + } RequestMethod::GetCompletions(( specifier, position, @@ -4067,7 +4449,7 @@ impl RequestMethod { json!({ "id": id, "method": "getCompletions", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, "preferences": preferences, "formatCodeSettings": format_code_settings, @@ -4076,13 +4458,13 @@ impl RequestMethod { RequestMethod::GetDefinition((specifier, position)) => json!({ "id": id, "method": "getDefinition", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, }), RequestMethod::GetDiagnostics(specifiers) => json!({ "id": id, "method": "getDiagnostics", - "specifiers": specifiers.iter().map(|s| state.denormalize_specifier(s)).collect::<Vec<String>>(), + "specifiers": specifiers.iter().map(|s| state.specifier_map.denormalize(s)).collect::<Vec<String>>(), }), RequestMethod::GetDocumentHighlights(( specifier, @@ -4091,22 +4473,22 @@ impl RequestMethod { )) => json!({ "id": id, "method": "getDocumentHighlights", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, - "filesToSearch": files_to_search, + "filesToSearch": files_to_search.iter().map(|s| state.specifier_map.denormalize(s)).collect::<Vec<_>>(), }), RequestMethod::GetEncodedSemanticClassifications((specifier, span)) => { json!({ "id": id, "method": "getEncodedSemanticClassifications", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "span": span, }) } RequestMethod::GetImplementation((specifier, position)) => json!({ "id": id, "method": "getImplementation", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, }), RequestMethod::GetNavigateToItems(GetNavigateToItemsArgs { @@ -4123,17 +4505,17 @@ impl RequestMethod { RequestMethod::GetNavigationTree(specifier) => json!({ "id": id, "method": "getNavigationTree", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), }), RequestMethod::GetOutliningSpans(specifier) => json!({ "id": id, "method": "getOutliningSpans", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), }), RequestMethod::GetQuickInfo((specifier, position)) => json!({ "id": id, "method": "getQuickInfo", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, }), RequestMethod::FindReferences { @@ -4142,14 +4524,14 @@ impl RequestMethod { } => json!({ "id": id, "method": "findReferences", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, }), RequestMethod::GetSignatureHelpItems((specifier, position, options)) => { json!({ "id": id, "method": "getSignatureHelpItems", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position, "options": options, }) @@ -4158,7 +4540,7 @@ impl RequestMethod { json!({ "id": id, "method": "getSmartSelectionRange", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position }) } @@ -4172,14 +4554,14 @@ impl RequestMethod { } => json!({ "id": id, "method": "getTypeDefinition", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position }), RequestMethod::PrepareCallHierarchy((specifier, position)) => { json!({ "id": id, "method": "prepareCallHierarchy", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position }) } @@ -4190,7 +4572,7 @@ impl RequestMethod { json!({ "id": id, "method": "provideCallHierarchyIncomingCalls", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position }) } @@ -4201,7 +4583,7 @@ impl RequestMethod { json!({ "id": id, "method": "provideCallHierarchyOutgoingCalls", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "position": position }) } @@ -4209,7 +4591,7 @@ impl RequestMethod { json!({ "id": id, "method": "provideInlayHints", - "specifier": state.denormalize_specifier(specifier), + "specifier": state.specifier_map.denormalize(specifier), "span": span, "preferences": preferences, }) @@ -4316,7 +4698,7 @@ mod tests { let cache = Arc::new(GlobalHttpCache::new(location.clone(), RealDenoCacheEnv)); let state_snapshot = Arc::new(mock_state_snapshot(sources, &location)); - let mut runtime = js_runtime(Default::default(), cache); + let mut runtime = js_runtime(Default::default(), cache, Default::default()); start(&mut runtime, debug).unwrap(); let ts_config = TsConfig::new(config); assert_eq!( |