diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 2c1a961c79083..c3e91ccc9fc00 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -273,6 +273,7 @@ impl Gen for IfStatement<'_> { } fn print_if(if_stmt: &IfStatement<'_>, p: &mut Codegen, ctx: Context) { + p.print_space_before_identifier(); p.print_str("if"); p.print_soft_space(); p.print_ascii_byte(b'('); @@ -362,6 +363,7 @@ impl Gen for ForStatement<'_> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span); p.print_indent(); + p.print_space_before_identifier(); p.print_str("for"); p.print_soft_space(); p.print_ascii_byte(b'('); @@ -471,17 +473,23 @@ impl Gen for DoWhileStatement<'_> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span); p.print_indent(); - p.print_str("do "); - if let Statement::BlockStatement(block) = &self.body { - p.print_block_statement(block, ctx); - p.print_soft_space(); - } else { - p.print_soft_newline(); - p.indent(); - self.body.print(p, ctx); - p.print_semicolon_if_needed(); - p.dedent(); - p.print_indent(); + p.print_space_before_identifier(); + p.print_str("do"); + match &self.body { + Statement::BlockStatement(block) => { + p.print_soft_space(); + p.print_block_statement(block, ctx); + p.print_soft_space(); + } + Statement::EmptyStatement(s) => s.print(p, ctx), + _ => { + p.print_soft_newline(); + p.indent(); + self.body.print(p, ctx); + p.print_semicolon_if_needed(); + p.dedent(); + p.print_indent(); + } } p.print_str("while"); p.print_soft_space(); @@ -505,6 +513,7 @@ impl Gen for ContinueStatement<'_> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span); p.print_indent(); + p.print_space_before_identifier(); p.print_str("continue"); if let Some(label) = &self.label { p.print_soft_space(); @@ -518,6 +527,7 @@ impl Gen for BreakStatement<'_> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span); p.print_indent(); + p.print_space_before_identifier(); p.print_str("break"); if let Some(label) = &self.label { p.print_soft_space(); @@ -682,6 +692,7 @@ impl Gen for VariableDeclaration<'_> { p.start_of_annotation_comment = Some(self.span.start); } + p.print_space_before_identifier(); p.print_str(match self.kind { VariableDeclarationKind::Const => "const", VariableDeclarationKind::Let => "let", diff --git a/crates/oxc_codegen/tests/integration/unit.rs b/crates/oxc_codegen/tests/integration/unit.rs index 007e41c80da27..ce1f90a38954c 100644 --- a/crates/oxc_codegen/tests/integration/unit.rs +++ b/crates/oxc_codegen/tests/integration/unit.rs @@ -87,6 +87,12 @@ fn for_stmt() { ); } +#[test] +fn do_while_stmt() { + test("do ; while (true);", "do;\nwhile (true);\n"); + test_minify("do ; while (true);", "do;while(true);"); +} + #[test] fn if_stmt() { test( diff --git a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs index 6b7982c743b62..0b875554d8d8d 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs @@ -140,16 +140,19 @@ impl<'a, 'b> PeepholeRemoveDeadCode { if stmt.body.len() == 1 && !stmt.body[0].is_declaration() { return Some(stmt.body.remove(0)); } - if stmt.body.len() == 0 - && (ctx.parent().is_while_statement() - || ctx.parent().is_for_statement() - || ctx.parent().is_for_in_statement() - || ctx.parent().is_for_of_statement() - || ctx.parent().is_block_statement() - || ctx.parent().is_program()) - { - // Remove the block if it is empty and the parent is a block statement. - return Some(ctx.ast.statement_empty(stmt.span)); + if stmt.body.len() == 0 { + let parent = ctx.parent(); + if parent.is_while_statement() + || parent.is_do_while_statement() + || parent.is_for_statement() + || parent.is_for_in_statement() + || parent.is_for_of_statement() + || parent.is_block_statement() + || parent.is_program() + { + // Remove the block if it is empty and the parent is a block statement. + return Some(ctx.ast.statement_empty(stmt.span)); + } } None } @@ -563,6 +566,7 @@ mod test { // fold("for (x of y) {x}", "for(x of y);"); fold("for (let x = 1; x <10; x++ ) {}", "for (let x = 1; x <10; x++ );"); fold("for (var x = 1; x <10; x++ ) {}", "for (var x = 1; x <10; x++ );"); + fold("do { } while (true)", "do;while(true)"); } #[test] diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index f88a6dbb09732..975e36aa0a364 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -11,17 +11,17 @@ Original | minified | minified | gzip | gzip | Fixture 544.10 kB | 71.79 kB | 72.48 kB | 26.18 kB | 26.20 kB | lodash.js -555.77 kB | 273.14 kB | 270.13 kB | 90.95 kB | 90.80 kB | d3.js +555.77 kB | 273.13 kB | 270.13 kB | 90.95 kB | 90.80 kB | d3.js 1.01 MB | 460.31 kB | 458.89 kB | 126.84 kB | 126.71 kB | bundle.min.js -1.25 MB | 652.68 kB | 646.76 kB | 163.53 kB | 163.73 kB | three.js +1.25 MB | 652.67 kB | 646.76 kB | 163.53 kB | 163.73 kB | three.js 2.14 MB | 726.14 kB | 724.14 kB | 180.16 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 331.89 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 331.88 kB | 331.56 kB | echarts.js -6.69 MB | 2.32 MB | 2.31 MB | 492.77 kB | 488.28 kB | antd.js +6.69 MB | 2.32 MB | 2.31 MB | 492.76 kB | 488.28 kB | antd.js 10.95 MB | 3.50 MB | 3.49 MB | 909.12 kB | 915.50 kB | typescript.js