mirror of
https://github.com/denoland/deno.git
synced 2025-08-03 02:22:40 +00:00
refactor(lsp): use deno_ast and cache swc ASTs (#11780)
This commit is contained in:
parent
a5bcf7033e
commit
2c2e3ec1ca
39 changed files with 1037 additions and 1758 deletions
|
@ -1,11 +1,18 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use super::analysis;
|
||||
use super::config::Config;
|
||||
use super::config::WorkspaceSettings;
|
||||
use super::language_server;
|
||||
use super::text::LineIndex;
|
||||
use super::tsc;
|
||||
use crate::ast::ParsedModule;
|
||||
use super::tsc::NavigationTree;
|
||||
|
||||
use deno_core::error::anyhow;
|
||||
use deno_ast::swc::ast;
|
||||
use deno_ast::swc::common::Span;
|
||||
use deno_ast::swc::visit::Node;
|
||||
use deno_ast::swc::visit::Visit;
|
||||
use deno_ast::swc::visit::VisitWith;
|
||||
use deno_ast::ParsedSource;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::resolve_url;
|
||||
use deno_core::serde::Deserialize;
|
||||
|
@ -18,11 +25,6 @@ use regex::Regex;
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
use swc_common::Span;
|
||||
use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::Node;
|
||||
use swc_ecmascript::visit::Visit;
|
||||
use swc_ecmascript::visit::VisitWith;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref ABSTRACT_MODIFIER: Regex = Regex::new(r"\babstract\b").unwrap();
|
||||
|
@ -44,24 +46,24 @@ pub struct CodeLensData {
|
|||
pub specifier: ModuleSpecifier,
|
||||
}
|
||||
|
||||
fn span_to_range(span: &Span, parsed_module: &ParsedModule) -> lsp::Range {
|
||||
let start = parsed_module.get_location(span.lo);
|
||||
let end = parsed_module.get_location(span.hi);
|
||||
fn span_to_range(span: &Span, parsed_source: &ParsedSource) -> lsp::Range {
|
||||
let start = parsed_source.source().line_and_column_index(span.lo);
|
||||
let end = parsed_source.source().line_and_column_index(span.hi);
|
||||
lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: (start.line - 1) as u32,
|
||||
character: start.col as u32,
|
||||
line: start.line_index as u32,
|
||||
character: start.column_index as u32,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: (end.line - 1) as u32,
|
||||
character: end.col as u32,
|
||||
line: end.line_index as u32,
|
||||
character: end.column_index as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
struct DenoTestCollector<'a> {
|
||||
code_lenses: Vec<lsp::CodeLens>,
|
||||
parsed_module: &'a ParsedModule,
|
||||
parsed_source: &'a ParsedSource,
|
||||
specifier: ModuleSpecifier,
|
||||
test_vars: HashSet<String>,
|
||||
}
|
||||
|
@ -69,18 +71,18 @@ struct DenoTestCollector<'a> {
|
|||
impl<'a> DenoTestCollector<'a> {
|
||||
pub fn new(
|
||||
specifier: ModuleSpecifier,
|
||||
parsed_module: &'a ParsedModule,
|
||||
parsed_source: &'a ParsedSource,
|
||||
) -> Self {
|
||||
Self {
|
||||
code_lenses: Vec::new(),
|
||||
parsed_module,
|
||||
parsed_source,
|
||||
specifier,
|
||||
test_vars: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_code_lens<N: AsRef<str>>(&mut self, name: N, span: &Span) {
|
||||
let range = span_to_range(span, self.parsed_module);
|
||||
let range = span_to_range(span, self.parsed_source);
|
||||
self.code_lenses.push(lsp::CodeLens {
|
||||
range,
|
||||
command: Some(lsp::Command {
|
||||
|
@ -370,36 +372,37 @@ pub(crate) async fn resolve_code_lens(
|
|||
|
||||
pub(crate) async fn collect(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
parsed_source: Option<&ParsedSource>,
|
||||
config: &Config,
|
||||
line_index: &LineIndex,
|
||||
navigation_tree: &NavigationTree,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
let mut code_lenses = collect_test(specifier, language_server)?;
|
||||
code_lenses.extend(collect_tsc(specifier, language_server).await?);
|
||||
let mut code_lenses = collect_test(specifier, parsed_source, config)?;
|
||||
code_lenses.extend(
|
||||
collect_tsc(
|
||||
specifier,
|
||||
&config.get_workspace_settings(),
|
||||
line_index,
|
||||
navigation_tree,
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
Ok(code_lenses)
|
||||
}
|
||||
|
||||
fn collect_test(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
parsed_source: Option<&ParsedSource>,
|
||||
config: &Config,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
if language_server.config.specifier_code_lens_test(specifier) {
|
||||
let source = language_server
|
||||
.get_text_content(specifier)
|
||||
.ok_or_else(|| anyhow!("Missing text content: {}", specifier))?;
|
||||
let media_type = language_server
|
||||
.get_media_type(specifier)
|
||||
.ok_or_else(|| anyhow!("Missing media type: {}", specifier))?;
|
||||
// we swallow parsed errors, as they are meaningless here.
|
||||
// TODO(@kitsonk) consider caching previous code_lens results to return if
|
||||
// there is a parse error to avoid issues of lenses popping in and out
|
||||
if let Ok(parsed_module) =
|
||||
analysis::parse_module(specifier, &source, &media_type)
|
||||
{
|
||||
if config.specifier_code_lens_test(specifier) {
|
||||
if let Some(parsed_source) = parsed_source {
|
||||
let mut collector =
|
||||
DenoTestCollector::new(specifier.clone(), &parsed_module);
|
||||
parsed_module.module.visit_with(
|
||||
DenoTestCollector::new(specifier.clone(), parsed_source);
|
||||
parsed_source.module().visit_with(
|
||||
&ast::Invalid {
|
||||
span: swc_common::DUMMY_SP,
|
||||
span: deno_ast::swc::common::DUMMY_SP,
|
||||
},
|
||||
&mut collector,
|
||||
);
|
||||
|
@ -412,13 +415,10 @@ fn collect_test(
|
|||
/// Return tsc navigation tree code lenses.
|
||||
async fn collect_tsc(
|
||||
specifier: &ModuleSpecifier,
|
||||
language_server: &mut language_server::Inner,
|
||||
workspace_settings: &WorkspaceSettings,
|
||||
line_index: &LineIndex,
|
||||
navigation_tree: &NavigationTree,
|
||||
) -> Result<Vec<lsp::CodeLens>, AnyError> {
|
||||
let workspace_settings = language_server.config.get_workspace_settings();
|
||||
let line_index = language_server
|
||||
.get_line_index_sync(specifier)
|
||||
.ok_or_else(|| anyhow!("Missing line index."))?;
|
||||
let navigation_tree = language_server.get_navigation_tree(specifier).await?;
|
||||
let code_lenses = Rc::new(RefCell::new(Vec::new()));
|
||||
navigation_tree.walk(&|i, mp| {
|
||||
let mut code_lenses = code_lenses.borrow_mut();
|
||||
|
@ -428,7 +428,7 @@ async fn collect_tsc(
|
|||
let source = CodeLensSource::Implementations;
|
||||
match i.kind {
|
||||
tsc::ScriptElementKind::InterfaceElement => {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
tsc::ScriptElementKind::ClassElement
|
||||
| tsc::ScriptElementKind::MemberFunctionElement
|
||||
|
@ -436,7 +436,7 @@ async fn collect_tsc(
|
|||
| tsc::ScriptElementKind::MemberGetAccessorElement
|
||||
| tsc::ScriptElementKind::MemberSetAccessorElement => {
|
||||
if ABSTRACT_MODIFIER.is_match(&i.kind_modifiers) {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -448,31 +448,31 @@ async fn collect_tsc(
|
|||
let source = CodeLensSource::References;
|
||||
if let Some(parent) = &mp {
|
||||
if parent.kind == tsc::ScriptElementKind::EnumElement {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
}
|
||||
match i.kind {
|
||||
tsc::ScriptElementKind::FunctionElement => {
|
||||
if workspace_settings.code_lens.references_all_functions {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
}
|
||||
tsc::ScriptElementKind::ConstElement
|
||||
| tsc::ScriptElementKind::LetElement
|
||||
| tsc::ScriptElementKind::VariableElement => {
|
||||
if EXPORT_MODIFIER.is_match(&i.kind_modifiers) {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
}
|
||||
tsc::ScriptElementKind::ClassElement => {
|
||||
if i.text != "<class>" {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
}
|
||||
tsc::ScriptElementKind::InterfaceElement
|
||||
| tsc::ScriptElementKind::TypeElement
|
||||
| tsc::ScriptElementKind::EnumElement => {
|
||||
code_lenses.push(i.to_code_lens(&line_index, specifier, &source));
|
||||
code_lenses.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
tsc::ScriptElementKind::LocalFunctionElement
|
||||
| tsc::ScriptElementKind::MemberGetAccessorElement
|
||||
|
@ -485,11 +485,8 @@ async fn collect_tsc(
|
|||
tsc::ScriptElementKind::ClassElement
|
||||
| tsc::ScriptElementKind::InterfaceElement
|
||||
| tsc::ScriptElementKind::TypeElement => {
|
||||
code_lenses.push(i.to_code_lens(
|
||||
&line_index,
|
||||
specifier,
|
||||
&source,
|
||||
));
|
||||
code_lenses
|
||||
.push(i.to_code_lens(line_index, specifier, &source));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -505,8 +502,10 @@ async fn collect_tsc(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::SourceTextInfo;
|
||||
|
||||
use super::*;
|
||||
use crate::media_type::MediaType;
|
||||
|
||||
#[test]
|
||||
fn test_deno_test_collector() {
|
||||
|
@ -519,13 +518,16 @@ mod tests {
|
|||
|
||||
Deno.test("test b", function anotherTest() {});
|
||||
"#;
|
||||
let parsed_module =
|
||||
analysis::parse_module(&specifier, source, &MediaType::TypeScript)
|
||||
.unwrap();
|
||||
let parsed_module = crate::lsp::analysis::parse_module(
|
||||
&specifier,
|
||||
SourceTextInfo::from_string(source.to_string()),
|
||||
MediaType::TypeScript,
|
||||
)
|
||||
.unwrap();
|
||||
let mut collector = DenoTestCollector::new(specifier, &parsed_module);
|
||||
parsed_module.module.visit_with(
|
||||
parsed_module.module().visit_with(
|
||||
&ast::Invalid {
|
||||
span: swc_common::DUMMY_SP,
|
||||
span: deno_ast::swc::common::DUMMY_SP,
|
||||
},
|
||||
&mut collector,
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue