diff options
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r-- | cli/lsp/documents.rs | 158 |
1 files changed, 103 insertions, 55 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index ca771e656..18c3710fb 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -17,6 +17,7 @@ use crate::resolver::JsxResolver; use crate::text_encoding; use deno_ast::MediaType; +use deno_ast::ParsedSource; use deno_ast::SourceTextInfo; use deno_core::error::custom_error; use deno_core::error::AnyError; @@ -71,30 +72,6 @@ static TSX_HEADERS: Lazy<HashMap<String, String>> = Lazy::new(|| { .collect() }); -/// The default parser from `deno_graph` does not include the configuration -/// options we require here, and so implementing an empty struct that provides -/// the trait. -#[derive(Debug, Default)] -struct SourceParser {} - -impl deno_graph::SourceParser for SourceParser { - fn parse_module( - &self, - specifier: &ModuleSpecifier, - source: Arc<str>, - media_type: MediaType, - ) -> Result<deno_ast::ParsedSource, deno_ast::Diagnostic> { - deno_ast::parse_module(deno_ast::ParseParams { - specifier: specifier.to_string(), - text_info: SourceTextInfo::new(source), - media_type, - capture_tokens: true, - scope_analysis: true, - maybe_syntax: None, - }) - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum LanguageId { JavaScript, @@ -218,7 +195,7 @@ impl AssetOrDocument { pub fn maybe_parsed_source( &self, - ) -> Option<Result<deno_ast::ParsedSource, deno_graph::ModuleGraphError>> { + ) -> Option<Result<deno_ast::ParsedSource, deno_ast::Diagnostic>> { self.document().and_then(|d| d.maybe_parsed_source()) } @@ -231,6 +208,11 @@ impl AssetOrDocument { } } +type MaybeModuleResult = + Option<Result<deno_graph::Module, deno_graph::ModuleGraphError>>; +type MaybeParsedSourceResult = + Option<Result<ParsedSource, deno_ast::Diagnostic>>; + #[derive(Debug, Clone)] struct DocumentInner { /// contains the last-known-good set of dependencies from parsing the module @@ -239,9 +221,9 @@ struct DocumentInner { line_index: Arc<LineIndex>, maybe_language_id: Option<LanguageId>, maybe_lsp_version: Option<i32>, - maybe_module: - Option<Result<deno_graph::Module, deno_graph::ModuleGraphError>>, + maybe_module: MaybeModuleResult, maybe_navigation_tree: Option<Arc<tsc::NavigationTree>>, + maybe_parsed_source: MaybeParsedSourceResult, specifier: ModuleSpecifier, text_info: SourceTextInfo, } @@ -257,23 +239,21 @@ impl Document { content: Arc<str>, maybe_resolver: Option<&dyn deno_graph::source::Resolver>, ) -> Self { - let parser = SourceParser::default(); // we only ever do `Document::new` on on disk resources that are supposed to // be diagnosable, unlike `Document::open`, so it is safe to unconditionally // parse the module. - let maybe_module = Some(deno_graph::parse_module( + let (maybe_module, maybe_parsed_source) = lsp_deno_graph_analyze( &specifier, - maybe_headers, content.clone(), - Some(&deno_graph::ModuleKind::Esm), + maybe_headers, maybe_resolver, - Some(&parser), - )); + ); let dependencies = if let Some(Ok(module)) = &maybe_module { Arc::new(module.dependencies.clone()) } else { Arc::new(BTreeMap::new()) }; + // todo(dsherret): retrieve this from the parsed source if it let text_info = SourceTextInfo::new(content); let line_index = Arc::new(LineIndex::new(text_info.text_str())); Self(Arc::new(DocumentInner { @@ -284,6 +264,7 @@ impl Document { maybe_lsp_version: None, maybe_module, maybe_navigation_tree: None, + maybe_parsed_source, text_info, specifier, })) @@ -297,18 +278,15 @@ impl Document { maybe_resolver: Option<&dyn deno_graph::source::Resolver>, ) -> Self { let maybe_headers = language_id.as_headers(); - let parser = SourceParser::default(); - let maybe_module = if language_id.is_diagnosable() { - Some(deno_graph::parse_module( + let (maybe_module, maybe_parsed_source) = if language_id.is_diagnosable() { + lsp_deno_graph_analyze( &specifier, - maybe_headers, content.clone(), - Some(&deno_graph::ModuleKind::Esm), + maybe_headers, maybe_resolver, - Some(&parser), - )) + ) } else { - None + (None, None) }; let dependencies = if let Some(Ok(module)) = &maybe_module { Arc::new(module.dependencies.clone()) @@ -325,6 +303,7 @@ impl Document { maybe_lsp_version: Some(version), maybe_module, maybe_navigation_tree: None, + maybe_parsed_source, text_info: source, specifier, })) @@ -353,7 +332,7 @@ impl Document { } } let content: Arc<str> = content.into(); - let maybe_module = if self + let (maybe_module, maybe_parsed_source) = if self .0 .maybe_language_id .as_ref() @@ -365,17 +344,14 @@ impl Document { .maybe_language_id .as_ref() .and_then(|li| li.as_headers()); - let parser = SourceParser::default(); - Some(deno_graph::parse_module( + lsp_deno_graph_analyze( &self.0.specifier, - maybe_headers, content.clone(), - Some(&deno_graph::ModuleKind::Esm), + maybe_headers, maybe_resolver, - Some(&parser), - )) + ) } else { - None + (None, None) }; let dependencies = if let Some(Ok(module)) = &maybe_module { Arc::new(module.dependencies.clone()) @@ -393,6 +369,7 @@ impl Document { text_info, line_index, maybe_module, + maybe_parsed_source, maybe_lsp_version: Some(version), maybe_navigation_tree: None, ..(*self.0).clone() @@ -493,12 +470,8 @@ impl Document { pub fn maybe_parsed_source( &self, - ) -> Option<Result<deno_ast::ParsedSource, deno_graph::ModuleGraphError>> { - let module_result = self.maybe_module()?; - match module_result { - Ok(module) => Some(Ok(module.maybe_parsed_source.clone()?)), - Err(err) => Some(Err(err.clone())), - } + ) -> Option<Result<deno_ast::ParsedSource, deno_ast::Diagnostic>> { + self.0.maybe_parsed_source.clone() } pub fn maybe_navigation_tree(&self) -> Option<Arc<tsc::NavigationTree>> { @@ -1138,6 +1111,81 @@ impl Documents { } } +/// The default parser from `deno_graph` does not include the configuration +/// options we require for the lsp. +#[derive(Debug, Default)] +struct LspModuleParser; + +impl deno_graph::ModuleParser for LspModuleParser { + fn parse_module( + &self, + specifier: &deno_graph::ModuleSpecifier, + source: Arc<str>, + media_type: MediaType, + ) -> deno_core::anyhow::Result<ParsedSource, deno_ast::Diagnostic> { + deno_ast::parse_module(deno_ast::ParseParams { + specifier: specifier.to_string(), + text_info: SourceTextInfo::new(source), + media_type, + capture_tokens: true, + scope_analysis: true, + maybe_syntax: None, + }) + } +} + +fn lsp_deno_graph_analyze( + specifier: &ModuleSpecifier, + content: Arc<str>, + maybe_headers: Option<&HashMap<String, String>>, + maybe_resolver: Option<&dyn deno_graph::source::Resolver>, +) -> (MaybeModuleResult, MaybeParsedSourceResult) { + use deno_graph::ModuleParser; + + let analyzer = deno_graph::CapturingModuleAnalyzer::new( + Some(Box::new(LspModuleParser::default())), + None, + ); + let parsed_source_result = analyzer.parse_module( + specifier, + content.clone(), + get_media_type(specifier, maybe_headers), + ); + let module_result = match &parsed_source_result { + Ok(_) => deno_graph::parse_module( + specifier, + maybe_headers, + content, + Some(&deno_graph::ModuleKind::Esm), + maybe_resolver, + Some(&analyzer), + ), + Err(err) => Err(deno_graph::ModuleGraphError::ParseErr( + specifier.clone(), + err.clone(), + )), + }; + + (Some(module_result), Some(parsed_source_result)) +} + +// todo(dsherret): use `MediaType::from_specifier_and_headers` once +// https://github.com/denoland/deno_ast/pull/108 is merged +fn get_media_type( + specifier: &ModuleSpecifier, + maybe_headers: Option<&HashMap<String, String>>, +) -> MediaType { + if let Some(headers) = maybe_headers { + if let Some(content_type) = headers.get("content-type") { + MediaType::from_content_type(specifier, content_type) + } else { + MediaType::from(specifier) + } + } else { + MediaType::from(specifier) + } +} + #[cfg(test)] mod tests { use super::*; |