mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(prettier): start adding parent stack (#1415)
This commit is contained in:
parent
781cd5a21a
commit
1dacb645d0
6 changed files with 150 additions and 83 deletions
|
|
@ -56,7 +56,7 @@ impl<'a> Prettier<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn alloc(&self, doc: Doc<'a>) -> Box<'a, Doc<'a>> {
|
||||
pub(crate) fn boxed(&self, doc: Doc<'a>) -> Box<'a, Doc<'a>> {
|
||||
Box(self.allocator.alloc(doc))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_ast::{ast::*, AstKind};
|
||||
|
||||
use crate::{doc::Doc, format::array, hardline, indent, ss, Prettier};
|
||||
|
||||
|
|
@ -15,6 +15,20 @@ pub(super) fn print_block<'a>(
|
|||
if let Some(doc) = print_block_body(p, stmts, directives, true, false) {
|
||||
parts.push(indent![p, hardline!(), doc]);
|
||||
parts.push(hardline!());
|
||||
} else {
|
||||
let parent = p.parent_kind();
|
||||
if !(matches!(
|
||||
parent,
|
||||
AstKind::FunctionBody(_)
|
||||
| AstKind::ArrowExpression(_)
|
||||
| AstKind::Function(_)
|
||||
| AstKind::ForStatement(_)
|
||||
| AstKind::WhileStatement(_)
|
||||
| AstKind::DoWhileStatement(_)
|
||||
) || matches!(p.current_kind(), AstKind::StaticBlock(_)))
|
||||
{
|
||||
parts.push(hardline!());
|
||||
}
|
||||
}
|
||||
parts.push(ss!("}"));
|
||||
Doc::Array(parts)
|
||||
|
|
|
|||
|
|
@ -5,12 +5,6 @@
|
|||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_span::GetSpan;
|
||||
|
||||
mod array;
|
||||
mod arrow_function;
|
||||
mod binaryish;
|
||||
|
|
@ -25,10 +19,16 @@ mod statement;
|
|||
mod string;
|
||||
mod ternary;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast::{ast::*, AstKind};
|
||||
use oxc_span::GetSpan;
|
||||
|
||||
use crate::{
|
||||
array,
|
||||
doc::{Doc, Separator},
|
||||
format, group, hardline, indent, softline, ss, string, Prettier,
|
||||
format, group, hardline, indent, softline, ss, string, wrap, Prettier,
|
||||
};
|
||||
|
||||
use self::{
|
||||
|
|
@ -53,6 +53,7 @@ where
|
|||
|
||||
impl<'a> Format<'a> for Program<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
p.enter_node(AstKind::Program(p.alloc(self)));
|
||||
let mut parts = p.vec();
|
||||
if let Some(hashbang) = &self.hashbang {
|
||||
parts.push(hashbang.format(p));
|
||||
|
|
@ -65,6 +66,7 @@ impl<'a> Format<'a> for Program<'a> {
|
|||
{
|
||||
parts.push(doc);
|
||||
}
|
||||
p.leave_node();
|
||||
Doc::Array(parts)
|
||||
}
|
||||
}
|
||||
|
|
@ -155,42 +157,44 @@ impl<'a> Format<'a> for IfStatement<'a> {
|
|||
|
||||
impl<'a> Format<'a> for BlockStatement<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
block::print_block(p, &self.body, None)
|
||||
wrap!(p, self, BlockStatement, { block::print_block(p, &self.body, None) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Format<'a> for ForStatement<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
let mut parts = p.vec();
|
||||
wrap!(p, self, ForStatement, {
|
||||
let mut parts = p.vec();
|
||||
|
||||
parts.push(ss!("for ("));
|
||||
parts.push(ss!("for ("));
|
||||
|
||||
let mut parts_head = p.vec();
|
||||
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));
|
||||
}
|
||||
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)));
|
||||
let parts_head = indent!(p, group!(p, Doc::Array(parts_head)));
|
||||
|
||||
parts.push(group!(p, parts_head));
|
||||
parts.push(group!(p, parts_head));
|
||||
|
||||
parts.push(ss!(")"));
|
||||
parts.push(ss!(")"));
|
||||
|
||||
let body = format!(p, self.body);
|
||||
parts.push(adjust_clause(p, &self.body, body, false));
|
||||
let body = format!(p, self.body);
|
||||
parts.push(adjust_clause(p, &self.body, body, false));
|
||||
|
||||
Doc::Group(parts)
|
||||
Doc::Group(parts)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,43 +259,47 @@ impl<'a> Format<'a> for ForStatementLeft<'a> {
|
|||
|
||||
impl<'a> Format<'a> for WhileStatement<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
let mut parts = p.vec();
|
||||
wrap!(p, self, WhileStatement, {
|
||||
let mut parts = p.vec();
|
||||
|
||||
parts.push(ss!("while ("));
|
||||
parts.push(group!(p, indent!(p, softline!(), format!(p, self.test)), softline!()));
|
||||
parts.push(ss!(")"));
|
||||
parts.push(ss!("while ("));
|
||||
parts.push(group!(p, indent!(p, softline!(), format!(p, self.test)), softline!()));
|
||||
parts.push(ss!(")"));
|
||||
|
||||
let body = format!(p, self.body);
|
||||
parts.push(adjust_clause(p, &self.body, body, false));
|
||||
let body = format!(p, self.body);
|
||||
parts.push(adjust_clause(p, &self.body, body, false));
|
||||
|
||||
Doc::Group(parts)
|
||||
Doc::Group(parts)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Format<'a> for DoWhileStatement<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
let mut parts = p.vec();
|
||||
wrap!(p, self, DoWhileStatement, {
|
||||
let mut parts = p.vec();
|
||||
|
||||
let clause = format!(p, self.body);
|
||||
let clause = adjust_clause(p, &self.body, clause, false);
|
||||
let do_body = group!(p, ss!("do"), clause);
|
||||
let clause = format!(p, self.body);
|
||||
let clause = adjust_clause(p, &self.body, clause, false);
|
||||
let do_body = group!(p, ss!("do"), clause);
|
||||
|
||||
parts.push(do_body);
|
||||
parts.push(do_body);
|
||||
|
||||
if matches!(self.body, Statement::BlockStatement(_)) {
|
||||
parts.push(ss!(" "));
|
||||
} else {
|
||||
parts.push(hardline!());
|
||||
}
|
||||
if matches!(self.body, Statement::BlockStatement(_)) {
|
||||
parts.push(ss!(" "));
|
||||
} else {
|
||||
parts.push(hardline!());
|
||||
}
|
||||
|
||||
parts.push(ss!("while ("));
|
||||
parts.push(group!(p, indent!(p, softline!(), format!(p, self.test)), softline!()));
|
||||
parts.push(ss!(")"));
|
||||
if p.options.semi {
|
||||
parts.push(ss!(";"));
|
||||
}
|
||||
parts.push(ss!("while ("));
|
||||
parts.push(group!(p, indent!(p, softline!(), format!(p, self.test)), softline!()));
|
||||
parts.push(ss!(")"));
|
||||
if p.options.semi {
|
||||
parts.push(ss!(";"));
|
||||
}
|
||||
|
||||
Doc::Array(parts)
|
||||
Doc::Array(parts)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -402,6 +410,7 @@ impl<'a> Format<'a> for LabeledStatement<'a> {
|
|||
|
||||
impl<'a> Format<'a> for TryStatement<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
p.enter_node(AstKind::TryStatement(p.alloc(self)));
|
||||
let mut parts = p.vec();
|
||||
parts.push(ss!("try "));
|
||||
parts.push(format!(p, self.block));
|
||||
|
|
@ -413,6 +422,7 @@ impl<'a> Format<'a> for TryStatement<'a> {
|
|||
parts.push(ss!(" finally "));
|
||||
parts.push(format!(p, finalizer));
|
||||
}
|
||||
p.leave_node();
|
||||
Doc::Array(parts)
|
||||
}
|
||||
}
|
||||
|
|
@ -854,13 +864,15 @@ impl<'a> Format<'a> for VariableDeclarator<'a> {
|
|||
|
||||
impl<'a> Format<'a> for Function<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
function::print_function(p, self, None)
|
||||
wrap!(p, self, Function, { function::print_function(p, self, None) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Format<'a> for FunctionBody<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
block::print_block(p, &self.statements, Some(&self.directives))
|
||||
wrap!(p, self, FunctionBody, {
|
||||
block::print_block(p, &self.statements, Some(&self.directives))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1325,11 +1337,13 @@ impl<'a> Format<'a> for ObjectProperty<'a> {
|
|||
}
|
||||
if method {
|
||||
if let Expression::FunctionExpression(func_expr) = &self.value {
|
||||
parts.push(function::print_function(
|
||||
p,
|
||||
func_expr,
|
||||
Some(self.key.span().source_text(p.source_text)),
|
||||
));
|
||||
wrap!(p, func_expr, Function, {
|
||||
parts.push(function::print_function(
|
||||
p,
|
||||
func_expr,
|
||||
Some(self.key.span().source_text(p.source_text)),
|
||||
));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
parts.push(format!(p, self.key));
|
||||
|
|
@ -1367,7 +1381,7 @@ impl<'a> Format<'a> for PropertyKey<'a> {
|
|||
|
||||
impl<'a> Format<'a> for ArrowExpression<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
arrow_function::print_arrow_function(p, self)
|
||||
wrap!(p, self, ArrowExpression, { arrow_function::print_arrow_function(p, self) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1815,7 +1829,9 @@ impl<'a> Format<'a> for JSXFragment<'a> {
|
|||
|
||||
impl<'a> Format<'a> for StaticBlock<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
array![p, ss!("static "), block::print_block(p, &self.body, None)]
|
||||
wrap!(p, self, StaticBlock, {
|
||||
array![p, ss!("static "), block::print_block(p, &self.body, None)]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ mod printer;
|
|||
|
||||
use std::{iter::Peekable, vec};
|
||||
|
||||
use doc::Doc;
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::{ast::Program, CommentKind, Trivias};
|
||||
use oxc_ast::{ast::Program, AstKind, CommentKind, Trivias};
|
||||
|
||||
use crate::{doc::Doc, format::Format, printer::Printer};
|
||||
|
||||
pub use crate::options::{ArrowParens, EndOfLine, PrettierOptions, QuoteProps, TrailingComma};
|
||||
use crate::{format::Format, printer::Printer};
|
||||
|
||||
pub struct Prettier<'a> {
|
||||
allocator: &'a Allocator,
|
||||
|
|
@ -29,6 +29,10 @@ pub struct Prettier<'a> {
|
|||
|
||||
/// A stack of comments that will be carefully placed in the right places.
|
||||
trivias: Peekable<vec::IntoIter<(u32, u32, CommentKind)>>,
|
||||
|
||||
/// The stack of AST Nodes
|
||||
/// See <https://github.com/prettier/prettier/blob/main/src/common/ast-path.js>
|
||||
nodes: Vec<AstKind<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Prettier<'a> {
|
||||
|
|
@ -38,8 +42,13 @@ impl<'a> Prettier<'a> {
|
|||
trivias: Trivias,
|
||||
options: PrettierOptions,
|
||||
) -> Self {
|
||||
let trivias = trivias.into_iter().peekable();
|
||||
Self { allocator, source_text, options, trivias }
|
||||
Self {
|
||||
allocator,
|
||||
source_text,
|
||||
options,
|
||||
trivias: trivias.into_iter().peekable(),
|
||||
nodes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(mut self, program: &Program<'a>) -> String {
|
||||
|
|
@ -51,21 +60,46 @@ impl<'a> Prettier<'a> {
|
|||
program.format(&mut self)
|
||||
}
|
||||
|
||||
pub(crate) fn should_print_es5_comma(&self) -> bool {
|
||||
fn enter_node(&mut self, kind: AstKind<'a>) {
|
||||
self.nodes.push(kind);
|
||||
}
|
||||
|
||||
fn leave_node(&mut self) {
|
||||
self.nodes.pop();
|
||||
}
|
||||
|
||||
fn current_kind(&self) -> AstKind<'a> {
|
||||
self.nodes[self.nodes.len() - 1]
|
||||
}
|
||||
|
||||
fn parent_kind(&self) -> AstKind<'a> {
|
||||
self.nodes[self.nodes.len() - 2]
|
||||
}
|
||||
|
||||
/// A hack for erasing the lifetime requirement.
|
||||
#[allow(clippy::unused_self)]
|
||||
fn alloc<T>(&self, t: &T) -> &'a T {
|
||||
// SAFETY:
|
||||
// This should be safe as long as `src` is an reference from the allocator.
|
||||
// But honestly, I'm not really sure if this is safe.
|
||||
unsafe { std::mem::transmute(t) }
|
||||
}
|
||||
|
||||
fn should_print_es5_comma(&self) -> bool {
|
||||
self.should_print_comma_impl(false)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn should_print_all_comma(&self) -> bool {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
pub(crate) fn is_next_line_empty(&self, end: u32) -> bool {
|
||||
fn is_next_line_empty(&self, end: u32) -> bool {
|
||||
self.source_text[end as usize..].chars().nth(1).is_some_and(|c| c == '\n')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,16 @@ macro_rules! group {
|
|||
#[macro_export]
|
||||
macro_rules! if_break {
|
||||
($p:ident, $s:expr) => {{
|
||||
Doc::IfBreak($p.alloc(Doc::Str($s)))
|
||||
Doc::IfBreak($p.boxed(Doc::Str($s)))
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! wrap {
|
||||
($p:ident, $self:expr, $kind:ident, $block:block) => {{
|
||||
$p.enter_node(AstKind::$kind($p.alloc($self)));
|
||||
let doc = $block;
|
||||
$p.leave_node();
|
||||
doc
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Compatibility: 105/838 (12.53%)
|
||||
Compatibility: 108/838 (12.89%)
|
||||
|
||||
# Failed
|
||||
|
||||
|
|
@ -616,9 +616,6 @@ Compatibility: 105/838 (12.53%)
|
|||
### line-suffix-boundary
|
||||
* line-suffix-boundary/boundary.js
|
||||
|
||||
### logical-assignment
|
||||
* logical-assignment/logical-assignment.js
|
||||
|
||||
### logical_expressions
|
||||
* logical_expressions/issue-7024.js
|
||||
* logical_expressions/logical_expression_operators.js
|
||||
|
|
@ -658,7 +655,6 @@ Compatibility: 105/838 (12.53%)
|
|||
### module-blocks
|
||||
* module-blocks/comments.js
|
||||
* module-blocks/module-blocks.js
|
||||
* module-blocks/non-module-blocks.js
|
||||
* module-blocks/range.js
|
||||
* module-blocks/worker.js
|
||||
|
||||
|
|
@ -765,9 +761,6 @@ Compatibility: 105/838 (12.53%)
|
|||
* objects/assignment-expression/object-property.js
|
||||
* objects/assignment-expression/object-value.js
|
||||
|
||||
### optional-catch-binding
|
||||
* optional-catch-binding/optional_catch_binding.js
|
||||
|
||||
### optional-chaining
|
||||
* optional-chaining/chaining.js
|
||||
* optional-chaining/comments.js
|
||||
|
|
|
|||
Loading…
Reference in a new issue