mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(prettier) improve class printing (#1565)
This commit is contained in:
parent
2bfd28e6f5
commit
522cf29489
6 changed files with 177 additions and 19 deletions
|
|
@ -96,6 +96,7 @@ pub enum AstKind<'a> {
|
|||
FormalParameter(&'a FormalParameter<'a>),
|
||||
|
||||
Class(&'a Class<'a>),
|
||||
ClassBody(&'a ClassBody<'a>),
|
||||
ClassHeritage(&'a Expression<'a>),
|
||||
StaticBlock(&'a StaticBlock<'a>),
|
||||
PropertyDefinition(&'a PropertyDefinition<'a>),
|
||||
|
|
@ -398,6 +399,7 @@ impl<'a> GetSpan for AstKind<'a> {
|
|||
Self::FormalParameter(x) => x.span,
|
||||
|
||||
Self::Class(x) => x.span,
|
||||
Self::ClassBody(x) => x.span,
|
||||
Self::ClassHeritage(x) => x.span(),
|
||||
Self::StaticBlock(x) => x.span,
|
||||
Self::PropertyDefinition(x) => x.span,
|
||||
|
|
@ -569,6 +571,7 @@ impl<'a> AstKind<'a> {
|
|||
c.id.as_ref().map_or_else(|| "<anonymous>", |id| id.name.as_str())
|
||||
)
|
||||
.into(),
|
||||
Self::ClassBody(_) => "ClassBody".into(),
|
||||
Self::ClassHeritage(_) => "ClassHeritage".into(),
|
||||
Self::StaticBlock(_) => "StaticBlock".into(),
|
||||
Self::PropertyDefinition(_) => "PropertyDefinition".into(),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use oxc_ast::{
|
||||
ast::{
|
||||
AssignmentExpression, AssignmentTarget, AssignmentTargetPattern, AssignmentTargetProperty,
|
||||
BindingPatternKind, Expression, Statement, VariableDeclarator,
|
||||
AccessorProperty, AssignmentExpression, AssignmentTarget, AssignmentTargetPattern,
|
||||
AssignmentTargetProperty, BindingPatternKind, Expression, PropertyDefinition, Statement,
|
||||
VariableDeclarator,
|
||||
},
|
||||
AstKind,
|
||||
};
|
||||
|
|
@ -12,6 +13,8 @@ use crate::{
|
|||
group, indent, line, ss, Format, Prettier,
|
||||
};
|
||||
|
||||
use super::class::ClassMemberish;
|
||||
|
||||
pub(super) fn print_assignment_expression<'a>(
|
||||
p: &mut Prettier<'a>,
|
||||
assignment_expr: &AssignmentExpression<'a>,
|
||||
|
|
@ -41,12 +44,27 @@ pub(super) fn print_variable_declarator<'a>(
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum AssignmentLikeNode<'a, 'b> {
|
||||
pub(super) enum AssignmentLikeNode<'a, 'b> {
|
||||
AssignmentExpression(&'b AssignmentExpression<'a>),
|
||||
VariableDeclarator(&'b VariableDeclarator<'a>),
|
||||
PropertyDefinition(&'b PropertyDefinition<'a>),
|
||||
AccessorProperty(&'b AccessorProperty<'a>),
|
||||
}
|
||||
|
||||
fn print_assignment<'a>(
|
||||
impl<'a, 'b> From<ClassMemberish<'a, 'b>> for AssignmentLikeNode<'a, 'b> {
|
||||
fn from(class_memberish: ClassMemberish<'a, 'b>) -> Self {
|
||||
match class_memberish {
|
||||
ClassMemberish::PropertyDefinition(property_def) => {
|
||||
Self::PropertyDefinition(property_def)
|
||||
}
|
||||
ClassMemberish::AccessorProperty(accessor_prop) => {
|
||||
Self::AccessorProperty(accessor_prop)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn print_assignment<'a>(
|
||||
p: &mut Prettier<'a>,
|
||||
node: AssignmentLikeNode<'a, '_>,
|
||||
left_doc: Doc<'a>,
|
||||
|
|
@ -239,6 +257,7 @@ fn is_complex_destructuring(expr: &AssignmentLikeNode) -> bool {
|
|||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +277,9 @@ fn is_arrow_function_variable_declarator(expr: &AssignmentLikeNode) -> bool {
|
|||
}
|
||||
false
|
||||
}
|
||||
AssignmentLikeNode::AssignmentExpression(_) => false,
|
||||
AssignmentLikeNode::AssignmentExpression(_)
|
||||
| AssignmentLikeNode::PropertyDefinition(_)
|
||||
| AssignmentLikeNode::AccessorProperty(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ pub(super) fn print_block<'a>(
|
|||
| AstKind::ForStatement(_)
|
||||
| AstKind::WhileStatement(_)
|
||||
| AstKind::DoWhileStatement(_)
|
||||
| AstKind::MethodDefinition(_)
|
||||
| AstKind::PropertyDefinition(_)
|
||||
) || (matches!(parent, AstKind::CatchClause(_))
|
||||
&& !matches!(p.parent_parent_kind(), Some(AstKind::TryStatement(stmt)) if stmt.finalizer.is_some()))
|
||||
|| matches!(p.current_kind(), AstKind::StaticBlock(_)))
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@ use oxc_ast::ast::*;
|
|||
use crate::{
|
||||
array,
|
||||
doc::{Doc, DocBuilder},
|
||||
format::assignment,
|
||||
hardline, ss, Format, Prettier,
|
||||
};
|
||||
|
||||
use super::assignment::AssignmentLikeNode;
|
||||
|
||||
pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a> {
|
||||
let mut parts = p.vec();
|
||||
parts.push(ss!("class "));
|
||||
|
|
@ -25,25 +28,156 @@ pub(super) fn print_class<'a>(p: &mut Prettier<'a>, class: &Class<'a>) -> Doc<'a
|
|||
}
|
||||
|
||||
pub(super) fn print_class_body<'a>(p: &mut Prettier<'a>, class_body: &ClassBody<'a>) -> Doc<'a> {
|
||||
let mut inner_parts = p.vec();
|
||||
let mut parts_inner = p.vec();
|
||||
|
||||
for class_element in &class_body.body {
|
||||
inner_parts.push(class_element.format(p));
|
||||
for (i, node) in class_body.body.iter().enumerate() {
|
||||
parts_inner.push(node.format(p));
|
||||
|
||||
if !p.options.semi
|
||||
&& matches!(
|
||||
node,
|
||||
ClassElement::PropertyDefinition(_)
|
||||
| ClassElement::AccessorProperty(_)
|
||||
| ClassElement::TSAbstractPropertyDefinition(_)
|
||||
)
|
||||
{
|
||||
parts_inner.push(ss!(";"));
|
||||
}
|
||||
|
||||
if i < class_body.body.len() - 1 {
|
||||
parts_inner.extend(hardline!());
|
||||
|
||||
// TODO: if the next line is empty, add another hardline
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: if there are any dangling comments, print them
|
||||
|
||||
let mut parts = p.vec();
|
||||
// TODO is class_body.len() != 0, print hardline after heritage
|
||||
|
||||
parts.push(ss!("{"));
|
||||
if !inner_parts.is_empty() {
|
||||
if !parts_inner.is_empty() {
|
||||
let indent = {
|
||||
let mut parts = p.vec();
|
||||
parts.extend(hardline!());
|
||||
parts.push(Doc::Array(inner_parts));
|
||||
parts.push(Doc::Array(parts_inner));
|
||||
Doc::Indent(parts)
|
||||
};
|
||||
parts.push(array![p, indent]);
|
||||
parts.extend(hardline!());
|
||||
}
|
||||
|
||||
parts.push(ss!("}"));
|
||||
|
||||
Doc::Array(parts)
|
||||
}
|
||||
|
||||
pub enum ClassMemberish<'a, 'b> {
|
||||
PropertyDefinition(&'b PropertyDefinition<'a>),
|
||||
AccessorProperty(&'b AccessorProperty<'a>),
|
||||
}
|
||||
|
||||
impl<'a, 'b> ClassMemberish<'a, 'b> {
|
||||
fn format_key(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => {
|
||||
property_definition.key.format(p)
|
||||
}
|
||||
ClassMemberish::AccessorProperty(accessor_property) => accessor_property.key.format(p),
|
||||
}
|
||||
}
|
||||
|
||||
fn decorators(&self) -> Option<&oxc_allocator::Vec<Decorator<'a>>> {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => {
|
||||
Some(&property_definition.decorators)
|
||||
}
|
||||
|
||||
ClassMemberish::AccessorProperty(accessor_property) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => property_definition.r#static,
|
||||
ClassMemberish::AccessorProperty(accessor_property) => accessor_property.r#static,
|
||||
}
|
||||
}
|
||||
fn is_override(&self) -> bool {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => {
|
||||
property_definition.r#override
|
||||
}
|
||||
ClassMemberish::AccessorProperty(accessor_property) => false,
|
||||
}
|
||||
}
|
||||
fn is_readonly(&self) -> bool {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => property_definition.readonly,
|
||||
ClassMemberish::AccessorProperty(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn right_expr(&self) -> Option<&Expression<'a>> {
|
||||
match self {
|
||||
ClassMemberish::PropertyDefinition(property_definition) => {
|
||||
property_definition.value.as_ref()
|
||||
}
|
||||
ClassMemberish::AccessorProperty(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn print_class_property<'a>(
|
||||
p: &mut Prettier<'a>,
|
||||
node: &ClassMemberish<'a, '_>,
|
||||
) -> Doc<'a> {
|
||||
let mut parts = p.vec();
|
||||
|
||||
if node.decorators().is_some_and(|x| !x.is_empty()) {
|
||||
// TODO: print decorators
|
||||
}
|
||||
|
||||
// TODO: print typescript accessibility token
|
||||
// TODO: print declare token
|
||||
|
||||
if node.is_static() {
|
||||
parts.push(ss!("static "));
|
||||
}
|
||||
|
||||
if node.is_override() {
|
||||
parts.push(ss!("override "));
|
||||
}
|
||||
|
||||
if node.is_readonly() {
|
||||
parts.push(ss!("readonly "));
|
||||
}
|
||||
|
||||
// TODO: print abstract token
|
||||
|
||||
if matches!(node, ClassMemberish::AccessorProperty(_)) {
|
||||
parts.push(ss!("readonly "));
|
||||
}
|
||||
|
||||
parts.push(node.format_key(p));
|
||||
|
||||
// TODO: print optional token
|
||||
// TODO: print definite token
|
||||
// TODO: print type annotation
|
||||
|
||||
let right_expr = node.right_expr();
|
||||
let node = match node {
|
||||
ClassMemberish::PropertyDefinition(v) => AssignmentLikeNode::PropertyDefinition(v),
|
||||
ClassMemberish::AccessorProperty(v) => AssignmentLikeNode::AccessorProperty(v),
|
||||
};
|
||||
let mut result =
|
||||
assignment::print_assignment(p, node, Doc::Array(parts), Doc::Str(" ="), right_expr);
|
||||
|
||||
if p.options.semi {
|
||||
let mut parts = p.vec();
|
||||
parts.push(result);
|
||||
result = Doc::Array(parts);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1874,7 +1874,7 @@ impl<'a> Format<'a> for Class<'a> {
|
|||
|
||||
impl<'a> Format<'a> for ClassBody<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
class::print_class_body(p, self)
|
||||
wrap!(p, self, ClassBody, { class::print_class_body(p, self) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2034,19 +2034,21 @@ impl<'a> Format<'a> for StaticBlock<'a> {
|
|||
|
||||
impl<'a> Format<'a> for MethodDefinition<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
function::print_method(p, self)
|
||||
wrap!(p, self, MethodDefinition, { function::print_method(p, self) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Format<'a> for PropertyDefinition<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
line!()
|
||||
wrap!(p, self, PropertyDefinition, {
|
||||
class::print_class_property(p, &class::ClassMemberish::PropertyDefinition(self))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Format<'a> for AccessorProperty<'a> {
|
||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||
line!()
|
||||
class::print_class_property(p, &class::ClassMemberish::AccessorProperty(self))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Compatibility: 180/591 (30.46%)
|
||||
Compatibility: 182/591 (30.80%)
|
||||
|
||||
# Failed
|
||||
|
||||
|
|
@ -128,7 +128,6 @@ Compatibility: 180/591 (30.46%)
|
|||
* class-static-block/class-static-block.js
|
||||
|
||||
### classes
|
||||
* classes/asi.js
|
||||
* classes/assignment.js
|
||||
* classes/class-fields-features.js
|
||||
* classes/empty.js
|
||||
|
|
@ -230,9 +229,6 @@ Compatibility: 180/591 (30.46%)
|
|||
### comments-pipeline-own-line
|
||||
* comments-pipeline-own-line/pipeline_own_line.js
|
||||
|
||||
### computed-props
|
||||
* computed-props/classes.js
|
||||
|
||||
### conditional
|
||||
* conditional/comments.js
|
||||
* conditional/new-ternary-examples.js
|
||||
|
|
|
|||
Loading…
Reference in a new issue