mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(prettier) port should_break_after_operator (#1606)
This commit is contained in:
parent
967aa35526
commit
b7b3073f3f
3 changed files with 141 additions and 11 deletions
|
|
@ -1,8 +1,9 @@
|
|||
use oxc_ast::{
|
||||
ast::{
|
||||
AccessorProperty, AssignmentExpression, AssignmentTarget, AssignmentTargetPattern,
|
||||
AssignmentTargetProperty, BindingPatternKind, Expression, ObjectProperty,
|
||||
PropertyDefinition, PropertyKind, Statement, VariableDeclarator,
|
||||
AccessorProperty, Argument, AssignmentExpression, AssignmentTarget,
|
||||
AssignmentTargetPattern, AssignmentTargetProperty, BindingPatternKind, Expression,
|
||||
ObjectProperty, PropertyDefinition, PropertyKind, Statement, TSTypeParameterInstantiation,
|
||||
VariableDeclarator,
|
||||
},
|
||||
AstKind,
|
||||
};
|
||||
|
|
@ -13,7 +14,7 @@ use crate::{
|
|||
group, indent, line, ss, Format, Prettier,
|
||||
};
|
||||
|
||||
use super::class::ClassMemberish;
|
||||
use super::{binaryish::should_inline_logical_expression, class::ClassMemberish};
|
||||
|
||||
pub(super) fn print_assignment_expression<'a>(
|
||||
p: &mut Prettier<'a>,
|
||||
|
|
@ -200,6 +201,10 @@ fn choose_layout<'a>(
|
|||
// wrapping object properties with very short keys usually doesn't add much value
|
||||
let has_short_key = is_object_property_with_short_key(p, assignment_like_node, left_doc);
|
||||
|
||||
if should_break_after_operator(p, right_expr, has_short_key) {
|
||||
return Layout::BreakAfterOperator;
|
||||
}
|
||||
|
||||
if !can_break_left_doc
|
||||
&& (has_short_key
|
||||
|| matches!(
|
||||
|
|
@ -299,3 +304,112 @@ fn is_object_property_with_short_key<'a>(
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
/// https://github.com/prettier/prettier/blob/eebf0e4b5ec8ac24393c56ced4b4819d4c551f31/src/language-js/print/assignment.js#L182
|
||||
fn should_break_after_operator<'a>(
|
||||
p: &Prettier<'a>,
|
||||
expr: &Expression<'a>,
|
||||
has_short_key: bool,
|
||||
) -> bool {
|
||||
if matches!(expr, Expression::BinaryExpression(_) | Expression::LogicalExpression(_))
|
||||
&& !should_inline_logical_expression(expr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
match expr {
|
||||
Expression::SequenceExpression(_) => return true,
|
||||
Expression::ConditionalExpression(conditional_expr) => {
|
||||
return matches!(
|
||||
conditional_expr.test,
|
||||
Expression::LogicalExpression(_) | Expression::BinaryExpression(_)
|
||||
) && !should_inline_logical_expression(&conditional_expr.test);
|
||||
}
|
||||
Expression::ClassExpression(class_expr) => {
|
||||
if class_expr.decorators.len() > 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if has_short_key {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut current_expr = expr;
|
||||
|
||||
while let Expression::UnaryExpression(_) | Expression::TSNonNullExpression(_) = current_expr {
|
||||
current_expr = match current_expr {
|
||||
Expression::UnaryExpression(unary) => &unary.argument,
|
||||
Expression::TSNonNullExpression(non_null_expr) => &non_null_expr.expression,
|
||||
// SAFETY: the `while` loop above ensures that `current_expr` is either a `UnaryExpression` or a `TSNonNullExpression`.
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
if current_expr.is_string_literal() || is_poorly_breakable_member_or_call_chain(p, expr) {
|
||||
return true;
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn is_poorly_breakable_member_or_call_chain<'a>(p: &Prettier<'a>, expr: &Expression<'a>) -> bool {
|
||||
let mut is_chain_expression = false;
|
||||
let mut is_ident_or_this_expr = false;
|
||||
let mut call_expressions = vec![];
|
||||
|
||||
let mut expression = Some(expr);
|
||||
|
||||
while let Some(node) = expression.take() {
|
||||
expression = match node {
|
||||
Expression::TSNonNullExpression(non_null_expr) => Some(&non_null_expr.expression),
|
||||
Expression::CallExpression(call_expr) => {
|
||||
is_chain_expression = true;
|
||||
let callee = &call_expr.callee;
|
||||
call_expressions.push(call_expr);
|
||||
Some(callee)
|
||||
}
|
||||
Expression::MemberExpression(member_expr) => {
|
||||
is_chain_expression = true;
|
||||
Some(member_expr.object())
|
||||
}
|
||||
Expression::Identifier(_) | Expression::ThisExpression(_) => {
|
||||
is_ident_or_this_expr = true;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_chain_expression || !is_ident_or_this_expr {
|
||||
return false;
|
||||
}
|
||||
|
||||
for call_expression in call_expressions {
|
||||
let is_poorly_breakable_call = call_expression.arguments.len() == 0
|
||||
|| (call_expression.arguments.len() == 1
|
||||
&& is_lone_short_argument(&call_expression.arguments[0]));
|
||||
|
||||
if !is_poorly_breakable_call {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(type_parameters) = &call_expression.type_parameters {
|
||||
return is_complex_type_arguments(type_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn is_lone_short_argument(arg: &Argument) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_complex_type_arguments(type_parameters: &TSTypeParameterInstantiation) -> bool {
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,3 +39,25 @@ pub(super) fn print_binaryish_expression<'a>(
|
|||
Doc::Array(parts)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn should_inline_logical_expression(expr: &Expression) -> bool {
|
||||
let Expression::LogicalExpression(logical_expr) = expr else { return false };
|
||||
|
||||
if let Expression::ObjectExpression(obj_expr) = &logical_expr.right {
|
||||
if obj_expr.properties.len() > 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Expression::ArrayExpression(array_expr) = &logical_expr.right {
|
||||
if array_expr.elements.len() > 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(logical_expr.right, Expression::JSXElement(_) | Expression::JSXFragment(_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Compatibility: 217/561 (38.68%)
|
||||
Compatibility: 221/561 (39.39%)
|
||||
|
||||
# Failed
|
||||
|
||||
|
|
@ -46,7 +46,6 @@ Compatibility: 217/561 (38.68%)
|
|||
* assignment/discussion-15196.js
|
||||
* assignment/issue-10218.js
|
||||
* assignment/issue-15534.js
|
||||
* assignment/issue-2482-2.js
|
||||
* assignment/issue-2540.js
|
||||
* assignment/issue-6922.js
|
||||
* assignment/issue-7572.js
|
||||
|
|
@ -78,9 +77,6 @@ Compatibility: 217/561 (38.68%)
|
|||
* binary-expressions/short-right.js
|
||||
* binary-expressions/test.js
|
||||
|
||||
### binary_math
|
||||
* binary_math/parens.js
|
||||
|
||||
### break-calls
|
||||
* break-calls/break.js
|
||||
* break-calls/parent.js
|
||||
|
|
@ -117,7 +113,6 @@ Compatibility: 217/561 (38.68%)
|
|||
|
||||
### classes-private-fields
|
||||
* classes-private-fields/private_fields.js
|
||||
* classes-private-fields/with_comments.js
|
||||
|
||||
### comments
|
||||
* comments/arrow.js
|
||||
|
|
@ -358,7 +353,6 @@ Compatibility: 217/561 (38.68%)
|
|||
* objects/escape-sequence-key.js
|
||||
* objects/expand.js
|
||||
* objects/expression.js
|
||||
* objects/right-break.js
|
||||
|
||||
### objects/assignment-expression
|
||||
* objects/assignment-expression/object-value.js
|
||||
|
|
|
|||
Loading…
Reference in a new issue