mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
fix(codegen): improve typescript codegen (#3708)
Remaining issues are tracked in https://github.com/oxc-project/oxc/issues/3692
This commit is contained in:
parent
910193e0aa
commit
da1e2d0e9b
9 changed files with 4847 additions and 4859 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -27,6 +27,3 @@ tasks/coverage/babel/
|
|||
tasks/coverage/test262/
|
||||
tasks/coverage/typescript/
|
||||
tasks/prettier_conformance/prettier/
|
||||
|
||||
# Ignore the failures directory, which is used to store the results of the codegen coverage tests
|
||||
tasks/coverage/failures/
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use oxc_syntax::precedence::{GetPrecedence, Precedence};
|
|||
use crate::ast::{
|
||||
match_member_expression, ArrowFunctionExpression, AssignmentExpression, AwaitExpression,
|
||||
BinaryExpression, CallExpression, ConditionalExpression, Expression, ImportExpression,
|
||||
LogicalExpression, MemberExpression, NewExpression, SequenceExpression, UnaryExpression,
|
||||
UpdateExpression, YieldExpression,
|
||||
LogicalExpression, MemberExpression, NewExpression, SequenceExpression, TSTypeAssertion,
|
||||
UnaryExpression, UpdateExpression, YieldExpression,
|
||||
};
|
||||
|
||||
impl<'a> GetPrecedence for Expression<'a> {
|
||||
|
|
@ -119,3 +119,9 @@ impl<'a> GetPrecedence for MemberExpression<'a> {
|
|||
Precedence::Member
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> GetPrecedence for TSTypeAssertion<'a> {
|
||||
fn precedence(&self) -> Precedence {
|
||||
Precedence::lowest()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,10 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Statement<'a> {
|
|||
Self::WhileStatement(stmt) => stmt.gen(p, ctx),
|
||||
Self::WithStatement(stmt) => stmt.gen(p, ctx),
|
||||
match_module_declaration!(Self) => self.to_module_declaration().gen(p, ctx),
|
||||
match_declaration!(Self) => self.to_declaration().gen(p, ctx),
|
||||
match_declaration!(Self) => {
|
||||
p.print_indent();
|
||||
self.to_declaration().gen(p, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +153,7 @@ fn print_if<const MINIFY: bool>(
|
|||
|
||||
match &if_stmt.consequent {
|
||||
Statement::BlockStatement(block) => {
|
||||
p.print_block1(block, ctx);
|
||||
p.print_block_statement(block, ctx);
|
||||
}
|
||||
stmt if wrap_to_avoid_ambiguous_else(stmt) => {
|
||||
p.print_block_start(stmt.span().start);
|
||||
|
|
@ -173,7 +176,7 @@ fn print_if<const MINIFY: bool>(
|
|||
p.print_str(b"else ");
|
||||
match alternate {
|
||||
Statement::BlockStatement(block) => {
|
||||
p.print_block1(block, ctx);
|
||||
p.print_block_statement(block, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
Statement::IfStatement(if_stmt) => {
|
||||
|
|
@ -215,7 +218,7 @@ fn wrap_to_avoid_ambiguous_else(stmt: &Statement) -> bool {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for BlockStatement<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_indent();
|
||||
p.print_block1(self, ctx);
|
||||
p.print_block_statement(self, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
}
|
||||
|
|
@ -249,13 +252,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForStatement<'a> {
|
|||
p.print_semicolon();
|
||||
|
||||
if let Some(update) = self.update.as_ref() {
|
||||
p.print_soft_space();
|
||||
p.print_expression(update);
|
||||
}
|
||||
|
||||
p.print(b')');
|
||||
p.print_soft_space();
|
||||
self.body.gen(p, ctx);
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +276,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForInStatement<'a> {
|
|||
p.print_expression(&self.right);
|
||||
p.print(b')');
|
||||
p.print_soft_space();
|
||||
self.body.gen(p, ctx);
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -292,11 +294,10 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForOfStatement<'a> {
|
|||
p.print_soft_space();
|
||||
p.print_space_before_identifier();
|
||||
p.print_str(b"of ");
|
||||
p.print_soft_space();
|
||||
self.right.gen_expr(p, Precedence::Assign, Context::default());
|
||||
p.print(b')');
|
||||
p.print_soft_space();
|
||||
self.body.gen(p, ctx);
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -321,10 +322,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for WhileStatement<'a> {
|
|||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_str(b"while");
|
||||
p.print_soft_space();
|
||||
p.print(b'(');
|
||||
p.print_expression(&self.test);
|
||||
p.print(b')');
|
||||
self.body.gen(p, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +337,8 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for DoWhileStatement<'a> {
|
|||
p.print_indent();
|
||||
p.print_str(b"do ");
|
||||
if let Statement::BlockStatement(block) = &self.body {
|
||||
p.print_block1(block, ctx);
|
||||
p.print_block_statement(block, ctx);
|
||||
p.print_soft_space();
|
||||
} else {
|
||||
p.print_soft_newline();
|
||||
p.indent();
|
||||
|
|
@ -344,6 +348,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for DoWhileStatement<'a> {
|
|||
p.print_indent();
|
||||
}
|
||||
p.print_str(b"while");
|
||||
p.print_soft_space();
|
||||
p.print(b'(');
|
||||
p.print_expression(&self.test);
|
||||
p.print(b')');
|
||||
|
|
@ -356,6 +361,7 @@ impl<const MINIFY: bool> Gen<MINIFY> for EmptyStatement {
|
|||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_semicolon();
|
||||
p.print_soft_newline();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -390,15 +396,17 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for SwitchStatement<'a> {
|
|||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_str(b"switch");
|
||||
p.print_soft_space();
|
||||
p.print(b'(');
|
||||
p.print_expression(&self.discriminant);
|
||||
p.print(b')');
|
||||
p.print_block_start(self.span.start);
|
||||
for case in &self.cases {
|
||||
p.add_source_mapping(case.span.start);
|
||||
case.gen(p, ctx);
|
||||
}
|
||||
p.print_block_end(self.span.end);
|
||||
p.print_soft_space();
|
||||
p.print_curly_braces(self.span, self.cases.is_empty(), |p| {
|
||||
for case in &self.cases {
|
||||
p.add_source_mapping(case.span.start);
|
||||
case.gen(p, ctx);
|
||||
}
|
||||
});
|
||||
p.print_soft_newline();
|
||||
p.needs_semicolon = false;
|
||||
}
|
||||
|
|
@ -410,13 +418,22 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for SwitchCase<'a> {
|
|||
p.print_indent();
|
||||
match &self.test {
|
||||
Some(test) => {
|
||||
p.print_str(b"case");
|
||||
p.print_hard_space();
|
||||
p.print_str(b"case ");
|
||||
p.print_expression(test);
|
||||
}
|
||||
None => p.print_str(b"default"),
|
||||
}
|
||||
p.print_colon();
|
||||
|
||||
if self.consequent.len() == 1 {
|
||||
if let Statement::BlockStatement(block) = &self.consequent[0] {
|
||||
p.print_soft_space();
|
||||
p.print_block_statement(block, ctx);
|
||||
p.print_soft_newline();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
p.print_soft_newline();
|
||||
p.indent();
|
||||
for item in &self.consequent {
|
||||
|
|
@ -446,7 +463,8 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for LabeledStatement<'a> {
|
|||
p.print_indent();
|
||||
self.label.gen(p, ctx);
|
||||
p.print_colon();
|
||||
self.body.gen(p, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -454,21 +472,29 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TryStatement<'a> {
|
|||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_space_before_identifier();
|
||||
p.print_str(b"try");
|
||||
p.print_block1(&self.block, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_block_statement(&self.block, ctx);
|
||||
if let Some(handler) = &self.handler {
|
||||
p.print_soft_space();
|
||||
p.print_str(b"catch");
|
||||
if let Some(param) = &handler.param {
|
||||
p.print_soft_space();
|
||||
p.print_str(b"(");
|
||||
param.pattern.gen(p, ctx);
|
||||
p.print_str(b")");
|
||||
}
|
||||
p.print_block1(&handler.body, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_block_statement(&handler.body, ctx);
|
||||
}
|
||||
if let Some(finalizer) = &self.finalizer {
|
||||
p.print_soft_space();
|
||||
p.print_str(b"finally");
|
||||
p.print_block1(finalizer, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_block_statement(finalizer, ctx);
|
||||
}
|
||||
p.print_soft_newline();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -490,7 +516,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for WithStatement<'a> {
|
|||
p.print(b'(');
|
||||
p.print_expression(&self.object);
|
||||
p.print(b')');
|
||||
self.body.gen(p, ctx);
|
||||
p.print_body(&self.body, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -510,16 +536,8 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ModuleDeclaration<'a> {
|
|||
Self::ExportAllDeclaration(decl) => decl.gen(p, ctx),
|
||||
Self::ExportDefaultDeclaration(decl) => decl.gen(p, ctx),
|
||||
Self::ExportNamedDeclaration(decl) => decl.gen(p, ctx),
|
||||
Self::TSExportAssignment(decl) => {
|
||||
p.print_str(b"export = ");
|
||||
decl.expression.gen_expr(p, Precedence::lowest(), ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
Self::TSNamespaceExportDeclaration(decl) => {
|
||||
p.print_str(b"export as namespace ");
|
||||
decl.id.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
Self::TSExportAssignment(decl) => decl.gen(p, ctx),
|
||||
Self::TSNamespaceExportDeclaration(decl) => decl.gen(p, ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -528,18 +546,15 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Declaration<'a> {
|
|||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
match self {
|
||||
Self::VariableDeclaration(decl) => {
|
||||
p.print_indent();
|
||||
decl.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
Self::FunctionDeclaration(decl) => {
|
||||
p.print_indent();
|
||||
p.print_space_before_identifier();
|
||||
decl.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
Self::ClassDeclaration(decl) => {
|
||||
p.print_indent();
|
||||
p.print_space_before_identifier();
|
||||
decl.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
|
|
@ -549,9 +564,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Declaration<'a> {
|
|||
declaration.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
Self::TSModuleDeclaration(decl) => {
|
||||
decl.gen(p, ctx);
|
||||
}
|
||||
Self::TSModuleDeclaration(decl) => decl.gen(p, ctx),
|
||||
Self::TSTypeAliasDeclaration(decl) => {
|
||||
if decl.modifiers.contains(ModifierKind::Export) {
|
||||
p.print_str(b"export ");
|
||||
|
|
@ -573,9 +586,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Declaration<'a> {
|
|||
}
|
||||
Declaration::TSInterfaceDeclaration(decl) => decl.gen(p, ctx),
|
||||
Declaration::TSEnumDeclaration(decl) => decl.gen(p, ctx),
|
||||
Declaration::TSImportEqualsDeclaration(decl) => {
|
||||
decl.gen(p, ctx);
|
||||
}
|
||||
Declaration::TSImportEqualsDeclaration(decl) => decl.gen(p, ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -668,11 +679,11 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Function<'a> {
|
|||
p.print_str(b": ");
|
||||
return_type.gen(p, ctx);
|
||||
}
|
||||
p.print_soft_space();
|
||||
if let Some(body) = &self.body {
|
||||
p.print_soft_space();
|
||||
body.gen(p, ctx);
|
||||
} else {
|
||||
p.print_semicolon_after_statement();
|
||||
p.print_semicolon();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -680,14 +691,14 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Function<'a> {
|
|||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for FunctionBody<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_block_start(self.span.start);
|
||||
p.print_directives_and_statements_with_semicolon_order(
|
||||
Some(&self.directives),
|
||||
&self.statements,
|
||||
ctx,
|
||||
true,
|
||||
);
|
||||
p.print_block_end(self.span.end);
|
||||
p.print_curly_braces(self.span, self.is_empty(), |p| {
|
||||
p.print_directives_and_statements_with_semicolon_order(
|
||||
Some(&self.directives),
|
||||
&self.statements,
|
||||
ctx,
|
||||
true,
|
||||
);
|
||||
});
|
||||
p.needs_semicolon = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -721,6 +732,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for FormalParameters<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_str(b"import ");
|
||||
if self.import_kind.is_type() {
|
||||
p.print_str(b"type ");
|
||||
|
|
@ -843,6 +855,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportAttribute<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportNamedDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
if p.options.preserve_annotate_comments {
|
||||
match &self.declaration {
|
||||
Some(Declaration::FunctionDeclaration(_)) => {
|
||||
|
|
@ -869,7 +882,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportNamedDeclaration<'a> {
|
|||
p.print_str(b"type ");
|
||||
}
|
||||
match &self.declaration {
|
||||
Some(decl) => decl.gen(p, ctx),
|
||||
Some(decl) => {
|
||||
decl.gen(p, ctx);
|
||||
}
|
||||
None => {
|
||||
p.print(b'{');
|
||||
if !self.specifiers.is_empty() {
|
||||
|
|
@ -884,12 +899,30 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportNamedDeclaration<'a> {
|
|||
p.print_soft_space();
|
||||
source.gen(p, ctx);
|
||||
}
|
||||
p.needs_semicolon = true;
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSExportAssignment<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_indent();
|
||||
p.print_str(b"export = ");
|
||||
self.expression.gen_expr(p, Precedence::lowest(), ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSNamespaceExportDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_indent();
|
||||
p.print_str(b"export as namespace ");
|
||||
self.id.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportSpecifier<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
if self.export_kind.is_type() {
|
||||
|
|
@ -917,6 +950,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ModuleExportName<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportAllDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_str(b"export ");
|
||||
if self.export_kind.is_type() {
|
||||
p.print_str(b"type ");
|
||||
|
|
@ -942,6 +976,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportAllDeclaration<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ExportDefaultDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_indent();
|
||||
p.print_str(b"export default ");
|
||||
self.declaration.gen(p, ctx);
|
||||
}
|
||||
|
|
@ -1443,28 +1478,18 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ArrayExpression<'a> {
|
|||
impl<'a, const MINIFY: bool> GenExpr<MINIFY> for ObjectExpression<'a> {
|
||||
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) {
|
||||
let n = p.code_len();
|
||||
let is_multi_line = !self.properties.is_empty();
|
||||
p.wrap(p.start_of_stmt == n || p.start_of_arrow_expr == n, |p| {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print(b'{');
|
||||
if is_multi_line {
|
||||
p.indent();
|
||||
}
|
||||
for (i, item) in self.properties.iter().enumerate() {
|
||||
if i != 0 {
|
||||
p.print_comma();
|
||||
p.print_curly_braces(self.span, self.properties.is_empty(), |p| {
|
||||
for (index, item) in self.properties.iter().enumerate() {
|
||||
if index != 0 {
|
||||
p.print_comma();
|
||||
p.print_soft_space();
|
||||
}
|
||||
p.print_indent();
|
||||
item.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
p.print_soft_newline();
|
||||
p.print_indent();
|
||||
item.gen(p, ctx);
|
||||
}
|
||||
if is_multi_line {
|
||||
p.print_soft_newline();
|
||||
p.dedent();
|
||||
p.print_indent();
|
||||
}
|
||||
p.print(b'}');
|
||||
p.add_source_mapping(self.span.end);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1516,6 +1541,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ObjectProperty<'a> {
|
|||
func.params.gen(p, ctx);
|
||||
p.print(b')');
|
||||
if let Some(body) = &func.body {
|
||||
p.print_soft_space();
|
||||
body.gen(p, ctx);
|
||||
}
|
||||
return;
|
||||
|
|
@ -1532,6 +1558,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ObjectProperty<'a> {
|
|||
}
|
||||
if !self.shorthand {
|
||||
p.print_colon();
|
||||
p.print_soft_space();
|
||||
}
|
||||
self.value.gen_expr(p, Precedence::Assign, Context::default());
|
||||
}
|
||||
|
|
@ -1597,6 +1624,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for YieldExpression<'a> {
|
|||
p.print_str(b"yield");
|
||||
if self.delegate {
|
||||
p.print(b'*');
|
||||
p.print_soft_space();
|
||||
}
|
||||
if let Some(argument) = self.argument.as_ref() {
|
||||
if !self.delegate {
|
||||
|
|
@ -1620,6 +1648,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for UpdateExpression<'a> {
|
|||
p.prev_op_end = p.code().len();
|
||||
self.argument.gen_expr(p, Precedence::Prefix, ctx);
|
||||
} else {
|
||||
p.print_space_before_operator(self.operator.into());
|
||||
self.argument.gen_expr(p, Precedence::Postfix, ctx);
|
||||
p.print_str(operator);
|
||||
p.prev_op = Some(self.operator.into());
|
||||
|
|
@ -2045,35 +2074,47 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for Class<'a> {
|
|||
super_class.gen_expr(p, Precedence::Call, Context::default());
|
||||
}
|
||||
p.print_soft_space();
|
||||
p.print_block_start(self.body.span.start);
|
||||
for item in &self.body.body {
|
||||
p.print_indent();
|
||||
p.print_semicolon_if_needed();
|
||||
item.gen(p, ctx);
|
||||
if matches!(
|
||||
item,
|
||||
ClassElement::PropertyDefinition(_)
|
||||
| ClassElement::AccessorProperty(_)
|
||||
| ClassElement::TSIndexSignature(_)
|
||||
) {
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
p.print_soft_newline();
|
||||
}
|
||||
p.print_block_end(self.body.span.end);
|
||||
self.body.gen(p, ctx);
|
||||
p.needs_semicolon = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ClassBody<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_curly_braces(self.span, self.body.is_empty(), |p| {
|
||||
for item in &self.body {
|
||||
p.print_semicolon_if_needed();
|
||||
p.print_indent();
|
||||
item.gen(p, ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for ClassElement<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
match self {
|
||||
Self::StaticBlock(elem) => elem.gen(p, ctx),
|
||||
Self::MethodDefinition(elem) => elem.gen(p, ctx),
|
||||
Self::PropertyDefinition(elem) => elem.gen(p, ctx),
|
||||
Self::AccessorProperty(elem) => elem.gen(p, ctx),
|
||||
Self::TSIndexSignature(elem) => elem.gen(p, ctx),
|
||||
Self::StaticBlock(elem) => {
|
||||
elem.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
Self::MethodDefinition(elem) => {
|
||||
elem.gen(p, ctx);
|
||||
p.print_soft_newline();
|
||||
}
|
||||
Self::PropertyDefinition(elem) => {
|
||||
elem.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
Self::AccessorProperty(elem) => {
|
||||
elem.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
Self::TSIndexSignature(elem) => {
|
||||
elem.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2284,12 +2325,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for StaticBlock<'a> {
|
|||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.add_source_mapping(self.span.start);
|
||||
p.print_str(b"static");
|
||||
p.print_block_start(self.span.start);
|
||||
for stmt in &self.body {
|
||||
p.print_semicolon_if_needed();
|
||||
stmt.gen(p, ctx);
|
||||
}
|
||||
p.print_block_end(self.span.end);
|
||||
p.print_curly_braces(self.span, self.body.is_empty(), |p| {
|
||||
for stmt in &self.body {
|
||||
p.print_semicolon_if_needed();
|
||||
stmt.gen(p, ctx);
|
||||
}
|
||||
});
|
||||
p.needs_semicolon = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -2343,9 +2384,10 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for MethodDefinition<'a> {
|
|||
return_type.gen(p, ctx);
|
||||
}
|
||||
if let Some(body) = &self.value.body {
|
||||
p.print_soft_space();
|
||||
body.gen(p, ctx);
|
||||
} else {
|
||||
p.print_semicolon_after_statement();
|
||||
p.print_semicolon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2380,7 +2422,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for PropertyDefinition<'a> {
|
|||
type_annotation.gen(p, ctx);
|
||||
}
|
||||
if let Some(value) = &self.value {
|
||||
p.print_soft_space();
|
||||
p.print_equal();
|
||||
p.print_soft_space();
|
||||
value.gen_expr(p, Precedence::Assign, Context::default());
|
||||
}
|
||||
}
|
||||
|
|
@ -2407,6 +2451,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for AccessorProperty<'a> {
|
|||
p.print_equal();
|
||||
value.gen_expr(p, Precedence::Assign, Context::default());
|
||||
}
|
||||
p.print_semicolon();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2487,6 +2532,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ArrayPattern<'a> {
|
|||
for (index, item) in self.elements.iter().enumerate() {
|
||||
if index != 0 {
|
||||
p.print_comma();
|
||||
if item.is_some() {
|
||||
p.print_soft_space();
|
||||
}
|
||||
}
|
||||
if let Some(item) = item {
|
||||
item.gen(p, ctx);
|
||||
|
|
@ -2496,6 +2544,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ArrayPattern<'a> {
|
|||
}
|
||||
}
|
||||
if let Some(rest) = &self.rest {
|
||||
p.print_soft_space();
|
||||
rest.gen(p, ctx);
|
||||
}
|
||||
p.print(b']');
|
||||
|
|
@ -2506,7 +2555,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ArrayPattern<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentPattern<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
self.left.gen(p, ctx);
|
||||
p.print_soft_space();
|
||||
p.print_equal();
|
||||
p.print_soft_space();
|
||||
self.right.gen_expr(p, Precedence::Assign, Context::default());
|
||||
}
|
||||
}
|
||||
|
|
@ -2825,12 +2876,14 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTemplateLiteralType<'a> {
|
|||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTypeLiteral<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_block_start(self.span.start);
|
||||
for item in &self.members {
|
||||
item.gen(p, ctx);
|
||||
p.print_semicolon();
|
||||
}
|
||||
p.print_block_end(self.span.end);
|
||||
p.print_curly_braces(self.span, self.members.is_empty(), |p| {
|
||||
for item in &self.members {
|
||||
p.print_indent();
|
||||
item.gen(p, ctx);
|
||||
p.print_semicolon();
|
||||
p.print_soft_newline();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3123,6 +3176,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSNamedTupleMember<'a> {
|
|||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleDeclaration<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_indent();
|
||||
if self.modifiers.contains(ModifierKind::Export) {
|
||||
p.print_str(b"export ");
|
||||
}
|
||||
|
|
@ -3131,31 +3185,50 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleDeclaration<'a> {
|
|||
}
|
||||
p.print_str(b"module");
|
||||
p.print_space_before_identifier();
|
||||
let name = self.id.name();
|
||||
p.wrap_quote(name, |p, _| p.print_str(name.as_bytes()));
|
||||
p.print_hard_space();
|
||||
match &self.body {
|
||||
Some(TSModuleDeclarationBody::TSModuleDeclaration(body)) => {
|
||||
p.print_block_start(body.span.start);
|
||||
body.gen(p, ctx);
|
||||
p.print_block_end(body.span.end);
|
||||
}
|
||||
Some(TSModuleDeclarationBody::TSModuleBlock(body)) => {
|
||||
p.print_block_start(body.span.start);
|
||||
for item in &body.body {
|
||||
p.print_semicolon_if_needed();
|
||||
item.gen(p, ctx);
|
||||
self.id.gen(p, ctx);
|
||||
|
||||
if let Some(body) = &self.body {
|
||||
let mut body = body;
|
||||
loop {
|
||||
match body {
|
||||
TSModuleDeclarationBody::TSModuleDeclaration(b) => {
|
||||
p.print(b'.');
|
||||
b.id.gen(p, ctx);
|
||||
if let Some(b) = &b.body {
|
||||
body = b;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TSModuleDeclarationBody::TSModuleBlock(body) => {
|
||||
p.print_soft_space();
|
||||
body.gen(p, ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.print_semicolon_if_needed();
|
||||
p.print_block_end(body.span.end);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if MINIFY {
|
||||
p.print_semicolon();
|
||||
p.needs_semicolon = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleDeclarationName<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
match self {
|
||||
Self::Identifier(ident) => ident.gen(p, ctx),
|
||||
Self::StringLiteral(s) => s.gen(p, ctx),
|
||||
}
|
||||
p.print_hard_space();
|
||||
p.print_soft_newline();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleBlock<'a> {
|
||||
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
|
||||
p.print_curly_braces(self.span, self.body.is_empty(), |p| {
|
||||
for item in &self.body {
|
||||
item.gen(p, ctx);
|
||||
p.print_semicolon_if_needed();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3187,14 +3260,14 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSInterfaceDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
p.print_soft_space();
|
||||
p.print_block_start(self.body.span.start);
|
||||
for item in &self.body.body {
|
||||
p.print_indent();
|
||||
p.print_semicolon_if_needed();
|
||||
item.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
p.print_block_end(self.body.span.end);
|
||||
p.print_curly_braces(self.body.span, self.body.body.is_empty(), |p| {
|
||||
for item in &self.body.body {
|
||||
p.print_indent();
|
||||
p.print_semicolon_if_needed();
|
||||
item.gen(p, ctx);
|
||||
p.print_semicolon_after_statement();
|
||||
}
|
||||
});
|
||||
if MINIFY {
|
||||
p.print_hard_space();
|
||||
}
|
||||
|
|
@ -3228,10 +3301,19 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSEnumDeclaration<'a> {
|
|||
p.print_str(b"enum ");
|
||||
self.id.gen(p, ctx);
|
||||
p.print_space_before_identifier();
|
||||
p.print_block_start(self.span.start);
|
||||
p.print_list(&self.members, ctx);
|
||||
p.print_block_end(self.span.end);
|
||||
p.print_hard_space();
|
||||
p.print_curly_braces(self.span, self.members.is_empty(), |p| {
|
||||
for member in &self.members {
|
||||
p.print_indent();
|
||||
member.gen(p, ctx);
|
||||
p.print_comma();
|
||||
p.print_soft_newline();
|
||||
}
|
||||
});
|
||||
if MINIFY {
|
||||
p.print_hard_space();
|
||||
}
|
||||
p.print_soft_newline();
|
||||
p.needs_semicolon = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3247,6 +3329,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSEnumMember<'a> {
|
|||
p.print_str(b"]");
|
||||
}
|
||||
}
|
||||
if let Some(init) = &self.initializer {
|
||||
p.print_soft_space();
|
||||
p.print_equal();
|
||||
p.print_soft_space();
|
||||
init.gen_expr(p, Precedence::lowest(), ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3294,10 +3382,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleReference<'a> {
|
|||
|
||||
impl<'a, const MINIFY: bool> GenExpr<MINIFY> for TSTypeAssertion<'a> {
|
||||
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, precedence: Precedence, ctx: Context) {
|
||||
p.print_str(b"<");
|
||||
self.type_annotation.gen(p, ctx);
|
||||
p.print_str(b">");
|
||||
self.expression.gen_expr(p, precedence, ctx);
|
||||
p.wrap(precedence > self.precedence(), |p| {
|
||||
p.print_str(b"<");
|
||||
self.type_annotation.gen(p, ctx);
|
||||
p.print_str(b">");
|
||||
self.expression.gen_expr(p, Precedence::Grouping, ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -311,18 +311,32 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
}
|
||||
|
||||
fn print_sequence<T: Gen<MINIFY>>(&mut self, items: &[T], separator: Separator, ctx: Context) {
|
||||
let len = items.len();
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
for item in items {
|
||||
item.gen(self, ctx);
|
||||
match separator {
|
||||
Separator::Semicolon => self.print_semicolon(),
|
||||
Separator::Comma => self.print(b','),
|
||||
Separator::None => {}
|
||||
}
|
||||
if index != len - 1 {}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_curly_braces<F: FnOnce(&mut Self)>(&mut self, span: Span, single_line: bool, op: F) {
|
||||
self.add_source_mapping(span.start);
|
||||
self.print(b'{');
|
||||
if !single_line {
|
||||
self.print_soft_newline();
|
||||
self.indent();
|
||||
}
|
||||
op(self);
|
||||
if !single_line {
|
||||
self.dedent();
|
||||
self.print_indent();
|
||||
}
|
||||
self.add_source_mapping(span.end);
|
||||
self.print(b'}');
|
||||
}
|
||||
|
||||
fn print_block_start(&mut self, position: u32) {
|
||||
self.add_source_mapping(position);
|
||||
self.print(b'{');
|
||||
|
|
@ -337,11 +351,21 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
self.print(b'}');
|
||||
}
|
||||
|
||||
fn print_block1(&mut self, stmt: &BlockStatement<'_>, ctx: Context) {
|
||||
self.print_block_start(stmt.span.start);
|
||||
self.print_directives_and_statements_with_semicolon_order(None, &stmt.body, ctx, true);
|
||||
self.print_block_end(stmt.span.end);
|
||||
self.needs_semicolon = false;
|
||||
fn print_body(&mut self, stmt: &Statement<'_>, ctx: Context) {
|
||||
match stmt {
|
||||
Statement::BlockStatement(stmt) => {
|
||||
self.print_block_statement(stmt, ctx);
|
||||
self.print_soft_newline();
|
||||
}
|
||||
stmt => stmt.gen(self, ctx),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_block_statement(&mut self, stmt: &BlockStatement<'_>, ctx: Context) {
|
||||
self.print_curly_braces(stmt.span, stmt.body.is_empty(), |p| {
|
||||
p.print_directives_and_statements_with_semicolon_order(None, &stmt.body, ctx, true);
|
||||
p.needs_semicolon = false;
|
||||
});
|
||||
}
|
||||
|
||||
fn print_block<T: Gen<MINIFY>>(
|
||||
|
|
@ -379,6 +403,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
for (index, item) in items.iter().enumerate() {
|
||||
if index != 0 {
|
||||
self.print_comma();
|
||||
self.print_soft_space();
|
||||
}
|
||||
item.gen_expr(self, precedence, ctx);
|
||||
}
|
||||
|
|
@ -461,6 +486,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
|
|||
if let Some(Statement::ExpressionStatement(s)) = statements.first() {
|
||||
if matches!(s.expression.get_inner_expression(), Expression::StringLiteral(_)) {
|
||||
self.print_semicolon();
|
||||
self.print_soft_newline();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -132,13 +132,13 @@ fn new_expr() {
|
|||
|
||||
#[test]
|
||||
fn for_stmt() {
|
||||
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 (let x = 0; x < 10; x++) {}", "for (let x = 0; x < 10; x++) {}\n", None);
|
||||
test("for (;;) {}", "for (;;) {}\n", None);
|
||||
test("for (let x = 1;;) {}", "for (let x = 1;;) {}\n", None);
|
||||
test("for (;true;) {}", "for (; true;) {}\n", None);
|
||||
test("for (;;i++) {}", "for (;; i++) {}\n", None);
|
||||
|
||||
test("for (using x = 1;;) {}", "for (using x = 1;;) {\n}\n", None);
|
||||
test("for (using x = 1;;) {}", "for (using x = 1;;) {}\n", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -178,7 +178,11 @@ fn typescript() {
|
|||
// type-only imports/exports
|
||||
test_ts("import type { Foo } from 'foo';", "import type {Foo} from 'foo';\n", false);
|
||||
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);
|
||||
test_ts(
|
||||
"export { Foo, type Bar } from 'foo';",
|
||||
"export { Foo, type Bar } from 'foo';\n",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
fn test_comment_helper(source_text: &str, expected: &str) {
|
||||
|
|
@ -201,17 +205,8 @@ fn annotate_comment() {
|
|||
/* #__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() {
|
||||
},]);
|
||||
])",
|
||||
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() {},]);
|
||||
",
|
||||
);
|
||||
|
||||
|
|
@ -225,9 +220,7 @@ fn annotate_comment() {
|
|||
/* #__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,]);
|
||||
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(
|
||||
|
|
@ -240,9 +233,7 @@ fn annotate_comment() {
|
|||
/* #__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,]);
|
||||
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,]);
|
||||
",
|
||||
);
|
||||
//
|
||||
|
|
@ -258,17 +249,13 @@ fn annotate_comment() {
|
|||
async function* d() {}
|
||||
",
|
||||
r"// #__NO_SIDE_EFFECTS__
|
||||
function a() {
|
||||
}
|
||||
function a() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
function* b() {
|
||||
}
|
||||
function* b() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
async function c() {
|
||||
}
|
||||
async function c() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
async function* d() {
|
||||
}
|
||||
async function* d() {}
|
||||
",
|
||||
);
|
||||
|
||||
|
|
@ -284,17 +271,13 @@ async function* d() {
|
|||
async function* d() {}
|
||||
",
|
||||
r"// #__NO_SIDE_EFFECTS__
|
||||
function a() {
|
||||
}
|
||||
function a() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
function* b() {
|
||||
}
|
||||
function* b() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
async function c() {
|
||||
}
|
||||
async function c() {}
|
||||
// #__NO_SIDE_EFFECTS__
|
||||
async function* d() {
|
||||
}
|
||||
async function* d() {}
|
||||
",
|
||||
);
|
||||
|
||||
|
|
@ -303,15 +286,11 @@ async function* d() {
|
|||
/* @__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() {
|
||||
}
|
||||
/* @__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)
|
||||
|
|
@ -324,24 +303,12 @@ async function* d() {
|
|||
/* #__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 = () => {
|
||||
};
|
||||
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)
|
||||
|
|
@ -354,24 +321,12 @@ export const c2 = /* #__NO_SIDE_EFFECTS__ */ () => {
|
|||
/* #__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 = () => {
|
||||
};
|
||||
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 = () => {};
|
||||
",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,10 +252,8 @@ impl<'a> ParserImpl<'a> {
|
|||
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl))
|
||||
} else if self.at(Kind::LCurly) {
|
||||
let block = self.parse_ts_module_block()?;
|
||||
self.asi()?;
|
||||
Some(TSModuleDeclarationBody::TSModuleBlock(block))
|
||||
} else {
|
||||
self.asi()?;
|
||||
None
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,9 +2,8 @@ commit: d8086f14
|
|||
|
||||
codegen_typescript Summary:
|
||||
AST Parsed : 5283/5283 (100.00%)
|
||||
Positive Passed: 5278/5283 (99.91%)
|
||||
Default failed: "compiler/castExpressionParentheses.ts"
|
||||
Default failed: "compiler/genericTypeAssertions3.ts"
|
||||
Default failed: "compiler/jsxMultilineAttributeStringValues.tsx"
|
||||
Default failed: "compiler/jsxMultilineAttributeValuesReact.tsx"
|
||||
Default failed: "conformance/jsx/tsxReactEmitEntities.tsx"
|
||||
Positive Passed: 5279/5283 (99.92%)
|
||||
Normal failed: "compiler/genericTypeAssertions3.ts"
|
||||
Normal failed: "compiler/jsxMultilineAttributeStringValues.tsx"
|
||||
Normal failed: "compiler/jsxMultilineAttributeValuesReact.tsx"
|
||||
Normal failed: "conformance/jsx/tsxReactEmitEntities.tsx"
|
||||
|
|
|
|||
|
|
@ -13,18 +13,13 @@ use crate::{
|
|||
typescript::TypeScriptCase,
|
||||
};
|
||||
|
||||
fn get_result(
|
||||
case_name: &str,
|
||||
file_name: &Path,
|
||||
source_text: &str,
|
||||
source_type: SourceType,
|
||||
) -> TestResult {
|
||||
let normal_result = get_normal_result(case_name, file_name, source_text, source_type);
|
||||
let minify_result = get_minify_result(case_name, file_name, source_text, source_type);
|
||||
|
||||
fn get_result(source_text: &str, source_type: SourceType) -> TestResult {
|
||||
let normal_result = get_normal_result(source_text, source_type);
|
||||
if !normal_result {
|
||||
return TestResult::CodegenError("Default");
|
||||
}
|
||||
return TestResult::CodegenError("Normal");
|
||||
};
|
||||
|
||||
let minify_result = get_minify_result(source_text, source_type);
|
||||
if !minify_result {
|
||||
return TestResult::CodegenError("Minify");
|
||||
}
|
||||
|
|
@ -32,82 +27,27 @@ fn get_result(
|
|||
TestResult::Passed
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn write_failure(
|
||||
case_name: &str,
|
||||
file_name: &Path,
|
||||
result_type: &str,
|
||||
original: &str,
|
||||
parser_result1: &str,
|
||||
source_text1: &str,
|
||||
parser_result2: &str,
|
||||
source_text2: &str,
|
||||
) {
|
||||
let base_path = Path::new(&format!("./tasks/coverage/failures/{case_name}"))
|
||||
.join(file_name)
|
||||
.join(result_type);
|
||||
let _ = std::fs::create_dir_all(&base_path);
|
||||
std::fs::write(base_path.join("original.ts"), original).expect("Error writing original.ts");
|
||||
std::fs::write(base_path.join("parser_result1.txt"), parser_result1)
|
||||
.expect("Error writing parser_result1.json");
|
||||
std::fs::write(base_path.join("source_text1.ts"), source_text1)
|
||||
.expect("Error writing source_text1.ts");
|
||||
std::fs::write(base_path.join("parser_result2.txt"), parser_result2)
|
||||
.expect("Error writing parser_result2.json");
|
||||
std::fs::write(base_path.join("source_text2.ts"), source_text2)
|
||||
.expect("Error writing source_text2.ts");
|
||||
}
|
||||
|
||||
/// Idempotency test
|
||||
fn get_normal_result(
|
||||
case_name: &str,
|
||||
file_name: &Path,
|
||||
source_text: &str,
|
||||
source_type: SourceType,
|
||||
) -> bool {
|
||||
fn get_normal_result(source_text: &str, source_type: SourceType) -> bool {
|
||||
let options = CodegenOptions::default();
|
||||
let allocator = Allocator::default();
|
||||
let parse_result1 = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let source_text1 = Codegen::<false>::new("", source_text, parse_result1.trivias, options)
|
||||
.build(&parse_result1.program)
|
||||
.source_text;
|
||||
let parse_result2 = Parser::new(&allocator, &source_text1, source_type).parse();
|
||||
let source_text2 = Codegen::<false>::new("", &source_text1, parse_result2.trivias, options)
|
||||
.build(&parse_result2.program)
|
||||
.source_text;
|
||||
let result = source_text1 == source_text2;
|
||||
let source_text1 = {
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
Codegen::<false>::new("", source_text, ret.trivias, options).build(&ret.program).source_text
|
||||
};
|
||||
|
||||
if !result {
|
||||
let parse_result1 = format!(
|
||||
"Panicked: {:#?}\nErrors:\n{:#?}\nProgram:\n{:#?}",
|
||||
parse_result1.panicked, parse_result1.errors, parse_result1.program
|
||||
);
|
||||
let parse_result2 = format!(
|
||||
"Panicked: {:#?}\nErrors:\n{:#?}\nProgram:\n{:#?}",
|
||||
parse_result2.panicked, parse_result2.errors, parse_result2.program
|
||||
);
|
||||
write_failure(
|
||||
case_name,
|
||||
file_name,
|
||||
"normal",
|
||||
source_text,
|
||||
&parse_result1,
|
||||
&source_text1,
|
||||
&parse_result2,
|
||||
&source_text2,
|
||||
);
|
||||
}
|
||||
let source_text2 = {
|
||||
let ret = Parser::new(&allocator, &source_text1, source_type).parse();
|
||||
Codegen::<false>::new("", &source_text1, ret.trivias, options)
|
||||
.build(&ret.program)
|
||||
.source_text
|
||||
};
|
||||
|
||||
result
|
||||
source_text1 == source_text2
|
||||
}
|
||||
|
||||
/// Minify idempotency test
|
||||
fn get_minify_result(
|
||||
case_name: &str,
|
||||
file_name: &Path,
|
||||
source_text: &str,
|
||||
source_type: SourceType,
|
||||
) -> bool {
|
||||
fn get_minify_result(source_text: &str, source_type: SourceType) -> bool {
|
||||
let options = CodegenOptions::default();
|
||||
let allocator = Allocator::default();
|
||||
let parse_result1 = Parser::new(&allocator, source_text, source_type).parse();
|
||||
|
|
@ -119,30 +59,7 @@ fn get_minify_result(
|
|||
let source_text2 = Codegen::<true>::new("", &source_text1, parse_result2.trivias, options)
|
||||
.build(&parse_result2.program)
|
||||
.source_text;
|
||||
let result = source_text1 == source_text2;
|
||||
|
||||
if !result {
|
||||
let parse_result1 = format!(
|
||||
"Panicked: {:#?}\nErrors:\n{:#?}\nProgram:\n{:#?}",
|
||||
parse_result1.panicked, parse_result1.errors, parse_result1.program
|
||||
);
|
||||
let parse_result2 = format!(
|
||||
"Panicked: {:#?}\nErrors:\n{:#?}\nProgram:\n{:#?}",
|
||||
parse_result2.panicked, parse_result2.errors, parse_result2.program
|
||||
);
|
||||
write_failure(
|
||||
case_name,
|
||||
file_name,
|
||||
"minify",
|
||||
source_text,
|
||||
&parse_result1,
|
||||
&source_text1,
|
||||
&parse_result2,
|
||||
&source_text2,
|
||||
);
|
||||
}
|
||||
|
||||
result
|
||||
source_text1 == source_text2
|
||||
}
|
||||
|
||||
pub struct CodegenTest262Case {
|
||||
|
|
@ -174,7 +91,7 @@ impl Case for CodegenTest262Case {
|
|||
let source_text = self.base.code();
|
||||
let is_module = self.base.meta().flags.contains(&TestFlag::Module);
|
||||
let source_type = SourceType::default().with_module(is_module);
|
||||
let result = get_result("test262", self.base.path(), source_text, source_type);
|
||||
let result = get_result(source_text, source_type);
|
||||
self.base.set_result(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -207,7 +124,7 @@ impl Case for CodegenBabelCase {
|
|||
fn run(&mut self) {
|
||||
let source_text = self.base.code();
|
||||
let source_type = self.base.source_type();
|
||||
let result = get_result("babel", self.base.path(), source_text, source_type);
|
||||
let result = get_result(source_text, source_type);
|
||||
self.base.set_result(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -240,7 +157,7 @@ impl Case for CodegenTypeScriptCase {
|
|||
fn run(&mut self) {
|
||||
let source_text = self.base.code();
|
||||
let source_type = self.base.source_type();
|
||||
let result = get_result("typescript", self.base.path(), source_text, source_type);
|
||||
let result = get_result(source_text, source_type);
|
||||
self.base.set_result(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -273,7 +190,7 @@ impl Case for CodegenMiscCase {
|
|||
fn run(&mut self) {
|
||||
let source_text = self.base.code();
|
||||
let source_type = self.base.source_type();
|
||||
let result = get_result("misc", self.base.path(), source_text, source_type);
|
||||
let result = get_result(source_text, source_type);
|
||||
self.base.set_result(result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue