diff --git a/crates/oxc_prettier/src/format/mod.rs b/crates/oxc_prettier/src/format/mod.rs index d57aa9a93..c4f22cf7d 100644 --- a/crates/oxc_prettier/src/format/mod.rs +++ b/crates/oxc_prettier/src/format/mod.rs @@ -876,6 +876,9 @@ impl<'a> Format<'a> for ImportDeclaration<'a> { } parts.push(ss!(" from ")); parts.push(self.source.format(p)); + if p.options.semi { + parts.push(ss!(";")); + } Doc::Array(parts) } } @@ -895,7 +898,7 @@ impl<'a> Format<'a> for ImportSpecifier { if self.imported.span() == self.local.span { self.local.format(p) } else { - array![p, self.imported.format(p), ss!("as"), self.local.format(p)] + array![p, self.imported.format(p), ss!(" as "), self.local.format(p)] } } } @@ -927,7 +930,6 @@ impl<'a> Format<'a> for ImportAttribute { impl<'a> Format<'a> for ExportNamedDeclaration<'a> { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { let mut parts = p.vec(); - parts.push(ss!(" ")); parts.push(module::print_module_specifiers(p, &self.specifiers)); if let Some(decl) = &self.declaration { parts.push(decl.format(p)); @@ -950,7 +952,11 @@ impl<'a> Format<'a> for TSNamespaceExportDeclaration { impl<'a> Format<'a> for ExportSpecifier { fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> { - Doc::Line + if self.exported.span() == self.local.span() { + self.local.format(p) + } else { + array![p, self.local.format(p), ss!(" as "), self.exported.format(p)] + } } } diff --git a/crates/oxc_prettier/src/format/module.rs b/crates/oxc_prettier/src/format/module.rs index dab5298fb..6b1816021 100644 --- a/crates/oxc_prettier/src/format/module.rs +++ b/crates/oxc_prettier/src/format/module.rs @@ -2,7 +2,10 @@ use oxc_allocator::Vec; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; -use crate::{doc::Doc, ss, Format, Prettier}; +use crate::{ + doc::{Doc, Separator}, + group, if_break, indent, line, softline, ss, Format, Prettier, +}; pub(super) fn print_export_declaration<'a>( p: &mut Prettier<'a>, @@ -54,7 +57,8 @@ fn print_semicolon_after_export_declaration<'a>( | ExportDefaultDeclarationKind::TSInterfaceDeclaration(_) | ExportDefaultDeclarationKind::TSEnumDeclaration(_) => None, }, - ModuleDeclaration::ExportAllDeclaration(_) => Some(ss!(";")), + ModuleDeclaration::ExportAllDeclaration(_) + | ModuleDeclaration::ExportNamedDeclaration(_) => Some(ss!(";")), _ => None, } } @@ -64,19 +68,39 @@ pub fn print_module_specifiers<'a, T: Format<'a>>( specifiers: &Vec<'a, T>, ) -> Doc<'a> { let mut parts = p.vec(); - parts.push(ss!("{")); - - if !specifiers.is_empty() { + if specifiers.is_empty() { + parts.push(ss!("{}")); + } else { parts.push(ss!(" ")); - for (i, specifier) in specifiers.iter().enumerate() { - if i != 0 { - parts.push(ss!(", ")); + let can_break = specifiers.len() > 1; + + if can_break { + let docs = specifiers.iter().map(|s| s.format(p)).collect::>(); + parts.push(group![ + p, + ss!("{"), + indent![ + p, + if p.options.bracket_spacing { line!() } else { softline!() }, + Doc::Array(p.join(Separator::CommaLine, docs)) + ], + if_break!(p, if p.should_print_es5_comma() { "," } else { "" }), + if p.options.bracket_spacing { line!() } else { softline!() }, + ss!("}") + ]); + } else { + parts.push(ss!("{")); + if p.options.bracket_spacing { + parts.push(ss!(" ")); } - parts.push(specifier.format(p)); + parts.extend(specifiers.iter().map(|s| s.format(p))); + if p.options.bracket_spacing { + parts.push(ss!(" ")); + } + parts.push(ss!("}")); } } - parts.push(ss!("}")); Doc::Array(parts) } diff --git a/crates/oxc_prettier/src/lib.rs b/crates/oxc_prettier/src/lib.rs index cdd1045d6..7cb4f875d 100644 --- a/crates/oxc_prettier/src/lib.rs +++ b/crates/oxc_prettier/src/lib.rs @@ -49,4 +49,18 @@ impl<'a> Prettier<'a> { pub fn doc(mut self, program: &Program<'a>) -> Doc<'a> { program.format(&mut self) } + + pub(crate) fn should_print_es5_comma(&self) -> bool { + self.should_print_comma_impl(false) + } + + #[allow(unused)] + pub(crate) fn should_print_all_comma(&self) -> bool { + self.should_print_comma_impl(true) + } + + pub(crate) fn should_print_comma_impl(&self, level_all: bool) -> bool { + let trailing_comma = self.options.trailing_comma; + trailing_comma.is_all() || (trailing_comma.is_es5() && !level_all) + } } diff --git a/crates/oxc_prettier/src/options.rs b/crates/oxc_prettier/src/options.rs index 8f16b75a2..1e8066d49 100644 --- a/crates/oxc_prettier/src/options.rs +++ b/crates/oxc_prettier/src/options.rs @@ -124,7 +124,7 @@ pub enum QuoteProps { Preserve, } -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] pub enum TrailingComma { /// Trailing commas wherever possible (including function parameters and calls). #[default] @@ -135,6 +135,20 @@ pub enum TrailingComma { None, } +impl TrailingComma { + pub fn is_all(self) -> bool { + self == Self::All + } + + pub fn is_es5(self) -> bool { + self == Self::ES5 + } + + pub fn is_none(self) -> bool { + self == Self::None + } +} + impl FromStr for TrailingComma { type Err = (); diff --git a/tasks/prettier_conformance/prettier.snap.md b/tasks/prettier_conformance/prettier.snap.md index 9573b3494..3029d2462 100644 --- a/tasks/prettier_conformance/prettier.snap.md +++ b/tasks/prettier_conformance/prettier.snap.md @@ -1,4 +1,4 @@ -Compatibility: 92/881 (10.44%) +Compatibility: 98/881 (11.12%) # Failed @@ -128,7 +128,6 @@ Compatibility: 92/881 (10.44%) * babel-plugins/jsx.js * babel-plugins/logical-assignment-operators.js * babel-plugins/module-blocks.js -* babel-plugins/module-string-names.js * babel-plugins/nullish-coalescing-operator.js * babel-plugins/numeric-separator.js * babel-plugins/object-rest-spread.js @@ -491,8 +490,6 @@ Compatibility: 92/881 (10.44%) * export/bracket.js * export/empty.js * export/same-local-and-exported.js -* export/test.js -* export/undefined.js ### export-default * export-default/binary_and_template.js @@ -593,7 +590,6 @@ Compatibility: 92/881 (10.44%) * ignore/semi/directive.js ### import -* import/brackets.js * import/comments.js * import/empty-import.js * import/inline.js @@ -706,10 +702,6 @@ Compatibility: 92/881 (10.44%) * module-blocks/range.js * module-blocks/worker.js -### module-string-names -* module-string-names/module-string-names-export.js -* module-string-names/module-string-names-import.js - ### multiparser-comments * multiparser-comments/comment-inside.js * multiparser-comments/comments.js