diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index 4b9d814fb..f7ed65f60 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -30,7 +30,7 @@ use oxc_span::GetSpan; use crate::{ array, doc::{Doc, Separator}, - format, group, hardline, indent, softline, ss, string, wrap, Prettier, + format, group, hardline, indent, line, softline, ss, string, wrap, Prettier, }; use self::{ @@ -177,36 +177,33 @@ impl<'a> Format<'a> for BlockStatement<'a> { impl<'a> Format<'a> for ForStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { wrap!(p, self, ForStatement, { - let mut parts = p.vec(); - - parts.push(ss!("for (")); - - let mut parts_head = p.vec(); - - if let Some(init) = &self.init { - parts_head.push(format!(p, init)); - } - parts_head.push(ss!(";")); - parts_head.push(Doc::Line); - if let Some(init) = &self.test { - parts_head.push(format!(p, init)); - } - parts_head.push(ss!(";")); - parts_head.push(Doc::Line); - if let Some(init) = &self.update { - parts_head.push(format!(p, init)); - } - - let parts_head = indent!(p, group!(p, Doc::Array(parts_head))); - - parts.push(group!(p, parts_head)); - - parts.push(ss!(")")); - let body = format!(p, self.body); - parts.push(misc::adjust_clause(p, &self.body, body, false)); + let body = misc::adjust_clause(p, &self.body, body, false); - Doc::Group(parts) + if self.init.is_none() && self.test.is_none() && self.update.is_none() { + return group![p, ss!("for (;;)"), body]; + } + + let parts_head = { + let mut parts_head = p.vec(); + parts_head.push(softline!()); + if let Some(init) = &self.init { + parts_head.push(format!(p, init)); + } + parts_head.push(ss!(";")); + parts_head.push(line!()); + if let Some(init) = &self.test { + parts_head.push(format!(p, init)); + } + parts_head.push(ss!(";")); + parts_head.push(line!()); + if let Some(init) = &self.update { + parts_head.push(format!(p, init)); + } + Doc::Indent(parts_head) + }; + + group![p, ss!("for ("), group![p, parts_head, softline!()], ss!(")"), body] }) } } @@ -223,40 +220,37 @@ impl<'a> Format<'a> for ForStatementInit<'a> { impl<'a> Format<'a> for ForInStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - - parts.push(ss!("for (")); - parts.push(format!(p, self.left)); - parts.push(ss!(" in ")); - parts.push(format!(p, self.right)); - parts.push(ss!(")")); - - let body = format!(p, self.body); - parts.push(misc::adjust_clause(p, &self.body, body, false)); - - Doc::Group(parts) + wrap!(p, self, ForInStatement, { + let mut parts = p.vec(); + parts.push(ss!("for (")); + parts.push(format!(p, self.left)); + parts.push(ss!(" in ")); + parts.push(format!(p, self.right)); + parts.push(ss!(")")); + let body = format!(p, self.body); + parts.push(misc::adjust_clause(p, &self.body, body, false)); + Doc::Group(parts) + }) } } impl<'a> Format<'a> for ForOfStatement<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - - parts.push(ss!("for")); - - if self.r#await { - parts.push(ss!(" await")); - } - parts.push(ss!(" (")); - parts.push(format!(p, self.left)); - parts.push(ss!(" of ")); - parts.push(format!(p, self.right)); - parts.push(ss!(")")); - - let body = format!(p, self.body); - parts.push(misc::adjust_clause(p, &self.body, body, false)); - - Doc::Group(parts) + wrap!(p, self, ForOfStatement, { + let mut parts = p.vec(); + parts.push(ss!("for")); + if self.r#await { + parts.push(ss!(" await")); + } + parts.push(ss!(" (")); + parts.push(format!(p, self.left)); + parts.push(ss!(" of ")); + parts.push(format!(p, self.right)); + parts.push(ss!(")")); + let body = format!(p, self.body); + parts.push(misc::adjust_clause(p, &self.body, body, false)); + Doc::Group(parts) + }) } } @@ -516,20 +510,31 @@ impl<'a> Format<'a> for Declaration<'a> { impl<'a> Format<'a> for VariableDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let kind = self.kind.as_str(); - let mut decls = p.vec(); - decls.extend(self.declarations.iter().map(|decl| decl.format(p))); + wrap!(p, self, VariableDeclaration, { + // We generally want to terminate all variable declarations with a + // semicolon, except when they in the () part of for loops. + let parent_for_loop = match p.parent_kind() { + AstKind::ForStatement(stmt) => Some(stmt.body.span()), + AstKind::ForInStatement(stmt) => Some(stmt.body.span()), + AstKind::ForOfStatement(stmt) => Some(stmt.body.span()), + _ => None, + }; - let mut parts = p.vec(); - parts.push(ss!(kind)); - parts.push(ss!(" ")); - parts.push(Doc::Array(decls)); + let kind = self.kind.as_str(); + let mut decls = p.vec(); + decls.extend(self.declarations.iter().map(|decl| decl.format(p))); - if p.options.semi { - parts.push(ss!(";")); - } + let mut parts = p.vec(); + parts.push(ss!(kind)); + parts.push(ss!(" ")); + parts.push(Doc::Array(decls)); - Doc::Group(parts) + if !parent_for_loop.is_some_and(|span| span != self.span) { + parts.push(ss!(";")); + } + + Doc::Group(parts) + }) } } @@ -1415,13 +1420,11 @@ impl<'a> Format<'a> for YieldExpression<'a> { impl<'a> Format<'a> for UpdateExpression<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - let mut parts = p.vec(); - parts.push(p.str(self.operator.as_str())); - parts.push(format!(p, self.argument)); if self.prefix { - parts.reverse(); + array![p, ss!(self.operator.as_str()), format!(p, self.argument)] + } else { + array![p, format!(p, self.argument), ss!(self.operator.as_str())] } - Doc::Array(parts) } } diff --git a/tasks/prettier_conformance/prettier.snap.md b/tasks/prettier_conformance/prettier.snap.md index cf9f276e4..c4b29535e 100644 --- a/tasks/prettier_conformance/prettier.snap.md +++ b/tasks/prettier_conformance/prettier.snap.md @@ -1,4 +1,4 @@ -Compatibility: 114/838 (13.60%) +Compatibility: 119/838 (14.20%) # Failed @@ -406,7 +406,6 @@ Compatibility: 114/838 (13.60%) * empty-paren-comment/empty_paren_comment.js ### empty-statement -* empty-statement/body.js * empty-statement/no-newline.js ### end-of-line @@ -473,8 +472,6 @@ Compatibility: 114/838 (13.60%) * for/continue-and-break-comment-1.js * for/continue-and-break-comment-2.js * for/continue-and-break-comment-without-blocks.js -* for/for.js -* for/in.js ### for-await * for-await/for-await.js @@ -620,7 +617,6 @@ Compatibility: 114/838 (13.60%) * member/expand.js ### method-chain -* method-chain/13018.js * method-chain/bracket_0-1.js * method-chain/bracket_0.js * method-chain/break-last-call.js @@ -984,9 +980,6 @@ Compatibility: 114/838 (13.60%) * unicode/combining-characters.js * unicode/nbsp-jsx.js -### update-expression -* update-expression/update_expression.js - ### v8_intrinsic * v8_intrinsic/avoid-conflicts-to-pipeline.js * v8_intrinsic/intrinsic_call.js