feat(codegen): improve codegen formatting (#3735)

This commit is contained in:
Boshen 2024-06-18 11:10:36 +00:00
parent 4d462636cb
commit 5a99d30eba
6 changed files with 4789 additions and 4744 deletions

View file

@ -193,45 +193,46 @@ fn print_if<const MINIFY: bool>(
p.print(b'('); p.print(b'(');
p.print_expression(&if_stmt.test); p.print_expression(&if_stmt.test);
p.print(b')'); p.print(b')');
p.print_soft_space();
match &if_stmt.consequent { match &if_stmt.consequent {
Statement::BlockStatement(block) => { Statement::BlockStatement(block) => {
p.print_soft_space();
p.print_block_statement(block, ctx); p.print_block_statement(block, ctx);
}
stmt if wrap_to_avoid_ambiguous_else(stmt) => {
p.print_block_start(stmt.span().start);
stmt.gen(p, ctx);
p.needs_semicolon = false;
p.print_block_end(stmt.span().end);
}
stmt => {
stmt.gen(p, ctx);
}
}
if if_stmt.alternate.is_some() { if if_stmt.alternate.is_some() {
p.print_soft_space(); p.print_soft_space();
} else { } else {
p.print_soft_newline(); p.print_soft_newline();
} }
}
stmt if wrap_to_avoid_ambiguous_else(stmt) => {
p.print_soft_space();
p.print_block_start(stmt.span().start);
stmt.gen(p, ctx);
p.needs_semicolon = false;
p.print_block_end(stmt.span().end);
if if_stmt.alternate.is_some() {
p.print_soft_space();
} else {
p.print_soft_newline();
}
}
stmt => p.print_body(stmt, false, ctx),
}
if let Some(alternate) = if_stmt.alternate.as_ref() { if let Some(alternate) = if_stmt.alternate.as_ref() {
p.print_semicolon_if_needed(); p.print_semicolon_if_needed();
p.print_space_before_identifier(); p.print_space_before_identifier();
p.print_str(b"else "); p.print_str(b"else");
match alternate { match alternate {
Statement::BlockStatement(block) => { Statement::BlockStatement(block) => {
p.print_soft_space();
p.print_block_statement(block, ctx); p.print_block_statement(block, ctx);
p.print_soft_newline(); p.print_soft_newline();
} }
Statement::IfStatement(if_stmt) => { Statement::IfStatement(if_stmt) => {
p.print_hard_space();
print_if(if_stmt, p, ctx); print_if(if_stmt, p, ctx);
} }
_ => { stmt => p.print_body(stmt, true, ctx),
p.print_soft_newline();
p.indent();
alternate.gen(p, ctx);
p.dedent();
}
} }
} }
} }
@ -296,12 +297,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForStatement<'a> {
p.print_semicolon(); p.print_semicolon();
if let Some(update) = self.update.as_ref() { if let Some(update) = self.update.as_ref() {
p.print_soft_space();
p.print_expression(update); p.print_expression(update);
} }
p.print(b')'); p.print(b')');
p.print_soft_space(); p.print_body(&self.body, false, ctx);
p.print_body(&self.body, ctx);
} }
} }
@ -319,8 +320,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForInStatement<'a> {
p.print_hard_space(); p.print_hard_space();
p.print_expression(&self.right); p.print_expression(&self.right);
p.print(b')'); p.print(b')');
p.print_soft_space(); p.print_body(&self.body, false, ctx);
p.print_body(&self.body, ctx);
} }
} }
@ -340,8 +340,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ForOfStatement<'a> {
p.print_str(b"of "); p.print_str(b"of ");
self.right.gen_expr(p, Precedence::Assign, Context::default()); self.right.gen_expr(p, Precedence::Assign, Context::default());
p.print(b')'); p.print(b')');
p.print_soft_space(); p.print_body(&self.body, false, ctx);
p.print_body(&self.body, ctx);
} }
} }
@ -370,8 +369,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for WhileStatement<'a> {
p.print(b'('); p.print(b'(');
p.print_expression(&self.test); p.print_expression(&self.test);
p.print(b')'); p.print(b')');
p.print_soft_space(); p.print_body(&self.body, false, ctx);
p.print_body(&self.body, ctx);
} }
} }
@ -470,13 +468,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for SwitchCase<'a> {
p.print_colon(); p.print_colon();
if self.consequent.len() == 1 { if self.consequent.len() == 1 {
if let Statement::BlockStatement(block) = &self.consequent[0] { p.print_body(&self.consequent[0], false, ctx);
p.print_soft_space();
p.print_block_statement(block, ctx);
p.print_soft_newline();
return; return;
} }
}
p.print_soft_newline(); p.print_soft_newline();
p.indent(); p.indent();
@ -503,12 +497,14 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ReturnStatement<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for LabeledStatement<'a> { impl<'a, const MINIFY: bool> Gen<MINIFY> for LabeledStatement<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
if !MINIFY && (p.indent > 0 || p.print_next_indent_as_space) {
p.add_source_mapping(self.span.start); p.add_source_mapping(self.span.start);
p.print_indent(); p.print_indent();
}
p.print_space_before_identifier();
self.label.gen(p, ctx); self.label.gen(p, ctx);
p.print_colon(); p.print_colon();
p.print_soft_space(); p.print_body(&self.body, false, ctx);
p.print_body(&self.body, ctx);
} }
} }
@ -531,6 +527,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TryStatement<'a> {
} }
p.print_soft_space(); p.print_soft_space();
p.print_block_statement(&handler.body, ctx); p.print_block_statement(&handler.body, ctx);
if self.finalizer.is_some() {
p.print_soft_newline();
}
} }
if let Some(finalizer) = &self.finalizer { if let Some(finalizer) = &self.finalizer {
p.print_soft_space(); p.print_soft_space();
@ -560,7 +559,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for WithStatement<'a> {
p.print(b'('); p.print(b'(');
p.print_expression(&self.object); p.print_expression(&self.object);
p.print(b')'); p.print(b')');
p.print_body(&self.body, ctx); p.print_body(&self.body, false, ctx);
} }
} }
@ -716,6 +715,10 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
} }
if let Some(specifiers) = &self.specifiers { if let Some(specifiers) = &self.specifiers {
if specifiers.is_empty() { if specifiers.is_empty() {
p.print_str(b"{}");
p.print_soft_space();
p.print_str(b"from");
p.print_soft_space();
p.print(b'\''); p.print(b'\'');
p.print_str(self.source.value.as_bytes()); p.print_str(self.source.value.as_bytes());
p.print(b'\''); p.print(b'\'');
@ -732,19 +735,23 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
match specifier { match specifier {
ImportDeclarationSpecifier::ImportDefaultSpecifier(spec) => { ImportDeclarationSpecifier::ImportDefaultSpecifier(spec) => {
if in_block { if in_block {
p.print_soft_space();
p.print_str(b"},"); p.print_str(b"},");
in_block = false; in_block = false;
} else if index != 0 { } else if index != 0 {
p.print_comma(); p.print_comma();
p.print_soft_space();
} }
spec.local.gen(p, ctx); spec.local.gen(p, ctx);
} }
ImportDeclarationSpecifier::ImportNamespaceSpecifier(spec) => { ImportDeclarationSpecifier::ImportNamespaceSpecifier(spec) => {
if in_block { if in_block {
p.print_soft_space();
p.print_str(b"},"); p.print_str(b"},");
in_block = false; in_block = false;
} else if index != 0 { } else if index != 0 {
p.print_comma(); p.print_comma();
p.print_soft_space();
} }
p.print_str(b"* as "); p.print_str(b"* as ");
spec.local.gen(p, ctx); spec.local.gen(p, ctx);
@ -752,12 +759,15 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
ImportDeclarationSpecifier::ImportSpecifier(spec) => { ImportDeclarationSpecifier::ImportSpecifier(spec) => {
if in_block { if in_block {
p.print_comma(); p.print_comma();
p.print_soft_space();
} else { } else {
if index != 0 { if index != 0 {
p.print_comma(); p.print_comma();
p.print_soft_space();
} }
in_block = true; in_block = true;
p.print(b'{'); p.print(b'{');
p.print_soft_space();
} }
if spec.import_kind.is_type() { if spec.import_kind.is_type() {
@ -785,6 +795,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportDeclaration<'a> {
} }
} }
if in_block { if in_block {
p.print_soft_space();
p.print(b'}'); p.print(b'}');
} }
p.print_str(b" from "); p.print_str(b" from ");
@ -825,6 +836,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ImportAttribute<'a> {
ImportAttributeKey::StringLiteral(literal) => literal.gen(p, ctx), ImportAttributeKey::StringLiteral(literal) => literal.gen(p, ctx),
}; };
p.print_colon(); p.print_colon();
p.print_soft_space();
self.value.gen(p, ctx); self.value.gen(p, ctx);
} }
} }
@ -1477,14 +1489,16 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for ObjectExpression<'a> {
fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) { fn gen_expr(&self, p: &mut Codegen<{ MINIFY }>, _precedence: Precedence, ctx: Context) {
let n = p.code_len(); let n = p.code_len();
p.wrap(p.start_of_stmt == n || p.start_of_arrow_expr == n, |p| { p.wrap(p.start_of_stmt == n || p.start_of_arrow_expr == n, |p| {
let single_line = self.properties.is_empty(); let single_line = self.properties.len() <= 1;
p.print_curly_braces(self.span, single_line, |p| { p.print_curly_braces(self.span, single_line, |p| {
for (index, item) in self.properties.iter().enumerate() { for (index, item) in self.properties.iter().enumerate() {
if index != 0 { if index != 0 {
p.print_comma(); p.print_comma();
p.print_soft_newline(); p.print_soft_newline();
} }
if !single_line {
p.print_indent(); p.print_indent();
}
item.gen(p, ctx); item.gen(p, ctx);
} }
if !single_line { if !single_line {
@ -1691,9 +1705,10 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for BinaryExpression<'a> {
self.left.gen_expr(p, left_precedence, ctx); self.left.gen_expr(p, left_precedence, ctx);
if self.operator.is_keyword() { if self.operator.is_keyword() {
p.print_space_before_identifier(); p.print_space_before_identifier();
} else {
p.print_soft_space();
} }
self.operator.gen(p, ctx); self.operator.gen(p, ctx);
p.print_soft_space();
let right_precedence = if self.precedence().is_left_associative() { let right_precedence = if self.precedence().is_left_associative() {
self.precedence() self.precedence()
} else { } else {
@ -1714,6 +1729,7 @@ impl<const MINIFY: bool> Gen<MINIFY> for BinaryOperator {
let op: Operator = (*self).into(); let op: Operator = (*self).into();
p.print_space_before_operator(op); p.print_space_before_operator(op);
p.print_str(operator); p.print_str(operator);
p.print_soft_space();
p.prev_op = Some(op); p.prev_op = Some(op);
p.prev_op_end = p.code().len(); p.prev_op_end = p.code().len();
} }
@ -1755,7 +1771,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for ConditionalExpression<'a> {
p.print_soft_space(); p.print_soft_space();
self.consequent.gen_expr(p, Precedence::Assign, ctx.and_in(true)); self.consequent.gen_expr(p, Precedence::Assign, ctx.and_in(true));
p.print_soft_space(); p.print_soft_space();
p.print(b':'); p.print_colon();
p.print_soft_space(); p.print_soft_space();
self.alternate.gen_expr(p, Precedence::Assign, ctx.union_in_if(wrap)); self.alternate.gen_expr(p, Precedence::Assign, ctx.union_in_if(wrap));
}); });
@ -1898,7 +1914,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentTargetMaybeDefault<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentTargetWithDefault<'a> { impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentTargetWithDefault<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
self.binding.gen(p, ctx); self.binding.gen(p, ctx);
p.print_soft_space();
p.print_equal(); p.print_equal();
p.print_soft_space();
self.init.gen_expr(p, Precedence::Assign, Context::default()); self.init.gen_expr(p, Precedence::Assign, Context::default());
} }
} }
@ -1916,7 +1934,9 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentTargetPropertyIdentifier<
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
self.binding.gen(p, ctx); self.binding.gen(p, ctx);
if let Some(expr) = &self.init { if let Some(expr) = &self.init {
p.print_soft_space();
p.print_equal(); p.print_equal();
p.print_soft_space();
expr.gen_expr(p, Precedence::Assign, Context::default()); expr.gen_expr(p, Precedence::Assign, Context::default());
} }
} }
@ -1938,6 +1958,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for AssignmentTargetPropertyProperty<'a
} }
} }
p.print_colon(); p.print_colon();
p.print_soft_space();
self.binding.gen(p, ctx); self.binding.gen(p, ctx);
} }
} }
@ -2157,7 +2178,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for JSXElementName<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for JSXNamespacedName<'a> { impl<'a, const MINIFY: bool> Gen<MINIFY> for JSXNamespacedName<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
self.namespace.gen(p, ctx); self.namespace.gen(p, ctx);
p.print(b':'); p.print_colon();
self.property.gen(p, ctx); self.property.gen(p, ctx);
} }
} }
@ -2175,7 +2196,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for JSXAttribute<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
self.name.gen(p, ctx); self.name.gen(p, ctx);
if let Some(value) = &self.value { if let Some(value) = &self.value {
p.print(b'='); p.print_equal();
value.gen(p, ctx); value.gen(p, ctx);
} }
} }
@ -2326,6 +2347,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for StaticBlock<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
p.add_source_mapping(self.span.start); p.add_source_mapping(self.span.start);
p.print_str(b"static"); p.print_str(b"static");
p.print_soft_space();
p.print_curly_braces(self.span, self.body.is_empty(), |p| { p.print_curly_braces(self.span, self.body.is_empty(), |p| {
for stmt in &self.body { for stmt in &self.body {
p.print_semicolon_if_needed(); p.print_semicolon_if_needed();
@ -2487,6 +2509,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ObjectPattern<'a> {
fn gen(&self, p: &mut Codegen<MINIFY>, ctx: Context) { fn gen(&self, p: &mut Codegen<MINIFY>, ctx: Context) {
p.add_source_mapping(self.span.start); p.add_source_mapping(self.span.start);
p.print(b'{'); p.print(b'{');
p.print_soft_space();
p.print_list(&self.properties, ctx); p.print_list(&self.properties, ctx);
if let Some(rest) = &self.rest { if let Some(rest) = &self.rest {
if !self.properties.is_empty() { if !self.properties.is_empty() {
@ -2494,6 +2517,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for ObjectPattern<'a> {
} }
rest.gen(p, ctx); rest.gen(p, ctx);
} }
p.print_soft_space();
p.print(b'}'); p.print(b'}');
p.add_source_mapping(self.span.end); p.add_source_mapping(self.span.end);
} }
@ -2513,6 +2537,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for BindingProperty<'a> {
} }
if !self.shorthand { if !self.shorthand {
p.print_colon(); p.print_colon();
p.print_soft_space();
} }
self.value.gen(p, ctx); self.value.gen(p, ctx);
} }
@ -2876,13 +2901,16 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTemplateLiteralType<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTypeLiteral<'a> { impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTypeLiteral<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
p.print_curly_braces(self.span, self.members.is_empty(), |p| { let single_line = self.members.len() <= 1;
p.print_curly_braces(self.span, single_line, |p| {
for item in &self.members { for item in &self.members {
p.print_indent(); p.print_indent();
item.gen(p, ctx); item.gen(p, ctx);
if !single_line {
p.print_semicolon(); p.print_semicolon();
p.print_soft_newline(); p.print_soft_newline();
} }
}
}); });
} }
} }

View file

@ -84,6 +84,7 @@ pub struct Codegen<'a, const MINIFY: bool> {
prev_op_end: usize, prev_op_end: usize,
prev_reg_exp_end: usize, prev_reg_exp_end: usize,
need_space_before_dot: usize, need_space_before_dot: usize,
print_next_indent_as_space: bool,
/// For avoiding `;` if the previous statement ends with `}`. /// For avoiding `;` if the previous statement ends with `}`.
needs_semicolon: bool, needs_semicolon: bool,
@ -95,7 +96,7 @@ pub struct Codegen<'a, const MINIFY: bool> {
start_of_default_export: usize, start_of_default_export: usize,
/// Track the current indentation level /// Track the current indentation level
indentation: u8, indent: u8,
// Builders // Builders
sourcemap_builder: Option<SourcemapBuilder>, sourcemap_builder: Option<SourcemapBuilder>,
@ -139,13 +140,14 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
code: Vec::with_capacity(capacity), code: Vec::with_capacity(capacity),
needs_semicolon: false, needs_semicolon: false,
need_space_before_dot: 0, need_space_before_dot: 0,
print_next_indent_as_space: false,
prev_op_end: 0, prev_op_end: 0,
prev_reg_exp_end: 0, prev_reg_exp_end: 0,
prev_op: None, prev_op: None,
start_of_stmt: 0, start_of_stmt: 0,
start_of_arrow_expr: 0, start_of_arrow_expr: 0,
start_of_default_export: 0, start_of_default_export: 0,
indentation: 0, indent: 0,
sourcemap_builder, sourcemap_builder,
move_comment_map: MoveCommentMap::default(), move_comment_map: MoveCommentMap::default(),
} }
@ -224,30 +226,36 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
self.move_comment_map.get(&start) self.move_comment_map.get(&start)
} }
#[inline]
fn print_soft_space(&mut self) { fn print_soft_space(&mut self) {
if !MINIFY { if !MINIFY {
self.print(b' '); self.print(b' ');
} }
} }
#[inline]
pub fn print_hard_space(&mut self) { pub fn print_hard_space(&mut self) {
self.print(b' '); self.print(b' ');
} }
#[inline]
fn print_soft_newline(&mut self) { fn print_soft_newline(&mut self) {
if !MINIFY { if !MINIFY {
self.print(b'\n'); self.print(b'\n');
} }
} }
#[inline]
fn print_semicolon(&mut self) { fn print_semicolon(&mut self) {
self.print(b';'); self.print(b';');
} }
#[inline]
fn print_comma(&mut self) { fn print_comma(&mut self) {
self.print(b','); self.print(b',');
} }
#[inline]
fn print_space_before_identifier(&mut self) { fn print_space_before_identifier(&mut self) {
if self if self
.peek_nth(0) .peek_nth(0)
@ -257,32 +265,41 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
fn peek_nth(&self, n: usize) -> Option<char> { fn peek_nth(&self, n: usize) -> Option<char> {
#[allow(unsafe_code)] #[allow(unsafe_code)]
// SAFETY: criteria of `from_utf8_unchecked` are met. // SAFETY: criteria of `from_utf8_unchecked` are met.
unsafe { std::str::from_utf8_unchecked(self.code()) }.chars().nth_back(n) unsafe { std::str::from_utf8_unchecked(self.code()) }.chars().nth_back(n)
} }
#[inline]
fn indent(&mut self) { fn indent(&mut self) {
if !MINIFY { if !MINIFY {
self.indentation += 1; self.indent += 1;
} }
} }
#[inline]
fn dedent(&mut self) { fn dedent(&mut self) {
if !MINIFY { if !MINIFY {
self.indentation -= 1; self.indent -= 1;
} }
} }
#[inline]
fn print_indent(&mut self) { fn print_indent(&mut self) {
if !MINIFY { if MINIFY {
for _ in 0..self.indentation { return;
self.print(b'\t');
} }
if self.print_next_indent_as_space {
self.print_hard_space();
self.print_next_indent_as_space = false;
return;
} }
self.code.extend(std::iter::repeat(b'\t').take(self.indent as usize));
} }
#[inline]
fn print_semicolon_after_statement(&mut self) { fn print_semicolon_after_statement(&mut self) {
if MINIFY { if MINIFY {
self.needs_semicolon = true; self.needs_semicolon = true;
@ -291,6 +308,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
fn print_semicolon_if_needed(&mut self) { fn print_semicolon_if_needed(&mut self) {
if self.needs_semicolon { if self.needs_semicolon {
self.print_semicolon(); self.print_semicolon();
@ -298,14 +316,17 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
fn print_ellipsis(&mut self) { fn print_ellipsis(&mut self) {
self.print_str(b"..."); self.print_str(b"...");
} }
#[inline]
pub fn print_colon(&mut self) { pub fn print_colon(&mut self) {
self.print(b':'); self.print(b':');
} }
#[inline]
fn print_equal(&mut self) { fn print_equal(&mut self) {
self.print(b'='); self.print(b'=');
} }
@ -351,13 +372,24 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
self.print(b'}'); self.print(b'}');
} }
fn print_body(&mut self, stmt: &Statement<'_>, ctx: Context) { fn print_body(&mut self, stmt: &Statement<'_>, need_space: bool, ctx: Context) {
match stmt { match stmt {
Statement::BlockStatement(stmt) => { Statement::BlockStatement(stmt) => {
self.print_soft_space();
self.print_block_statement(stmt, ctx); self.print_block_statement(stmt, ctx);
self.print_soft_newline(); self.print_soft_newline();
} }
stmt => stmt.gen(self, ctx), Statement::EmptyStatement(_) => {
self.print_semicolon();
self.print_soft_newline();
}
stmt => {
if need_space && MINIFY {
self.print_hard_space();
}
self.print_next_indent_as_space = true;
stmt.gen(self, ctx);
}
} }
} }
@ -390,6 +422,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
pub fn print_expression(&mut self, expr: &Expression<'_>) { pub fn print_expression(&mut self, expr: &Expression<'_>) {
expr.gen_expr(self, Precedence::lowest(), Context::default()); expr.gen_expr(self, Precedence::lowest(), Context::default());
} }
@ -422,10 +455,6 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
fn print_space_before_operator(&mut self, next: Operator) { fn print_space_before_operator(&mut self, next: Operator) {
if !MINIFY {
self.print_hard_space();
return;
}
if self.prev_op_end != self.code.len() { if self.prev_op_end != self.code.len() {
return; return;
} }
@ -457,6 +486,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
fn wrap<F: FnMut(&mut Self)>(&mut self, wrap: bool, mut f: F) { fn wrap<F: FnMut(&mut Self)>(&mut self, wrap: bool, mut f: F) {
if wrap { if wrap {
self.print(b'('); self.print(b'(');
@ -467,6 +497,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
} }
} }
#[inline]
fn wrap_quote<F: FnMut(&mut Self, char)>(&mut self, s: &str, mut f: F) { fn wrap_quote<F: FnMut(&mut Self, char)>(&mut self, s: &str, mut f: F) {
let quote = choose_quote(s); let quote = choose_quote(s);
self.print(quote as u8); self.print(quote as u8);

View file

@ -121,7 +121,7 @@ fn template() {
fn module_decl() { fn module_decl() {
test("export * as foo from 'foo'", "export * as foo from 'foo';\n", None); test("export * as foo from 'foo'", "export * as foo from 'foo';\n", None);
test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n", None); test("import x from './foo.js' with {}", "import x from './foo.js' with {\n};\n", None);
test("import {} from './foo.js' with {}", "import './foo.js' with {\n};\n", None); test("import {} from './foo.js' with {}", "import {} from './foo.js' with {\n};\n", None);
test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n", None); test("export * from './foo.js' with {}", "export * from './foo.js' with {\n};\n", None);
} }
@ -176,8 +176,12 @@ fn typescript() {
test_ts("function isString(value: unknown): asserts value is string {\n\tif (typeof value !== 'string') {\n\t\tthrow new Error('Not a string');\n\t}\n}", "function isString(value: unknown): asserts value is string {\n\tif (typeof value !== 'string') {\n\t\tthrow new Error('Not a string');\n\t}\n}\n", false); test_ts("function isString(value: unknown): asserts value is string {\n\tif (typeof value !== 'string') {\n\t\tthrow new Error('Not a string');\n\t}\n}", "function isString(value: unknown): asserts value is string {\n\tif (typeof value !== 'string') {\n\t\tthrow new Error('Not a string');\n\t}\n}\n", false);
// type-only imports/exports // type-only imports/exports
test_ts("import type { Foo } from 'foo';", "import type {Foo} from 'foo';\n", false); 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(
"import { Foo, type Bar } from 'foo';",
"import { Foo, type Bar } from 'foo';\n",
false,
);
test_ts( test_ts(
"export { Foo, type Bar } from 'foo';", "export { Foo, type Bar } from 'foo';",
"export { Foo, type Bar } from 'foo';\n", "export { Foo, type Bar } from 'foo';\n",

File diff suppressed because it is too large Load diff

View file

@ -17,61 +17,49 @@ Mismatch: "declarationSingleFileHasErrorsReported.ts"
#### "declarationLinkedAliases.ts" #### #### "declarationLinkedAliases.ts" ####
//// [declarationLinkedAliases.ts] //// //// [declarationLinkedAliases.ts] ////
import {A} from 'mod'; import { A } from 'mod';
import B = A.C; import B = A.C;
export { B }; export { B };
//// [declarationLinkedAliases.d.ts] //// //// [declarationLinkedAliases.d.ts] ////
import {A} from 'mod'; import { A } from 'mod';
import B = A.C; import B = A.C;
export { B }; export { B };
#### "declarationLocalAliasOfImportAlias.ts" #### #### "declarationLocalAliasOfImportAlias.ts" ####
//// [declarationLocalAliasOfImportAlias.ts] //// //// [declarationLocalAliasOfImportAlias.ts] ////
import {Record} from './a'; import { Record } from './a';
export type Foo<K extends string> = Record<K, number>; export type Foo<K extends string> = Record<K, number>;
export const obj = { export const obj = {doThing<K extends string>(_k: K) {
doThing<K extends string>(_k: K) {
return ({} as any); return ({} as any);
} }};
};
//// [declarationLocalAliasOfImportAlias.d.ts] //// //// [declarationLocalAliasOfImportAlias.d.ts] ////
import {Record} from './a'; import { Record } from './a';
export type Foo<K extends string> = Record<K, number>; export type Foo<K extends string> = Record<K, number>;
export declare const obj: { export declare const obj: {doThing<K extends string>(_k: K): Foo<K>};
doThing<K extends string>(_k: K): Foo<K>;
};
#### "declarationSelfReferentialConstraint.ts" #### #### "declarationSelfReferentialConstraint.ts" ####
//// [declarationSelfReferentialConstraint.ts] //// //// [declarationSelfReferentialConstraint.ts] ////
export const object = { export const object = {foo: <T extends ((Set<T>) | ([]))>(): void => {}};
foo: <T extends ((Set<T>) | ([]))>(): void => {}
};
//// [declarationSelfReferentialConstraint.d.ts] //// //// [declarationSelfReferentialConstraint.d.ts] ////
export declare const object: { export declare const object: {foo: <T extends ((Set<T>) | ([]))>() => void};
foo: <T extends ((Set<T>) | ([]))>() => void;
};
#### "declarationTypeParameterConstraint.ts" #### #### "declarationTypeParameterConstraint.ts" ####
//// [declarationTypeParameterConstraint.ts] //// //// [declarationTypeParameterConstraint.ts] ////
import {type In,type Out,type Base} from './a'; import { type In, type Out, type Base } from './a';
export const object = { export const object = {doThing<T extends Base>(_t: T, _in: In[T]) {
doThing<T extends Base>(_t: T, _in: In[T]) {
return; return;
} }};
};
//// [declarationTypeParameterConstraint.d.ts] //// //// [declarationTypeParameterConstraint.d.ts] ////
import {type In,type Out,type Base} from './a'; import { type In, type Out, type Base } from './a';
export declare const object: { export declare const object: {doThing<T extends Base>(_t: T, _in: In[T]): Out[T]};
doThing<T extends Base>(_t: T, _in: In[T]): Out[T];
};
#### "declarationTypeWithComputedName.ts" #### #### "declarationTypeWithComputedName.ts" ####
//// [declarationTypeWithComputedName.ts] //// //// [declarationTypeWithComputedName.ts] ////
import {Foo} from './a'; import { Foo } from './a';
export type Bar = { export type Bar = {
[Foo.A]: 1; [Foo.A]: 1;
[Foo.B]: 2; [Foo.B]: 2;
@ -82,7 +70,7 @@ export const valBar = ((null as any) as {
}); });
//// [declarationTypeWithComputedName.d.ts] //// //// [declarationTypeWithComputedName.d.ts] ////
import {Foo} from './a'; import { Foo } from './a';
export type Bar = { export type Bar = {
[Foo.A]: 1; [Foo.A]: 1;
[Foo.B]: 2; [Foo.B]: 2;
@ -100,9 +88,7 @@ export const fn2 = (a: MissingGlobalType) => (null as MissingGlobalType);
export const x2: typeof missingGlobalValue = null; export const x2: typeof missingGlobalValue = null;
export const fn3 = (a: typeof missingGlobalValue): typeof missingGlobalValue => null; export const fn3 = (a: typeof missingGlobalValue): typeof missingGlobalValue => null;
export const fn4 = (a: typeof missingGlobalValue) => (null as typeof missingGlobalValue); export const fn4 = (a: typeof missingGlobalValue) => (null as typeof missingGlobalValue);
export const o: { export const o: {[missingGlobalValue]: string} = null;
[missingGlobalValue]: string;
} = null;
//// [declarationUnresolvedGlobalReferencesNoErrors.d.ts] //// //// [declarationUnresolvedGlobalReferencesNoErrors.d.ts] ////
export declare const x: MissingGlobalType; export declare const x: MissingGlobalType;
@ -111,18 +97,16 @@ export declare const fn2: (a: MissingGlobalType) => MissingGlobalType;
export declare const x2: typeof missingGlobalValue; export declare const x2: typeof missingGlobalValue;
export declare const fn3: (a: typeof missingGlobalValue) => typeof missingGlobalValue; export declare const fn3: (a: typeof missingGlobalValue) => typeof missingGlobalValue;
export declare const fn4: (a: typeof missingGlobalValue) => typeof missingGlobalValue; export declare const fn4: (a: typeof missingGlobalValue) => typeof missingGlobalValue;
export declare const o: { export declare const o: {[missingGlobalValue]: string};
[missingGlobalValue]: string;
};
#### "declarationUnresolvedTypeReference.ts" #### #### "declarationUnresolvedTypeReference.ts" ####
//// [declarationUnresolvedTypeReference.ts] //// //// [declarationUnresolvedTypeReference.ts] ////
import {type Type} from './a'; import { type Type } from './a';
export const foo = (_: Type): void => {}; export const foo = (_: Type): void => {};
export const bar = (_: import('./a').Type): void => {}; export const bar = (_: import('./a').Type): void => {};
//// [declarationUnresolvedTypeReference.d.ts] //// //// [declarationUnresolvedTypeReference.d.ts] ////
import {type Type} from './a'; import { type Type } from './a';
export declare const foo: (_: Type) => void; export declare const foo: (_: Type) => void;
export declare const bar: (_: import('./a').Type) => void; export declare const bar: (_: import('./a').Type) => void;
@ -153,12 +137,8 @@ export const c: number = 1;
export interface A { export interface A {
x: number; x: number;
} }
let expr: { let expr: {x: number};
x: number; expr = {x: 12};
};
expr = {
x: 12
};
export default expr; export default expr;
//// [declarationsSimple.d.ts] //// //// [declarationsSimple.d.ts] ////
@ -166,7 +146,5 @@ export declare const c: number;
export interface A { export interface A {
x: number; x: number;
} }
declare let expr: { declare let expr: {x: number};
x: number;
};
export default expr; export default expr;

View file

@ -1,6 +1,6 @@
commit: 12619ffe commit: 12619ffe
Passed: 478/927 Passed: 474/927
# All Passed: # All Passed:
* babel-preset-react * babel-preset-react
@ -445,12 +445,16 @@ Passed: 478/927
* opts/optimizeConstEnums/input.ts * opts/optimizeConstEnums/input.ts
* opts/rewriteImportExtensions/input.ts * opts/rewriteImportExtensions/input.ts
# babel-plugin-transform-typescript (134/151) # babel-plugin-transform-typescript (130/151)
* enum/mix-references/input.ts * enum/mix-references/input.ts
* enum/ts5.0-const-foldable/input.ts * enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts * exports/declared-types/input.ts
* exports/interface/input.ts * exports/interface/input.ts
* imports/elide-no-import-specifiers/input.ts
* imports/import-removed-exceptions/input.ts
* imports/only-remove-type-imports/input.ts
* imports/type-only-export-specifier-2/input.ts * imports/type-only-export-specifier-2/input.ts
* imports/type-only-import-specifier-4/input.ts
* optimize-const-enums/custom-values/input.ts * optimize-const-enums/custom-values/input.ts
* optimize-const-enums/custom-values-exported/input.ts * optimize-const-enums/custom-values-exported/input.ts
* optimize-const-enums/declare/input.ts * optimize-const-enums/declare/input.ts