diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index e216ea69f..2c4c766ce 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -38,6 +38,8 @@ pub trait GenExpr: GetSpan { impl Gen for Program<'_> { fn gen(&self, p: &mut Codegen, ctx: Context) { + p.is_jsx = self.source_type.is_jsx(); + if let Some(hashbang) = &self.hashbang { hashbang.print(p, ctx); } @@ -2976,6 +2978,10 @@ impl Gen for TSTypeParameterDeclaration<'_> { p.print_soft_newline(); p.dedent(); p.print_indent(); + } else if p.is_jsx { + // `() => {}` + // ^ We need a comma here, otherwise it will be regarded as a JSX element. + p.print_str(","); } p.print_ascii_byte(b'>'); } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index b47218d45..f9c8e9e60 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -89,6 +89,9 @@ pub struct Codegen<'a> { need_space_before_dot: usize, print_next_indent_as_space: bool, binary_expr_stack: Vec>, + /// Indicates the output is JSX type, it is set in [`Program::gen`] and the result + /// is obtained by [`oxc_span::SourceType::is_jsx`] + is_jsx: bool, /// For avoiding `;` if the previous statement ends with `}`. needs_semicolon: bool, @@ -170,6 +173,7 @@ impl<'a> Codegen<'a> { start_of_stmt: 0, start_of_arrow_expr: 0, start_of_default_export: 0, + is_jsx: false, indent: 0, quote: b'"', print_comments, diff --git a/crates/oxc_codegen/tests/integration/tester.rs b/crates/oxc_codegen/tests/integration/tester.rs index c8955cab6..69f89835f 100644 --- a/crates/oxc_codegen/tests/integration/tester.rs +++ b/crates/oxc_codegen/tests/integration/tester.rs @@ -8,7 +8,24 @@ pub fn test(source_text: &str, expected: &str) { } pub fn test_options(source_text: &str, expected: &str, options: CodegenOptions) { - let source_type = SourceType::jsx(); + test_options_with_source_type(source_text, expected, SourceType::jsx(), options); +} + +pub fn test_tsx(source_text: &str, expected: &str) { + test_options_with_source_type( + source_text, + expected, + SourceType::tsx(), + CodegenOptions::default(), + ); +} + +pub fn test_options_with_source_type( + source_text: &str, + expected: &str, + source_type: SourceType, + options: CodegenOptions, +) { let allocator = Allocator::default(); let ret = Parser::new(&allocator, source_text, source_type).parse(); let result = CodeGenerator::new().with_options(options).build(&ret.program).code; diff --git a/crates/oxc_codegen/tests/integration/ts.rs b/crates/oxc_codegen/tests/integration/ts.rs index ca06641ef..1d9daa585 100644 --- a/crates/oxc_codegen/tests/integration/ts.rs +++ b/crates/oxc_codegen/tests/integration/ts.rs @@ -1,6 +1,6 @@ use oxc_codegen::CodegenOptions; -use crate::{snapshot, snapshot_options}; +use crate::{snapshot, snapshot_options, tester::test_tsx}; #[test] fn ts() { @@ -99,3 +99,9 @@ export { default as name16 } from "module-name"; &CodegenOptions { minify: true, ..CodegenOptions::default() }, ); } + +#[test] +fn tsx() { + test_tsx("() => {}", "() => {};\n"); + test_tsx("() => {}", "<\n\tT,\n\tB\n>() => {};\n"); +}