diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index abffd4a087352..da6ffa2ef56f0 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1072,30 +1072,14 @@ impl<'a, const MINIFY: bool> GenExpr for Expression<'a> { Self::JSXFragment(fragment) => fragment.gen(p, ctx), Self::ParenthesizedExpression(e) => e.gen_expr(p, precedence, ctx), Self::TSAsExpression(e) => e.gen_expr(p, precedence, ctx), - Self::TSSatisfiesExpression(e) => { - e.expression.gen_expr(p, precedence, ctx); - p.print_str(" satisfies "); - e.type_annotation.gen(p, ctx); - } + Self::TSSatisfiesExpression(e) => e.gen_expr(p, precedence, ctx), Self::TSTypeAssertion(e) => e.gen_expr(p, precedence, ctx), - Self::TSNonNullExpression(e) => e.expression.gen_expr(p, precedence, ctx), - Self::TSInstantiationExpression(e) => e.expression.gen_expr(p, precedence, ctx), + Self::TSNonNullExpression(e) => e.gen_expr(p, precedence, ctx), + Self::TSInstantiationExpression(e) => e.gen_expr(p, precedence, ctx), } } } -impl<'a, const MINIFY: bool> GenExpr for TSAsExpression<'a> { - fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { - p.print_char(b'('); - p.print_char(b'('); - self.expression.gen_expr(p, precedence, ctx); - p.print_char(b')'); - p.print_str(" as "); - self.type_annotation.gen(p, ctx); - p.print_char(b')'); - } -} - impl<'a, const MINIFY: bool> GenExpr for ParenthesizedExpression<'a> { fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { self.expression.gen_expr(p, precedence, ctx); @@ -1887,10 +1871,10 @@ impl<'a, const MINIFY: bool> GenExpr for SimpleAssignmentTarget<'a> { self.to_member_expression().gen_expr(p, precedence, ctx); } Self::TSAsExpression(e) => e.gen_expr(p, precedence, ctx), - Self::TSSatisfiesExpression(e) => e.expression.gen_expr(p, precedence, ctx), - Self::TSNonNullExpression(e) => e.expression.gen_expr(p, precedence, ctx), + Self::TSSatisfiesExpression(e) => e.gen_expr(p, precedence, ctx), + Self::TSNonNullExpression(e) => e.gen_expr(p, precedence, ctx), Self::TSTypeAssertion(e) => e.gen_expr(p, precedence, ctx), - Self::TSInstantiationExpression(e) => e.expression.gen_expr(p, precedence, ctx), + Self::TSInstantiationExpression(e) => e.gen_expr(p, precedence, ctx), } } } @@ -2127,6 +2111,60 @@ impl<'a, const MINIFY: bool> GenExpr for NewExpression<'a> { } } +impl<'a, const MINIFY: bool> GenExpr for TSAsExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { + p.print_char(b'('); + p.print_char(b'('); + self.expression.gen_expr(p, precedence, ctx); + p.print_char(b')'); + p.print_str(" as "); + self.type_annotation.gen(p, ctx); + p.print_char(b')'); + } +} + +impl<'a, const MINIFY: bool> GenExpr for TSSatisfiesExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { + // TODO: print properly + self.expression.gen_expr(p, precedence, ctx); + } +} + +impl<'a, const MINIFY: bool> GenExpr for TSNonNullExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { + p.wrap(matches!(self.expression, Expression::ParenthesizedExpression(_)), |p| { + self.expression.gen_expr(p, precedence, ctx); + }); + p.print_char(b'!'); + if MINIFY { + p.print_hard_space(); + } + } +} + +impl<'a, const MINIFY: bool> GenExpr for TSInstantiationExpression<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { + // TODO: print properly + self.expression.gen_expr(p, precedence, ctx); + } +} + +impl<'a, const MINIFY: bool> GenExpr for TSTypeAssertion<'a> { + fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { + p.wrap(precedence >= self.precedence(), |p| { + p.print_str("<"); + // var r = < (x: T) => T > ((x) => { return null; }); + // ^ make sure space is printed here. + if matches!(self.type_annotation, TSType::TSFunctionType(_)) { + p.print_hard_space(); + } + self.type_annotation.gen(p, ctx); + p.print_str(">"); + self.expression.gen_expr(p, Precedence::Member, ctx); + }); + } +} + impl<'a, const MINIFY: bool> Gen for MetaProperty<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.add_source_mapping(self.span.start); @@ -3599,22 +3637,6 @@ impl<'a, const MINIFY: bool> Gen for TSModuleReference<'a> { } } -impl<'a, const MINIFY: bool> GenExpr for TSTypeAssertion<'a> { - fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) { - p.wrap(precedence >= self.precedence(), |p| { - p.print_str("<"); - // var r = < (x: T) => T > ((x) => { return null; }); - // ^ make sure space is printed here. - if matches!(self.type_annotation, TSType::TSFunctionType(_)) { - p.print_hard_space(); - } - self.type_annotation.gen(p, ctx); - p.print_str(">"); - self.expression.gen_expr(p, Precedence::Member, ctx); - }); - } -} - impl Gen for TSAccessibility { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { match self { diff --git a/crates/oxc_codegen/tests/integration/snapshots/ts.snap b/crates/oxc_codegen/tests/integration/snapshots/ts.snap index 7020a24877d6f..fdda8c3fe8830 100644 --- a/crates/oxc_codegen/tests/integration/snapshots/ts.snap +++ b/crates/oxc_codegen/tests/integration/snapshots/ts.snap @@ -94,3 +94,15 @@ abstract class A {private abstract static readonly prop: string} abstract class A { private abstract static readonly prop: string; } + +a = x!; +a = x!; + +b = (x as y); +b = ((x) as y); + +c = foo; +c = foo; + +d = x satisfies y; +d = x; diff --git a/crates/oxc_codegen/tests/integration/ts.rs b/crates/oxc_codegen/tests/integration/ts.rs index 5ecbcb2cd50a4..b5552c09c178b 100644 --- a/crates/oxc_codegen/tests/integration/ts.rs +++ b/crates/oxc_codegen/tests/integration/ts.rs @@ -5,6 +5,16 @@ use oxc_codegen::{CodeGenerator, CodegenOptions}; use oxc_parser::Parser; use oxc_span::SourceType; +fn codegen(source_text: &str) -> String { + let allocator = Allocator::default(); + let source_type = SourceType::default().with_typescript(true).with_module(true); + let ret = Parser::new(&allocator, source_text, source_type).parse(); + CodeGenerator::new() + .with_options(CodegenOptions { single_quote: true }) + .build(&ret.program) + .source_text +} + #[test] fn ts() { let cases = [ @@ -36,6 +46,10 @@ fn ts() { "class A {constructor(public readonly a: number) {}}", "abstract class A {private abstract static m() {}}", "abstract class A {private abstract static readonly prop: string}", + "a = x!;", + "b = (x as y);", + "c = foo;", + "d = x satisfies y;", ]; let snapshot = cases.into_iter().fold(String::new(), |mut w, case| { @@ -47,13 +61,3 @@ fn ts() { insta::assert_snapshot!("ts", snapshot); }); } - -fn codegen(source_text: &str) -> String { - let allocator = Allocator::default(); - let source_type = SourceType::default().with_typescript(true).with_module(true); - let ret = Parser::new(&allocator, source_text, source_type).parse(); - CodeGenerator::new() - .with_options(CodegenOptions { single_quote: true }) - .build(&ret.program) - .source_text -} diff --git a/tasks/coverage/transformer_typescript.snap b/tasks/coverage/transformer_typescript.snap index 83273acb8617f..5b2859aeba82e 100644 --- a/tasks/coverage/transformer_typescript.snap +++ b/tasks/coverage/transformer_typescript.snap @@ -2,7 +2,8 @@ commit: d8086f14 transformer_typescript Summary: AST Parsed : 6456/6456 (100.00%) -Positive Passed: 6453/6456 (99.95%) +Positive Passed: 6452/6456 (99.94%) Mismatch: "compiler/constEnumNamespaceReferenceCausesNoImport2.ts" +Mismatch: "compiler/incrementOnNullAssertion.ts" Mismatch: "conformance/externalModules/typeOnly/exportDeclaration.ts" Mismatch: "conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx"