From 0cdb45a1ff17d07bb8894e53fb4df5e4d9f5d94b Mon Sep 17 00:00:00 2001 From: IWANABETHATGUY Date: Thu, 30 May 2024 15:25:23 +0800 Subject: [PATCH] feat(oxc_codegen): preserve annotate comment (#3465) 1. Copy tests from https://github.com/evanw/esbuild/blob/efa3dd2d8e895f7f9a9bef0d588560bbae7d776e/internal/bundler_tests/bundler_dce_test.go#L3833-L3971 2. Add option to preserve annotate comment like `/* #__NO_SIDE_EFFECTS__ */` and `/* #__PURE__ */` --- Cargo.lock | 9 + Cargo.toml | 1 + crates/oxc_codegen/Cargo.toml | 4 +- crates/oxc_codegen/examples/codegen.rs | 8 +- crates/oxc_codegen/examples/sourcemap.rs | 5 +- crates/oxc_codegen/src/annotation_comment.rs | 70 +++ crates/oxc_codegen/src/gen.rs | 61 ++- crates/oxc_codegen/src/lib.rs | 87 +++- crates/oxc_codegen/tests/mod.rs | 397 ++++++++++++++---- crates/oxc_linter/src/context.rs | 2 +- crates/oxc_minifier/examples/minifier.rs | 4 +- crates/oxc_minifier/tests/mod.rs | 4 +- .../oxc_transformer/examples/transformer.rs | 2 +- crates/oxc_wasm/src/lib.rs | 4 +- tasks/benchmark/benches/codegen_sourcemap.rs | 2 +- tasks/benchmark/benches/sourcemap.rs | 3 +- tasks/coverage/src/codegen.rs | 24 +- tasks/coverage/src/minifier.rs | 4 +- tasks/coverage/src/runtime/mod.rs | 7 +- tasks/coverage/src/sourcemap.rs | 1 + tasks/minsize/src/lib.rs | 4 +- tasks/transform_conformance/src/test_case.rs | 13 +- 22 files changed, 574 insertions(+), 142 deletions(-) create mode 100644 crates/oxc_codegen/src/annotation_comment.rs diff --git a/Cargo.lock b/Cargo.lock index db15559607267..e4feb0e550cfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,6 +441,12 @@ dependencies = [ "syn", ] +[[package]] +name = "daachorse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b7ef7a4be509357f4804d0a22e830daddb48f19fd604e4ad32ddce04a94c36" + [[package]] name = "dashmap" version = "5.5.3" @@ -1401,12 +1407,15 @@ version = "0.13.1" dependencies = [ "base64", "bitflags 2.5.0", + "daachorse", + "once_cell", "oxc_allocator", "oxc_ast", "oxc_parser", "oxc_sourcemap", "oxc_span", "oxc_syntax", + "rustc-hash", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 20d73e09213c0..96d0c64d2f88c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -176,6 +176,7 @@ cfg-if = "1.0.0" schemars = "0.8.21" oxc-browserslist = "0.16.1" criterion2 = { version = "0.9.0", default-features = false } +daachorse = { version = "1.0.0" } [workspace.metadata.cargo-shear] ignored = ["napi", "oxc_traverse"] diff --git a/crates/oxc_codegen/Cargo.toml b/crates/oxc_codegen/Cargo.toml index 64d47a6ee9e9b..41f9f37a1d82a 100644 --- a/crates/oxc_codegen/Cargo.toml +++ b/crates/oxc_codegen/Cargo.toml @@ -25,7 +25,9 @@ oxc_allocator = { workspace = true } oxc_syntax = { workspace = true } oxc_sourcemap = { workspace = true } bitflags = { workspace = true } - +once_cell = { workspace = true } +daachorse = { workspace = true } +rustc-hash = { workspace = true } [dev-dependencies] oxc_parser = { workspace = true } base64 = { workspace = true } diff --git a/crates/oxc_codegen/examples/codegen.rs b/crates/oxc_codegen/examples/codegen.rs index d527f3fd27baf..5fcbd44269856 100644 --- a/crates/oxc_codegen/examples/codegen.rs +++ b/crates/oxc_codegen/examples/codegen.rs @@ -28,14 +28,16 @@ fn main() -> std::io::Result<()> { println!("Original:"); println!("{source_text}"); - let options = CodegenOptions { enable_source_map: false, enable_typescript: true }; + let options = + CodegenOptions { enable_source_map: false, enable_typescript: true, ..Default::default() }; let printed = - Codegen::::new("", &source_text, options.clone()).build(&ret.program).source_text; + Codegen::::new("", &source_text, options, None).build(&ret.program).source_text; println!("Printed:"); println!("{printed}"); let ret = Parser::new(&allocator, &printed, source_type).parse(); - let minified = Codegen::::new("", &source_text, options).build(&ret.program).source_text; + let minified = + Codegen::::new("", &source_text, options, None).build(&ret.program).source_text; println!("Minified:"); println!("{minified}"); diff --git a/crates/oxc_codegen/examples/sourcemap.rs b/crates/oxc_codegen/examples/sourcemap.rs index bb1d50329f2d0..807422626454d 100644 --- a/crates/oxc_codegen/examples/sourcemap.rs +++ b/crates/oxc_codegen/examples/sourcemap.rs @@ -26,10 +26,11 @@ fn main() -> std::io::Result<()> { return Ok(()); } - let codegen_options = CodegenOptions { enable_source_map: true, enable_typescript: true }; + let codegen_options = + CodegenOptions { enable_source_map: true, enable_typescript: true, ..Default::default() }; let CodegenReturn { source_text, source_map } = - Codegen::::new(path.to_string_lossy().as_ref(), &source_text, codegen_options) + Codegen::::new(path.to_string_lossy().as_ref(), &source_text, codegen_options, None) .build(&ret.program); if let Some(source_map) = source_map { diff --git a/crates/oxc_codegen/src/annotation_comment.rs b/crates/oxc_codegen/src/annotation_comment.rs new file mode 100644 index 0000000000000..ec6c6aadf98dd --- /dev/null +++ b/crates/oxc_codegen/src/annotation_comment.rs @@ -0,0 +1,70 @@ +use std::usize; + +use daachorse::DoubleArrayAhoCorasick; +use once_cell::sync::Lazy; +use oxc_ast::{Comment, CommentKind}; + +use crate::Codegen; +static MATCHER: Lazy> = Lazy::new(|| { + let patterns = vec!["#__NO_SIDE_EFFECTS__", "@__NO_SIDE_EFFECTS__", "@__PURE__", "#__PURE__"]; + + DoubleArrayAhoCorasick::new(patterns).unwrap() +}); + +pub fn get_leading_annotate_comment( + node_start: u32, + codegen: &mut Codegen<{ MINIFY }>, +) -> Option<(u32, Comment)> { + let maybe_leading_comment = codegen.try_get_leading_comment(node_start); + let (comment_start, comment) = maybe_leading_comment?; + let real_end = match comment.kind { + CommentKind::SingleLine => comment.end, + CommentKind::MultiLine => comment.end + 2, + }; + let source_code = codegen.source_code; + let content_between = &source_code[real_end as usize..node_start as usize]; + // Used for VariableDeclaration (Rollup only respects "const" and only for the first one) + if content_between.chars().all(|ch| ch.is_ascii_whitespace()) { + let comment_content = &source_code[*comment_start as usize..comment.end as usize]; + if MATCHER.find_iter(&comment_content).next().is_some() { + return Some((*comment_start, *comment)); + } + None + } else { + None + } +} + +pub fn print_comment( + comment_start: u32, + comment: Comment, + p: &mut Codegen<{ MINIFY }>, +) { + match comment.kind { + CommentKind::SingleLine => { + p.print_str("//"); + p.print_range_of_source_code(comment_start as usize..comment.end as usize); + p.print_soft_newline(); + p.print_indent(); + } + CommentKind::MultiLine => { + p.print_str("/*"); + p.print_range_of_source_code(comment_start as usize..comment.end as usize); + p.print_str("*/"); + p.print_soft_space(); + } + } +} + +pub fn gen_comment(node_start: u32, codegen: &mut Codegen<{ MINIFY }>) { + if !codegen.options.preserve_annotate_comments { + return; + } + if let Some((comment_start, comment)) = codegen.try_take_moved_comment(node_start) { + print_comment::(comment_start, comment, codegen); + } + let maybe_leading_annotate_comment = get_leading_annotate_comment(node_start, codegen); + if let Some((comment_start, comment)) = maybe_leading_annotate_comment { + print_comment::(comment_start, comment, codegen); + } +} diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 85c186fe1962c..11b3d300fc1d3 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1,3 +1,4 @@ +use crate::annotation_comment::{gen_comment, get_leading_annotate_comment}; use oxc_allocator::{Box, Vec}; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; @@ -29,6 +30,11 @@ where } } +/// the [GenComment] trait only generate annotate comments like `/* @__PURE__ */` and `/* @__NO_SIDE_EFFECTS__ */`. +pub trait GenComment { + fn gen_comment(&self, _p: &mut Codegen<{ MINIFY }>, _ctx: Context) {} +} + impl<'a, const MINIFY: bool, T> GenExpr for Box<'a, T> where T: GenExpr, @@ -611,10 +617,24 @@ impl<'a, const MINIFY: bool> Gen for VariableDeclaration<'a> { if p.options.enable_typescript && self.modifiers.contains(ModifierKind::Declare) { p.print_str(b"declare "); } + + if p.options.preserve_annotate_comments + && matches!(self.kind, VariableDeclarationKind::Const) + { + if let Some(declarator) = self.declarations.first() { + if let Some(ref init) = declarator.init { + if let Some(leading_annotate_comment) = + get_leading_annotate_comment(self.span.start, p) + { + p.move_comment(init.span().start, leading_annotate_comment); + } + } + } + } p.print_str(match self.kind { - VariableDeclarationKind::Const => b"const", - VariableDeclarationKind::Let => b"let", - VariableDeclarationKind::Var => b"var", + VariableDeclarationKind::Const => "const", + VariableDeclarationKind::Let => "let", + VariableDeclarationKind::Var => "var", }); if !self.declarations.is_empty() { p.print_hard_space(); @@ -637,6 +657,7 @@ impl<'a, const MINIFY: bool> Gen for VariableDeclarator<'a> { impl<'a, const MINIFY: bool> Gen for Function<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.add_source_mapping(self.span.start); + self.gen_comment(p, ctx); if !p.options.enable_typescript && self.is_typescript_syntax() { return; } @@ -847,6 +868,27 @@ impl<'a, const MINIFY: bool> Gen for ExportNamedDeclaration<'a> { if !p.options.enable_typescript && self.is_typescript_syntax() { return; } + if p.options.preserve_annotate_comments { + match &self.declaration { + Some(Declaration::FunctionDeclaration(_)) => { + gen_comment(self.span.start, p); + } + Some(Declaration::VariableDeclaration(var_decl)) + if matches!(var_decl.kind, VariableDeclarationKind::Const) => + { + if let Some(declarator) = var_decl.declarations.first() { + if let Some(ref init) = declarator.init { + if let Some(leading_annotate_comment) = + get_leading_annotate_comment(self.span.start, p) + { + p.move_comment(init.span().start, leading_annotate_comment); + } + } + } + } + _ => {} + }; + } p.print_str(b"export "); if p.options.enable_typescript && self.export_kind.is_type() { p.print_str(b"type "); @@ -1009,6 +1051,18 @@ impl<'a, const MINIFY: bool> GenExpr for Expression<'a> { } } +impl GenComment for ArrowFunctionExpression<'_> { + fn gen_comment(&self, codegen: &mut Codegen<{ MINIFY }>, _ctx: Context) { + gen_comment(self.span.start, codegen); + } +} + +impl GenComment for Function<'_> { + fn gen_comment(&self, codegen: &mut Codegen<{ MINIFY }>, _ctx: Context) { + gen_comment(self.span.start, codegen); + } +} + impl<'a, const MINIFY: bool> GenExpr for TSAsExpression<'a> { fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { if p.options.enable_typescript { @@ -1538,6 +1592,7 @@ impl<'a, const MINIFY: bool> Gen for PropertyKey<'a> { impl<'a, const MINIFY: bool> GenExpr for ArrowFunctionExpression<'a> { fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { p.wrap(precedence > Precedence::Assign, |p| { + self.gen_comment(p, ctx); if self.r#async { p.add_source_mapping(self.span.start); p.print_str(b"async"); diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index d2d0eb5abb703..8a2d56da4d5be 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -8,14 +8,18 @@ //! Code adapted from //! * [esbuild](https://github.com/evanw/esbuild/blob/main/internal/js_printer/js_printer.go) +mod annotation_comment; mod context; mod gen; mod gen_ts; mod operator; mod sourcemap_builder; +use std::ops::Range; + #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; +use oxc_ast::{Comment, Trivias}; use oxc_span::{Atom, Span}; use oxc_syntax::{ identifier::is_identifier_part, @@ -23,6 +27,7 @@ use oxc_syntax::{ precedence::Precedence, symbol::SymbolId, }; +use rustc_hash::FxHashMap; use sourcemap_builder::SourcemapBuilder; pub use crate::{ @@ -32,13 +37,16 @@ pub use crate::{ }; // use crate::mangler::Mangler; -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Copy)] pub struct CodegenOptions { /// Pass in the filename to enable source map support. pub enable_source_map: bool, /// Enable TypeScript code generation. pub enable_typescript: bool, + + /// Enable preserve annotate comments, like `/* #__PURE__ */` and `/* #__NO_SIDE_EFFECTS__ */`. + pub preserve_annotate_comments: bool, } pub struct CodegenReturn { @@ -46,7 +54,7 @@ pub struct CodegenReturn { pub source_map: Option, } -pub struct Codegen { +pub struct Codegen<'a, const MINIFY: bool> { #[allow(unused)] options: CodegenOptions, @@ -72,6 +80,16 @@ pub struct Codegen { indentation: u8, sourcemap_builder: Option, + comment_gen_related: Option, + source_code: &'a str, +} + +pub struct CommentGenRelated { + pub trivials: Trivias, + /// The key of map is the node start position, + /// the first element of value is the start of the comment + /// the second element of value includes the end of the comment and comment kind. + pub move_comment_map: FxHashMap, } #[derive(Debug, Clone, Copy)] @@ -81,16 +99,21 @@ pub enum Separator { None, } -impl Codegen { - pub fn new(source_name: &str, source_text: &str, options: CodegenOptions) -> Self { +impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> { + pub fn new( + source_name: &str, + source_code: &'a str, + options: CodegenOptions, + comment_gen_related: Option, + ) -> Self { // Initialize the output code buffer to reduce memory reallocation. // Minification will reduce by at least half of the original size. - let source_len = source_text.len(); + let source_len = source_code.len(); let capacity = if MINIFY { source_len / 2 } else { source_len }; let sourcemap_builder = options.enable_source_map.then(|| { let mut sourcemap_builder = SourcemapBuilder::default(); - sourcemap_builder.with_name_and_source(source_name, source_text); + sourcemap_builder.with_name_and_source(source_name, source_code); sourcemap_builder }); @@ -108,6 +131,8 @@ impl Codegen { start_of_default_export: 0, indentation: 0, sourcemap_builder, + comment_gen_related, + source_code, } } @@ -143,9 +168,53 @@ impl Codegen { self.code.push(ch); } - /// Push a string into the buffer - pub fn print_str(&mut self, s: &[u8]) { - self.code.extend_from_slice(s); + /// Push a single character into the buffer + pub fn print_str>(&mut self, s: T) { + self.code.extend_from_slice(s.as_ref()); + } + + /// This method to avoid rustc borrow checker issue. + /// Since if you want to print a range of source code, you need to borrow the source code + /// immutable first, and call the [Self::print_str] which is a mutable borrow. + pub fn print_range_of_source_code(&mut self, range: Range) { + self.code.extend_from_slice(self.source_code[range].as_bytes()); + } + + /// In some scenario, we want to move the comment that should be codegened to another position. + /// ```js + /// /* @__NO_SIDE_EFFECTS__ */ export const a = function() { + /// + /// }, b = 10000; + /// + /// ``` + /// should generate such output: + /// ```js + /// export const /* @__NO_SIDE_EFFECTS__ */ a = function() { + /// + /// }, b = 10000; + /// ``` + pub fn move_comment(&mut self, position: u32, full_comment_info: (u32, Comment)) { + if let Some(comment_gen_related) = &mut self.comment_gen_related { + comment_gen_related.move_comment_map.insert(position, full_comment_info); + } + } + + pub fn try_get_leading_comment(&self, start: u32) -> Option<(&u32, &Comment)> { + self.comment_gen_related.as_ref().and_then(|comment_gen_related| { + comment_gen_related.trivials.comments_range(0..start).next_back() + }) + } + + pub fn try_take_moved_comment(&mut self, node_start: u32) -> Option<(u32, Comment)> { + self.comment_gen_related.as_mut().and_then(|comment_gen_related| { + comment_gen_related.move_comment_map.remove(&node_start) + }) + } + + pub fn try_get_leading_comment_from_move_map(&self, start: u32) -> Option<&(u32, Comment)> { + self.comment_gen_related + .as_ref() + .and_then(|comment_gen_related| comment_gen_related.move_comment_map.get(&start)) } fn print_soft_space(&mut self) { diff --git a/crates/oxc_codegen/tests/mod.rs b/crates/oxc_codegen/tests/mod.rs index b9e9444917439..34aa8f0ae9051 100644 --- a/crates/oxc_codegen/tests/mod.rs +++ b/crates/oxc_codegen/tests/mod.rs @@ -2,15 +2,26 @@ use oxc_allocator::Allocator; use oxc_codegen::{Codegen, CodegenOptions}; use oxc_parser::Parser; use oxc_span::SourceType; +use rustc_hash::FxHashMap; -fn test(source_text: &str, expected: &str) { +fn test(source_text: &str, expected: &str, options: Option) { let allocator = Allocator::default(); let source_type = SourceType::default().with_module(true); - let program = Parser::new(&allocator, source_text, source_type).parse().program; + let parse_return = Parser::new(&allocator, source_text, source_type).parse(); + let program = parse_return.program; let program = allocator.alloc(program); - let result = Codegen::::new("", source_text, CodegenOptions::default()) - .build(program) - .source_text; + let options = options.unwrap_or_default(); + let result = Codegen::::new( + "", + source_text, + options, + Some(oxc_codegen::CommentGenRelated { + trivials: parse_return.trivias, + move_comment_map: FxHashMap::default(), + }), + ) + .build(program) + .source_text; assert_eq!(expected, result, "for source {source_text}, expect {expected}, got {result}"); } @@ -23,46 +34,47 @@ fn test_ts(source_text: &str, expected: &str, is_typescript_definition: bool) { let program = Parser::new(&allocator, source_text, source_type).parse().program; let program = allocator.alloc(program); let codegen_options = CodegenOptions { enable_typescript: true, ..CodegenOptions::default() }; - let result = Codegen::::new("", source_text, codegen_options).build(program).source_text; + let result = + Codegen::::new("", source_text, codegen_options, None).build(program).source_text; assert_eq!(expected, result, "for source {source_text}, expect {expected}, got {result}"); } #[test] fn string() { - test("let x = ''", "let x = '';\n"); - test(r"let x = '\b'", "let x = '\\b';\n"); - test(r"let x = '\f'", "let x = '\\f';\n"); - test("let x = '\t'", "let x = '\\t';\n"); - test(r"let x = '\v'", "let x = '\\v';\n"); - test("let x = '\\n'", "let x = '\\n';\n"); - test("let x = '\\''", "let x = \"'\";\n"); - test("let x = '\\\"'", "let x = '\"';\n"); - // test( "let x = '\\'''", "let x = `''`;\n"); - test("let x = '\\\\'", "let x = '\\\\';\n"); - test("let x = '\x00'", "let x = '\\0';\n"); - test("let x = '\x00!'", "let x = '\\0!';\n"); - test("let x = '\x001'", "let x = '\\x001';\n"); - test("let x = '\\0'", "let x = '\\0';\n"); - test("let x = '\\0!'", "let x = '\\0!';\n"); - test("let x = '\x07'", "let x = '\\x07';\n"); - test("let x = '\x07!'", "let x = '\\x07!';\n"); - test("let x = '\x071'", "let x = '\\x071';\n"); - test("let x = '\\7'", "let x = '\\x07';\n"); - test("let x = '\\7!'", "let x = '\\x07!';\n"); - // test( "let x = '\\01'", "let x = '\x01';\n"); - // test( "let x = '\x10'", "let x = '\x10';\n"); - // test( "let x = '\\x10'", "let x = '\x10';\n"); - test("let x = '\x1B'", "let x = '\\x1B';\n"); - test("let x = '\\x1B'", "let x = '\\x1B';\n"); - // test( r#"let x = '\uABCD'"#, r#"let x = "\uABCD";"#); - // test( "let x = '\\uABCD'", r#"let x = '\uABCD';\n"#); - // test( r#"let x = '\U000123AB'"#, r#"let x = '\U000123AB';\n"#); - // test( "let x = '\\u{123AB}'", r#"let x = '\U000123AB';\n"#); - // test( "let x = '\\uD808\\uDFAB'", r#"let x = '\U000123AB';\n"#); - test("let x = '\\uD808'", "let x = '\\\\ud808';\n"); - test("let x = '\\uD808X'", "let x = '\\\\ud808X';\n"); - test("let x = '\\uDFAB'", "let x = '\\\\udfab';\n"); - test("let x = '\\uDFABX'", "let x = '\\\\udfabX';\n"); + test("let x = ''", "let x = '';\n", None); + test(r"let x = '\b'", "let x = '\\b';\n", None); + test(r"let x = '\f'", "let x = '\\f';\n", None); + test("let x = '\t'", "let x = '\\t';\n", None); + test(r"let x = '\v'", "let x = '\\v';\n", None); + test("let x = '\\n'", "let x = '\\n';\n", None); + test("let x = '\\''", "let x = \"'\";\n", None); + test("let x = '\\\"'", "let x = '\"';\n", None); + // test( "let x = '\\'''", "let x = `''`;\n", None); + test("let x = '\\\\'", "let x = '\\\\';\n", None); + test("let x = '\x00'", "let x = '\\0';\n", None); + test("let x = '\x00!'", "let x = '\\0!';\n", None); + test("let x = '\x001'", "let x = '\\x001';\n", None); + test("let x = '\\0'", "let x = '\\0';\n", None); + test("let x = '\\0!'", "let x = '\\0!';\n", None); + test("let x = '\x07'", "let x = '\\x07';\n", None); + test("let x = '\x07!'", "let x = '\\x07!';\n", None); + test("let x = '\x071'", "let x = '\\x071';\n", None); + test("let x = '\\7'", "let x = '\\x07';\n", None); + test("let x = '\\7!'", "let x = '\\x07!';\n", None); + // test( "let x = '\\01'", "let x = '\x01';\n", None); + // test( "let x = '\x10'", "let x = '\x10';\n", None); + // test( "let x = '\\x10'", "let x = '\x10';\n", None); + test("let x = '\x1B'", "let x = '\\x1B';\n", None); + test("let x = '\\x1B'", "let x = '\\x1B';\n", None); + // test( r#"let x = '\uABCD'"#, r#"let x = "\uABCD";"#, None); + // test( "let x = '\\uABCD'", r#"let x = '\uABCD';\n"#, None); + // test( r#"let x = '\U000123AB'"#, r#"let x = '\U000123AB';\n"#, None); + // test( "let x = '\\u{123AB}'", r#"let x = '\U000123AB';\n"#, None); + // test( "let x = '\\uD808\\uDFAB'", r#"let x = '\U000123AB';\n"#, None); + test("let x = '\\uD808'", "let x = '\\\\ud808';\n", None); + test("let x = '\\uD808X'", "let x = '\\\\ud808X';\n", None); + test("let x = '\\uDFAB'", "let x = '\\\\udfab';\n", None); + test("let x = '\\uDFABX'", "let x = '\\\\udfabX';\n", None); // test( "let x = '\\x80'", r#"let x = '\U00000080';\n"#); // test( "let x = '\\xFF'", r#"let x = '\U000000FF';\n"#); @@ -72,72 +84,72 @@ fn string() { #[test] fn template() { - test("let x = `\\0`", "let x = `\\0`;\n"); - test("let x = `\\x01`", "let x = `\\x01`;\n"); - test("let x = `\\0${0}`", "let x = `\\0${0}`;\n"); - // test("let x = `\\x01${0}`", "let x = `\x01${0}`;\n"); - test("let x = `${0}\\0`", "let x = `${0}\\0`;\n"); - // test("let x = `${0}\\x01`", "let x = `${0}\x01`;\n"); - test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;\n"); - // test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;\n"); - - test("let x = String.raw`\\1`", "let x = String.raw`\\1`;\n"); - test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;\n"); - test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;\n"); - test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;\n"); - test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;\n"); - test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;\n"); - test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;\n"); - test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;\n"); - - test("let x = `${y}`", "let x = `${y}`;\n"); - test("let x = `$(y)`", "let x = `$(y)`;\n"); - test("let x = `{y}$`", "let x = `{y}$`;\n"); - test("let x = `$}y{`", "let x = `$}y{`;\n"); - test("let x = `\\${y}`", "let x = `\\${y}`;\n"); - // test("let x = `$\\{y}`", "let x = `\\${y}`;\n"); - - test("await tag`x`", "await tag`x`;\n"); - test("await (tag`x`)", "await tag`x`;\n"); - test("(await tag)`x`", "(await tag)`x`;\n"); - - test("await tag`${x}`", "await tag`${x}`;\n"); - test("await (tag`${x}`)", "await tag`${x}`;\n"); - test("(await tag)`${x}`", "(await tag)`${x}`;\n"); - - test("new tag`x`", "new tag`x`();\n"); - test("new (tag`x`)", "new tag`x`();\n"); - test("new tag()`x`", "new tag()`x`;\n"); - test("(new tag)`x`", "new tag()`x`;\n"); - - test("new tag`${x}`", "new tag`${x}`();\n"); - test("new (tag`${x}`)", "new tag`${x}`();\n"); - test("new tag()`${x}`", "new tag()`${x}`;\n"); - test("(new tag)`${x}`", "new tag()`${x}`;\n"); + test("let x = `\\0`", "let x = `\\0`;\n", None); + test("let x = `\\x01`", "let x = `\\x01`;\n", None); + test("let x = `\\0${0}`", "let x = `\\0${0}`;\n", None); + // test("let x = `\\x01${0}`", "let x = `\x01${0}`;\n", None); + test("let x = `${0}\\0`", "let x = `${0}\\0`;\n", None); + // test("let x = `${0}\\x01`", "let x = `${0}\x01`;\n", None); + test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;\n", None); + // test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;\n", None); + + test("let x = String.raw`\\1`", "let x = String.raw`\\1`;\n", None); + test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;\n", None); + test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;\n", None); + test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;\n", None); + test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;\n", None); + test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;\n", None); + test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;\n", None); + test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;\n", None); + + test("let x = `${y}`", "let x = `${y}`;\n", None); + test("let x = `$(y)`", "let x = `$(y)`;\n", None); + test("let x = `{y}$`", "let x = `{y}$`;\n", None); + test("let x = `$}y{`", "let x = `$}y{`;\n", None); + test("let x = `\\${y}`", "let x = `\\${y}`;\n", None); + // test("let x = `$\\{y}`", "let x = `\\${y}`;\n", None); + + test("await tag`x`", "await tag`x`;\n", None); + test("await (tag`x`)", "await tag`x`;\n", None); + test("(await tag)`x`", "(await tag)`x`;\n", None); + + test("await tag`${x}`", "await tag`${x}`;\n", None); + test("await (tag`${x}`)", "await tag`${x}`;\n", None); + test("(await tag)`${x}`", "(await tag)`${x}`;\n", None); + + test("new tag`x`", "new tag`x`();\n", None); + test("new (tag`x`)", "new tag`x`();\n", None); + test("new tag()`x`", "new tag()`x`;\n", None); + test("(new tag)`x`", "new tag()`x`;\n", None); + + test("new tag`${x}`", "new tag`${x}`();\n", None); + test("new (tag`${x}`)", "new tag`${x}`();\n", None); + test("new tag()`${x}`", "new tag()`${x}`;\n", None); + test("(new tag)`${x}`", "new tag()`${x}`;\n", None); } #[test] fn module_decl() { - test("export * as foo from 'foo'", "export * as foo from 'foo';\n"); - test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n"); - test("import {} from './foo.js' with {}", "import './foo.js' with {\n};\n"); - test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n"); + test("export * as foo from 'foo'", "export * as foo from 'foo';\n", None); + test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n", None); + test("import {} from './foo.js' with {}", "import './foo.js' with {\n};\n", None); + test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n", None); } #[test] fn new_expr() { - test("new (foo()).bar();", "new (foo()).bar();\n"); + test("new (foo()).bar();", "new (foo()).bar();\n", None); } #[test] fn for_stmt() { - test("for (let x = 0; x < 10; x++) {}", "for (let x = 0; x < 10; x++) {\n}\n"); - test("for (;;) {}", "for (;;) {\n}\n"); - test("for (let x = 1;;) {}", "for (let x = 1;;) {\n}\n"); - test("for (;true;) {}", "for (; true;) {\n}\n"); - test("for (;;i++) {}", "for (;; i++) {\n}\n"); + test("for (let x = 0; x < 10; x++) {}", "for (let x = 0; x < 10; x++) {\n}\n", None); + test("for (;;) {}", "for (;;) {\n}\n", None); + test("for (let x = 1;;) {}", "for (let x = 1;;) {\n}\n", None); + test("for (;true;) {}", "for (; true;) {\n}\n", None); + test("for (;;i++) {}", "for (;; i++) {\n}\n", None); - test("for (using x = 1;;) {}", "for (using x = 1;;) {\n}\n"); + test("for (using x = 1;;) {}", "for (using x = 1;;) {\n}\n", None); } #[test] @@ -179,3 +191,202 @@ fn typescript() { test_ts("import { Foo, type Bar } from 'foo';", "import {Foo,type Bar} from 'foo';\n", false); test_ts("export { Foo, type Bar } from 'foo';", "export { Foo, type Bar } from 'foo';", false); } + +fn test_comment_helper(source_text: &str, expected: &str) { + test( + source_text, + expected, + Some(CodegenOptions { + enable_source_map: true, + enable_typescript: false, + preserve_annotate_comments: true, + }), + ); +} +#[test] +fn annotate_comment() { + test_comment_helper( + r" + x([ + /* #__NO_SIDE_EFFECTS__ */ function() {}, + /* #__NO_SIDE_EFFECTS__ */ function y() {}, + /* #__NO_SIDE_EFFECTS__ */ function*() {}, + /* #__NO_SIDE_EFFECTS__ */ function* y() {}, + /* #__NO_SIDE_EFFECTS__ */ async function() {}, + /* #__NO_SIDE_EFFECTS__ */ async function y() {}, + /* #__NO_SIDE_EFFECTS__ */ async function*() {}, + /* #__NO_SIDE_EFFECTS__ */ async function* y() {}, + ]) + ", + r"x([/* #__NO_SIDE_EFFECTS__ */ function() { +}, /* #__NO_SIDE_EFFECTS__ */ function y() { +}, /* #__NO_SIDE_EFFECTS__ */ function* () { +}, /* #__NO_SIDE_EFFECTS__ */ function* y() { +}, /* #__NO_SIDE_EFFECTS__ */ async function() { +}, /* #__NO_SIDE_EFFECTS__ */ async function y() { +}, /* #__NO_SIDE_EFFECTS__ */ async function* () { +}, /* #__NO_SIDE_EFFECTS__ */ async function* y() { +},]); +", + ); + + test_comment_helper( + r" + x([ + /* #__NO_SIDE_EFFECTS__ */ y => y, + /* #__NO_SIDE_EFFECTS__ */ () => {}, + /* #__NO_SIDE_EFFECTS__ */ (y) => (y), + /* #__NO_SIDE_EFFECTS__ */ async y => y, + /* #__NO_SIDE_EFFECTS__ */ async () => {}, + /* #__NO_SIDE_EFFECTS__ */ async (y) => (y), + ])", + r"x([/* #__NO_SIDE_EFFECTS__ */ y => y, /* #__NO_SIDE_EFFECTS__ */ () => { +}, /* #__NO_SIDE_EFFECTS__ */ y => y, /* #__NO_SIDE_EFFECTS__ */ async y => y, /* #__NO_SIDE_EFFECTS__ */ async() => { +}, /* #__NO_SIDE_EFFECTS__ */ async y => y,]); +", + ); + test_comment_helper( + r" + x([ + /* #__NO_SIDE_EFFECTS__ */ y => y, + /* #__NO_SIDE_EFFECTS__ */ () => {}, + /* #__NO_SIDE_EFFECTS__ */ (y) => (y), + /* #__NO_SIDE_EFFECTS__ */ async y => y, + /* #__NO_SIDE_EFFECTS__ */ async () => {}, + /* #__NO_SIDE_EFFECTS__ */ async (y) => (y), + ])", + r"x([/* #__NO_SIDE_EFFECTS__ */ y => y, /* #__NO_SIDE_EFFECTS__ */ () => { +}, /* #__NO_SIDE_EFFECTS__ */ y => y, /* #__NO_SIDE_EFFECTS__ */ async y => y, /* #__NO_SIDE_EFFECTS__ */ async() => { +}, /* #__NO_SIDE_EFFECTS__ */ async y => y,]); +", + ); + // + test_comment_helper( + r" + // #__NO_SIDE_EFFECTS__ + function a() {} + // #__NO_SIDE_EFFECTS__ + function* b() {} + // #__NO_SIDE_EFFECTS__ + async function c() {} + // #__NO_SIDE_EFFECTS__ + async function* d() {} + ", + r"// #__NO_SIDE_EFFECTS__ +function a() { +} +// #__NO_SIDE_EFFECTS__ +function* b() { +} +// #__NO_SIDE_EFFECTS__ +async function c() { +} +// #__NO_SIDE_EFFECTS__ +async function* d() { +} +", + ); + + test_comment_helper( + r" + // #__NO_SIDE_EFFECTS__ + function a() {} + // #__NO_SIDE_EFFECTS__ + function* b() {} + // #__NO_SIDE_EFFECTS__ + async function c() {} + // #__NO_SIDE_EFFECTS__ + async function* d() {} + ", + r"// #__NO_SIDE_EFFECTS__ +function a() { +} +// #__NO_SIDE_EFFECTS__ +function* b() { +} +// #__NO_SIDE_EFFECTS__ +async function c() { +} +// #__NO_SIDE_EFFECTS__ +async function* d() { +} +", + ); + + test_comment_helper( + r" + /* @__NO_SIDE_EFFECTS__ */ export function a() {} + /* @__NO_SIDE_EFFECTS__ */ export function* b() {} + /* @__NO_SIDE_EFFECTS__ */ export async function c() {} + /* @__NO_SIDE_EFFECTS__ */ export async function* d() {} ", + r"/* @__NO_SIDE_EFFECTS__ */ export function a() { +} +/* @__NO_SIDE_EFFECTS__ */ export function* b() { +} +/* @__NO_SIDE_EFFECTS__ */ export async function c() { +} +/* @__NO_SIDE_EFFECTS__ */ export async function* d() { +} +", + ); + // Only "c0" and "c2" should have "no side effects" (Rollup only respects "const" and only for the first one) + test_comment_helper( + r" + /* #__NO_SIDE_EFFECTS__ */ export var v0 = function() {}, v1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ export let l0 = function() {}, l1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ export const c0 = function() {}, c1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ export var v2 = () => {}, v3 = () => {} + /* #__NO_SIDE_EFFECTS__ */ export let l2 = () => {}, l3 = () => {} + /* #__NO_SIDE_EFFECTS__ */ export const c2 = () => {}, c3 = () => {} + ", + r"export var v0 = function() { +}, v1 = function() { +}; +export let l0 = function() { +}, l1 = function() { +}; +export const c0 = /* #__NO_SIDE_EFFECTS__ */ function() { +}, c1 = function() { +}; +export var v2 = () => { +}, v3 = () => { +}; +export let l2 = () => { +}, l3 = () => { +}; +export const c2 = /* #__NO_SIDE_EFFECTS__ */ () => { +}, c3 = () => { +}; +", + ); + // Only "c0" and "c2" should have "no side effects" (Rollup only respects "const" and only for the first one) + test_comment_helper( + r" + /* #__NO_SIDE_EFFECTS__ */ var v0 = function() {}, v1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ let l0 = function() {}, l1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ const c0 = function() {}, c1 = function() {} + /* #__NO_SIDE_EFFECTS__ */ var v2 = () => {}, v3 = () => {} + /* #__NO_SIDE_EFFECTS__ */ let l2 = () => {}, l3 = () => {} + /* #__NO_SIDE_EFFECTS__ */ const c2 = () => {}, c3 = () => {} + ", + r"var v0 = function() { +}, v1 = function() { +}; +let l0 = function() { +}, l1 = function() { +}; +const c0 = /* #__NO_SIDE_EFFECTS__ */ function() { +}, c1 = function() { +}; +var v2 = () => { +}, v3 = () => { +}; +let l2 = () => { +}, l3 = () => { +}; +const c2 = /* #__NO_SIDE_EFFECTS__ */ () => { +}, c3 = () => { +}; +", + ); +} diff --git a/crates/oxc_linter/src/context.rs b/crates/oxc_linter/src/context.rs index 8e735811d7209..be6ba77fcde79 100644 --- a/crates/oxc_linter/src/context.rs +++ b/crates/oxc_linter/src/context.rs @@ -158,7 +158,7 @@ impl<'a> LintContext<'a> { #[allow(clippy::unused_self)] pub fn codegen(&self) -> Codegen { - Codegen::::new("", "", CodegenOptions::default()) + Codegen::::new("", "", CodegenOptions::default(), None) } /* JSDoc */ diff --git a/crates/oxc_minifier/examples/minifier.rs b/crates/oxc_minifier/examples/minifier.rs index d806d25807523..7e976e221bd10 100644 --- a/crates/oxc_minifier/examples/minifier.rs +++ b/crates/oxc_minifier/examples/minifier.rs @@ -43,9 +43,9 @@ fn minify(source_text: &str, source_type: SourceType, mangle: bool, whitespace: let options = MinifierOptions { mangle, ..MinifierOptions::default() }; Minifier::new(options).build(&allocator, program); if whitespace { - Codegen::::new("", source_text, CodegenOptions::default()).build(program) + Codegen::::new("", source_text, CodegenOptions::default(), None).build(program) } else { - Codegen::::new("", source_text, CodegenOptions::default()).build(program) + Codegen::::new("", source_text, CodegenOptions::default(), None).build(program) } .source_text } diff --git a/crates/oxc_minifier/tests/mod.rs b/crates/oxc_minifier/tests/mod.rs index f44023666e410..1bd653139f73a 100644 --- a/crates/oxc_minifier/tests/mod.rs +++ b/crates/oxc_minifier/tests/mod.rs @@ -19,7 +19,9 @@ pub(crate) fn minify( let program = Parser::new(&allocator, source_text, source_type).parse().program; let program = allocator.alloc(program); Minifier::new(options).build(&allocator, program); - Codegen::::new("", source_text, CodegenOptions::default()).build(program).source_text + Codegen::::new("", source_text, CodegenOptions::default(), None) + .build(program) + .source_text } pub(crate) fn test(source_text: &str, expected: &str) { diff --git a/crates/oxc_transformer/examples/transformer.rs b/crates/oxc_transformer/examples/transformer.rs index e16d8323d13bf..a6a181d59b8f3 100644 --- a/crates/oxc_transformer/examples/transformer.rs +++ b/crates/oxc_transformer/examples/transformer.rs @@ -37,7 +37,7 @@ fn main() { .build(&mut program) .unwrap(); - let printed = Codegen::::new("", &source_text, CodegenOptions::default()) + let printed = Codegen::::new("", &source_text, CodegenOptions::default(), None) .build(&program) .source_text; println!("Transformed:\n"); diff --git a/crates/oxc_wasm/src/lib.rs b/crates/oxc_wasm/src/lib.rs index 9f4e864346f60..d829cd63456d6 100644 --- a/crates/oxc_wasm/src/lib.rs +++ b/crates/oxc_wasm/src/lib.rs @@ -274,9 +274,9 @@ impl Oxc { ..CodegenOptions::default() }; self.codegen_text = if minifier_options.whitespace() { - Codegen::::new("", source_text, codegen_options).build(program).source_text + Codegen::::new("", source_text, codegen_options, None).build(program).source_text } else { - Codegen::::new("", source_text, codegen_options).build(program).source_text + Codegen::::new("", source_text, codegen_options, None).build(program).source_text }; Ok(()) diff --git a/tasks/benchmark/benches/codegen_sourcemap.rs b/tasks/benchmark/benches/codegen_sourcemap.rs index c49dd04ffd1e8..3765df1af48ca 100644 --- a/tasks/benchmark/benches/codegen_sourcemap.rs +++ b/tasks/benchmark/benches/codegen_sourcemap.rs @@ -17,7 +17,7 @@ fn bench_codegen_sourcemap(criterion: &mut Criterion) { let codegen_options = CodegenOptions { enable_source_map: true, ..CodegenOptions::default() }; b.iter_with_large_drop(|| { - Codegen::::new(file.file_name.as_str(), source_text, codegen_options.clone()) + Codegen::::new(file.file_name.as_str(), source_text, codegen_options, None) .build(&program) .source_map }); diff --git a/tasks/benchmark/benches/sourcemap.rs b/tasks/benchmark/benches/sourcemap.rs index e13f9ad935f0c..812629411716e 100644 --- a/tasks/benchmark/benches/sourcemap.rs +++ b/tasks/benchmark/benches/sourcemap.rs @@ -22,7 +22,8 @@ fn bench_sourcemap(criterion: &mut Criterion) { let CodegenReturn { source_map, source_text } = Codegen::::new( file.file_name.as_str(), source_text, - codegen_options.clone(), + codegen_options, + None, ) .build(&program); let line = source_text.matches('\n').count() as u32; diff --git a/tasks/coverage/src/codegen.rs b/tasks/coverage/src/codegen.rs index a3e517dbdeb93..7bb3625e939e0 100644 --- a/tasks/coverage/src/codegen.rs +++ b/tasks/coverage/src/codegen.rs @@ -72,12 +72,13 @@ fn get_normal_result( let options = CodegenOptions::default(); let allocator = Allocator::default(); let parse_result1 = Parser::new(&allocator, source_text, source_type).parse(); - let source_text1 = Codegen::::new("", source_text, options.clone()) + let source_text1 = Codegen::::new("", source_text, options, None) .build(&parse_result1.program) .source_text; let parse_result2 = Parser::new(&allocator, &source_text1, source_type).parse(); - let source_text2 = - Codegen::::new("", &source_text1, options).build(&parse_result2.program).source_text; + let source_text2 = Codegen::::new("", &source_text1, options, None) + .build(&parse_result2.program) + .source_text; let result = source_text1 == source_text2; if !result { @@ -114,12 +115,13 @@ fn get_minify_result( let options = CodegenOptions::default(); let allocator = Allocator::default(); let parse_result1 = Parser::new(&allocator, source_text, source_type).parse(); - let source_text1 = Codegen::::new("", source_text, options.clone()) + let source_text1 = Codegen::::new("", source_text, options, None) .build(&parse_result1.program) .source_text; let parse_result2 = Parser::new(&allocator, source_text1.as_str(), source_type).parse(); - let source_text2 = - Codegen::::new("", &source_text1, options).build(&parse_result2.program).source_text; + let source_text2 = Codegen::::new("", &source_text1, options, None) + .build(&parse_result2.program) + .source_text; let result = source_text1 == source_text2; if !result { @@ -153,15 +155,17 @@ fn get_typescript_result( source_text: &str, source_type: SourceType, ) -> bool { - let options = CodegenOptions { enable_source_map: false, enable_typescript: true }; + let options = + CodegenOptions { enable_source_map: false, enable_typescript: true, ..Default::default() }; let allocator = Allocator::default(); let parse_result1 = Parser::new(&allocator, source_text, source_type).parse(); - let source_text1 = Codegen::::new("", source_text, options.clone()) + let source_text1 = Codegen::::new("", source_text, options, None) .build(&parse_result1.program) .source_text; let parse_result2 = Parser::new(&allocator, &source_text1, source_type).parse(); - let source_text2 = - Codegen::::new("", &source_text1, options).build(&parse_result2.program).source_text; + let source_text2 = Codegen::::new("", &source_text1, options, None) + .build(&parse_result2.program) + .source_text; let result = source_text1 == source_text2; if !result { diff --git a/tasks/coverage/src/minifier.rs b/tasks/coverage/src/minifier.rs index 3495220ad1861..34269ed9fd801 100644 --- a/tasks/coverage/src/minifier.rs +++ b/tasks/coverage/src/minifier.rs @@ -100,5 +100,7 @@ fn minify(source_text: &str, source_type: SourceType, options: MinifierOptions) let program = Parser::new(&allocator, source_text, source_type).parse().program; let program = allocator.alloc(program); Minifier::new(options).build(&allocator, program); - Codegen::::new("", source_text, CodegenOptions::default()).build(program).source_text + Codegen::::new("", source_text, CodegenOptions::default(), None) + .build(program) + .source_text } diff --git a/tasks/coverage/src/runtime/mod.rs b/tasks/coverage/src/runtime/mod.rs index 4c901dac53dc9..5e43777c79031 100644 --- a/tasks/coverage/src/runtime/mod.rs +++ b/tasks/coverage/src/runtime/mod.rs @@ -138,9 +138,10 @@ impl Case for CodegenRuntimeTest262Case { let source_type = SourceType::default().with_module(is_module); let allocator = Allocator::default(); let program = Parser::new(&allocator, source_text, source_type).parse().program; - let mut text = Codegen::::new("", source_text, CodegenOptions::default()) - .build(&program) - .source_text; + let mut text = + Codegen::::new("", source_text, CodegenOptions::default(), None) + .build(&program) + .source_text; if is_only_strict { text = format!("\"use strict\";\n{text}"); } diff --git a/tasks/coverage/src/sourcemap.rs b/tasks/coverage/src/sourcemap.rs index fbeea1c065649..7b47e5d778567 100644 --- a/tasks/coverage/src/sourcemap.rs +++ b/tasks/coverage/src/sourcemap.rs @@ -133,6 +133,7 @@ impl Case for SourcemapCase { self.path.to_string_lossy().as_ref(), source_text, codegen_options, + None, ) .build(&ret.program); diff --git a/tasks/minsize/src/lib.rs b/tasks/minsize/src/lib.rs index 0f46bf3355d42..8ba5ef17dc467 100644 --- a/tasks/minsize/src/lib.rs +++ b/tasks/minsize/src/lib.rs @@ -73,7 +73,9 @@ fn minify(source_text: &str, source_type: SourceType, options: MinifierOptions) let program = Parser::new(&allocator, source_text, source_type).parse().program; let program = allocator.alloc(program); Minifier::new(options).build(&allocator, program); - Codegen::::new("", source_text, CodegenOptions::default()).build(program).source_text + Codegen::::new("", source_text, CodegenOptions::default(), None) + .build(program) + .source_text } fn gzip_size(s: &str) -> usize { diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs index d24b0aec2bb3d..078fa72073285 100644 --- a/tasks/transform_conformance/src/test_case.rs +++ b/tasks/transform_conformance/src/test_case.rs @@ -175,7 +175,7 @@ pub trait TestCase { .build(&mut program); result.map(|()| { - Codegen::::new("", &source_text, CodegenOptions::default()) + Codegen::::new("", &source_text, CodegenOptions::default(), None) .build(&program) .source_text }) @@ -261,10 +261,9 @@ impl TestCase for ConformanceTestCase { ); let result = transformer.build(&mut program); if result.is_ok() { - transformed_code = - Codegen::::new("", &input, codegen_options.clone()) - .build(&program) - .source_text; + transformed_code = Codegen::::new("", &input, codegen_options, None) + .build(&program) + .source_text; } else { let error = result .err() @@ -306,7 +305,7 @@ impl TestCase for ConformanceTestCase { |output| { // Get expected code by parsing the source text, so we can get the same code generated result. let program = Parser::new(&allocator, &output, source_type).parse().program; - Codegen::::new("", &output, codegen_options.clone()) + Codegen::::new("", &output, codegen_options, None) .build(&program) .source_text }, @@ -374,7 +373,7 @@ impl ExecTestCase { let source_type = SourceType::from_path(&target_path).unwrap(); let transformed_program = Parser::new(&allocator, &source_text, source_type).parse().program; - let result = Codegen::::new("", &source_text, CodegenOptions::default()) + let result = Codegen::::new("", &source_text, CodegenOptions::default(), None) .build(&transformed_program) .source_text;