Skip to content

Commit

Permalink
refactor(prettier): Verify printing member expr (#8797)
Browse files Browse the repository at this point in the history
Part of #5068 

- MemberExpression
  - Computed
  - Static, PrivateField
  • Loading branch information
leaysgur authored Jan 31, 2025
1 parent c2fdfc4 commit 3e3fbef
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 29 deletions.
37 changes: 14 additions & 23 deletions crates/oxc_prettier/src/format/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
format::{
print::{
array, arrow_function, assignment, binaryish, block, call_expression, class, function,
function_parameters, literal, misc, module, object, property, statement,
function_parameters, literal, member, misc, module, object, property, statement,
template_literal, ternary,
},
Format,
Expand Down Expand Up @@ -870,6 +870,7 @@ impl<'a> Format<'a> for ThisExpression {

impl<'a> Format<'a> for MemberExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
// This `wrap!` should be used for each type, but they are not listed in the `AstKind`
wrap!(p, self, MemberExpression, {
match self {
Self::ComputedMemberExpression(expr) => expr.format(p),
Expand All @@ -882,38 +883,28 @@ impl<'a> Format<'a> for MemberExpression<'a> {

impl<'a> Format<'a> for ComputedMemberExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
let mut parts = Vec::new_in(p.allocator);
parts.push(self.object.format(p));
if self.optional {
parts.push(text!("?."));
}
parts.push(text!("["));
parts.push(self.expression.format(p));
parts.push(text!("]"));
array!(p, parts)
member::print_member_expression(
p,
&member::MemberExpressionLike::ComputedMemberExpression(self),
)
}
}

impl<'a> Format<'a> for StaticMemberExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
let mut parts = Vec::new_in(p.allocator);
parts.push(self.object.format(p));
if self.optional {
parts.push(text!("?"));
}
parts.push(text!("."));
parts.push(self.property.format(p));
array!(p, parts)
member::print_member_expression(
p,
&member::MemberExpressionLike::StaticMemberExpression(self),
)
}
}

impl<'a> Format<'a> for PrivateFieldExpression<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
let mut parts = Vec::new_in(p.allocator);
parts.push(self.object.format(p));
parts.push(if self.optional { text!("?.") } else { text!(".") });
parts.push(self.field.format(p));
array!(p, parts)
member::print_member_expression(
p,
&member::MemberExpressionLike::PrivateFieldExpression(self),
)
}
}

Expand Down
101 changes: 101 additions & 0 deletions crates/oxc_prettier/src/format/print/member.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use oxc_allocator::Vec;
use oxc_ast::ast::*;

use crate::{array, group, indent, ir::Doc, softline, text, Format, Prettier};

#[allow(clippy::enum_variant_names)]
pub enum MemberExpressionLike<'a, 'b> {
ComputedMemberExpression(&'b ComputedMemberExpression<'a>),
StaticMemberExpression(&'b StaticMemberExpression<'a>),
PrivateFieldExpression(&'b PrivateFieldExpression<'a>),
}

impl<'a> MemberExpressionLike<'a, '_> {
pub fn format_object(&self, p: &mut Prettier<'a>) -> Doc<'a> {
match self {
MemberExpressionLike::ComputedMemberExpression(expr) => expr.object.format(p),
MemberExpressionLike::StaticMemberExpression(expr) => expr.object.format(p),
MemberExpressionLike::PrivateFieldExpression(expr) => expr.object.format(p),
}
}

pub fn optional(&self) -> bool {
match self {
MemberExpressionLike::ComputedMemberExpression(expr) => expr.optional,
MemberExpressionLike::StaticMemberExpression(expr) => expr.optional,
MemberExpressionLike::PrivateFieldExpression(expr) => expr.optional,
}
}

pub fn format_property(&self, p: &mut Prettier<'a>) -> Doc<'a> {
match self {
MemberExpressionLike::ComputedMemberExpression(expr) => expr.expression.format(p),
MemberExpressionLike::StaticMemberExpression(expr) => expr.property.format(p),
MemberExpressionLike::PrivateFieldExpression(expr) => expr.field.format(p),
}
}
}

pub fn print_member_expression<'a>(
p: &mut Prettier<'a>,
member_expr: &MemberExpressionLike<'a, '_>,
) -> Doc<'a> {
let mut parts = Vec::new_in(p.allocator);

parts.push(member_expr.format_object(p));

let lookup_doc = print_member_lookup(p, member_expr);

// TODO: Calc `shouldInline` with parent
let should_inline = true;

if should_inline {
parts.push(lookup_doc);
} else {
parts.push(group!(p, [indent!(p, [softline!(), lookup_doc])]));
}

// TODO: Wrap with `label!` when in member-chain
array!(p, parts)
}

pub fn print_member_lookup<'a>(
p: &mut Prettier<'a>,
member_expr: &MemberExpressionLike<'a, '_>,
) -> Doc<'a> {
match member_expr {
MemberExpressionLike::StaticMemberExpression(_)
| MemberExpressionLike::PrivateFieldExpression(_) => {
let mut parts = Vec::new_in(p.allocator);
if member_expr.optional() {
parts.push(text!("?"));
}
parts.push(text!("."));
parts.push(member_expr.format_property(p));
array!(p, parts)
}
MemberExpressionLike::ComputedMemberExpression(expr) => {
if expr.expression.is_number_literal() {
let mut parts = Vec::new_in(p.allocator);
if expr.optional {
parts.push(text!("?."));
}
parts.push(text!("["));
parts.push(expr.expression.format(p));
parts.push(text!("]"));
return array!(p, parts);
}

let mut parts = Vec::new_in(p.allocator);
if expr.optional {
parts.push(text!("?."));
}
parts.push(text!("["));
parts.push(indent!(p, [softline!(), expr.expression.format(p)]));
parts.push(softline!());
parts.push(text!("]"));

group!(p, parts)
}
}
}
1 change: 1 addition & 0 deletions crates/oxc_prettier/src/format/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod class;
pub mod function;
pub mod function_parameters;
pub mod literal;
pub mod member;
pub mod misc;
pub mod module;
pub mod object;
Expand Down
8 changes: 4 additions & 4 deletions tasks/prettier_conformance/snapshots/prettier.js.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ js compatibility: 251/641 (39.16%)
| js/method-chain/comment.js | 💥 | 30.61% |
| js/method-chain/computed-merge.js | 💥 | 41.38% |
| js/method-chain/computed.js | 💥 | 0.00% |
| js/method-chain/conditional.js | 💥 | 61.22% |
| js/method-chain/conditional.js | 💥 | 78.43% |
| js/method-chain/d3.js | 💥 | 40.00% |
| js/method-chain/first_long.js | 💥 | 57.14% |
| js/method-chain/fluent-configuration.js | 💥 | 37.50% |
Expand Down Expand Up @@ -313,13 +313,13 @@ js compatibility: 251/641 (39.16%)
| js/template-align/indent.js | 💥💥 | 46.05% |
| js/template-literals/binary-exporessions.js | 💥 | 0.00% |
| js/template-literals/conditional-expressions.js | 💥 | 0.00% |
| js/template-literals/expressions.js | 💥 | 63.64% |
| js/template-literals/expressions.js | 💥 | 62.69% |
| js/template-literals/indention.js | 💥 | 51.16% |
| js/template-literals/logical-expressions.js | 💥 | 0.00% |
| js/template-literals/sequence-expressions.js | 💥 | 0.00% |
| js/ternaries/binary.js | 💥💥💥💥💥💥💥💥 | 13.93% |
| js/ternaries/func-call.js | 💥💥💥💥💥💥💥💥 | 45.20% |
| js/ternaries/indent-after-paren.js | 💥💥💥💥💥💥💥💥 | 37.35% |
| js/ternaries/indent-after-paren.js | 💥💥💥💥💥💥💥💥 | 39.32% |
| js/ternaries/indent.js | 💥💥💥💥💥💥💥💥 | 10.85% |
| js/ternaries/nested-in-condition.js | 💥💥💥💥💥💥💥💥 | 15.90% |
| js/ternaries/nested.js | 💥💥💥💥💥💥💥💥 | 26.56% |
Expand Down Expand Up @@ -393,4 +393,4 @@ js compatibility: 251/641 (39.16%)
| jsx/spread/attribute.js | 💥 | 30.19% |
| jsx/spread/child.js | 💥 | 26.67% |
| jsx/stateless-arrow-fn/test.js | 💥 | 14.79% |
| jsx/text-wrap/test.js | 💥 | 38.20% |
| jsx/text-wrap/test.js | 💥 | 38.05% |
4 changes: 2 additions & 2 deletions tasks/prettier_conformance/snapshots/prettier.ts.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ ts compatibility: 199/568 (35.04%)
| jsx/spread/attribute.js | 💥 | 30.19% |
| jsx/spread/child.js | 💥 | 26.67% |
| jsx/stateless-arrow-fn/test.js | 💥 | 14.79% |
| jsx/text-wrap/test.js | 💥 | 38.20% |
| jsx/text-wrap/test.js | 💥 | 38.05% |
| typescript/ambient/ambient.ts | 💥 | 88.24% |
| typescript/angular-component-examples/15934-computed.component.ts | 💥💥 | 61.54% |
| typescript/angular-component-examples/15934.component.ts | 💥💥 | 38.46% |
Expand Down Expand Up @@ -80,7 +80,7 @@ ts compatibility: 199/568 (35.04%)
| typescript/call-signature/call-signature.ts | 💥 | 86.44% |
| typescript/cast/as-const.ts | 💥 | 44.44% |
| typescript/cast/assert-and-assign.ts | 💥 | 0.00% |
| typescript/cast/generic-cast.ts | 💥 | 38.38% |
| typescript/cast/generic-cast.ts | 💥 | 37.75% |
| typescript/cast/hug-args.ts | 💥 | 21.05% |
| typescript/cast/parenthesis.ts | 💥 | 66.67% |
| typescript/cast/tuple-and-record.ts | 💥 | 0.00% |
Expand Down

0 comments on commit 3e3fbef

Please sign in to comment.