diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-04-27 15:46:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-27 15:46:39 +0200 |
commit | 1f52d180c08b5fc060ecf9d24e4d7f31377479b7 (patch) | |
tree | d2540ce182ded4b5bd3d542c76403e03a381c369 | |
parent | 8e9ab9e33ea2c972762cc345c584391c37731b33 (diff) |
refactor: factor out AstParser from DocParser (#4923)
-rw-r--r-- | cli/doc/class.rs | 21 | ||||
-rw-r--r-- | cli/doc/interface.rs | 12 | ||||
-rw-r--r-- | cli/doc/module.rs | 5 | ||||
-rw-r--r-- | cli/doc/namespace.rs | 4 | ||||
-rw-r--r-- | cli/doc/parser.rs | 150 | ||||
-rw-r--r-- | cli/lib.rs | 1 | ||||
-rw-r--r-- | cli/swc_util.rs | 164 |
7 files changed, 204 insertions, 153 deletions
diff --git a/cli/doc/class.rs b/cli/doc/class.rs index 004be9e74..c4603972b 100644 --- a/cli/doc/class.rs +++ b/cli/doc/class.rs @@ -118,7 +118,7 @@ pub fn get_doc_for_class_decl( Constructor(ctor) => { let ctor_js_doc = doc_parser.js_doc_for_span(ctor.span()); let constructor_name = - prop_name_to_string(&doc_parser.source_map, &ctor.key); + prop_name_to_string(&doc_parser.ast_parser.source_map, &ctor.key); let mut params = vec![]; @@ -146,17 +146,16 @@ pub fn get_doc_for_class_decl( accessibility: ctor.accessibility, name: constructor_name, params, - location: doc_parser - .source_map - .lookup_char_pos(ctor.span.lo()) - .into(), + location: doc_parser.ast_parser.get_span_location(ctor.span).into(), }; constructors.push(constructor_def); } Method(class_method) => { let method_js_doc = doc_parser.js_doc_for_span(class_method.span()); - let method_name = - prop_name_to_string(&doc_parser.source_map, &class_method.key); + let method_name = prop_name_to_string( + &doc_parser.ast_parser.source_map, + &class_method.key, + ); let fn_def = function_to_function_def(&class_method.function); let method_def = ClassMethodDef { js_doc: method_js_doc, @@ -168,8 +167,8 @@ pub fn get_doc_for_class_decl( kind: class_method.kind, function_def: fn_def, location: doc_parser - .source_map - .lookup_char_pos(class_method.span.lo()) + .ast_parser + .get_span_location(class_method.span) .into(), }; methods.push(method_def); @@ -198,8 +197,8 @@ pub fn get_doc_for_class_decl( accessibility: class_prop.accessibility, name: prop_name, location: doc_parser - .source_map - .lookup_char_pos(class_prop.span.lo()) + .ast_parser + .get_span_location(class_prop.span) .into(), }; properties.push(prop_def); diff --git a/cli/doc/interface.rs b/cli/doc/interface.rs index dd9acc650..fb7a2c853 100644 --- a/cli/doc/interface.rs +++ b/cli/doc/interface.rs @@ -114,8 +114,8 @@ pub fn get_doc_for_ts_interface_decl( name, js_doc: method_js_doc, location: doc_parser - .source_map - .lookup_char_pos(ts_method_sig.span.lo()) + .ast_parser + .get_span_location(ts_method_sig.span) .into(), optional: ts_method_sig.optional, params, @@ -151,8 +151,8 @@ pub fn get_doc_for_ts_interface_decl( name, js_doc: prop_js_doc, location: doc_parser - .source_map - .lookup_char_pos(ts_prop_sig.span.lo()) + .ast_parser + .get_span_location(ts_prop_sig.span) .into(), params, ts_type, @@ -183,8 +183,8 @@ pub fn get_doc_for_ts_interface_decl( let call_sig_def = InterfaceCallSignatureDef { js_doc: call_sig_js_doc, location: doc_parser - .source_map - .lookup_char_pos(ts_call_sig.span.lo()) + .ast_parser + .get_span_location(ts_call_sig.span) .into(), params, ts_type, diff --git a/cli/doc/module.rs b/cli/doc/module.rs index d2284b36c..2de9c7ca8 100644 --- a/cli/doc/module.rs +++ b/cli/doc/module.rs @@ -14,10 +14,7 @@ pub fn get_doc_node_for_export_decl( use crate::swc_ecma_ast::Decl; let js_doc = doc_parser.js_doc_for_span(export_span); - let location = doc_parser - .source_map - .lookup_char_pos(export_span.lo()) - .into(); + let location = doc_parser.ast_parser.get_span_location(export_span).into(); match &export_decl.decl { Decl::Class(class_decl) => { diff --git a/cli/doc/namespace.rs b/cli/doc/namespace.rs index 02f22b661..6cbc619e8 100644 --- a/cli/doc/namespace.rs +++ b/cli/doc/namespace.rs @@ -17,8 +17,8 @@ pub fn get_doc_for_ts_namespace_decl( ) -> DocNode { let js_doc = doc_parser.js_doc_for_span(ts_namespace_decl.span); let location = doc_parser - .source_map - .lookup_char_pos(ts_namespace_decl.span.lo()) + .ast_parser + .get_span_location(ts_namespace_decl.span) .into(); let namespace_name = ts_namespace_decl.id.sym.to_string(); diff --git a/cli/doc/parser.rs b/cli/doc/parser.rs index 35694aa9a..2a15daa59 100644 --- a/cli/doc/parser.rs +++ b/cli/doc/parser.rs @@ -1,39 +1,20 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::op_error::OpError; -use crate::swc_common; use crate::swc_common::comments::CommentKind; -use crate::swc_common::comments::Comments; -use crate::swc_common::errors::Diagnostic; -use crate::swc_common::errors::DiagnosticBuilder; -use crate::swc_common::errors::Emitter; -use crate::swc_common::errors::Handler; -use crate::swc_common::errors::HandlerFlags; -use crate::swc_common::FileName; -use crate::swc_common::Globals; -use crate::swc_common::SourceMap; use crate::swc_common::Span; use crate::swc_ecma_ast; use crate::swc_ecma_ast::Decl; use crate::swc_ecma_ast::ModuleDecl; use crate::swc_ecma_ast::Stmt; -use crate::swc_ecma_parser::lexer::Lexer; -use crate::swc_ecma_parser::JscTarget; -use crate::swc_ecma_parser::Parser; -use crate::swc_ecma_parser::Session; -use crate::swc_ecma_parser::SourceFileInput; -use crate::swc_ecma_parser::Syntax; -use crate::swc_ecma_parser::TsConfig; +use crate::swc_util::AstParser; +use crate::swc_util::SwcDiagnosticBuffer; use deno_core::ErrBox; use deno_core::ModuleSpecifier; use futures::Future; use regex::Regex; use std::collections::HashMap; -use std::error::Error; -use std::fmt; use std::pin::Pin; -use std::sync::Arc; -use std::sync::RwLock; use super::namespace::NamespaceDef; use super::node; @@ -42,50 +23,6 @@ use super::DocNode; use super::DocNodeKind; use super::Location; -#[derive(Clone, Debug)] -pub struct SwcDiagnosticBuffer { - pub diagnostics: Vec<Diagnostic>, -} - -impl Error for SwcDiagnosticBuffer {} - -impl fmt::Display for SwcDiagnosticBuffer { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let msg = self - .diagnostics - .iter() - .map(|d| d.message()) - .collect::<Vec<String>>() - .join(","); - - f.pad(&msg) - } -} - -#[derive(Clone)] -pub struct SwcErrorBuffer(Arc<RwLock<SwcDiagnosticBuffer>>); - -impl SwcErrorBuffer { - pub fn default() -> Self { - Self(Arc::new(RwLock::new(SwcDiagnosticBuffer { - diagnostics: vec![], - }))) - } -} - -impl Emitter for SwcErrorBuffer { - fn emit(&mut self, db: &DiagnosticBuilder) { - self.0.write().unwrap().diagnostics.push((**db).clone()); - } -} - -impl From<SwcErrorBuffer> for SwcDiagnosticBuffer { - fn from(buf: SwcErrorBuffer) -> Self { - let s = buf.0.read().unwrap(); - s.clone() - } -} - pub trait DocFileLoader { fn resolve( &self, @@ -102,34 +39,15 @@ pub trait DocFileLoader { } pub struct DocParser { + pub ast_parser: AstParser, pub loader: Box<dyn DocFileLoader>, - pub buffered_error: SwcErrorBuffer, - pub source_map: Arc<SourceMap>, - pub handler: Handler, - pub comments: Comments, - pub globals: Globals, } impl DocParser { pub fn new(loader: Box<dyn DocFileLoader>) -> Self { - let buffered_error = SwcErrorBuffer::default(); - - let handler = Handler::with_emitter_and_flags( - Box::new(buffered_error.clone()), - HandlerFlags { - dont_buffer_diagnostics: true, - can_emit_warnings: true, - ..Default::default() - }, - ); - DocParser { loader, - buffered_error, - source_map: Arc::new(SourceMap::default()), - handler, - comments: Comments::default(), - globals: Globals::new(), + ast_parser: AstParser::new(), } } @@ -138,47 +56,19 @@ impl DocParser { file_name: &str, source_code: &str, ) -> Result<ModuleDoc, SwcDiagnosticBuffer> { - swc_common::GLOBALS.set(&self.globals, || { - let swc_source_file = self.source_map.new_source_file( - FileName::Custom(file_name.to_string()), - source_code.to_string(), - ); - - let buffered_err = self.buffered_error.clone(); - let session = Session { - handler: &self.handler, - }; - - let mut ts_config = TsConfig::default(); - ts_config.dynamic_import = true; - let syntax = Syntax::Typescript(ts_config); - - let lexer = Lexer::new( - session, - syntax, - JscTarget::Es2019, - SourceFileInput::from(&*swc_source_file), - Some(&self.comments), - ); - - let mut parser = Parser::new_from(session, lexer); - - let module = - parser - .parse_module() - .map_err(move |mut err: DiagnosticBuilder| { - err.cancel(); - SwcDiagnosticBuffer::from(buffered_err) - })?; - - let doc_entries = self.get_doc_nodes_for_module_body(module.body.clone()); - let reexports = self.get_reexports_for_module_body(module.body); - let module_doc = ModuleDoc { - exports: doc_entries, - reexports, - }; - Ok(module_doc) - }) + self + .ast_parser + .parse_module(file_name, source_code, |parse_result| { + let module = parse_result?; + let doc_entries = + self.get_doc_nodes_for_module_body(module.body.clone()); + let reexports = self.get_reexports_for_module_body(module.body); + let module_doc = ModuleDoc { + exports: doc_entries, + reexports, + }; + Ok(module_doc) + }) } pub async fn parse(&self, file_name: &str) -> Result<Vec<DocNode>, ErrBox> { @@ -323,7 +213,7 @@ impl DocParser { fn details_for_span(&self, span: Span) -> (Option<String>, Location) { let js_doc = self.js_doc_for_span(span); - let location = self.source_map.lookup_char_pos(span.lo()).into(); + let location = self.ast_parser.get_span_location(span).into(); (js_doc, location) } @@ -567,13 +457,13 @@ impl DocParser { } pub fn js_doc_for_span(&self, span: Span) -> Option<String> { - let comments = self.comments.take_leading_comments(span.lo())?; + let comments = self.ast_parser.get_span_comments(span); let js_doc_comment = comments.iter().find(|comment| { comment.kind == CommentKind::Block && comment.text.starts_with('*') })?; let mut margin_pat = String::from(""); - if let Some(margin) = self.source_map.span_to_margin(span) { + if let Some(margin) = self.ast_parser.source_map.span_to_margin(span) { for _ in 0..margin { margin_pat.push(' '); } diff --git a/cli/lib.rs b/cli/lib.rs index 2cd077ebb..9d35710ab 100644 --- a/cli/lib.rs +++ b/cli/lib.rs @@ -53,6 +53,7 @@ pub mod signal; pub mod source_maps; mod startup_data; pub mod state; +mod swc_util; mod test_runner; pub mod test_util; mod tokio_util; diff --git a/cli/swc_util.rs b/cli/swc_util.rs new file mode 100644 index 000000000..2086a5ded --- /dev/null +++ b/cli/swc_util.rs @@ -0,0 +1,164 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::swc_common; +use crate::swc_common::comments::Comments; +use crate::swc_common::errors::Diagnostic; +use crate::swc_common::errors::DiagnosticBuilder; +use crate::swc_common::errors::Emitter; +use crate::swc_common::errors::Handler; +use crate::swc_common::errors::HandlerFlags; +use crate::swc_common::FileName; +use crate::swc_common::Globals; +use crate::swc_common::SourceMap; +use crate::swc_common::Span; +use crate::swc_ecma_ast; +use crate::swc_ecma_parser::lexer::Lexer; +use crate::swc_ecma_parser::JscTarget; +use crate::swc_ecma_parser::Parser; +use crate::swc_ecma_parser::Session; +use crate::swc_ecma_parser::SourceFileInput; +use crate::swc_ecma_parser::Syntax; +use crate::swc_ecma_parser::TsConfig; + +use std::error::Error; +use std::fmt; +use std::sync::Arc; +use std::sync::RwLock; + +#[derive(Clone, Debug)] +pub struct SwcDiagnosticBuffer { + pub diagnostics: Vec<Diagnostic>, +} + +impl Error for SwcDiagnosticBuffer {} + +impl fmt::Display for SwcDiagnosticBuffer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let msg = self + .diagnostics + .iter() + .map(|d| d.message()) + .collect::<Vec<String>>() + .join(","); + + f.pad(&msg) + } +} + +#[derive(Clone)] +pub struct SwcErrorBuffer(Arc<RwLock<SwcDiagnosticBuffer>>); + +impl SwcErrorBuffer { + pub fn default() -> Self { + Self(Arc::new(RwLock::new(SwcDiagnosticBuffer { + diagnostics: vec![], + }))) + } +} + +impl Emitter for SwcErrorBuffer { + fn emit(&mut self, db: &DiagnosticBuilder) { + self.0.write().unwrap().diagnostics.push((**db).clone()); + } +} + +impl From<SwcErrorBuffer> for SwcDiagnosticBuffer { + fn from(buf: SwcErrorBuffer) -> Self { + let s = buf.0.read().unwrap(); + s.clone() + } +} + +/// Low-level utility structure with common AST parsing functions. +/// +/// Allows to build more complicated parser by providing a callback +/// to `parse_module`. +pub struct AstParser { + pub buffered_error: SwcErrorBuffer, + pub source_map: Arc<SourceMap>, + pub handler: Handler, + pub comments: Comments, + pub globals: Globals, +} + +impl AstParser { + pub fn new() -> Self { + let buffered_error = SwcErrorBuffer::default(); + + let handler = Handler::with_emitter_and_flags( + Box::new(buffered_error.clone()), + HandlerFlags { + dont_buffer_diagnostics: true, + can_emit_warnings: true, + ..Default::default() + }, + ); + + AstParser { + buffered_error, + source_map: Arc::new(SourceMap::default()), + handler, + comments: Comments::default(), + globals: Globals::new(), + } + } + + pub fn parse_module<F, R>( + &self, + file_name: &str, + source_code: &str, + callback: F, + ) -> R + where + F: FnOnce(Result<swc_ecma_ast::Module, SwcDiagnosticBuffer>) -> R, + { + swc_common::GLOBALS.set(&self.globals, || { + let swc_source_file = self.source_map.new_source_file( + FileName::Custom(file_name.to_string()), + source_code.to_string(), + ); + + let buffered_err = self.buffered_error.clone(); + let session = Session { + handler: &self.handler, + }; + + let mut ts_config = TsConfig::default(); + ts_config.dynamic_import = true; + let syntax = Syntax::Typescript(ts_config); + + let lexer = Lexer::new( + session, + syntax, + JscTarget::Es2019, + SourceFileInput::from(&*swc_source_file), + Some(&self.comments), + ); + + let mut parser = Parser::new_from(session, lexer); + + let parse_result = + parser + .parse_module() + .map_err(move |mut err: DiagnosticBuilder| { + err.cancel(); + SwcDiagnosticBuffer::from(buffered_err) + }); + + callback(parse_result) + }) + } + + pub fn get_span_location(&self, span: Span) -> swc_common::Loc { + self.source_map.lookup_char_pos(span.lo()) + } + + pub fn get_span_comments( + &self, + span: Span, + ) -> Vec<swc_common::comments::Comment> { + self + .comments + .take_leading_comments(span.lo()) + .unwrap_or_else(|| vec![]) + } +} |