refactor(prettier): align line with prettier (#1559)

This PR alines all the line types with prettier

```
const hardlineWithoutBreakParent = { type: DOC_TYPE_LINE, hard: true };
const literallineWithoutBreakParent = {
  type: DOC_TYPE_LINE,
  hard: true,
  literal: true,
};


const line = { type: DOC_TYPE_LINE };
const softline = { type: DOC_TYPE_LINE, soft: true };
const hardline = [hardlineWithoutBreakParent, breakParent];
const literalline = [literallineWithoutBreakParent, breakParent];
```

101598f94f/src/document/builders.js (L165-L175)
This commit is contained in:
Boshen 2023-11-27 23:11:53 +08:00 committed by GitHub
parent 21dffec8be
commit 7d9d04c569
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 297 additions and 229 deletions

View file

@ -4,7 +4,7 @@ use oxc_span::Span;
use crate::{
array,
doc::{Doc, DocBuilder, Separator},
hardline, indent, line, ss, Prettier,
hardline, line, ss, Prettier,
};
use super::{Comment, CommentFlags, DanglingCommentsPrintOptions};
@ -60,18 +60,17 @@ impl<'a> Prettier<'a> {
parts.push(printed);
if comment.is_block {
let line_break = if self.has_newline(comment.end, /* backwards */ false) {
if self.has_newline(comment.end, /* backwards */ false) {
if self.has_newline(comment.start, /* backwards */ true) {
hardline!()
parts.extend(hardline!());
} else {
line!()
parts.push(line!());
}
} else {
ss!(" ")
parts.push(ss!(" "));
};
parts.push(line_break);
} else {
parts.push(hardline!());
parts.extend(hardline!());
}
if self
@ -79,7 +78,7 @@ impl<'a> Prettier<'a> {
.and_then(|idx| self.skip_newline(Some(idx), false))
.is_some_and(|i| self.has_newline(i, /* backwards */ false))
{
parts.push(hardline!());
parts.extend(hardline!());
}
}
@ -122,9 +121,9 @@ impl<'a> Prettier<'a> {
parts.push(printed);
let suffix = {
let mut parts = self.vec();
parts.push(hardline!());
parts.extend(hardline!());
if self.is_previous_line_empty(comment.start) {
parts.push(hardline!());
parts.extend(hardline!());
}
parts
};
@ -185,7 +184,12 @@ impl<'a> Prettier<'a> {
}
(!parts.is_empty()).then(|| Doc::Array(self.join(Separator::Hardline, parts))).map(|doc| {
if dangling_options.is_some_and(|options| options.ident) {
indent!(self, hardline!(), doc)
Doc::Indent({
let mut parts = self.vec();
parts.extend(hardline!());
parts.push(doc);
parts
})
} else {
doc
}

View file

@ -25,13 +25,7 @@ pub enum Doc<'a> {
/// Specify a line break.
/// If an expression fits on one line, the line break will be replaced with a space.
/// Line breaks always indent the next line with the current level of indentation.
Line,
/// Specify a line break.
/// The difference from line is that if the expression fits on one line, it will be replaced with nothing.
Softline,
/// Specify a line break that is **always** included in the output,
/// no matter if the expression fits on one line or not.
Hardline,
Line(Line),
/// This is used to implement trailing comments.
/// It's not practical to constantly check where the line ends to avoid accidentally printing some code at the end of a comment.
/// `lineSuffix` buffers docs passed to it and flushes them before any new line.
@ -46,6 +40,39 @@ pub enum Doc<'a> {
BreakParent,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Line {
pub hard: bool,
pub soft: bool,
pub literal: bool,
}
impl Line {
/// Specify a line break.
/// The difference from line is that if the expression fits on one line, it will be replaced with nothing.
pub fn softline() -> Self {
Self { soft: true, ..Self::default() }
}
/// Specify a line break that is **always** included in the output,
/// no matter if the expression fits on one line or not.
pub fn hardline() -> Self {
Self { hard: true, ..Self::default() }
}
pub fn literal_line() -> Self {
Self { literal: true, ..Self::default() }
}
pub fn hardline_without_break_parent() -> Self {
Self { hard: true, ..Self::default() }
}
pub fn literal_line_without_break_parent() -> Self {
Self { hard: true, literal: true, ..Self::default() }
}
}
#[derive(Debug)]
pub struct Group<'a> {
pub contents: Vec<'a, Doc<'a>>,
@ -72,11 +99,13 @@ impl<'a> Fill<'a> {
pub fn new(docs: Vec<'a, Doc<'a>>) -> Self {
Self { parts: docs }
}
pub fn drain_out_pair(&mut self) -> (Option<Doc<'a>>, Option<Doc<'a>>) {
let content = if self.parts.len() > 0 { Some(self.parts.remove(0)) } else { None };
let whitespace = if self.parts.len() > 0 { Some(self.parts.remove(0)) } else { None };
(content, whitespace)
}
pub fn dequeue(&mut self) -> Option<Doc<'a>> {
if self.parts.len() > 0 {
Some(self.parts.remove(0))
@ -87,9 +116,11 @@ impl<'a> Fill<'a> {
pub fn enqueue(&mut self, doc: Doc<'a>) {
self.parts.insert(0, doc);
}
pub fn parts(&self) -> &[Doc<'a>] {
&self.parts
}
pub fn take_parts(self) -> Vec<'a, Doc<'a>> {
self.parts
}
@ -134,8 +165,8 @@ pub trait DocBuilder<'a> {
for (i, doc) in docs.into_iter().enumerate() {
if i != 0 {
parts.push(match separator {
Separator::Softline => Doc::Softline,
Separator::Hardline => Doc::Hardline,
Separator::Softline => Doc::Line(Line::softline()),
Separator::Hardline => Doc::Line(Line::hardline()),
Separator::CommaLine => array![self, ss!(","), line!()],
});
}
@ -207,14 +238,14 @@ fn print_doc_to_debug(doc: &Doc<'_>) -> std::string::String {
}
string.push_str(" })");
}
Doc::Line => {
string.push_str("line");
}
Doc::Softline => {
string.push_str("softline");
}
Doc::Hardline => {
string.push_str("hardline");
Doc::Line(Line { soft, hard, .. }) => {
if *soft {
string.push_str("softline");
} else if *hard {
string.push_str("hardline");
} else {
string.push_str("line");
}
}
Doc::IfBreak(if_break) => {
string.push_str(&format!(

View file

@ -6,7 +6,7 @@ use crate::{
array,
comments::DanglingCommentsPrintOptions,
doc::{Doc, DocBuilder, Fill, Group},
group, if_break, indent, softline, ss, Prettier,
group, if_break, indent, line, softline, ss, Prettier,
};
use super::Format;
@ -129,7 +129,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
for (i, element) in array.elements.iter().enumerate() {
if i > 0 && i < array.elements.len() {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
}
parts.push(element.format(p));
@ -139,7 +139,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
for (i, element) in tuple.element_types.iter().enumerate() {
if i > 0 && i < tuple.element_types.len() {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
}
parts.push(element.format(p));
@ -149,7 +149,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
for (i, element) in array_pat.elements.iter().enumerate() {
if i > 0 && i < array_pat.elements.len() {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
}
if let Some(binding_pat) = element {
@ -159,7 +159,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
if let Some(rest) = &array_pat.rest {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
parts.push(rest.format(p));
}
}
@ -167,7 +167,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
for (i, element) in array_pat.elements.iter().enumerate() {
if i > 0 && i < array_pat.elements.len() {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
}
if let Some(binding_pat) = element {
@ -177,7 +177,7 @@ fn print_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {
if let Some(rest) = &array_pat.rest {
parts.push(ss!(","));
parts.push(Doc::Line);
parts.push(line!());
parts.push(rest.format(p));
}
}
@ -207,7 +207,7 @@ where
parts.push(part);
if !is_last {
parts.push(Doc::Line);
parts.push(line!());
}
}
}

View file

@ -9,7 +9,7 @@ use oxc_ast::{
use crate::{
array,
doc::{Doc, DocBuilder},
group, indent, ss, Format, Prettier,
group, indent, line, ss, Format, Prettier,
};
pub(super) fn print_assignment_expression<'a>(
@ -60,7 +60,7 @@ fn print_assignment<'a>(
match layout {
Layout::BreakAfterOperator => {
group!(p, group!(p, left_doc), op, group!(p, indent!(p, Doc::Line, right_doc)))
group!(p, group!(p, left_doc), op, group!(p, indent!(p, line!(), right_doc)))
}
Layout::NeverBreakAfterOperator => {
group!(p, group!(p, left_doc), op, ss!(" "), group!(p, right_doc))
@ -71,7 +71,7 @@ fn print_assignment<'a>(
p,
group!(p, left_doc),
op,
group!(p, indent!(p, Doc::Line)),
group!(p, indent!(p, line!())),
// TODO: wrap `right_doc` in indent_if_break!() when we have support for group IDs.
right_doc
)
@ -82,10 +82,10 @@ fn print_assignment<'a>(
// Parts of assignment chains aren't wrapped in groups.
// Once one of them breaks, the chain breaks too.
Layout::Chain => {
array!(p, group!(p, left_doc), op, Doc::Line, right_doc)
array!(p, group!(p, left_doc), op, line!(), right_doc)
}
Layout::ChainTail => {
array!(p, group!(p, left_doc), op, indent!(p, Doc::Line, right_doc))
array!(p, group!(p, left_doc), op, indent!(p, line!(), right_doc))
}
Layout::ChainTailArrowChain => {
array!(p, group!(p, left_doc), op, right_doc)

View file

@ -3,7 +3,7 @@ use oxc_syntax::operator::{BinaryOperator, LogicalOperator};
use crate::{
doc::{Doc, DocBuilder, Group},
group, ss, Format, Prettier,
group, line, ss, Format, Prettier,
};
pub enum BinaryishLeft<'a, 'b> {
@ -77,11 +77,11 @@ pub(super) fn print_binaryish_expression<'a>(
parts.push(ss!(" "));
if operator.is_binary() {
parts.push(group!(p, ss!(operator.as_str()), Doc::Line, right.format(p)));
parts.push(group!(p, ss!(operator.as_str()), line!(), right.format(p)));
Doc::Group(Group::new(parts, false))
} else {
parts.push(ss!(operator.as_str()));
parts.push(Doc::Line);
parts.push(line!());
parts.push(right.format(p));
Doc::Array(parts)
}

View file

@ -3,7 +3,7 @@ use oxc_ast::{ast::*, AstKind};
use super::{statement, Format};
use crate::{
doc::{Doc, DocBuilder},
hardline, indent, ss, Prettier,
hardline, ss, Prettier,
};
pub(super) fn print_block<'a>(
@ -14,8 +14,13 @@ pub(super) fn print_block<'a>(
let mut parts = p.vec();
parts.push(ss!("{"));
if let Some(doc) = print_block_body(p, stmts, directives, true, false) {
parts.push(indent![p, hardline!(), doc]);
parts.push(hardline!());
parts.push({
let mut parts = p.vec();
parts.extend(hardline!());
parts.push(doc);
Doc::Indent(parts)
});
parts.extend(hardline!());
} else {
let parent = p.parent_kind();
let parent_parent = p.parent_parent_kind();
@ -35,7 +40,7 @@ pub(super) fn print_block<'a>(
&& !matches!(p.parent_parent_kind(), Some(AstKind::TryStatement(stmt)) if stmt.finalizer.is_some()))
|| matches!(p.current_kind(), AstKind::StaticBlock(_)))
{
parts.push(hardline!());
parts.extend(hardline!());
}
}
parts.push(ss!("}"));
@ -69,7 +74,7 @@ pub(super) fn print_block_body<'a>(
}
if is_root {
parts.push(hardline!());
parts.extend(hardline!());
}
Some(Doc::Array(parts))

View file

@ -5,7 +5,7 @@ use oxc_span::{GetSpan, Span};
use crate::{
doc::{Doc, DocBuilder, Group},
if_break, ss, Format, Prettier,
if_break, line, softline, ss, Format, Prettier,
};
pub(super) enum CallExpressionLike<'a, 'b> {
@ -94,14 +94,14 @@ fn print_call_expression_arguments<'a>(
if i < arguments.len() - 1 {
parts_inner.push(ss!(","));
parts_inner.push(Doc::Line);
parts_inner.push(line!());
}
}
if should_break {
parts_inner.insert(0, Doc::Softline);
parts_inner.insert(0, softline!());
parts.push(Doc::Indent(parts_inner));
parts.push(if_break!(p, ",", "", None));
parts.push(Doc::Softline);
parts.push(softline!());
} else {
parts.extend(parts_inner);
}

View file

@ -3,7 +3,7 @@ use oxc_ast::ast::*;
use crate::{
array,
doc::{Doc, DocBuilder},
hardline, indent, ss, Format, Prettier,
hardline, ss, Format, Prettier,
};
pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> {
@ -34,7 +34,14 @@ pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody<
let mut parts = p.vec();
parts.push(ss!("{"));
if !inner_parts.is_empty() {
parts.push(array![p, indent!(p, hardline!(), Doc::Array(inner_parts)), hardline!()]);
let indent = {
let mut parts = p.vec();
parts.extend(hardline!());
parts.push(Doc::Array(inner_parts));
Doc::Indent(parts)
};
parts.push(array![p, indent]);
parts.extend(hardline!());
}
parts.push(ss!("}"));

View file

@ -1,7 +1,7 @@
use oxc_ast::{ast::*, AstKind};
use oxc_span::Span;
use crate::{array, doc::Doc, indent, ss, Prettier};
use crate::{array, doc::Doc, indent, line, ss, Prettier};
pub(super) fn adjust_clause<'a>(
p: &Prettier<'a>,
@ -17,7 +17,7 @@ pub(super) fn adjust_clause<'a>(
return array![p, ss!(" "), clause];
}
indent![p, Doc::Line, clause]
indent![p, line!(), clause]
}
pub(super) fn has_new_line_in_range(text: &str, start: u32, end: u32) -> bool {

View file

@ -62,7 +62,7 @@ impl<'a> Format<'a> for Program<'a> {
if let Some(hashbang) = &self.hashbang {
parts.push(hashbang.format(p));
if p.is_next_line_empty(hashbang.span.end - 1) {
parts.push(hardline!());
parts.extend(hardline!());
}
}
if let Some(doc) = block::print_block_body(
@ -94,7 +94,7 @@ impl<'a> Format<'a> for Directive {
if p.options.semi {
parts.push(ss!(";"));
}
parts.push(hardline!());
parts.extend(hardline!());
Doc::Array(parts)
}
}
@ -165,7 +165,11 @@ impl<'a> Format<'a> for IfStatement<'a> {
if let Some(alternate) = &self.alternate {
let else_on_same_line = matches!(alternate, Statement::BlockStatement(_));
parts.push(if else_on_same_line { ss!(" ") } else { hardline!() });
if else_on_same_line {
parts.push(ss!(" "));
} else {
parts.extend(hardline!());
}
parts.push(ss!("else"));
let alternate_doc = format!(p, alternate);
parts.push(group!(
@ -349,7 +353,7 @@ impl<'a> Format<'a> for DoWhileStatement<'a> {
if matches!(self.body, Statement::BlockStatement(_)) {
parts.push(ss!(" "));
} else {
parts.push(hardline!());
parts.extend(hardline!());
}
parts.push(ss!("while ("));
@ -417,14 +421,19 @@ impl<'a> Format<'a> for SwitchStatement<'a> {
let mut cases_parts = p.vec();
let len = self.cases.len();
for (i, case) in self.cases.iter().enumerate() {
cases_parts.push(indent!(p, hardline!(), format!(p, case)));
cases_parts.push({
let mut parts = p.vec();
parts.extend(hardline!());
parts.push(format!(p, case));
Doc::Indent(parts)
});
if i != len - 1 && p.is_next_line_empty(case.span.end) {
cases_parts.push(hardline!());
cases_parts.extend(hardline!());
}
}
parts.extend(cases_parts);
parts.push(hardline!());
parts.extend(hardline!());
parts.push(ss!("}"));
Doc::Array(parts)
@ -459,11 +468,15 @@ impl<'a> Format<'a> for SwitchCase<'a> {
if i != 0 && matches!(stmt, Statement::BreakStatement(_)) {
let last_stmt = &consequent[i - 1];
if p.is_next_line_empty(last_stmt.span().end) {
consequent_parts.push(hardline!());
consequent_parts.extend(hardline!());
}
}
consequent_parts.push(if is_only_one_block_statement { ss!(" ") } else { hardline!() });
if is_only_one_block_statement {
consequent_parts.push(ss!(" "));
} else {
consequent_parts.extend(hardline!());
}
consequent_parts.push(format!(p, stmt));
}
@ -618,7 +631,11 @@ impl<'a> Format<'a> for VariableDeclaration<'a> {
let mut d_parts = p.vec();
if i != 0 {
d_parts.push(p.str(","));
d_parts.push(if is_hardline { hardline!() } else { line!() });
if is_hardline {
d_parts.extend(hardline!());
} else {
d_parts.push(line!());
}
}
d_parts.push(decl.format(p));
Doc::Indent(d_parts)
@ -638,7 +655,7 @@ impl<'a> Format<'a> for VariableDeclaration<'a> {
impl<'a> Format<'a> for UsingDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -780,31 +797,31 @@ impl<'a> Format<'a> for TSVoidKeyword {
impl<'a> Format<'a> for TSArrayType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSConditionalType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSConstructorType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSFunctionType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSImportType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -827,7 +844,7 @@ impl<'a> Format<'a> for TSInferType<'a> {
impl<'a> Format<'a> for TSIntersectionType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -848,13 +865,13 @@ impl<'a> Format<'a> for TSLiteralType<'a> {
impl<'a> Format<'a> for TSMappedType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSQualifiedName<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -875,97 +892,97 @@ impl<'a> Format<'a> for TSTupleType<'a> {
impl<'a> Format<'a> for TSTypeLiteral<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeOperatorType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypePredicate<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeQuery<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeReference<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSUnionType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSDocNullableType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSDocUnknownType {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSInterfaceDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSEnumDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSModuleDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSImportEqualsDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeParameter<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeParameterDeclaration<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTypeParameterInstantiation<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSTupleElement<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -1065,13 +1082,13 @@ impl<'a> Format<'a> for ImportNamespaceSpecifier {
impl<'a> Format<'a> for Option<Vec<'a, ImportAttribute>> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for ImportAttribute {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -1093,13 +1110,13 @@ impl<'a> Format<'a> for ExportNamedDeclaration<'a> {
impl<'a> Format<'a> for TSExportAssignment<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSNamespaceExportDeclaration {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -1754,7 +1771,7 @@ impl<'a> Format<'a> for ImportExpression<'a> {
if !self.arguments.is_empty() {
for arg in &self.arguments {
indent_parts.push(ss!(","));
indent_parts.push(Doc::Line);
indent_parts.push(line!());
indent_parts.push(format!(p, arg));
}
}
@ -1877,133 +1894,133 @@ impl<'a> Format<'a> for ClassElement<'a> {
impl<'a> Format<'a> for JSXIdentifier {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXMemberExpressionObject<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXMemberExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXElementName<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXNamespacedName {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXAttributeName<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXAttribute<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXEmptyExpression {
fn format(&self, _: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXExpressionContainer<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXAttributeValue<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXSpreadAttribute<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXAttributeItem<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXOpeningElement<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXClosingElement<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXElement<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXOpeningFragment {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXClosingFragment {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXText {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXSpreadChild<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXChild<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for JSXFragment<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -2023,13 +2040,13 @@ impl<'a> Format<'a> for MethodDefinition<'a> {
impl<'a> Format<'a> for PropertyDefinition<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for AccessorProperty<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
@ -2120,18 +2137,18 @@ impl<'a> Format<'a> for RegExpFlags {
impl<'a> Format<'a> for TSAbstractMethodDefinition<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSAbstractPropertyDefinition<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}
impl<'a> Format<'a> for TSIndexSignature<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
Doc::Line
line!()
}
}

View file

@ -52,7 +52,7 @@ pub(super) fn print_object_properties<'a, F: Format<'a> + GetSpan>(
indent_parts.push(prop.format(p));
if i < properties.len() - 1 {
indent_parts.push(Doc::Str(","));
indent_parts.push(Doc::Line);
indent_parts.push(line!());
}
}
@ -60,9 +60,9 @@ pub(super) fn print_object_properties<'a, F: Format<'a> + GetSpan>(
parts.push(if_break!(p, ",", "", None));
if p.options.bracket_spacing {
parts.push(Doc::Line);
parts.push(line!());
} else {
parts.push(Doc::Softline);
parts.push(softline!());
}
parts.push(ss!("}"));

View file

@ -2,7 +2,7 @@ use oxc_allocator::Vec;
use oxc_ast::ast::Statement;
use crate::{
doc::{Doc, DocBuilder, Group},
doc::{Doc, DocBuilder, Group, Line},
hardline, Prettier,
};
use oxc_span::GetSpan;
@ -31,7 +31,9 @@ pub(super) fn print_statement_sequence<'a>(
if remove_last_statement_hardline && i == len - 1 {
match docs {
Doc::Array(ref mut docs) | Doc::Group(Group { contents: ref mut docs, .. }) => {
if matches!(docs.last(), Some(Doc::Hardline)) {
if docs.last().is_some_and(
|doc| matches!(doc, Doc::Line(line) if *line == Line::hardline()),
) {
docs.pop();
}
}
@ -42,10 +44,10 @@ pub(super) fn print_statement_sequence<'a>(
parts.push(docs);
if i < len - 1 {
parts.push(hardline!());
parts.extend(hardline!());
if p.is_next_line_empty(stmt.span().end) {
parts.push(hardline!());
parts.extend(hardline!());
}
}
}

View file

@ -1,6 +1,6 @@
use oxc_ast::ast::*;
use crate::{doc::Doc, group, indent, ss, Format, Prettier};
use crate::{doc::Doc, group, indent, line, ss, Format, Prettier};
pub(super) fn print_ternary<'a>(p: &mut Prettier<'a>, expr: &ConditionalExpression<'a>) -> Doc<'a> {
group![
@ -8,10 +8,10 @@ pub(super) fn print_ternary<'a>(p: &mut Prettier<'a>, expr: &ConditionalExpressi
expr.test.format(p),
indent!(
p,
Doc::Line,
line!(),
ss!("? "),
expr.consequent.format(p),
Doc::Line,
line!(),
ss!(": "),
expr.alternate.format(p)
)

View file

@ -52,21 +52,21 @@ macro_rules! indent_if_break {
#[macro_export]
macro_rules! line {
() => {
Doc::Line
Doc::Line($crate::doc::Line::default())
};
}
#[macro_export]
macro_rules! softline {
() => {
Doc::Softline
Doc::Line($crate::doc::Line::softline())
};
}
#[macro_export]
macro_rules! hardline {
() => {
Doc::Hardline
[Doc::Line($crate::doc::Line::hardline()), Doc::BreakParent]
};
}

View file

@ -16,7 +16,7 @@ impl<'a> Command<'a> {
}
}
#[derive(Clone, Debug, Copy, Eq, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Break,
Flat,
@ -24,17 +24,26 @@ pub enum Mode {
impl Mode {
pub fn is_break(self) -> bool {
matches!(self, Self::Break)
self == Self::Break
}
pub fn is_flat(self) -> bool {
self == Self::Flat
}
}
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct Indent {
pub root: bool,
pub length: usize,
}
impl Indent {
pub fn root() -> Self {
Self { length: 0 }
Self { root: true, length: 0 }
}
pub fn new(length: usize) -> Self {
Self { root: false, length }
}
}

View file

@ -9,7 +9,7 @@ use oxc_allocator::Allocator;
use std::collections::{HashMap, VecDeque};
use crate::{
doc::{Doc, DocBuilder, Fill, IfBreak},
doc::{Doc, DocBuilder, Fill, IfBreak, Line},
GroupId, PrettierOptions,
};
@ -71,27 +71,6 @@ impl<'a> Printer<'a> {
unsafe { String::from_utf8_unchecked(self.out) }
}
/// Reference:
/// * https://github.com/prettier/prettier/blob/main/src/document/utils.js#L156-L185
pub fn propagate_breaks(doc: &mut Doc<'_>) -> bool {
match doc {
Doc::Hardline => true,
Doc::Group(group) => {
let should_break =
group.contents.iter_mut().rev().any(|doc| Self::propagate_breaks(doc));
if should_break {
group.should_break = should_break;
}
group.should_break
}
Doc::IfBreak(d) => Self::propagate_breaks(&mut d.break_contents),
Doc::Array(arr) | Doc::Indent(arr) | Doc::IndentIfBreak(arr) => {
arr.iter_mut().any(|doc| Self::propagate_breaks(doc))
}
_ => false,
}
}
/// Turn Doc into a string
///
/// Reference:
@ -105,13 +84,11 @@ impl<'a> Printer<'a> {
Doc::Indent(docs) => self.handle_indent(indent, mode, docs),
Doc::Group(_) => self.handle_group(indent, mode, doc),
Doc::IndentIfBreak(docs) => self.handle_indent_if_break(indent, mode, docs),
Doc::Line => self.handle_line(indent, mode),
Doc::Softline => self.handle_softline(indent, mode),
Doc::Hardline => self.handle_line(indent, Mode::Break),
Doc::Line(line) => self.handle_line(line, indent, mode, doc),
Doc::LineSuffix(docs) => self.handle_line_suffix(indent, mode, docs),
Doc::IfBreak(if_break) => self.handle_if_break(if_break, indent, mode),
Doc::Fill(fill) => self.handle_fill(indent, mode, fill),
Doc::BreakParent => {} // No op
Doc::BreakParent => { /* No op */ }
}
if self.cmds.is_empty() && !self.line_suffix.is_empty() {
@ -120,6 +97,11 @@ impl<'a> Printer<'a> {
}
}
#[allow(clippy::cast_possible_wrap)]
fn remaining_width(&self) -> isize {
(self.options.print_width as isize) - (self.pos as isize)
}
fn handle_str(&mut self, s: &str) {
self.out.extend(s.as_bytes());
self.pos += s.len();
@ -133,7 +115,7 @@ impl<'a> Printer<'a> {
self.cmds.extend(
docs.into_iter()
.rev()
.map(|doc| Command::new(Indent { length: indent.length + 1 }, mode, doc)),
.map(|doc| Command::new(Indent::new(indent.length + 1), mode, doc)),
);
}
@ -192,39 +174,46 @@ impl<'a> Printer<'a> {
);
}
Mode::Break => {
self.cmds.extend(docs.into_iter().rev().map(|doc| {
Command::new(Indent { length: indent.length + 1 }, Mode::Break, doc)
}));
self.cmds.extend(
docs.into_iter()
.rev()
.map(|doc| Command::new(Indent::new(indent.length + 1), Mode::Break, doc)),
);
}
}
}
fn handle_line(&mut self, indent: Indent, mode: Mode) {
if mode.is_break() {
if !self.line_suffix.is_empty() {
self.cmds.extend(self.line_suffix.drain(..).rev());
fn handle_line(&mut self, line: Line, indent: Indent, mode: Mode, doc: Doc<'a>) {
if mode.is_flat() {
if line.hard {
// shouldRemeasure = true;
} else {
if !line.soft {
self.out.push(b' ');
self.pos += 1;
}
return;
}
}
self.handle_hardline(indent);
if !self.line_suffix.is_empty() {
self.cmds.push(Command::new(indent, mode, doc));
self.cmds.extend(self.line_suffix.drain(..).rev());
return;
}
if line.literal {
self.out.extend(self.new_line.as_bytes());
if !indent.root {
self.pos = 0;
}
} else {
self.out.push(b' ');
self.pos += 1;
self.trim();
self.out.extend(self.new_line.as_bytes());
self.pos = self.indent(indent.length);
}
}
fn handle_softline(&mut self, indent: Indent, mode: Mode) {
if mode.is_break() {
self.handle_line(indent, Mode::Break);
}
}
fn handle_hardline(&mut self, indent: Indent) {
self.trim();
self.out.extend(self.new_line.as_bytes());
self.pos = self.indent(indent.length);
}
fn handle_line_suffix(
&mut self,
indent: Indent,
@ -331,6 +320,27 @@ impl<'a> Printer<'a> {
};
}
fn indent(&mut self, size: usize) -> usize {
if self.options.use_tabs {
self.out.extend("\t".repeat(size).as_bytes());
size
} else {
let count = self.options.tab_width * size;
self.out.extend(" ".repeat(count).as_bytes());
count
}
}
fn trim(&mut self) {
while let Some(&last) = self.out.last() {
if last == b' ' || last == b'\t' {
self.out.pop();
} else {
break;
}
}
}
#[allow(clippy::cast_possible_wrap)]
fn fits(&self, next: &Command<'a>, width: isize) -> bool {
let mut remaining_width = width;
@ -339,7 +349,6 @@ impl<'a> Printer<'a> {
let mut cmds = self.cmds.iter().rev();
while let Some((mode, doc)) = queue.pop_front() {
let is_break = matches!(mode, Mode::Break);
match doc {
Doc::Str(string) => {
remaining_width -= string.len() as isize;
@ -369,20 +378,14 @@ impl<'a> Printer<'a> {
queue.push_front((mode, contents));
}
Doc::Line => {
if is_break {
Doc::Line(line) => {
if mode.is_break() || line.hard {
return true;
}
remaining_width -= 1_isize;
}
Doc::Softline => {
if is_break {
return true;
if !line.soft {
remaining_width -= 1_isize;
}
}
Doc::Hardline => {
return true;
}
Doc::Fill(fill) => {
for part in fill.parts().iter().rev() {
queue.push_front((mode, part));
@ -408,29 +411,24 @@ impl<'a> Printer<'a> {
true
}
fn indent(&mut self, size: usize) -> usize {
if self.options.use_tabs {
self.out.extend("\t".repeat(size).as_bytes());
size
} else {
let count = self.options.tab_width * size;
self.out.extend(" ".repeat(count).as_bytes());
count
}
}
fn trim(&mut self) {
while let Some(&last) = self.out.last() {
if last == b' ' || last == b'\t' {
self.out.pop();
} else {
break;
/// Reference:
/// * https://github.com/prettier/prettier/blob/main/src/document/utils.js#L156-L185
pub fn propagate_breaks(doc: &mut Doc<'_>) -> bool {
match doc {
Doc::BreakParent => true,
Doc::Group(group) => {
let should_break =
group.contents.iter_mut().rev().any(|doc| Self::propagate_breaks(doc));
if should_break {
group.should_break = should_break;
}
group.should_break
}
Doc::IfBreak(d) => Self::propagate_breaks(&mut d.break_contents),
Doc::Array(arr) | Doc::Indent(arr) | Doc::IndentIfBreak(arr) => {
arr.iter_mut().any(|doc| Self::propagate_breaks(doc))
}
_ => false,
}
}
#[allow(clippy::cast_possible_wrap)]
fn remaining_width(&self) -> isize {
(self.options.print_width as isize) - (self.pos as isize)
}
}

View file

@ -1,8 +1,4 @@
<<<<<<< HEAD
Compatibility: 173/591 (29.27%)
=======
Compatibility: 171/591 (28.93%)
>>>>>>> 169f7a38 (feat(prettier): add id on `IfBreak` and `Group`)
Compatibility: 177/591 (29.95%)
# Failed
@ -179,7 +175,6 @@ Compatibility: 171/591 (28.93%)
* comments/empty-statements.js
* comments/export-and-import.js
* comments/export.js
* comments/first-line.js
* comments/function-declaration.js
* comments/if.js
* comments/issue-3532.js