diff --git a/crates/oxc_ast/src/span.rs b/crates/oxc_ast/src/span.rs index bf2739d46..773d82bff 100644 --- a/crates/oxc_ast/src/span.rs +++ b/crates/oxc_ast/src/span.rs @@ -76,6 +76,12 @@ impl<'a> GetSpan for Expression<'a> { } } +impl GetSpan for Directive { + fn span(&self) -> Span { + self.span + } +} + impl<'a> GetSpan for BindingPatternKind<'a> { fn span(&self) -> Span { match self { diff --git a/crates/oxc_prettier/src/format/block.rs b/crates/oxc_prettier/src/format/block.rs index c4711b3d3..bea1df779 100644 --- a/crates/oxc_prettier/src/format/block.rs +++ b/crates/oxc_prettier/src/format/block.rs @@ -17,7 +17,7 @@ pub(super) fn print_block<'a>( parts.push(ss!("static ")); } parts.push(ss!("{")); - if let Some(doc) = print_block_body(p, stmts, directives, true) { + if let Some(doc) = print_block_body(p, stmts, directives, true, false) { parts.push(indent![p, hardline!(), doc]); parts.push(hardline!()); } @@ -30,6 +30,7 @@ pub(super) fn print_block_body<'a>( stmts: &Vec<'a, Statement<'a>>, directives: Option<&Vec<'a, Directive>>, remove_last_statement_hardline: bool, + is_program: bool, ) -> Option> { let has_directives = directives.is_some_and(|directives| !directives.is_empty()); let has_body = stmts.iter().any(|stmt| !matches!(stmt, Statement::EmptyStatement(_))); @@ -50,5 +51,9 @@ pub(super) fn print_block_body<'a>( parts.extend(statement::print_statement_sequence(p, stmts, remove_last_statement_hardline)); } + if is_program { + parts.push(hardline!()); + } + Some(Doc::Array(parts)) } diff --git a/crates/oxc_prettier/src/format/function.rs b/crates/oxc_prettier/src/format/function.rs index edf9e9532..7ba06e8a2 100644 --- a/crates/oxc_prettier/src/format/function.rs +++ b/crates/oxc_prettier/src/format/function.rs @@ -1,7 +1,7 @@ #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; -use crate::{doc::Doc, group, hardline, if_break, indent, softline, ss, Format, Prettier}; +use crate::{doc::Doc, group, if_break, indent, softline, ss, Format, Prettier}; pub(super) fn print_function<'a>(p: &mut Prettier<'a>, func: &Function<'a>) -> Doc<'a> { let mut parts = p.vec(); @@ -35,8 +35,6 @@ pub(super) fn print_function<'a>(p: &mut Prettier<'a>, func: &Function<'a>) -> D parts.push(p.str(";")); } - parts.push(hardline!()); - Doc::Array(parts) } @@ -61,7 +59,6 @@ pub(super) fn print_return_or_throw_argument<'a>( } parts.push(p.str(";")); - parts.push(hardline!()); Doc::Array(parts) } diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index 92ef293fd..836f7229d 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -26,9 +26,7 @@ mod ternary; use crate::{ array, doc::{Doc, Separator}, - format, group, hardline, indent, softline, ss, string, - util::is_next_line_empty, - Prettier, + format, group, hardline, indent, softline, ss, string, Prettier, }; use self::{ @@ -52,7 +50,8 @@ where impl<'a> Format<'a> for Program<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - block::print_block_body(p, &self.body, Some(&self.directives), false).unwrap_or(ss!("")) + block::print_block_body(p, &self.body, Some(&self.directives), false, true) + .unwrap_or(ss!("")) } } @@ -96,7 +95,6 @@ impl<'a> Format<'a> for ExpressionStatement<'a> { if p.options.semi { parts.push(ss!(";")); } - parts.push(Doc::Hardline); Doc::Array(parts) } } @@ -388,12 +386,6 @@ impl<'a> Format<'a> for VariableDeclaration<'a> { parts.push(ss!(";")); } - parts.push(Doc::Hardline); - - if is_next_line_empty(p.source_text, self.span) { - parts.push(Doc::Hardline); - } - Doc::Group(parts) } } @@ -504,7 +496,6 @@ impl<'a> Format<'a> for ImportDeclaration<'a> { } parts.push(ss!(" from ")); parts.push(self.source.format(p)); - parts.push(hardline!()); Doc::Array(parts) } } diff --git a/crates/oxc_prettier/src/format/module.rs b/crates/oxc_prettier/src/format/module.rs index fa5d95c95..a8442ea5d 100644 --- a/crates/oxc_prettier/src/format/module.rs +++ b/crates/oxc_prettier/src/format/module.rs @@ -25,5 +25,28 @@ pub(super) fn print_export_declaration<'a>( ModuleDeclaration::TSNamespaceExportDeclaration(decl) => decl.format(p), }); + if let Some(doc) = print_semicolon_after_export_declaration(p, decl) { + parts.push(doc); + } + Doc::Array(parts) } + +fn print_semicolon_after_export_declaration<'a>( + p: &Prettier<'a>, + decl: &ModuleDeclaration<'a>, +) -> Option> { + if !p.options.semi { + return None; + } + + let ModuleDeclaration::ExportDefaultDeclaration(decl) = decl else { return None }; + + match decl.declaration { + ExportDefaultDeclarationKind::Expression(_) => Some(ss!(";")), + ExportDefaultDeclarationKind::FunctionDeclaration(_) + | ExportDefaultDeclarationKind::ClassDeclaration(_) + | ExportDefaultDeclarationKind::TSInterfaceDeclaration(_) + | ExportDefaultDeclarationKind::TSEnumDeclaration(_) => None, + } +} diff --git a/crates/oxc_prettier/src/format/statement.rs b/crates/oxc_prettier/src/format/statement.rs index d12a6f22f..933a2dbdf 100644 --- a/crates/oxc_prettier/src/format/statement.rs +++ b/crates/oxc_prettier/src/format/statement.rs @@ -1,19 +1,22 @@ use oxc_allocator::Vec; -use crate::{doc::Doc, Prettier}; +use crate::{doc::Doc, hardline, Prettier}; +use oxc_span::GetSpan; use super::Format; +use crate::util::is_next_line_empty; -pub(super) fn print_statement_sequence<'a, F: Format<'a>>( +pub(super) fn print_statement_sequence<'a, F: Format<'a> + GetSpan>( p: &mut Prettier<'a>, stmts: &Vec<'a, F>, remove_last_statement_hardline: bool, ) -> Vec<'a, Doc<'a>> { let mut parts = p.vec(); - for (index, stmt) in stmts.iter().enumerate() { + + for (i, stmt) in stmts.iter().enumerate() { let mut docs = stmt.format(p); - if remove_last_statement_hardline && index == stmts.len() - 1 { + if remove_last_statement_hardline && i == stmts.len() - 1 { match docs { Doc::Array(ref mut docs) | Doc::Group(ref mut docs) => { if matches!(docs.last(), Some(Doc::Hardline)) { @@ -25,6 +28,15 @@ pub(super) fn print_statement_sequence<'a, F: Format<'a>>( } parts.push(docs); + + if i < stmts.len() - 1 { + parts.push(hardline!()); + + if is_next_line_empty(p.source_text, stmt.span()) { + parts.push(hardline!()); + } + } } + parts } diff --git a/tasks/prettier_conformance/prettier.snap.md b/tasks/prettier_conformance/prettier.snap.md index 6d9dec881..97433ee7f 100644 --- a/tasks/prettier_conformance/prettier.snap.md +++ b/tasks/prettier_conformance/prettier.snap.md @@ -1,4 +1,4 @@ -Compatibility: 11/173 (6.36%) +Compatibility: 12/173 (6.94%) # Failed @@ -85,7 +85,6 @@ Compatibility: 11/173 (6.36%) * import-meta * import-reflection * in -* invalid-code * label * last-argument-expansion * line-suffix-boundary