From 642484e2cbcf971daf40fe0fea964cec01ad5bc7 Mon Sep 17 00:00:00 2001 From: Boshen Date: Sat, 10 Feb 2024 17:31:09 +0800 Subject: [PATCH] feat(prettier): print newlines between array expression elements (#2379) --- crates/oxc_ast/src/ast/js.rs | 6 ++++ crates/oxc_prettier/src/format/array.rs | 33 +++++++++++++++++---- crates/oxc_prettier/src/lib.rs | 8 ++++- tasks/prettier_conformance/prettier.snap.md | 3 +- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 21cc87440..28ee8cffa 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -392,6 +392,12 @@ pub enum ArrayExpressionElement<'a> { Elision(Span), } +impl<'a> ArrayExpressionElement<'a> { + pub fn is_elision(&self) -> bool { + matches!(self, Self::Elision(_)) + } +} + /// Object Expression #[derive(Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type"))] diff --git a/crates/oxc_prettier/src/format/array.rs b/crates/oxc_prettier/src/format/array.rs index fd7013875..0bcd35788 100644 --- a/crates/oxc_prettier/src/format/array.rs +++ b/crates/oxc_prettier/src/format/array.rs @@ -36,6 +36,7 @@ impl<'a, 'b> Array<'a, 'b> { Self::ArrayAssignmentTarget(array) => array.span, } } + fn is_concisely_printed(&self) -> bool { match self { Self::ArrayExpression(array) => { @@ -65,7 +66,7 @@ impl<'a, 'b> Array<'a, 'b> { } } -pub(super) fn print_array<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> { +pub fn print_array<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> { if array.len() == 0 { return print_empty_array_elements(p, array); } @@ -131,12 +132,15 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> { match array { Array::ArrayExpression(array) => { for (i, element) in array.elements.iter().enumerate() { - if i > 0 && i < array.elements.len() { + parts.push(element.format(p)); + let is_last = i == array.elements.len() - 1; + if !is_last { parts.push(ss!(",")); parts.push(line!()); + if !element.is_elision() && is_line_after_element_empty(p, element.span().end) { + parts.push(softline!()); + } } - - parts.push(element.format(p)); } } Array::TSTupleType(tuple) => { @@ -212,7 +216,7 @@ where parts.push(part); if !is_last { - if p.is_next_line_empty_after_index(element.span().end) { + if is_line_after_element_empty(p, element.span().end) { let mut space_parts = p.vec(); space_parts.extend(hardline!()); space_parts.extend(hardline!()); @@ -295,3 +299,22 @@ fn should_break(array: &Array) -> bool { Array::ArrayAssignmentTarget(array) => false, } } + +fn skip_comment(p: &Prettier<'_>, idx: u32) -> Option { + p.skip_inline_comment(p.skip_trailing_comment(Some(idx))) +} + +#[allow(clippy::cast_possible_truncation)] +fn skip_to_comma(p: &Prettier<'_>, current_idx: Option) -> Option { + let current_idx = current_idx?; + match p.source_text[current_idx as usize..].chars().next() { + Some(',') => Some(current_idx), + Some(c) => skip_to_comma(p, skip_comment(p, current_idx + c.len_utf8() as u32)), + None => None, + } +} + +fn is_line_after_element_empty(p: &Prettier<'_>, index: u32) -> bool { + let Some(start_index) = skip_to_comma(p, Some(index)) else { return false }; + p.is_next_line_empty_after_index(start_index) +} diff --git a/crates/oxc_prettier/src/lib.rs b/crates/oxc_prettier/src/lib.rs index a68ecd83f..c983a5f78 100644 --- a/crates/oxc_prettier/src/lib.rs +++ b/crates/oxc_prettier/src/lib.rs @@ -160,7 +160,7 @@ impl<'a> Prettier<'a> { while idx != old_idx { old_idx = idx; idx = self.skip_to_line_end(idx); - // idx = self.skip_inline_comment(idx); + idx = self.skip_inline_comment(idx); idx = self.skip_spaces(idx, /* backwards */ false); } idx = self.skip_trailing_comment(idx); @@ -182,6 +182,12 @@ impl<'a> Prettier<'a> { self.skip_everything_but_new_line(Some(start_index), /* backwards */ false) } + #[allow(clippy::unused_self)] + fn skip_inline_comment(&self, start_index: Option) -> Option { + let start_index = start_index?; + Some(start_index) + } + fn skip_to_line_end(&self, start_index: Option) -> Option { self.skip(start_index, false, |c| matches!(c, ' ' | '\t' | ',' | ';')) } diff --git a/tasks/prettier_conformance/prettier.snap.md b/tasks/prettier_conformance/prettier.snap.md index 7824c86a8..db2e95042 100644 --- a/tasks/prettier_conformance/prettier.snap.md +++ b/tasks/prettier_conformance/prettier.snap.md @@ -1,11 +1,10 @@ -Compatibility: 237/562 (42.17%) +Compatibility: 238/562 (42.35%) # Failed ### arrays * arrays/numbers-negative-comment-after-minus.js * arrays/numbers-negative.js -* arrays/numbers-with-holes.js * arrays/numbers-with-trailing-comments.js * arrays/numbers-with-tricky-comments.js * arrays/numbers2.js