From b7012320984b5bd0d230f6775a1da82e6cbd8f8f Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Mon, 9 Dec 2024 07:17:02 +0000 Subject: [PATCH] fix(codegen): print quote correctly for directive (#7735) closes #7734 --- crates/oxc_codegen/src/gen.rs | 26 ++++++++++++++++--- .../oxc_codegen/tests/integration/tester.rs | 10 +++---- crates/oxc_codegen/tests/integration/unit.rs | 16 ++++++++++-- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 008433e8a5d49..9031b18700916 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -68,9 +68,29 @@ impl Gen for Directive<'_> { // A Use Strict Directive may not contain an EscapeSequence or LineContinuation. // So here should print original `directive` value, the `expression` value is escaped str. // See https://github.com/babel/babel/blob/v7.26.2/packages/babel-generator/src/generators/base.ts#L64 - p.wrap_quote(|p, _| { - p.print_str(self.directive.as_str()); - }); + let directive = self.directive.as_str(); + + let mut chars = directive.chars().peekable(); + let mut quote = p.quote; + while let Some(c) = chars.next() { + match c { + '"' => { + quote = b'\''; + break; + } + '\'' => { + quote = b'"'; + break; + } + '\\' => { + chars.next(); + } + _ => {} + } + } + p.print_ascii_byte(quote); + p.print_str(directive); + p.print_ascii_byte(quote); p.print_ascii_byte(b';'); p.print_soft_newline(); } diff --git a/crates/oxc_codegen/tests/integration/tester.rs b/crates/oxc_codegen/tests/integration/tester.rs index db34cc449f81a..c8955cab6aea5 100644 --- a/crates/oxc_codegen/tests/integration/tester.rs +++ b/crates/oxc_codegen/tests/integration/tester.rs @@ -4,18 +4,14 @@ use oxc_parser::Parser; use oxc_span::SourceType; pub fn test(source_text: &str, expected: &str) { - let source_type = SourceType::jsx(); - let allocator = Allocator::default(); - let ret = Parser::new(&allocator, source_text, source_type).parse(); - let result = CodeGenerator::new().build(&ret.program).code; - assert_eq!(result, expected, "\nfor source: {source_text:?}"); + test_options(source_text, expected, CodegenOptions::default()); } -pub fn test_without_source(source_text: &str, expected: &str) { +pub fn test_options(source_text: &str, expected: &str, options: CodegenOptions) { let source_type = SourceType::jsx(); let allocator = Allocator::default(); let ret = Parser::new(&allocator, source_text, source_type).parse(); - let result = CodeGenerator::new().build(&ret.program).code; + let result = CodeGenerator::new().with_options(options).build(&ret.program).code; assert_eq!(result, expected, "\nfor source: {source_text:?}"); } diff --git a/crates/oxc_codegen/tests/integration/unit.rs b/crates/oxc_codegen/tests/integration/unit.rs index 115611cf07ced..594cc10ee70c8 100644 --- a/crates/oxc_codegen/tests/integration/unit.rs +++ b/crates/oxc_codegen/tests/integration/unit.rs @@ -1,4 +1,6 @@ -use crate::tester::{test, test_minify, test_minify_same, test_without_source}; +use oxc_codegen::CodegenOptions; + +use crate::tester::{test, test_minify, test_minify_same, test_options}; #[test] fn module_decl() { @@ -94,7 +96,6 @@ fn regex() { fn test_all(source: &str, expect: &str, minify: &str) { test(source, expect); test_minify(source, minify); - test_without_source(source, expect); } test_all("/regex/giv", "/regex/giv;\n", "/regex/giv;"); test_all( @@ -383,3 +384,14 @@ fn big_int_minify() { test_minify("0xaef_en;", "44798n;"); test_minify("0xaefen;", "44798n;"); } + +#[test] +fn directive() { + let single_quote = CodegenOptions { single_quote: true, ..CodegenOptions::default() }; + test_options("\"'\"", "\"'\";\n", single_quote.clone()); + test_options("'\"'", "'\"';\n", single_quote); + let double_quote = CodegenOptions { single_quote: false, ..CodegenOptions::default() }; + test_options("\"'\"", "\"'\";\n", double_quote.clone()); + test_options("'\"'", "'\"';\n", double_quote.clone()); + test_options(r#""'\"""#, "\"'\\\"\";\n", double_quote); +}