mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(prettier): turn off preserve_parens and start working on need-parens (#1487)
This commit is contained in:
parent
f66e4d8ac3
commit
064353c97e
7 changed files with 389 additions and 75 deletions
|
|
@ -117,6 +117,7 @@ pub enum AstKind<'a> {
|
||||||
JSXElementName(&'a JSXElementName<'a>),
|
JSXElementName(&'a JSXElementName<'a>),
|
||||||
JSXExpressionContainer(&'a JSXExpressionContainer<'a>),
|
JSXExpressionContainer(&'a JSXExpressionContainer<'a>),
|
||||||
JSXAttributeItem(&'a JSXAttributeItem<'a>),
|
JSXAttributeItem(&'a JSXAttributeItem<'a>),
|
||||||
|
JSXSpreadAttribute(&'a JSXSpreadAttribute<'a>),
|
||||||
JSXText(&'a JSXText),
|
JSXText(&'a JSXText),
|
||||||
|
|
||||||
// TypeScript
|
// TypeScript
|
||||||
|
|
@ -369,6 +370,7 @@ impl<'a> GetSpan for AstKind<'a> {
|
||||||
Self::JSXElement(x) => x.span,
|
Self::JSXElement(x) => x.span,
|
||||||
Self::JSXFragment(x) => x.span,
|
Self::JSXFragment(x) => x.span,
|
||||||
Self::JSXAttributeItem(x) => x.span(),
|
Self::JSXAttributeItem(x) => x.span(),
|
||||||
|
Self::JSXSpreadAttribute(x) => x.span,
|
||||||
Self::JSXText(x) => x.span,
|
Self::JSXText(x) => x.span,
|
||||||
Self::JSXExpressionContainer(x) => x.span,
|
Self::JSXExpressionContainer(x) => x.span,
|
||||||
|
|
||||||
|
|
@ -538,6 +540,7 @@ impl<'a> AstKind<'a> {
|
||||||
Self::JSXElement(_) => "JSXElement".into(),
|
Self::JSXElement(_) => "JSXElement".into(),
|
||||||
Self::JSXFragment(_) => "JSXFragment".into(),
|
Self::JSXFragment(_) => "JSXFragment".into(),
|
||||||
Self::JSXAttributeItem(_) => "JSXAttributeItem".into(),
|
Self::JSXAttributeItem(_) => "JSXAttributeItem".into(),
|
||||||
|
Self::JSXSpreadAttribute(_) => "JSXSpreadAttribute".into(),
|
||||||
Self::JSXText(_) => "JSXText".into(),
|
Self::JSXText(_) => "JSXText".into(),
|
||||||
Self::JSXExpressionContainer(_) => "JSXExpressionContainer".into(),
|
Self::JSXExpressionContainer(_) => "JSXExpressionContainer".into(),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl FormatRunner {
|
||||||
let source_text = std::fs::read_to_string(path).unwrap();
|
let source_text = std::fs::read_to_string(path).unwrap();
|
||||||
let allocator = Allocator::default();
|
let allocator = Allocator::default();
|
||||||
let source_type = SourceType::from_path(path).unwrap();
|
let source_type = SourceType::from_path(path).unwrap();
|
||||||
let ret = Parser::new(&allocator, &source_text, source_type).parse();
|
let ret = Parser::new(&allocator, &source_text, source_type).preserve_parens(false).parse();
|
||||||
let _ = Prettier::new(&allocator, &source_text, ret.trivias, PrettierOptions::default())
|
let _ = Prettier::new(&allocator, &source_text, ret.trivias, PrettierOptions::default())
|
||||||
.build(&ret.program);
|
.build(&ret.program);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ fn main() {
|
||||||
let source_text = std::fs::read_to_string(path).unwrap_or_else(|_| panic!("{name} not found"));
|
let source_text = std::fs::read_to_string(path).unwrap_or_else(|_| panic!("{name} not found"));
|
||||||
let allocator = Allocator::default();
|
let allocator = Allocator::default();
|
||||||
let source_type = SourceType::from_path(path).unwrap();
|
let source_type = SourceType::from_path(path).unwrap();
|
||||||
let ret = Parser::new(&allocator, &source_text, source_type).parse();
|
let ret = Parser::new(&allocator, &source_text, source_type).preserve_parens(false).parse();
|
||||||
let output = Prettier::new(&allocator, &source_text, ret.trivias, PrettierOptions::default())
|
let output = Prettier::new(&allocator, &source_text, ret.trivias, PrettierOptions::default())
|
||||||
.build(&ret.program);
|
.build(&ret.program);
|
||||||
println!("{output}");
|
println!("{output}");
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,17 @@ impl<'a> Format<'a> for Statement<'a> {
|
||||||
|
|
||||||
impl<'a> Format<'a> for ExpressionStatement<'a> {
|
impl<'a> Format<'a> for ExpressionStatement<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
let mut parts = p.vec();
|
wrap!(p, self, ExpressionStatement, {
|
||||||
if let Some(doc) = p.print_leading_comments(self.span) {
|
let mut parts = p.vec();
|
||||||
parts.push(doc);
|
if let Some(doc) = p.print_leading_comments(self.span) {
|
||||||
}
|
parts.push(doc);
|
||||||
parts.push(self.expression.format(p));
|
}
|
||||||
if p.options.semi {
|
parts.push(self.expression.format(p));
|
||||||
parts.push(ss!(";"));
|
if p.options.semi {
|
||||||
}
|
parts.push(ss!(";"));
|
||||||
Doc::Array(parts)
|
}
|
||||||
|
Doc::Array(parts)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1291,7 +1293,9 @@ impl<'a> Format<'a> for RegExpLiteral {
|
||||||
|
|
||||||
impl<'a> Format<'a> for StringLiteral {
|
impl<'a> Format<'a> for StringLiteral {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
p.str(&string::print_string(self.value.as_str(), p.options.single_quote))
|
wrap!(p, self, StringLiteral, {
|
||||||
|
p.str(&string::print_string(self.value.as_str(), p.options.single_quote))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1303,11 +1307,13 @@ impl<'a> Format<'a> for ThisExpression {
|
||||||
|
|
||||||
impl<'a> Format<'a> for MemberExpression<'a> {
|
impl<'a> Format<'a> for MemberExpression<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
match self {
|
wrap!(p, self, MemberExpression, {
|
||||||
Self::ComputedMemberExpression(expr) => expr.format(p),
|
match self {
|
||||||
Self::StaticMemberExpression(expr) => expr.format(p),
|
Self::ComputedMemberExpression(expr) => expr.format(p),
|
||||||
Self::PrivateFieldExpression(expr) => expr.format(p),
|
Self::StaticMemberExpression(expr) => expr.format(p),
|
||||||
}
|
Self::PrivateFieldExpression(expr) => expr.format(p),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1380,7 +1386,7 @@ impl<'a> Format<'a> for ArrayExpressionElement<'a> {
|
||||||
|
|
||||||
impl<'a> Format<'a> for SpreadElement<'a> {
|
impl<'a> Format<'a> for SpreadElement<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
array![p, ss!("..."), format!(p, self.argument)]
|
wrap!(p, self, SpreadElement, { array![p, ss!("..."), format!(p, self.argument)] })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1488,16 +1494,18 @@ impl<'a> Format<'a> for ArrowExpression<'a> {
|
||||||
|
|
||||||
impl<'a> Format<'a> for YieldExpression<'a> {
|
impl<'a> Format<'a> for YieldExpression<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
let mut parts = p.vec();
|
wrap!(p, self, YieldExpression, {
|
||||||
parts.push(ss!("yield"));
|
let mut parts = p.vec();
|
||||||
if self.delegate {
|
parts.push(ss!("yield"));
|
||||||
parts.push(ss!("*"));
|
if self.delegate {
|
||||||
}
|
parts.push(ss!("*"));
|
||||||
if let Some(argument) = &self.argument {
|
}
|
||||||
parts.push(ss!(" "));
|
if let Some(argument) = &self.argument {
|
||||||
parts.push(format!(p, argument));
|
parts.push(ss!(" "));
|
||||||
}
|
parts.push(format!(p, argument));
|
||||||
Doc::Array(parts)
|
}
|
||||||
|
Doc::Array(parts)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1693,8 +1701,7 @@ impl<'a> Format<'a> for SequenceExpression<'a> {
|
||||||
|
|
||||||
impl<'a> Format<'a> for ParenthesizedExpression<'a> {
|
impl<'a> Format<'a> for ParenthesizedExpression<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
// TODO: This wrap need to be removed and all logic should go into `need_parens`.
|
unreachable!("Parser preserve_parens option need to be set to false.");
|
||||||
wrap!(p, self, ParenthesizedExpression, { self.expression.format(p) })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1738,19 +1745,21 @@ impl<'a> Format<'a> for TemplateElement {
|
||||||
|
|
||||||
impl<'a> Format<'a> for TaggedTemplateExpression<'a> {
|
impl<'a> Format<'a> for TaggedTemplateExpression<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
let mut parts = p.vec();
|
wrap!(p, self, TaggedTemplateExpression, {
|
||||||
|
let mut parts = p.vec();
|
||||||
|
|
||||||
parts.push(format!(p, self.tag));
|
parts.push(format!(p, self.tag));
|
||||||
|
|
||||||
if let Some(type_parameters) = &self.type_parameters {
|
if let Some(type_parameters) = &self.type_parameters {
|
||||||
parts.push(string!(p, "<"));
|
parts.push(string!(p, "<"));
|
||||||
parts.push(format!(p, type_parameters));
|
parts.push(format!(p, type_parameters));
|
||||||
parts.push(string!(p, ">"));
|
parts.push(string!(p, ">"));
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.push(format!(p, self.quasi));
|
parts.push(format!(p, self.quasi));
|
||||||
|
|
||||||
Doc::Array(parts)
|
Doc::Array(parts)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1805,7 +1814,7 @@ impl<'a> Format<'a> for MetaProperty {
|
||||||
|
|
||||||
impl<'a> Format<'a> for Class<'a> {
|
impl<'a> Format<'a> for Class<'a> {
|
||||||
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
|
||||||
class::print_class(p, self)
|
wrap!(p, self, Class, { class::print_class(p, self) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,19 @@
|
||||||
use oxc_ast::AstKind;
|
//! Direct port of needs-parens for adding or removing parentheses.
|
||||||
|
//!
|
||||||
|
//! See <https://github.com/prettier/prettier/blob/main/src/language-js/needs-parens.js>
|
||||||
|
|
||||||
|
#![allow(
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::match_same_arms,
|
||||||
|
clippy::match_like_matches_macro,
|
||||||
|
clippy::single_match
|
||||||
|
)]
|
||||||
|
use oxc_ast::{
|
||||||
|
ast::{AssignmentTarget, ChainElement, Expression, ModuleDeclaration, SimpleAssignmentTarget},
|
||||||
|
AstKind,
|
||||||
|
};
|
||||||
|
use oxc_span::{GetSpan, Span};
|
||||||
|
use oxc_syntax::operator::{BinaryOperator, UnaryOperator, UpdateOperator};
|
||||||
|
|
||||||
use crate::{array, doc::Doc, ss, Prettier};
|
use crate::{array, doc::Doc, ss, Prettier};
|
||||||
|
|
||||||
|
|
@ -12,35 +27,305 @@ impl<'a> Prettier<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn need_parens(&self, kind: AstKind<'a>) -> bool {
|
fn need_parens(&self, kind: AstKind<'a>) -> bool {
|
||||||
match kind {
|
let parent_kind = self.parent_kind();
|
||||||
// Only statements don't need parentheses.
|
if self.check_parent_kind(kind, parent_kind) {
|
||||||
kind if kind.is_statement() => return false,
|
return true;
|
||||||
AstKind::SequenceExpression(_) => {
|
|
||||||
let parent = self.parent_kind();
|
|
||||||
|
|
||||||
if matches!(parent, AstKind::Program(_)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AstKind::ObjectExpression(_) => {
|
|
||||||
let parent = self.parent_kind();
|
|
||||||
|
|
||||||
if matches!(parent, AstKind::Program(_)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AstKind::AssignmentExpression(_) => {
|
|
||||||
let parent = self.parent_kind();
|
|
||||||
|
|
||||||
if matches!(parent, AstKind::ArrowExpression(arrow_expr) if arrow_expr.expression) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// NOTE: This is a fallback which should be removed when all code are ported.
|
|
||||||
AstKind::ParenthesizedExpression(_) => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
AstKind::SequenceExpression(_) => !matches!(parent_kind, AstKind::Program(_)),
|
||||||
|
AstKind::ObjectExpression(e) => self.check_object_function_class(e.span),
|
||||||
|
AstKind::Function(f) if f.expression => self.check_object_function_class(f.span),
|
||||||
|
AstKind::Class(c) if c.is_expression() => self.check_object_function_class(c.span),
|
||||||
|
AstKind::AssignmentExpression(_) => {
|
||||||
|
matches!(parent_kind, AstKind::ArrowExpression(arrow_expr) if arrow_expr.expression)
|
||||||
|
}
|
||||||
|
AstKind::UpdateExpression(update_expr) => match parent_kind {
|
||||||
|
AstKind::UnaryExpression(unary_expr) => {
|
||||||
|
update_expr.prefix
|
||||||
|
&& ((update_expr.operator == UpdateOperator::Increment
|
||||||
|
&& unary_expr.operator == UnaryOperator::UnaryPlus)
|
||||||
|
|| (update_expr.operator == UpdateOperator::Decrement
|
||||||
|
&& unary_expr.operator == UnaryOperator::UnaryNegation))
|
||||||
|
}
|
||||||
|
_ => self.check_update_unary(update_expr.span),
|
||||||
|
},
|
||||||
|
AstKind::UnaryExpression(unary_expr) => match parent_kind {
|
||||||
|
AstKind::UnaryExpression(parent_expr) => {
|
||||||
|
let u_op = unary_expr.operator;
|
||||||
|
u_op == parent_expr.operator
|
||||||
|
&& (matches!(u_op, UnaryOperator::UnaryPlus | UnaryOperator::UnaryNegation))
|
||||||
|
}
|
||||||
|
_ => self.check_update_unary(unary_expr.span),
|
||||||
|
},
|
||||||
|
AstKind::YieldExpression(e) => match parent_kind {
|
||||||
|
AstKind::AwaitExpression(_) => true,
|
||||||
|
_ => self.check_yield_await(e.span),
|
||||||
|
},
|
||||||
|
AstKind::AwaitExpression(e) => self.check_yield_await(e.span),
|
||||||
|
AstKind::TSTypeAssertion(e) => self.check_binarish(e.span),
|
||||||
|
AstKind::TSAsExpression(e) => self.check_binarish(e.span),
|
||||||
|
AstKind::TSSatisfiesExpression(e) => self.check_binarish(e.span),
|
||||||
|
AstKind::LogicalExpression(e) => self.check_binarish(e.span),
|
||||||
|
AstKind::BinaryExpression(e) => match parent_kind {
|
||||||
|
AstKind::UpdateExpression(_) => true,
|
||||||
|
_ => self.check_binarish(e.span),
|
||||||
|
},
|
||||||
|
AstKind::MemberExpression(e) => self.check_member_call(e.span()),
|
||||||
|
AstKind::CallExpression(e) => self.check_member_call(e.span),
|
||||||
|
AstKind::TaggedTemplateExpression(e) => {
|
||||||
|
self.check_member_call_tagged_template_ts_non_null(e.span)
|
||||||
|
}
|
||||||
|
AstKind::TSNonNullExpression(e) => {
|
||||||
|
self.check_member_call_tagged_template_ts_non_null(e.span)
|
||||||
|
}
|
||||||
|
AstKind::Function(e) if e.expression => match parent_kind {
|
||||||
|
AstKind::CallExpression(call_expr) => call_expr.callee.span() == e.span,
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == e.span,
|
||||||
|
AstKind::TaggedTemplateExpression(_) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
AstKind::ArrowExpression(e) => match parent_kind {
|
||||||
|
AstKind::CallExpression(call_expr) => call_expr.callee.span() == e.span,
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == e.span,
|
||||||
|
AstKind::MemberExpression(member_expr) => member_expr.object().span() == e.span,
|
||||||
|
AstKind::TSAsExpression(_)
|
||||||
|
| AstKind::TSSatisfiesExpression(_)
|
||||||
|
| AstKind::TSNonNullExpression(_)
|
||||||
|
| AstKind::TaggedTemplateExpression(_)
|
||||||
|
| AstKind::UnaryExpression(_)
|
||||||
|
| AstKind::LogicalExpression(_)
|
||||||
|
| AstKind::AwaitExpression(_)
|
||||||
|
| AstKind::TSTypeAssertion(_) => true,
|
||||||
|
AstKind::ConditionalExpression(cond_expr) => cond_expr.test.span() == e.span,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
AstKind::Class(class) if class.is_expression() => match parent_kind {
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == class.span,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_parent_kind(&self, kind: AstKind<'a>, parent_kind: AstKind<'a>) -> bool {
|
||||||
|
match parent_kind {
|
||||||
|
AstKind::Class(class) => {
|
||||||
|
if let Some(h) = &class.super_class {
|
||||||
|
match kind {
|
||||||
|
AstKind::ArrowExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::AssignmentExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::AwaitExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::BinaryExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::ConditionalExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::LogicalExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::NewExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::ObjectExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::SequenceExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::TaggedTemplateExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::UnaryExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::UpdateExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::YieldExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::TSNonNullExpression(e) if e.span == h.span() => return true,
|
||||||
|
AstKind::Class(e)
|
||||||
|
if e.is_expression()
|
||||||
|
&& !e.decorators.is_empty()
|
||||||
|
&& e.span == h.span() =>
|
||||||
|
{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstKind::ModuleDeclaration(ModuleDeclaration::ExportDefaultDeclaration(_)) => {
|
||||||
|
return matches!(kind, AstKind::SequenceExpression(_))
|
||||||
|
|| self.should_wrap_function_for_export_default(kind)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_object_function_class(&self, span: Span) -> bool {
|
||||||
|
for ast_kind in self.nodes.iter().rev() {
|
||||||
|
if let AstKind::ExpressionStatement(e) = ast_kind {
|
||||||
|
if Self::starts_with_no_lookahead_token(&e.expression, span) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_update_unary(&self, span: Span) -> bool {
|
||||||
|
match self.parent_kind() {
|
||||||
|
AstKind::MemberExpression(member_expr) => member_expr.object().span() == span,
|
||||||
|
AstKind::TaggedTemplateExpression(_) => true,
|
||||||
|
AstKind::CallExpression(call_expr) => call_expr.callee.span() == span,
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == span,
|
||||||
|
AstKind::BinaryExpression(bin_expr) => {
|
||||||
|
bin_expr.left.span() == span && bin_expr.operator == BinaryOperator::Exponential
|
||||||
|
}
|
||||||
|
AstKind::TSNonNullExpression(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_yield_await(&self, span: Span) -> bool {
|
||||||
|
match self.parent_kind() {
|
||||||
|
AstKind::TaggedTemplateExpression(_)
|
||||||
|
| AstKind::UnaryExpression(_)
|
||||||
|
| AstKind::LogicalExpression(_)
|
||||||
|
| AstKind::SpreadElement(_)
|
||||||
|
| AstKind::TSAsExpression(_)
|
||||||
|
| AstKind::TSSatisfiesExpression(_)
|
||||||
|
| AstKind::TSNonNullExpression(_)
|
||||||
|
| AstKind::BinaryExpression(_) => true,
|
||||||
|
AstKind::MemberExpression(member_expr) => member_expr.object().span() == span,
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == span,
|
||||||
|
AstKind::CallExpression(new_expr) => new_expr.callee.span() == span,
|
||||||
|
AstKind::ConditionalExpression(con_expr) => con_expr.test.span() == span,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_binarish(&self, span: Span) -> bool {
|
||||||
|
match self.parent_kind() {
|
||||||
|
AstKind::TSAsExpression(_) => !self.is_binary_cast_expression(span),
|
||||||
|
AstKind::TSSatisfiesExpression(_) => !self.is_binary_cast_expression(span),
|
||||||
|
AstKind::ConditionalExpression(_) => self.is_binary_cast_expression(span),
|
||||||
|
AstKind::NewExpression(new_expr) => new_expr.callee.span() == span,
|
||||||
|
AstKind::CallExpression(new_expr) => new_expr.callee.span() == span,
|
||||||
|
AstKind::Class(class) => class.super_class.as_ref().is_some_and(|e| e.span() == span),
|
||||||
|
AstKind::TSTypeAssertion(_)
|
||||||
|
| AstKind::TaggedTemplateExpression(_)
|
||||||
|
| AstKind::UnaryExpression(_)
|
||||||
|
| AstKind::JSXSpreadAttribute(_)
|
||||||
|
| AstKind::SpreadElement(_)
|
||||||
|
| AstKind::AwaitExpression(_)
|
||||||
|
| AstKind::TSNonNullExpression(_)
|
||||||
|
| AstKind::UpdateExpression(_) => true,
|
||||||
|
AstKind::MemberExpression(member_expr) => member_expr.object().span() == span,
|
||||||
|
AstKind::AssignmentExpression(assign_expr) => {
|
||||||
|
assign_expr.left.span() == span && self.is_binary_cast_expression(span)
|
||||||
|
}
|
||||||
|
AstKind::AssignmentPattern(assign_pat) => {
|
||||||
|
assign_pat.left.span() == span && self.is_binary_cast_expression(span)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_member_call(&self, span: Span) -> bool {
|
||||||
|
// if (shouldAddParenthesesToChainElement(path)) {
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
self.check_member_call_tagged_template_ts_non_null(span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_member_call_tagged_template_ts_non_null(&self, span: Span) -> bool {
|
||||||
|
match self.parent_kind() {
|
||||||
|
AstKind::NewExpression(new_expr) if new_expr.callee.span() == span => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_wrap_function_for_export_default(&self, kind: AstKind<'a>) -> bool {
|
||||||
|
matches!(kind, AstKind::Function(f) if f.expression)
|
||||||
|
|| matches!(kind, AstKind::Class(c) if c.is_expression())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_binary_cast_expression(&self, _span: Span) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn starts_with_no_lookahead_token(e: &Expression<'a>, span: Span) -> bool {
|
||||||
|
match e {
|
||||||
|
Expression::BinaryExpression(e) => Self::starts_with_no_lookahead_token(&e.left, span),
|
||||||
|
Expression::LogicalExpression(e) => Self::starts_with_no_lookahead_token(&e.left, span),
|
||||||
|
Expression::AssignmentExpression(e) => match &e.left {
|
||||||
|
AssignmentTarget::SimpleAssignmentTarget(t) => match t {
|
||||||
|
SimpleAssignmentTarget::AssignmentTargetIdentifier(_) => false,
|
||||||
|
SimpleAssignmentTarget::MemberAssignmentTarget(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(e.object(), span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSAsExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSSatisfiesExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSNonNullExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSTypeAssertion(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AssignmentTarget::AssignmentTargetPattern(_) => false,
|
||||||
|
},
|
||||||
|
Expression::MemberExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(e.object(), span)
|
||||||
|
}
|
||||||
|
Expression::TaggedTemplateExpression(e) => {
|
||||||
|
if matches!(e.tag, Expression::FunctionExpression(_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Self::starts_with_no_lookahead_token(&e.tag, span)
|
||||||
|
}
|
||||||
|
Expression::CallExpression(e) => {
|
||||||
|
if matches!(e.callee, Expression::FunctionExpression(_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Self::starts_with_no_lookahead_token(&e.callee, span)
|
||||||
|
}
|
||||||
|
Expression::ConditionalExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.test, span)
|
||||||
|
}
|
||||||
|
Expression::UpdateExpression(e) => {
|
||||||
|
!e.prefix
|
||||||
|
&& match &e.argument {
|
||||||
|
SimpleAssignmentTarget::AssignmentTargetIdentifier(_) => false,
|
||||||
|
SimpleAssignmentTarget::MemberAssignmentTarget(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(e.object(), span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSAsExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSSatisfiesExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSNonNullExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
SimpleAssignmentTarget::TSTypeAssertion(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::SequenceExpression(e) => e
|
||||||
|
.expressions
|
||||||
|
.get(0)
|
||||||
|
.map_or(false, |e| Self::starts_with_no_lookahead_token(e, span)),
|
||||||
|
Expression::ChainExpression(e) => match &e.expression {
|
||||||
|
ChainElement::CallExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.callee, span)
|
||||||
|
}
|
||||||
|
ChainElement::MemberExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(e.object(), span)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expression::TSSatisfiesExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
Expression::TSAsExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
Expression::TSNonNullExpression(e) => {
|
||||||
|
Self::starts_with_no_lookahead_token(&e.expression, span)
|
||||||
|
}
|
||||||
|
_ => e.span() == span,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Compatibility: 138/601 (22.96%)
|
Compatibility: 131/601 (21.80%)
|
||||||
|
|
||||||
# Failed
|
# Failed
|
||||||
|
|
||||||
|
|
@ -85,7 +85,6 @@ Compatibility: 138/601 (22.96%)
|
||||||
* assignment-comments/string.js
|
* assignment-comments/string.js
|
||||||
|
|
||||||
### async
|
### async
|
||||||
* async/await-parse.js
|
|
||||||
* async/conditional-expression.js
|
* async/conditional-expression.js
|
||||||
* async/inline-await.js
|
* async/inline-await.js
|
||||||
* async/nested.js
|
* async/nested.js
|
||||||
|
|
@ -136,6 +135,9 @@ Compatibility: 138/601 (22.96%)
|
||||||
### call/invalid
|
### call/invalid
|
||||||
* call/invalid/null-arguments-item.js
|
* call/invalid/null-arguments-item.js
|
||||||
|
|
||||||
|
### chain-expression
|
||||||
|
* chain-expression/test.js
|
||||||
|
|
||||||
### class-comment
|
### class-comment
|
||||||
* class-comment/class-property.js
|
* class-comment/class-property.js
|
||||||
* class-comment/misc.js
|
* class-comment/misc.js
|
||||||
|
|
@ -313,14 +315,21 @@ Compatibility: 138/601 (22.96%)
|
||||||
* eol/range-1.js
|
* eol/range-1.js
|
||||||
* eol/range-and-cursor-1.js
|
* eol/range-and-cursor-1.js
|
||||||
|
|
||||||
|
### es6modules
|
||||||
|
* es6modules/export_default_function_expression.js
|
||||||
|
* es6modules/export_default_function_expression_named.js
|
||||||
|
|
||||||
### export
|
### export
|
||||||
* export/blank-line-between-specifiers.js
|
* export/blank-line-between-specifiers.js
|
||||||
* export/same-local-and-exported.js
|
* export/same-local-and-exported.js
|
||||||
|
|
||||||
### export-default
|
### export-default
|
||||||
* export-default/binary_and_template.js
|
* export-default/binary_and_template.js
|
||||||
|
* export-default/body.js
|
||||||
|
* export-default/class_instance.js
|
||||||
* export-default/function_in_template.js
|
* export-default/function_in_template.js
|
||||||
* export-default/function_tostring.js
|
* export-default/function_tostring.js
|
||||||
|
* export-default/iife.js
|
||||||
|
|
||||||
### export-default/escaped
|
### export-default/escaped
|
||||||
* export-default/escaped/default-escaped.js
|
* export-default/escaped/default-escaped.js
|
||||||
|
|
@ -330,12 +339,14 @@ Compatibility: 138/601 (22.96%)
|
||||||
|
|
||||||
### expression_statement
|
### expression_statement
|
||||||
* expression_statement/no_regression.js
|
* expression_statement/no_regression.js
|
||||||
|
* expression_statement/use_strict.js
|
||||||
|
|
||||||
### for
|
### for
|
||||||
* for/comment.js
|
* for/comment.js
|
||||||
* for/continue-and-break-comment-1.js
|
* for/continue-and-break-comment-1.js
|
||||||
* for/continue-and-break-comment-2.js
|
* for/continue-and-break-comment-2.js
|
||||||
* for/continue-and-break-comment-without-blocks.js
|
* for/continue-and-break-comment-without-blocks.js
|
||||||
|
* for/in.js
|
||||||
|
|
||||||
### function
|
### function
|
||||||
* function/function_expression.js
|
* function/function_expression.js
|
||||||
|
|
@ -371,6 +382,7 @@ Compatibility: 138/601 (22.96%)
|
||||||
* generator/async.js
|
* generator/async.js
|
||||||
|
|
||||||
### identifier/for-of
|
### identifier/for-of
|
||||||
|
* identifier/for-of/await.js
|
||||||
* identifier/for-of/let.js
|
* identifier/for-of/let.js
|
||||||
|
|
||||||
### identifier/parentheses
|
### identifier/parentheses
|
||||||
|
|
@ -411,6 +423,12 @@ Compatibility: 138/601 (22.96%)
|
||||||
### line-suffix-boundary
|
### line-suffix-boundary
|
||||||
* line-suffix-boundary/boundary.js
|
* line-suffix-boundary/boundary.js
|
||||||
|
|
||||||
|
### literal
|
||||||
|
* literal/number.js
|
||||||
|
|
||||||
|
### logical-assignment
|
||||||
|
* logical-assignment/logical-assignment.js
|
||||||
|
|
||||||
### logical_expressions
|
### logical_expressions
|
||||||
* logical_expressions/issue-7024.js
|
* logical_expressions/issue-7024.js
|
||||||
* logical_expressions/logical_expression_operators.js
|
* logical_expressions/logical_expression_operators.js
|
||||||
|
|
@ -446,6 +464,9 @@ Compatibility: 138/601 (22.96%)
|
||||||
* method-chain/this.js
|
* method-chain/this.js
|
||||||
* method-chain/tuple-and-record.js
|
* method-chain/tuple-and-record.js
|
||||||
|
|
||||||
|
### method-chain/print-width-120
|
||||||
|
* method-chain/print-width-120/constructor.js
|
||||||
|
|
||||||
### module-blocks
|
### module-blocks
|
||||||
* module-blocks/comments.js
|
* module-blocks/comments.js
|
||||||
* module-blocks/module-blocks.js
|
* module-blocks/module-blocks.js
|
||||||
|
|
@ -649,11 +670,9 @@ Compatibility: 138/601 (22.96%)
|
||||||
|
|
||||||
### unary
|
### unary
|
||||||
* unary/object.js
|
* unary/object.js
|
||||||
* unary/series.js
|
|
||||||
|
|
||||||
### unary-expression
|
### unary-expression
|
||||||
* unary-expression/comments.js
|
* unary-expression/comments.js
|
||||||
* unary-expression/urnary_expression.js
|
|
||||||
|
|
||||||
### unicode
|
### unicode
|
||||||
* unicode/combining-characters.js
|
* unicode/combining-characters.js
|
||||||
|
|
@ -666,7 +685,5 @@ Compatibility: 138/601 (22.96%)
|
||||||
* while/indent.js
|
* while/indent.js
|
||||||
|
|
||||||
### yield
|
### yield
|
||||||
* yield/arrow.js
|
|
||||||
* yield/conditional.js
|
|
||||||
* yield/jsx-without-parenthesis.js
|
* yield/jsx-without-parenthesis.js
|
||||||
* yield/jsx.js
|
* yield/jsx.js
|
||||||
|
|
@ -311,7 +311,7 @@ impl TestRunner {
|
||||||
fn prettier(path: &Path, source_text: &str, prettier_options: PrettierOptions) -> String {
|
fn prettier(path: &Path, source_text: &str, prettier_options: PrettierOptions) -> String {
|
||||||
let allocator = Allocator::default();
|
let allocator = Allocator::default();
|
||||||
let source_type = SourceType::from_path(path).unwrap();
|
let source_type = SourceType::from_path(path).unwrap();
|
||||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
let ret = Parser::new(&allocator, source_text, source_type).preserve_parens(false).parse();
|
||||||
Prettier::new(&allocator, source_text, ret.trivias, prettier_options).build(&ret.program)
|
Prettier::new(&allocator, source_text, ret.trivias, prettier_options).build(&ret.program)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue