summaryrefslogtreecommitdiff
path: root/cli/lsp/documents.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r--cli/lsp/documents.rs158
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::*;