From d75cb1d4ff5e64e42c6b0e06689ed4e9c1eb06c5 Mon Sep 17 00:00:00 2001 From: Kitson Kelly Date: Tue, 18 Aug 2020 22:00:39 +1000 Subject: [PATCH] WIP --- compiler/ast.rs | 179 ++++++++++++++++++++------------------- compiler/lib.rs | 1 - compiler/module_graph.rs | 20 ++--- 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/compiler/ast.rs b/compiler/ast.rs index eef3a47ee2ae53..56115e6e472c75 100644 --- a/compiler/ast.rs +++ b/compiler/ast.rs @@ -45,7 +45,7 @@ use swc_ecmascript::visit::Visit; static TARGET: JscTarget = JscTarget::Es2020; -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Default, Eq, PartialEq)] pub struct Location { pub filename: String, pub line: usize, @@ -193,8 +193,9 @@ impl Default for EmitTranspileOptions { #[derive(Clone)] pub struct ParsedModule { comments: SingleThreadedComments, + pub leading_comments: Vec, module: Module, - source_map: Rc, + pub source_map: Rc, } impl fmt::Debug for ParsedModule { @@ -204,27 +205,17 @@ impl fmt::Debug for ParsedModule { } impl ParsedModule { - pub fn get_leading_comments(&self, span: &Span) -> Vec { - self - .comments - .with_leading(span.lo, |comments| comments.to_vec()) - } - /// Identifies all syntactical dependencies of a module (e.g. `import` and /// `export` statements). pub fn get_dependencies(&self) -> Vec { - let mut collector = DependencyCollector(Vec::new()); + let mut collector = DependencyCollector { + comments: &self.comments, + items: Vec::new(), + source_map: &self.source_map, + }; collector.visit_module(&self.module, &self.module); - collector.0 - } - - pub fn get_location(&self, span: &Span) -> Location { - self.source_map.lookup_char_pos(span.lo).into() - } - - pub fn get_module_leading_comments(&self) -> Vec { - self.get_leading_comments(&self.module.span) + collector.items } pub fn transpile( @@ -343,8 +334,11 @@ pub fn parse( sm.lookup_char_pos(span.lo) })) })?; + let leading_comments = + comments.with_leading(module.span.lo, |comments| comments.to_vec()); Ok(ParsedModule { + leading_comments, module, source_map: Rc::new(source_map), comments, @@ -355,24 +349,30 @@ pub fn parse( pub struct DependencyDescriptor { pub is_dynamic: bool, pub is_type: bool, - pub span: Span, + pub leading_comments: Vec, + pub location: Location, pub specifier: String, } -impl DependencyDescriptor { - pub fn default() -> Self { +impl Default for DependencyDescriptor { + fn default() -> Self { DependencyDescriptor { is_dynamic: false, is_type: false, - span: Span::default(), + leading_comments: Vec::new(), + location: Location::default(), specifier: String::default(), } } } -struct DependencyCollector(Vec); +struct DependencyCollector<'a> { + comments: &'a SingleThreadedComments, + pub items: Vec, + source_map: &'a SourceMap, +} -impl Visit for DependencyCollector { +impl<'a> Visit for DependencyCollector<'a> { fn visit_import_decl( &mut self, node: &swc_ecmascript::ast::ImportDecl, @@ -380,10 +380,15 @@ impl Visit for DependencyCollector { ) { let specifier = node.src.value.to_string(); let span = node.span; - self.0.push(DependencyDescriptor { - span, + let location: Location = self.source_map.lookup_char_pos(span.lo).into(); + let leading_comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + self.items.push(DependencyDescriptor { + leading_comments, + location, specifier, - ..DependencyDescriptor::default() + ..Default::default() }); } @@ -395,10 +400,15 @@ impl Visit for DependencyCollector { if let Some(src) = &node.src { let specifier = src.value.to_string(); let span = node.span; - self.0.push(DependencyDescriptor { - span, + let location: Location = self.source_map.lookup_char_pos(span.lo).into(); + let leading_comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + self.items.push(DependencyDescriptor { + leading_comments, + location, specifier, - ..DependencyDescriptor::default() + ..Default::default() }); } } @@ -410,10 +420,15 @@ impl Visit for DependencyCollector { ) { let specifier = node.src.value.to_string(); let span = node.span; - self.0.push(DependencyDescriptor { - span, + let location: Location = self.source_map.lookup_char_pos(span.lo).into(); + let leading_comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + self.items.push(DependencyDescriptor { + leading_comments, + location, specifier, - ..DependencyDescriptor::default() + ..Default::default() }); } @@ -424,11 +439,16 @@ impl Visit for DependencyCollector { ) { let specifier = node.arg.value.to_string(); let span = node.span; - self.0.push(DependencyDescriptor { + let location: Location = self.source_map.lookup_char_pos(span.lo).into(); + let leading_comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + self.items.push(DependencyDescriptor { is_type: true, - span, + leading_comments, + location, specifier, - ..DependencyDescriptor::default() + ..Default::default() }); } @@ -460,11 +480,17 @@ impl Visit for DependencyCollector { if let swc_ecmascript::ast::Lit::Str(str_) = lit { let specifier = str_.value.to_string(); let span = node.span; - self.0.push(DependencyDescriptor { + let location: Location = + self.source_map.lookup_char_pos(span.lo).into(); + let leading_comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + self.items.push(DependencyDescriptor { is_dynamic: true, - span, + leading_comments, + location, specifier, - ..DependencyDescriptor::default() + ..Default::default() }); } } @@ -475,8 +501,6 @@ impl Visit for DependencyCollector { #[cfg(test)] mod tests { use super::*; - use swc_common::BytePos; - use swc_common::SyntaxContext; #[test] fn test_parsed_module_get_dependencies() { @@ -495,20 +519,22 @@ mod tests { DependencyDescriptor { is_dynamic: false, is_type: false, - span: Span { - lo: BytePos(0), - hi: BytePos(33), - ctxt: SyntaxContext::empty() + leading_comments: Vec::new(), + location: Location { + filename: "https://deno.land/x/mod.js".to_owned(), + col: 0, + line: 0, }, specifier: "./test.ts".to_owned() }, DependencyDescriptor { is_dynamic: true, is_type: false, - span: Span { - lo: BytePos(56), - hi: BytePos(74), - ctxt: SyntaxContext::empty() + leading_comments: Vec::new(), + location: Location { + filename: "https://deno.land/x/mod.js".to_owned(), + col: 18, + line: 1, }, specifier: "./foo.ts".to_owned() } @@ -516,44 +542,23 @@ mod tests { ); } - #[test] - fn test_parsed_module_get_location() { - let specifier = - ModuleSpecifier::resolve_url_or_path("https://deno.land/x/mod.ts") - .unwrap(); - let source = r#"import * as bar from "./test.ts";"#; - let parsed_module = parse(&specifier, source, MediaType::TypeScript) - .expect("could not parse module"); - let dependencies = parsed_module.get_dependencies(); - let first = dependencies.first().unwrap(); - let actual = parsed_module.get_location(&first.span); - assert_eq!( - actual, - Location { - filename: "https://deno.land/x/mod.ts".to_owned(), - line: 1, - col: 0 - } - ); - } - - #[test] - fn test_parsed_module_get_leading_comments() { - let specifier = - ModuleSpecifier::resolve_url_or_path("https://deno.land/x/mod.ts") - .unwrap(); - let source = r#"// this is the first comment - // this is the second comment - import * as bar from "./test.ts";"#; - let parsed_module = parse(&specifier, source, MediaType::TypeScript) - .expect("could not parse module"); - let dependencies = parsed_module.get_dependencies(); - let first = dependencies.first().unwrap(); - let actual = parsed_module.get_leading_comments(&first.span); - assert_eq!(actual[0].text, " this is the first comment".to_string()); - assert_eq!(actual[1].text, " this is the second comment".to_string()); - assert_eq!(actual.len(), 2); - } + // #[test] + // fn test_parsed_module_get_leading_comments() { + // let specifier = + // ModuleSpecifier::resolve_url_or_path("https://deno.land/x/mod.ts") + // .unwrap(); + // let source = r#"// this is the first comment + // // this is the second comment + // import * as bar from "./test.ts";"#; + // let parsed_module = parse(&specifier, source, MediaType::TypeScript) + // .expect("could not parse module"); + // let dependencies = parsed_module.get_dependencies(); + // let first = dependencies.first().unwrap(); + // let actual = parsed_module.get_leading_comments(&first.span); + // assert_eq!(actual[0].text, " this is the first comment".to_string()); + // assert_eq!(actual[1].text, " this is the second comment".to_string()); + // assert_eq!(actual.len(), 2); + // } #[test] fn test_transpile() { diff --git a/compiler/lib.rs b/compiler/lib.rs index f0ac53f6cce7cc..716a584d02a4e7 100644 --- a/compiler/lib.rs +++ b/compiler/lib.rs @@ -198,7 +198,6 @@ pub mod tests { } type Handler = Rc>; - type SetupResult = Result<(GraphBuilder, Handler, Box<[u8]>)>; fn setup(rebuild: bool, maybe_import_map: Option) -> SetupResult { diff --git a/compiler/module_graph.rs b/compiler/module_graph.rs index c5971084f0307d..9f523048884c27 100644 --- a/compiler/module_graph.rs +++ b/compiler/module_graph.rs @@ -405,10 +405,12 @@ impl Module { let parsed_module = parse(&self.specifier, &self.source, self.media_type)?; // Parse out any triple slash references - let leading_comments = parsed_module.get_module_leading_comments(); - for comment in leading_comments.iter() { + for comment in parsed_module.leading_comments.iter() { if let Some(ts_reference) = parse_ts_reference(&comment.text) { - let location = parsed_module.get_location(&comment.span); + let location: Location = parsed_module + .source_map + .lookup_char_pos(comment.span.lo) + .into(); match ts_reference { TypeScriptReference::Path(import) => { let specifier = self.resolve_import(&import, Some(location))?; @@ -435,16 +437,14 @@ impl Module { // Parse out all the syntactical dependencies for a module let dependencies = parsed_module.get_dependencies(); for desc in dependencies.iter() { - let location = parsed_module.get_location(&desc.span); - let specifier = self.resolve_import(&desc.specifier, Some(location))?; + let specifier = + self.resolve_import(&desc.specifier, Some(desc.location.clone()))?; // Parse out any `@deno-types` pragmas and modify dependency - let comments = parsed_module.get_leading_comments(&desc.span); - let maybe_types_specifier = if !comments.is_empty() { - let comment = comments.last().unwrap(); + let maybe_types_specifier = if !desc.leading_comments.is_empty() { + let comment = desc.leading_comments.last().unwrap(); if let Some(deno_types) = parse_deno_types(&comment.text).as_ref() { - let location = parsed_module.get_location(&comment.span); - Some(self.resolve_import(deno_types, Some(location))?) + Some(self.resolve_import(deno_types, Some(desc.location.clone()))?) } else { None }