diff --git a/Cargo.lock b/Cargo.lock index 27dd44bcd85..96d1fbc7689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1611,6 +1611,7 @@ version = "0.0.0" dependencies = [ "cfg-if", "countme", + "indexmap", "rome_diagnostics", "rome_js_parser", "rome_js_syntax", diff --git a/crates/rome_formatter/Cargo.toml b/crates/rome_formatter/Cargo.toml index 4c17bf2ad8b..7ece3cf9e60 100644 --- a/crates/rome_formatter/Cargo.toml +++ b/crates/rome_formatter/Cargo.toml @@ -16,6 +16,7 @@ cfg-if = "1.0.0" schemars = { version = "0.8.10", optional = true } rustc-hash = "1.1.0" countme = "3.0.1" +indexmap = "1.9.1" [dev-dependencies] rome_js_parser = { path = "../rome_js_parser"} diff --git a/crates/rome_formatter/src/buffer.rs b/crates/rome_formatter/src/buffer.rs index 75742f1636a..6e586bcc2bc 100644 --- a/crates/rome_formatter/src/buffer.rs +++ b/crates/rome_formatter/src/buffer.rs @@ -1,5 +1,8 @@ use super::{write, Arguments, FormatElement}; +use crate::format_element::Interned; +use crate::prelude::LineMode; use crate::{Format, FormatResult, FormatState}; +use rustc_hash::FxHashMap; use std::any::{Any, TypeId}; use std::fmt::Debug; use std::ops::{Deref, DerefMut}; @@ -428,6 +431,177 @@ where } } +/// A Buffer that removes any soft line breaks. +/// +/// * Removes [`lines`](FormatElement::Line) with the mode [`Soft`](LineMode::Soft). +/// * Replaces [`lines`](FormatElement::Line) with the mode [`Soft`](LineMode::SoftOrSpace) with a [`Space`](FormatElement::Space) +/// +/// # Examples +/// +/// ``` +/// use rome_formatter::prelude::*; +/// use rome_formatter::{format, write}; +/// +/// # fn main() -> FormatResult<()> { +/// use rome_formatter::{RemoveSoftLinesBuffer, SimpleFormatContext, VecBuffer}; +/// use rome_formatter::prelude::format_with; +/// let formatted = format!( +/// SimpleFormatContext::default(), +/// [format_with(|f| { +/// let mut buffer = RemoveSoftLinesBuffer::new(f); +/// +/// write!( +/// buffer, +/// [ +/// text("The next soft line or space gets replaced by a space"), +/// soft_line_break_or_space(), +/// text("and the line here"), +/// soft_line_break(), +/// text("is removed entirely.") +/// ] +/// ) +/// })] +/// )?; +/// +/// assert_eq!( +/// formatted.document().as_ref(), +/// &[ +/// FormatElement::Text(Text::Static { text: "The next soft line or space gets replaced by a space" }), +/// FormatElement::Space, +/// FormatElement::Text(Text::Static { text: "and the line here" }), +/// FormatElement::Text(Text::Static { text: "is removed entirely." }) +/// ] +/// ); +/// +/// # Ok(()) +/// # } +/// ``` +pub struct RemoveSoftLinesBuffer<'a, Context> { + inner: &'a mut dyn Buffer, + + /// Caches the interned elements after the soft line breaks have been removed. + /// + /// The `key` is the [Interned] element as it has been passed to [Self::write_element] or the child of another + /// [Interned] element. The `value` is the matching document of the key where all soft line breaks have been removed. + /// + /// It's fine to not snapshot the cache. The worst that can happen is that it holds on interned elements + /// that are now unused. But there's little harm in that and the cache is cleaned when dropping the buffer. + interned_cache: FxHashMap, +} + +impl<'a, Context> RemoveSoftLinesBuffer<'a, Context> { + /// Creates a new buffer that removes the soft line breaks before writing them into `buffer`. + pub fn new(inner: &'a mut dyn Buffer) -> Self { + Self { + inner, + interned_cache: FxHashMap::default(), + } + } + + /// Removes the soft line breaks from an interned element. + fn clean_interned(&mut self, interned: &Interned) -> Interned { + clean_interned(interned, &mut self.interned_cache) + } +} + +// Extracted to function to avoid monomorphization +fn clean_interned( + interned: &Interned, + interned_cache: &mut FxHashMap, +) -> Interned { + match interned_cache.get(interned) { + Some(cleaned) => cleaned.clone(), + None => { + // Find the first soft line break element or interned element that must be changed + let result = interned + .iter() + .enumerate() + .find_map(|(index, element)| match element { + FormatElement::Line(LineMode::Soft | LineMode::SoftOrSpace) => { + let mut cleaned = Vec::new(); + cleaned.extend_from_slice(&interned[..index]); + Some((cleaned, &interned[index..])) + } + FormatElement::Interned(inner) => { + let cleaned_inner = clean_interned(inner, interned_cache); + + if &cleaned_inner != inner { + let mut cleaned = Vec::with_capacity(interned.len()); + cleaned.extend_from_slice(&interned[..index]); + cleaned.push(FormatElement::Interned(cleaned_inner)); + Some((cleaned, &interned[index + 1..])) + } else { + None + } + } + + _ => None, + }); + + let result = match result { + // Copy the whole interned buffer so that becomes possible to change the necessary elements. + Some((mut cleaned, rest)) => { + for element in rest { + let element = match element { + FormatElement::Line(LineMode::Soft) => continue, + FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space, + FormatElement::Interned(interned) => { + FormatElement::Interned(clean_interned(interned, interned_cache)) + } + element => element.clone(), + }; + cleaned.push(element) + } + + Interned::new(cleaned) + } + // No change necessary, return existing interned element + None => interned.clone(), + }; + + interned_cache.insert(interned.clone(), result.clone()); + result + } + } +} + +impl Buffer for RemoveSoftLinesBuffer<'_, Context> { + type Context = Context; + + fn write_element(&mut self, element: FormatElement) -> FormatResult<()> { + let element = match element { + FormatElement::Line(LineMode::Soft) => return Ok(()), + FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space, + FormatElement::Interned(interned) => { + FormatElement::Interned(self.clean_interned(&interned)) + } + element => element, + }; + + self.inner.write_element(element) + } + + fn elements(&self) -> &[FormatElement] { + self.inner.elements() + } + + fn state(&self) -> &FormatState { + self.inner.state() + } + + fn state_mut(&mut self) -> &mut FormatState { + self.inner.state_mut() + } + + fn snapshot(&self) -> BufferSnapshot { + self.inner.snapshot() + } + + fn restore_snapshot(&mut self, snapshot: BufferSnapshot) { + self.inner.restore_snapshot(snapshot) + } +} + pub trait BufferExtensions: Buffer + Sized { /// Returns a new buffer that calls the passed inspector for every element that gets written to the output #[must_use] diff --git a/crates/rome_formatter/src/format_element.rs b/crates/rome_formatter/src/format_element.rs index e289a1c1634..2d40b160215 100644 --- a/crates/rome_formatter/src/format_element.rs +++ b/crates/rome_formatter/src/format_element.rs @@ -335,7 +335,7 @@ impl BestFitting { /// ## Safety /// The slice must contain at least two variants. #[doc(hidden)] - pub(crate) unsafe fn from_vec_unchecked(variants: Vec>) -> Self { + pub unsafe fn from_vec_unchecked(variants: Vec>) -> Self { debug_assert!( variants.len() >= 2, "Requires at least the least expanded and most expanded variants" diff --git a/crates/rome_formatter/src/lib.rs b/crates/rome_formatter/src/lib.rs index 68e86f5dbab..839f82eacb6 100644 --- a/crates/rome_formatter/src/lib.rs +++ b/crates/rome_formatter/src/lib.rs @@ -47,7 +47,10 @@ use crate::format_element::document::Document; use crate::printed_tokens::PrintedTokens; use crate::printer::{Printer, PrinterOptions}; pub use arguments::{Argument, Arguments}; -pub use buffer::{Buffer, BufferExtensions, BufferSnapshot, Inspect, PreambleBuffer, VecBuffer}; +pub use buffer::{ + Buffer, BufferExtensions, BufferSnapshot, Inspect, PreambleBuffer, RemoveSoftLinesBuffer, + VecBuffer, +}; pub use builders::BestFitting; use crate::builders::syntax_token_cow_slice; @@ -565,6 +568,14 @@ pub enum FormatError { /// In case printing the document failed because it has an invalid structure. InvalidDocument(InvalidDocumentError), + + /// Formatting failed because some content encountered a situation where a layout + /// choice by an enclosing [`Format`] resulted in a poor layout for a child [`Format`]. + /// + /// It's up to an enclosing [`Format`] to handle the error and pick another layout. + /// This error should not be raised if there's no outer [`Format`] handling the poor layout error, + /// avoiding that formatting of the whole document fails. + PoorLayout, } impl std::fmt::Display for FormatError { @@ -576,6 +587,9 @@ impl std::fmt::Display for FormatError { "formatting range {input:?} is larger than syntax tree {tree:?}" ), FormatError::InvalidDocument(error) => std::write!(fmt, "Invalid document: {error}\n\n This is an internal Rome error. Please report if necessary."), + FormatError::PoorLayout => { + std::write!(fmt, "Poor layout: The formatter wasn't able to pick a good layout for your document. This is an internal Rome error. Please report if necessary.") + } } } } @@ -1479,6 +1493,30 @@ impl FormatState { } } + #[cfg(not(debug_assertions))] + #[inline] + pub fn set_token_tracking_disabled(&mut self, _: bool) {} + + /// Disables or enables token tracking for a portion of the code. + /// + /// It can be useful to disable the token tracking when it is necessary to re-format a node with different parameters. + #[cfg(debug_assertions)] + pub fn set_token_tracking_disabled(&mut self, enabled: bool) { + self.printed_tokens.set_disabled(enabled) + } + + #[cfg(not(debug_assertions))] + #[inline] + pub fn is_token_tracking_disabled(&self) -> bool { + false + } + + /// Returns `true` if token tracking is currently disabled. + #[cfg(debug_assertions)] + pub fn is_token_tracking_disabled(&self) -> bool { + self.printed_tokens.is_disabled() + } + /// Asserts in debug builds that all tokens have been printed. #[inline] pub fn assert_formatted_all_tokens( @@ -1500,7 +1538,7 @@ where pub fn snapshot(&self) -> FormatStateSnapshot { FormatStateSnapshot { #[cfg(debug_assertions)] - printed_tokens: self.printed_tokens.clone(), + printed_tokens: self.printed_tokens.snapshot(), } } @@ -1512,7 +1550,7 @@ where cfg_if::cfg_if! { if #[cfg(debug_assertions)] { - self.printed_tokens = printed_tokens; + self.printed_tokens.restore(printed_tokens); } } } @@ -1520,5 +1558,5 @@ where pub struct FormatStateSnapshot { #[cfg(debug_assertions)] - printed_tokens: PrintedTokens, + printed_tokens: printed_tokens::PrintedTokensSnapshot, } diff --git a/crates/rome_formatter/src/printed_tokens.rs b/crates/rome_formatter/src/printed_tokens.rs index bf66c11c854..1e48f16c7b8 100644 --- a/crates/rome_formatter/src/printed_tokens.rs +++ b/crates/rome_formatter/src/printed_tokens.rs @@ -1,5 +1,5 @@ +use indexmap::IndexSet; use rome_rowan::{Direction, Language, SyntaxNode, SyntaxToken, TextSize}; -use std::collections::BTreeSet; /// Tracks the ranges of the formatted (including replaced or tokens formatted as verbatim) tokens. /// @@ -8,7 +8,14 @@ use std::collections::BTreeSet; #[derive(Debug, Clone, Default)] pub struct PrintedTokens { /// Key: Start of a token's range - offsets: BTreeSet, + offsets: IndexSet, + disabled: bool, +} + +#[derive(Copy, Clone)] +pub struct PrintedTokensSnapshot { + len: usize, + disabled: bool, } impl PrintedTokens { @@ -17,6 +24,10 @@ impl PrintedTokens { /// ## Panics /// If this token has been formatted before. pub fn track_token(&mut self, token: &SyntaxToken) { + if self.disabled { + return; + } + let range = token.text_trimmed_range(); if !self.offsets.insert(range.start()) { @@ -24,36 +35,47 @@ impl PrintedTokens { } } + /// Enables or disables the assertion tracking + pub(crate) fn set_disabled(&mut self, disabled: bool) { + self.disabled = disabled; + } + + pub(crate) fn is_disabled(&self) -> bool { + self.disabled + } + + pub(crate) fn snapshot(&self) -> PrintedTokensSnapshot { + PrintedTokensSnapshot { + len: self.offsets.len(), + disabled: self.disabled, + } + } + + pub(crate) fn restore(&mut self, snapshot: PrintedTokensSnapshot) { + let PrintedTokensSnapshot { len, disabled } = snapshot; + + self.offsets.truncate(len); + self.disabled = disabled + } + /// Asserts that all tokens of the passed in node have been tracked /// /// ## Panics /// If any descendant token of `root` hasn't been tracked pub fn assert_all_tracked(&self, root: &SyntaxNode) { - let mut descendants = root.descendants_tokens(Direction::Next); - let mut offsets = self.offsets.iter(); - - loop { - match (descendants.next(), offsets.next()) { - (Some(descendant), Some(offset)) => match descendant.text_trimmed_range().start() { - descendant_offset if descendant_offset < *offset => { - panic!("token has not been seen by the formatter: {descendant:#?}.\ + let mut offsets = self.offsets.clone(); + + for token in root.descendants_tokens(Direction::Next) { + if !offsets.remove(&token.text_trimmed_range().start()) { + panic!("token has not been seen by the formatter: {token:#?}.\ \nUse `format_replaced` if you want to replace a token from the formatted output.\ \nUse `format_removed` if you want to remove a token from the formatted output.\n\ - parent: {:#?}", descendant.parent()) - } - descendant_offset if descendant_offset > *offset => { - panic!("tracked offset {offset:?} doesn't match any token of {root:#?}. Have you passed a token from another tree?"); - } - _ => {} - }, - (Some(descendant), None) => { - panic!("token has not been seen by the formatter: {descendant:#?}.\n Use `formatter.format_replaced` if you intentionally remove or replace a token from the formatted output.") - } - (None, Some(offset)) => { - panic!("tracked offset {offset:?} doesn't match any token of {root:#?}. Have you passed a token from another tree?"); - } - (None, None) => break, - }; + parent: {:#?}", token.parent()) + } + } + + for offset in offsets { + panic!("tracked offset {offset:?} doesn't match any token of {root:#?}. Have you passed a token from another tree?"); } } } diff --git a/crates/rome_formatter/src/printer/printer_options/mod.rs b/crates/rome_formatter/src/printer/printer_options/mod.rs index d769046bdcd..1f78dd59a72 100644 --- a/crates/rome_formatter/src/printer/printer_options/mod.rs +++ b/crates/rome_formatter/src/printer/printer_options/mod.rs @@ -23,13 +23,6 @@ impl PrintWidth { pub fn new(width: u32) -> Self { Self(width) } - - /// Returns a print width that guarantees that any content, regardless of its width, fits on the line. - /// - /// This has the effect that the printer never prints a line break for any soft line break. - pub fn infinite() -> Self { - Self(u32::MAX) - } } impl Default for PrintWidth { diff --git a/crates/rome_js_formatter/src/context.rs b/crates/rome_js_formatter/src/context.rs index 53655f227d9..c374aed0421 100644 --- a/crates/rome_js_formatter/src/context.rs +++ b/crates/rome_js_formatter/src/context.rs @@ -1,9 +1,10 @@ use crate::comments::{FormatJsLeadingComment, JsCommentStyle, JsComments}; use rome_formatter::printer::PrinterOptions; use rome_formatter::{ - CstFormatContext, FormatContext, FormatOptions, IndentStyle, LineWidth, TransformSourceMap, + CstFormatContext, FormatContext, FormatElement, FormatOptions, IndentStyle, LineWidth, + TransformSourceMap, }; -use rome_js_syntax::{JsLanguage, SourceType}; +use rome_js_syntax::{JsAnyFunctionBody, JsLanguage, SourceType}; use std::fmt; use std::fmt::Debug; use std::rc::Rc; @@ -16,6 +17,28 @@ pub struct JsFormatContext { /// The comments of the nodes and tokens in the program. comments: Rc, + /// Stores the formatted content of one function body. + /// + /// Used during formatting of call arguments where function expressions and arrow function expressions + /// are formatted a second time if they are the first or last call argument. + /// + /// Caching the body in the call arguments formatting is important. It minimises the cases + /// where the algorithm is quadratic, in case the function or arrow expression contains another + /// call expression with a function or call expression as first or last argument. + /// + /// It's sufficient to only store a single cached body to cover the vast majority of cases + /// (there's no exception in any of our tests nor benchmark tests). The only case not covered is when + /// a parameter has an initializer that contains a call expression: + /// + /// ```javascript + /// test(( + /// problematic = test(() => body) + /// ) => {}); + /// ``` + /// + /// This should be rare enough for us not to care about it. + cached_function_body: Option<(JsAnyFunctionBody, FormatElement)>, + source_map: Option, } @@ -24,10 +47,41 @@ impl JsFormatContext { Self { options, comments: Rc::new(comments), + cached_function_body: None, source_map: None, } } + /// Returns the formatted content for the passed function body if it is cached or `None` if the currently + /// cached content belongs to another function body or the cache is empty. + /// + /// See [JsFormatContext::cached_function_body] for more in depth documentation. + pub(crate) fn get_cached_function_body( + &self, + body: &JsAnyFunctionBody, + ) -> Option { + self.cached_function_body + .as_ref() + .and_then(|(expected_body, formatted)| { + if expected_body == body { + Some(formatted.clone()) + } else { + None + } + }) + } + + /// Sets the currently cached formatted function body. + /// + /// See [JsFormatContext::cached_function_body] for more in depth documentation. + pub(crate) fn set_cached_function_body( + &mut self, + body: &JsAnyFunctionBody, + formatted: FormatElement, + ) { + self.cached_function_body = Some((body.clone(), formatted)) + } + pub fn with_source_map(mut self, source_map: Option) -> Self { self.source_map = source_map; self diff --git a/crates/rome_js_formatter/src/js/bindings/parameters.rs b/crates/rome_js_formatter/src/js/bindings/parameters.rs index 781d676230f..e2725a21760 100644 --- a/crates/rome_js_formatter/src/js/bindings/parameters.rs +++ b/crates/rome_js_formatter/src/js/bindings/parameters.rs @@ -1,11 +1,11 @@ use crate::prelude::*; use rome_formatter::{write, CstFormatContext}; -use crate::js::expressions::call_arguments::is_test_call_expression; use crate::js::lists::parameter_list::{ AnyParameter, FormatJsAnyParameterList, JsAnyParameterList, }; +use crate::utils::test_call::is_test_call_expression; use rome_js_syntax::{ JsAnyConstructorParameter, JsAnyFormalParameter, JsCallExpression, JsConstructorParameters, JsParameters, JsSyntaxKind, JsSyntaxToken, TsType, diff --git a/crates/rome_js_formatter/src/js/declarations/function_declaration.rs b/crates/rome_js_formatter/src/js/declarations/function_declaration.rs index 279afab1531..c9abc172bc6 100644 --- a/crates/rome_js_formatter/src/js/declarations/function_declaration.rs +++ b/crates/rome_js_formatter/src/js/declarations/function_declaration.rs @@ -1,6 +1,8 @@ use crate::prelude::*; -use rome_formatter::write; +use crate::js::expressions::call_arguments::GroupedCallArgumentLayout; +use crate::utils::function_body::{FormatMaybeCachedFunctionBody, FunctionBodyCacheMode}; +use rome_formatter::{write, RemoveSoftLinesBuffer}; use rome_js_syntax::{ JsAnyBinding, JsFunctionBody, JsFunctionDeclaration, JsFunctionExportDefaultDeclaration, JsFunctionExpression, JsParameters, JsSyntaxToken, TsAnyReturnType, @@ -25,6 +27,12 @@ declare_node_union! { TsDeclareFunctionDeclaration } +#[derive(Copy, Clone, Debug, Default)] +pub struct FormatFunctionOptions { + pub call_argument_layout: Option, + pub body_cache_mode: FunctionBodyCacheMode, +} + impl FormatFunction { fn async_token(&self) -> Option { match self { @@ -113,10 +121,20 @@ impl FormatFunction { FormatFunction::TsDeclareFunctionDeclaration(_) => None, }) } -} -impl Format for FormatFunction { - fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> { + /// Formats the function with the specified `options`. + /// + /// # Errors + /// + /// Returns [`FormatError::PoorLayout`] if [`call_argument_layout`](FormatFunctionOptions::call_argument_layout] is `Some` + /// and the function parameters contain some content that [*force a group to break*](FormatElements::will_break). + /// + /// This error is handled by [FormatJsCallArguments]. + pub(crate) fn fmt_with_options( + &self, + f: &mut JsFormatter, + options: &FormatFunctionOptions, + ) -> FormatResult<()> { if let Some(async_token) = self.async_token() { write!(f, [async_token.format(), space()])?; } @@ -141,6 +159,24 @@ impl Format for FormatFunction { write!(f, [type_parameters.format()])?; + let format_parameters = format_with(|f: &mut JsFormatter| { + if options.call_argument_layout.is_some() { + let mut buffer = RemoveSoftLinesBuffer::new(f); + + let mut recording = buffer.start_recording(); + write!(recording, [parameters.format()])?; + let recorded = recording.stop(); + + if recorded.will_break() { + return Err(FormatError::PoorLayout); + } + } else { + parameters.format().fmt(f)?; + } + + Ok(()) + }); + write!( f, [group(&format_with(|f| { @@ -156,23 +192,39 @@ impl Format for FormatFunction { )?; if group_parameters { - write!(f, [group(¶meters.format())])?; + write!(f, [group(&format_parameters)])?; } else { - write!(f, [parameters.format()])?; + write!(f, [format_parameters])?; } - write![f, [format_return_type_annotation]] + write!(f, [format_return_type_annotation]) }))] )?; if let Some(body) = self.body()? { - write!(f, [space(), body.format()])?; + write!( + f, + [ + space(), + FormatMaybeCachedFunctionBody { + body: &body.into(), + mode: options.body_cache_mode + } + ] + )?; } Ok(()) } } +impl Format for FormatFunction { + fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> { + self.fmt_with_options(f, &FormatFunctionOptions::default())?; + Ok(()) + } +} + /// Returns `true` if the function parameters should be grouped. /// Grouping the parameters has the effect that the return type will break first. pub(crate) fn should_group_function_parameters( diff --git a/crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs b/crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs index 27d633b36e4..f3fc43b106a 100644 --- a/crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs +++ b/crates/rome_js_formatter/src/js/expressions/arrow_function_expression.rs @@ -1,11 +1,15 @@ use crate::prelude::*; -use rome_formatter::{format_args, write, CstFormatContext, FormatRuleWithOptions}; +use rome_formatter::{ + format_args, write, CstFormatContext, FormatRuleWithOptions, RemoveSoftLinesBuffer, +}; use std::iter::once; +use crate::js::expressions::call_arguments::GroupedCallArgumentLayout; use crate::parentheses::{ is_binary_like_left_or_right, is_callee, is_conditional_test, update_or_lower_expression_needs_parentheses, NeedsParentheses, }; +use crate::utils::function_body::{FormatMaybeCachedFunctionBody, FunctionBodyCacheMode}; use crate::utils::{ resolve_left_most_expression, AssignmentLikeLayout, JsAnyBinaryLikeLeftExpression, }; @@ -16,16 +20,23 @@ use rome_js_syntax::{ }; use rome_rowan::SyntaxResult; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Copy, Clone, Default)] pub struct FormatJsArrowFunctionExpression { - assignment_layout: Option, + options: FormatJsArrowFunctionExpressionOptions, +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct FormatJsArrowFunctionExpressionOptions { + pub assignment_layout: Option, + pub call_arg_layout: Option, + pub body_cache_mode: FunctionBodyCacheMode, } impl FormatRuleWithOptions for FormatJsArrowFunctionExpression { - type Options = Option; + type Options = FormatJsArrowFunctionExpressionOptions; fn with_options(mut self, options: Self::Options) -> Self { - self.assignment_layout = options; + self.options = options; self } } @@ -36,11 +47,8 @@ impl FormatNodeRule for FormatJsArrowFunctionExpressi node: &JsArrowFunctionExpression, f: &mut JsFormatter, ) -> FormatResult<()> { - let layout = ArrowFunctionLayout::for_arrow( - node.clone(), - f.context().comments(), - self.assignment_layout, - )?; + let layout = + ArrowFunctionLayout::for_arrow(node.clone(), f.context().comments(), &self.options)?; match layout { ArrowFunctionLayout::Chain(chain) => { @@ -56,7 +64,7 @@ impl FormatNodeRule for FormatJsArrowFunctionExpressi write!( f, [ - format_signature(&arrow), + format_signature(&arrow, self.options.call_arg_layout.is_some()), space(), arrow.fat_arrow_token().format() ] @@ -132,27 +140,43 @@ impl FormatNodeRule for FormatJsArrowFunctionExpressi _ => false, }; + let format_body = FormatMaybeCachedFunctionBody { + body: &body, + mode: self.options.body_cache_mode, + }; + if body_has_soft_line_break && !should_add_parens && !body_has_leading_line_comment { - write![f, [format_signature, space(), body.format()]] + write![f, [format_signature, space(), format_body]] } else { + let is_last_call_arg = matches!( + self.options.call_arg_layout, + Some(GroupedCallArgumentLayout::GroupedLastArgument) + ); + write!( f, [ format_signature, - group(&soft_line_indent_or_space(&format_with(|f| { - if should_add_parens { - write!(f, [if_group_fits_on_line(&text("("))])?; - } - - write!(f, [body.format()])?; - - if should_add_parens { - write!(f, [if_group_fits_on_line(&text(")"))])?; - } - - Ok(()) - }))) + group(&format_args![ + soft_line_indent_or_space(&format_with(|f| { + if should_add_parens { + write!(f, [if_group_fits_on_line(&text("("))])?; + } + + write!(f, [format_body])?; + + if should_add_parens { + write!(f, [if_group_fits_on_line(&text(")"))])?; + } + + Ok(()) + })), + is_last_call_arg.then_some(format_args![ + if_group_breaks(&text(",")), + soft_line_break() + ]) + ]) ] ) } @@ -174,14 +198,27 @@ impl FormatNodeRule for FormatJsArrowFunctionExpressi } } -/// writes the arrow function type parameters, parameters, and return type annotation -fn format_signature(arrow: &JsArrowFunctionExpression) -> impl Format + '_ { - format_with(|f| { +/// Writes the arrow function type parameters, parameters, and return type annotation. +/// +/// Formats the parameters and return type annotation without any soft line breaks if `is_first_or_last_call_argument` is `true` +/// so that the parameters and return type are kept on the same line. +/// +/// # Errors +/// +/// Returns [`FormatError::PoorLayout`] if `is_first_or_last_call_argument` is `true` but the parameters +/// or return type annotation contain any content that forces a [*group to break](FormatElements::will_break). +/// +/// This error gets captured by [FormatJsCallArguments]. +fn format_signature( + arrow: &JsArrowFunctionExpression, + is_first_or_last_call_argument: bool, +) -> impl Format + '_ { + format_with(move |f| { if let Some(async_token) = arrow.async_token() { write!(f, [async_token.format(), space()])?; } - let format_parameters = format_with(|f| { + let format_parameters = format_with(|f: &mut JsFormatter| { write!(f, [arrow.type_parameters().format()])?; match arrow.parameters()? { @@ -201,10 +238,33 @@ fn format_signature(arrow: &JsArrowFunctionExpression) -> impl Format, + options: FormatJsArrowFunctionExpressionOptions, /// Whether the group wrapping the signatures should be expanded or not. expand_signatures: bool, @@ -315,14 +374,13 @@ impl Format for ArrowChain { head, tail, expand_signatures, - assignment_layout, .. } = self; let head_parent = head.syntax().parent(); let tail_body = tail.body()?; - let is_assignment_rhs = assignment_layout.is_some(); + let is_assignment_rhs = self.options.assignment_layout.is_some(); let is_callee = head_parent .as_ref() @@ -339,7 +397,7 @@ impl Format for ArrowChain { let break_before_chain = (is_callee && body_on_separate_line) || matches!( - assignment_layout, + self.options.assignment_layout, Some(AssignmentLikeLayout::ChainTailArrowFunction) ); @@ -354,7 +412,7 @@ impl Format for ArrowChain { f, [ format_leading_comments(arrow.syntax()), - format_signature(arrow) + format_signature(arrow, self.options.call_arg_layout.is_some()) ] )?; @@ -382,6 +440,11 @@ impl Format for ArrowChain { }); let format_tail_body_inner = format_with(|f| { + let format_tail_body = FormatMaybeCachedFunctionBody { + body: &tail_body, + mode: self.options.body_cache_mode, + }; + // Ensure that the parens of sequence expressions end up on their own line if the // body breaks if matches!( @@ -392,12 +455,12 @@ impl Format for ArrowChain { f, [group(&format_args![ text("("), - soft_block_indent(&tail_body.format()), + soft_block_indent(&format_tail_body), text(")") ])] ) } else { - write!(f, [tail_body.format()]) + write!(f, [format_tail_body]) } }); @@ -450,7 +513,7 @@ impl ArrowFunctionLayout { fn for_arrow( arrow: JsArrowFunctionExpression, comments: &JsComments, - assignment_layout: Option, + options: &FormatJsArrowFunctionExpressionOptions, ) -> SyntaxResult { let mut head = None; let mut middle = Vec::new(); @@ -461,7 +524,11 @@ impl ArrowFunctionLayout { match current.body()? { JsAnyFunctionBody::JsAnyExpression(JsAnyExpression::JsArrowFunctionExpression( next, - )) if !comments.is_suppressed(next.syntax()) => { + )) if matches!( + options.call_arg_layout, + None | Some(GroupedCallArgumentLayout::GroupedLastArgument) + ) && !comments.is_suppressed(next.syntax()) => + { should_break = should_break || should_break_chain(¤t)?; if head.is_none() { @@ -480,7 +547,7 @@ impl ArrowFunctionLayout { middle, tail: current, expand_signatures: should_break, - assignment_layout, + options: *options, }), } } diff --git a/crates/rome_js_formatter/src/js/expressions/call_arguments.rs b/crates/rome_js_formatter/src/js/expressions/call_arguments.rs index f6dcb0f4bc4..68e4909b4b2 100644 --- a/crates/rome_js_formatter/src/js/expressions/call_arguments.rs +++ b/crates/rome_js_formatter/src/js/expressions/call_arguments.rs @@ -1,14 +1,19 @@ -use crate::js::expressions::arrow_function_expression::is_multiline_template_starting_on_same_line; +use crate::js::declarations::function_declaration::FormatFunctionOptions; +use crate::js::expressions::arrow_function_expression::{ + is_multiline_template_starting_on_same_line, FormatJsArrowFunctionExpressionOptions, +}; +use crate::js::lists::array_element_list::can_concisely_print_array_list; use crate::prelude::*; -use crate::utils::{is_call_like_expression, write_arguments_multi_line}; -use rome_formatter::{format_args, write, CstFormatContext}; +use crate::utils::function_body::FunctionBodyCacheMode; +use crate::utils::test_call::is_test_call_expression; +use crate::utils::{is_long_curried_call, write_arguments_multi_line}; +use rome_formatter::{format_args, format_element, write, VecBuffer}; use rome_js_syntax::{ - JsAnyCallArgument, JsAnyExpression, JsAnyFunctionBody, JsAnyLiteralExpression, JsAnyName, - JsAnyStatement, JsArrayExpression, JsArrowFunctionExpression, JsCallArgumentList, - JsCallArguments, JsCallArgumentsFields, JsCallExpression, JsExpressionStatement, - TsReferenceType, + JsAnyCallArgument, JsAnyExpression, JsAnyFunctionBody, JsAnyLiteralExpression, JsAnyStatement, + JsCallArgumentList, JsCallArguments, JsCallArgumentsFields, JsCallExpression, + JsExpressionStatement, JsFunctionExpression, JsLanguage, TsAnyReturnType, TsType, }; -use rome_rowan::{AstSeparatedList, SyntaxResult, SyntaxTokenText}; +use rome_rowan::{AstSeparatedElement, AstSeparatedList, SyntaxResult}; #[derive(Debug, Clone, Default)] pub struct FormatJsCallArguments; @@ -21,10 +26,7 @@ impl FormatNodeRule for FormatJsCallArguments { r_paren_token, } = node.as_fields(); - let l_paren_token = l_paren_token?; - let r_paren_token = r_paren_token?; - let arguments_len = args.len(); - if arguments_len == 0 { + if args.is_empty() { return write!( f, [ @@ -37,8 +39,20 @@ impl FormatNodeRule for FormatJsCallArguments { let call_expression = node.parent::(); - if is_commonjs_or_amd_call(node, call_expression.as_ref())? + let (is_commonjs_or_amd_call, is_test_call) = + call_expression + .as_ref() + .map_or((Ok(false), Ok(false)), |call| { + ( + is_commonjs_or_amd_call(node, call), + is_test_call_expression(call), + ) + }); + + if is_commonjs_or_amd_call? || is_multiline_template_only_args(node) + || is_react_hook_with_deps_array(node, f.comments()) + || is_test_call? { return write!( f, @@ -57,178 +71,685 @@ impl FormatNodeRule for FormatJsCallArguments { ); } - let mut iter = args.iter(); - let first_argument = iter.next(); - let second_argument = iter.next(); - let third_argument = iter.next(); - - if let (Some(first_argument), Some(second_argument)) = (first_argument, second_argument) { - let first_argument = first_argument?; - let second_argument = second_argument?; - - let is_framework_test_call = - if let Some(call_expression) = node.parent::() { - let callee = call_expression.callee()?; - - is_framework_test_call(IsTestFrameworkCallPayload { - first_argument: &first_argument, - second_argument: &second_argument, - third_argument: &third_argument, - arguments_len, - callee: &callee, - })? - } else { - false - }; + let last_index = args.len().saturating_sub(1); + let mut has_empty_line = false; + + let arguments: Vec<_> = args + .elements() + .enumerate() + .map(|(index, element)| { + let leading_lines = element + .node() + .map_or(0, |node| get_lines_before(node.syntax())); + has_empty_line = has_empty_line || leading_lines > 1; + + FormatCallArgument::Default { + element, + is_last: index == last_index, + leading_lines, + } + }) + .collect(); + + if has_empty_line || is_function_composition_args(node) { + return write!( + f, + [FormatAllArgsBrokenOut { + l_paren: &l_paren_token.format(), + args: &arguments, + r_paren: &r_paren_token.format(), + expand: true, + }] + ); + } + + if let Some(group_layout) = arguments_grouped_layout(&args, f.comments()) { + write_grouped_arguments(node, arguments, group_layout, f) + } else if is_long_curried_call(call_expression.as_ref()) { + write!( + f, + [ + l_paren_token.format(), + soft_block_indent(&format_once(|f| { + write_arguments_multi_line(arguments.iter(), f) + })), + r_paren_token.format(), + ] + ) + } else { + write!( + f, + [FormatAllArgsBrokenOut { + l_paren: &l_paren_token.format(), + args: &arguments, + r_paren: &r_paren_token.format(), + expand: false + }] + ) + } + } + + fn fmt_dangling_comments(&self, _: &JsCallArguments, _: &mut JsFormatter) -> FormatResult<()> { + // Formatted inside of `fmt_fields` + Ok(()) + } +} + +/// Helper for formatting a call argument +enum FormatCallArgument { + /// Argument that has not been inspected if its formatted content breaks. + Default { + element: AstSeparatedElement, + + /// Whether this is the last element. + is_last: bool, + + /// The number of lines before this node + leading_lines: usize, + }, - let is_react_hook_with_deps_array = is_react_hook_with_deps_array( - &first_argument, - &second_argument, - f.context().comments(), - )?; + /// The argument has been formatted because a caller inspected if it [Self::will_break]. + /// + /// Allows to re-use the formatted output rather than having to call into the formatting again. + Inspected { + /// The formatted element + content: FormatResult>, - if is_framework_test_call || is_react_hook_with_deps_array { - write!(f, [l_paren_token.format(),])?; - let separated = args - .format_separated(",") - .with_trailing_separator(TrailingSeparator::Omit); + /// The separated element + element: AstSeparatedElement, + + /// The lines before this element + leading_lines: usize, + }, +} + +impl FormatCallArgument { + /// Returns `true` if this argument contains any content that forces a group to [`break`](FormatElements::will_break). + fn will_break(&mut self, f: &mut JsFormatter) -> bool { + match &self { + FormatCallArgument::Default { + element, + leading_lines, + .. + } => { + let interned = f.intern(&self); + + let breaks = match &interned { + Ok(Some(element)) => element.will_break(), + _ => false, + }; - f.join_with(space()).entries(separated).finish()?; - return write!(f, [r_paren_token.format()]); + *self = FormatCallArgument::Inspected { + content: interned, + element: element.clone(), + leading_lines: *leading_lines, + }; + breaks } - }; + FormatCallArgument::Inspected { + content: Ok(Some(result)), + .. + } => result.will_break(), + FormatCallArgument::Inspected { .. } => false, + } + } + + /// Formats the node of this argument and caches the function body. + /// + /// See [JsFormatContext::cached_function_body] + /// + /// # Panics + /// + /// If [`cache_function_body`](Self::cache_function_body) or [`will_break`](Self::will_break) has been called on this argument before. + fn cache_function_body(&mut self, f: &mut JsFormatter) { + match &self { + FormatCallArgument::Default { + element, + leading_lines, + .. + } => { + let interned = f.intern(&format_once(|f| { + self.fmt_with_cache_mode(FunctionBodyCacheMode::Cache, f)?; + Ok(()) + })); + + *self = FormatCallArgument::Inspected { + content: interned, + element: element.clone(), + leading_lines: *leading_lines, + }; + } + FormatCallArgument::Inspected { .. } => { + panic!("`cache` must be called before inspecting or formatting the element."); + } + } + } - // we now extracts the formatted version of trivias and tokens of the delimiters - // tokens on the left - let l_paren = l_paren_token.format(); - - // tokens on the right - let r_paren = r_paren_token.format(); - - let comments = f.context().comments(); - let should_group_first_argument = should_group_first_argument(&args, comments)?; - let should_group_last_argument = should_group_last_argument(&args, comments)?; - - // if the first or last groups needs grouping, then we prepare some special formatting - if should_group_first_argument || should_group_last_argument { - // We finished the "simple cases", we now need to use `best_fitting`. - // We now need to allocate a new vector with cached nodes, this is needed because - // we can't attempt to print the same node twice without incur in "printed token twice" errors. - // We also disallow the trailing separator, we are interested in doing it manually. - let mut separated: Vec<_> = args - .format_separated(",") - .with_trailing_separator(TrailingSeparator::Omit) - .map(|e| e.memoized()) - .collect(); - - let mut any_argument_breaks = false; - let mut first_last_breaks = false; - - for (index, argument) in separated.iter_mut().enumerate() { - let breaks = argument.inspect(f)?.will_break(); - - any_argument_breaks = any_argument_breaks || breaks; - - if (should_group_first_argument && index > 0) - || (should_group_last_argument && index < args.len() - 1) - { - first_last_breaks = first_last_breaks || breaks; - if breaks { - break; + fn fmt_with_cache_mode( + &self, + cache_mode: FunctionBodyCacheMode, + f: &mut JsFormatter, + ) -> FormatResult<()> { + match self { + // Re-use the cached formatted output if there is any. + FormatCallArgument::Inspected { content, .. } => match content.clone()? { + Some(element) => { + f.write_element(element)?; + Ok(()) + } + None => Ok(()), + }, + FormatCallArgument::Default { + element, is_last, .. + } => { + match element.node()? { + JsAnyCallArgument::JsAnyExpression(JsAnyExpression::JsFunctionExpression( + function, + )) => { + write!( + f, + [function.format().with_options(FormatFunctionOptions { + body_cache_mode: cache_mode, + ..FormatFunctionOptions::default() + })] + )?; + } + JsAnyCallArgument::JsAnyExpression( + JsAnyExpression::JsArrowFunctionExpression(arrow), + ) => { + write!( + f, + [arrow + .format() + .with_options(FormatJsArrowFunctionExpressionOptions { + body_cache_mode: cache_mode, + ..FormatJsArrowFunctionExpressionOptions::default() + })] + )?; + } + node => write!(f, [node.format()])?, + } + + if let Some(separator) = element.trailing_separator()? { + if *is_last { + write!(f, [format_removed(separator)]) + } else { + write!(f, [separator.format()]) } + } else if !is_last { + Err(FormatError::SyntaxError) + } else { + Ok(()) } } + } + } - let format_flat_arguments = format_with(|f| { - f.join_with(soft_line_break_or_space()) - .entries(separated.iter()) - .finish() - }); - - // We now cache them the delimiters tokens. This is needed because `[rome_formatter::best_fitting]` will try to - // print each version first - // tokens on the left - let l_paren = l_paren.memoized(); - - // tokens on the right - let r_paren = r_paren.memoized(); - - // This is the version of where all the arguments are broken out - let all_arguments_expanded = format_with(|f| { - // this formatting structure replicates what we have inside the `format_delimited` - // function, but here we use a different way to print the trailing separator - write!( - f, - [group(&format_args![ - l_paren, - soft_block_indent(&format_with(|f| { - write_arguments_multi_line(separated.iter(), f) - })), - r_paren - ]) - .should_expand(true)] - ) - }); - - if first_last_breaks { - return write!(f, [all_arguments_expanded]); + /// Returns the number of leading lines before the argument's node + fn leading_lines(&self) -> usize { + match self { + FormatCallArgument::Default { leading_lines, .. } => *leading_lines, + FormatCallArgument::Inspected { leading_lines, .. } => *leading_lines, + } + } + + /// Returns the [`separated element`](AstSeparatedElement) of this argument. + fn element(&self) -> &AstSeparatedElement { + match self { + FormatCallArgument::Default { element, .. } => element, + FormatCallArgument::Inspected { element, .. } => element, + } + } +} + +impl Format for FormatCallArgument { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + self.fmt_with_cache_mode(FunctionBodyCacheMode::default(), f)?; + Ok(()) + } +} + +/// Writes the function arguments, and groups the first or last argument depending on `group_layout`. +fn write_grouped_arguments( + call_arguments: &JsCallArguments, + mut arguments: Vec, + group_layout: GroupedCallArgumentLayout, + f: &mut JsFormatter, +) -> FormatResult<()> { + let l_paren_token = call_arguments.l_paren_token(); + let r_paren_token = call_arguments.r_paren_token(); + + let grouped_breaks = { + let (grouped_arg, other_args) = match group_layout { + GroupedCallArgumentLayout::GroupedFirstArgument => { + let (first, tail) = arguments.split_at_mut(1); + (&mut first[0], tail) + } + GroupedCallArgumentLayout::GroupedLastArgument => { + let end_index = arguments.len().saturating_sub(1); + let (head, last) = arguments.split_at_mut(end_index); + (&mut last[0], head) } + }; - let edge_arguments_do_not_break = format_with(|f| { - // `should_group_first_argument` and `should_group_last_argument` are mutually exclusive - // which means that if one is `false`, then the other is `true`. - // This means that in this branch we format the case where `should_group_first_argument`, - // in the else branch we format the case where `should_group_last_argument` is `true`. - write!(f, [l_paren])?; - if should_group_first_argument { - // special formatting of the first element - let mut iter = separated.iter(); - // SAFETY: check on the existence of at least one argument are done before - let first = iter.next().unwrap(); - f.join_with(&space()).entry(&first).entries(iter).finish()?; - } else { - // special formatting of the last element - let mut iter = separated.iter(); - // SAFETY: check on the existence of at least one argument are done before - let last = iter.next_back().unwrap(); - f.join_with(&space()).entries(iter).entry(&last).finish()?; + let non_grouped_breaks = other_args.iter_mut().any(|arg| arg.will_break(f)); + + // if any of the not grouped elements break, then fall back to the variant where + // all arguments are printed in expanded mode. + if non_grouped_breaks { + return write!( + f, + [FormatAllArgsBrokenOut { + l_paren: &l_paren_token.format(), + args: &arguments, + r_paren: &r_paren_token.format(), + expand: true + }] + ); + } + + match grouped_arg.element().node()? { + JsAnyCallArgument::JsAnyExpression(JsAnyExpression::JsArrowFunctionExpression(_)) => { + grouped_arg.cache_function_body(f); + } + JsAnyCallArgument::JsAnyExpression(JsAnyExpression::JsFunctionExpression(function)) + if !other_args.is_empty() && !has_no_parameters(function) => + { + grouped_arg.cache_function_body(f); + } + _ => { + // Node doesn't have a function body or its a function that doesn't get re-formatted. + } + } + + grouped_arg.will_break(f) + }; + + // We now cache them the delimiters tokens. This is needed because `[rome_formatter::best_fitting]` will try to + // print each version first + // tokens on the left + let l_paren = l_paren_token.format().memoized(); + + // tokens on the right + let r_paren = r_paren_token.format().memoized(); + + // First write the most expanded variant because it needs `arguments`. + let most_expanded = { + let mut buffer = VecBuffer::new(f.state_mut()); + buffer.write_element(FormatElement::Tag(Tag::StartEntry))?; + + write!( + buffer, + [FormatAllArgsBrokenOut { + l_paren: &l_paren, + args: &arguments, + r_paren: &r_paren, + expand: true + }] + )?; + buffer.write_element(FormatElement::Tag(Tag::EndEntry))?; + + buffer.into_vec() + }; + + // Now reformat the first or last argument if they happen to be a function or arrow function expression. + // Function and arrow function expression apply a custom formatting that removes soft line breaks from the parameters, + // type parameters, and return type annotation. + // + // This implementation caches the function body of the "normal" formatted function or arrow function expression + // to avoid quadratic complexity if the functions' body contains another call expression with an arrow or function expression + // as first or last argument. + let last_index = arguments.len() - 1; + let grouped = arguments + .into_iter() + .enumerate() + .map(|(index, argument)| { + let layout = match group_layout { + GroupedCallArgumentLayout::GroupedFirstArgument if index == 0 => { + Some(GroupedCallArgumentLayout::GroupedFirstArgument) } - write!(f, [r_paren]) - }); + GroupedCallArgumentLayout::GroupedLastArgument if index == last_index => { + Some(GroupedCallArgumentLayout::GroupedLastArgument) + } + _ => None, + }; - if any_argument_breaks { - write!(f, [expand_parent()])?; + FormatGroupedArgument { + argument, + single_argument_list: last_index == 0, + layout, } + .memoized() + }) + .collect::>(); + + // Write the most flat variant with the first or last argument grouped. + let most_flat = { + let snapshot = f.state_snapshot(); + let mut buffer = VecBuffer::new(f.state_mut()); + buffer.write_element(FormatElement::Tag(Tag::StartEntry))?; + + let result = write!( + buffer, + [ + l_paren, + format_with(|f| { + f.join_with(soft_line_break_or_space()) + .entries(grouped.iter()) + .finish() + }), + r_paren + ] + ); - write!( - f, - [best_fitting![ - format_args![l_paren, format_flat_arguments, r_paren], - group(&edge_arguments_do_not_break).should_expand(true), - all_arguments_expanded - ]] - ) - } else { - write!( - f, - [group(&format_args![ - l_paren, - soft_block_indent(&format_with(|f| { - let separated = args - .format_separated(",") - .with_trailing_separator(TrailingSeparator::Omit) - .nodes_grouped(); - write_arguments_multi_line(separated, f) - })), - r_paren, - ])] - ) + // Turns out, using the grouped layout isn't a good fit because some parameters of the + // grouped function or arrow expression break. In that case, fall back to the all args expanded + // formatting. + // This back tracking is required because testing if the grouped argument breaks would also return `true` + // if any content of the function body breaks. But, as far as this is concerned, it's only interested if + // any content in the signature breaks. + if matches!(result, Err(FormatError::PoorLayout)) { + drop(buffer); + f.restore_state_snapshot(snapshot); + + let mut most_expanded_iter = most_expanded.into_iter(); + // Skip over the Start/EndEntry items. + most_expanded_iter.next(); + most_expanded_iter.next_back(); + + return f.write_elements(most_expanded_iter); } + + buffer.write_element(FormatElement::Tag(Tag::EndEntry))?; + + buffer.into_vec().into_boxed_slice() + }; + + // Write the second variant that forces the group of the first/last argument to expand. + let middle_variant = { + let mut buffer = VecBuffer::new(f.state_mut()); + + buffer.write_element(FormatElement::Tag(Tag::StartEntry))?; + + write!( + buffer, + [ + l_paren, + format_with(|f| { + let mut joiner = f.join_with(soft_line_break_or_space()); + + match group_layout { + GroupedCallArgumentLayout::GroupedFirstArgument => { + joiner.entry(&group(&grouped[0]).should_expand(true)); + joiner.entries(&grouped[1..]).finish() + } + GroupedCallArgumentLayout::GroupedLastArgument => { + let last_index = grouped.len() - 1; + joiner.entries(&grouped[..last_index]); + joiner + .entry(&group(&grouped[last_index]).should_expand(true)) + .finish() + } + } + }), + r_paren + ] + )?; + + buffer.write_element(FormatElement::Tag(Tag::EndEntry))?; + + buffer.into_vec().into_boxed_slice() + }; + + if grouped_breaks { + write!(f, [expand_parent()])?; } - fn fmt_dangling_comments(&self, _: &JsCallArguments, _: &mut JsFormatter) -> FormatResult<()> { - // Formatted inside of `fmt_fields` - Ok(()) + // SAFETY: Safe because variants is guaranteed to contain exactly 3 entries: + // * most flat + // * middle + // * most expanded + // ... and best fitting only requires the most flat/and expanded. + unsafe { + f.write_element(FormatElement::BestFitting( + format_element::BestFitting::from_vec_unchecked(vec![ + most_flat, + middle_variant, + most_expanded.into_boxed_slice(), + ]), + )) + } +} + +/// Helper for formatting the first grouped argument (see [should_group_first_argument]). +struct FormatGroupedFirstArgument<'a> { + argument: &'a FormatCallArgument, + + /// Whether this is the only argument in the argument list. + is_only: bool, +} + +impl Format for FormatGroupedFirstArgument<'_> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + use JsAnyExpression::*; + + let element = self.argument.element(); + + match element.node()? { + // Call the arrow function formatting but explicitly passes the call argument layout down + // so that the arrow function formatting removes any soft line breaks between parameters and the return type. + JsAnyCallArgument::JsAnyExpression(JsArrowFunctionExpression(arrow)) => { + with_token_tracking_disabled(f, |f| { + write!( + f, + [arrow + .format() + .with_options(FormatJsArrowFunctionExpressionOptions { + body_cache_mode: FunctionBodyCacheMode::Cached, + call_arg_layout: Some( + GroupedCallArgumentLayout::GroupedFirstArgument + ), + ..FormatJsArrowFunctionExpressionOptions::default() + })] + )?; + + match element.trailing_separator()? { + None => { + if !self.is_only { + return Err(FormatError::SyntaxError); + } + } + // The separator is added inside of the arrow function formatting + Some(separator) => { + if self.is_only { + write!(f, [format_removed(separator)])?; + } else { + write!(f, [separator.format()])?; + } + } + } + + Ok(()) + }) + } + + // For all other nodes, use the normal formatting (which already has been cached) + _ => self.argument.fmt(f), + } + } +} + +/// Helper for formatting the last grouped argument (see [should_group_last_argument]). +struct FormatGroupedLastArgument<'a> { + argument: &'a FormatCallArgument, + /// Is this the only argument in the arguments list + is_only: bool, +} + +impl Format for FormatGroupedLastArgument<'_> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + use JsAnyExpression::*; + let element = self.argument.element(); + + // For function and arrow expressions, re-format the node and pass the argument that it is the + // last grouped argument. This changes the formatting of parameters, type parameters, and return types + // to remove any soft line breaks. + match element.node()? { + JsAnyCallArgument::JsAnyExpression(JsFunctionExpression(function)) + if !self.is_only && !has_no_parameters(function) => + { + with_token_tracking_disabled(f, |f| { + write!( + f, + [function.format().with_options(FormatFunctionOptions { + body_cache_mode: FunctionBodyCacheMode::Cached, + call_argument_layout: Some( + GroupedCallArgumentLayout::GroupedLastArgument + ), + })] + )?; + + if let Some(separator) = element.trailing_separator()? { + write!(f, [format_removed(separator)])?; + } + + Ok(()) + }) + } + + JsAnyCallArgument::JsAnyExpression(JsArrowFunctionExpression(arrow)) => { + with_token_tracking_disabled(f, |f| { + write!( + f, + [arrow + .format() + .with_options(FormatJsArrowFunctionExpressionOptions { + body_cache_mode: FunctionBodyCacheMode::Cached, + call_arg_layout: Some( + GroupedCallArgumentLayout::GroupedLastArgument + ), + ..FormatJsArrowFunctionExpressionOptions::default() + })] + )?; + + if let Some(separator) = element.trailing_separator()? { + write!(f, [format_removed(separator)])?; + } + + Ok(()) + }) + } + _ => self.argument.fmt(f), + } + } +} + +/// Disable the token tracking because it is necessary to format function/arrow expressions slightly different. +fn with_token_tracking_disabled R, R>( + f: &mut JsFormatter, + callback: F, +) -> R { + let was_disabled = f.state().is_token_tracking_disabled(); + f.state_mut().set_token_tracking_disabled(true); + + let result = callback(f); + + f.state_mut().set_token_tracking_disabled(was_disabled); + + result +} + +/// Tests if `expression` has an empty parameters list. +fn has_no_parameters(expression: &JsFunctionExpression) -> bool { + match expression.parameters() { + // Use default formatting for expressions without parameters, will return `Err` anyway + Err(_) => true, + Ok(parameters) => parameters.items().is_empty(), + } +} + +/// Helper for formatting a grouped call argument (see [should_group_first_argument] and [should_group_last_argument]). +struct FormatGroupedArgument { + argument: FormatCallArgument, + + /// Whether this argument is the only argument in the argument list. + single_argument_list: bool, + + /// The layout to use for this argument. + layout: Option, +} + +impl Format for FormatGroupedArgument { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + match self.layout { + Some(GroupedCallArgumentLayout::GroupedFirstArgument) => FormatGroupedFirstArgument { + argument: &self.argument, + is_only: self.single_argument_list, + } + .fmt(f), + Some(GroupedCallArgumentLayout::GroupedLastArgument) => FormatGroupedLastArgument { + argument: &self.argument, + is_only: self.single_argument_list, + } + .fmt(f), + None => self.argument.fmt(f), + } + } +} + +struct FormatAllArgsBrokenOut<'a> { + l_paren: &'a dyn Format, + args: &'a [FormatCallArgument], + r_paren: &'a dyn Format, + expand: bool, +} + +impl<'a> Format for FormatAllArgsBrokenOut<'a> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + write!( + f, + [group(&format_args![ + self.l_paren, + soft_block_indent(&format_with(|f| { + for (index, entry) in self.args.iter().enumerate() { + if index > 0 { + match entry.leading_lines() { + 0 | 1 => write!(f, [soft_line_break_or_space()])?, + _ => write!(f, [empty_line()])?, + } + } + + write!(f, [entry])?; + } + + write!(f, [if_group_breaks(&text(","))]) + })), + self.r_paren, + ]) + .should_expand(self.expand)] + ) + } +} + +#[derive(Copy, Clone, Debug)] +pub enum GroupedCallArgumentLayout { + /// Group the first call argument. + GroupedFirstArgument, + + /// Group the last call argument. + GroupedLastArgument, +} + +fn arguments_grouped_layout( + args: &JsCallArgumentList, + comments: &JsComments, +) -> Option { + if should_group_first_argument(args, comments).unwrap_or(false) { + Some(GroupedCallArgumentLayout::GroupedFirstArgument) + } else if should_group_last_argument(args, comments).unwrap_or(false) { + Some(GroupedCallArgumentLayout::GroupedLastArgument) + } else { + None } } @@ -237,112 +758,123 @@ fn should_group_first_argument( list: &JsCallArgumentList, comments: &JsComments, ) -> SyntaxResult { - if list.len() != 2 { - return Ok(false); - } + use JsAnyExpression::*; + let mut iter = list.iter(); - // SAFETY: checked at the beginning of the function - let first = iter.next().unwrap()?; - let second = iter.next().unwrap()?; - - let is_function_like = match first.as_js_any_expression() { - Some(JsAnyExpression::JsFunctionExpression(_)) => true, - Some(JsAnyExpression::JsArrowFunctionExpression(arrow)) => { - matches!(arrow.body()?, JsAnyFunctionBody::JsFunctionBody(_)) - } - _ => false, - }; + match (iter.next(), iter.next()) { + ( + Some(Ok(JsAnyCallArgument::JsAnyExpression(first))), + Some(Ok(JsAnyCallArgument::JsAnyExpression(second))), + ) if iter.next().is_none() => { + match &first { + JsFunctionExpression(_) => {} + JsArrowFunctionExpression(arrow) => { + if !matches!(arrow.body(), Ok(JsAnyFunctionBody::JsFunctionBody(_))) { + return Ok(false); + } + } + _ => return Ok(false), + }; - let (second_arg_is_function_like, can_group) = match second.as_js_any_expression() { - Some(second_expression) => { - let second_arg_is_function_like = matches!( - &second_expression, - JsAnyExpression::JsFunctionExpression(_) - | JsAnyExpression::JsArrowFunctionExpression(_) - | JsAnyExpression::JsConditionalExpression(_) - ); - ( - second_arg_is_function_like, - could_group_expression_argument(second_expression, false, comments)?, - ) - } - None => (false, false), - }; + if matches!( + second, + JsArrowFunctionExpression(_) | JsFunctionExpression(_) | JsConditionalExpression(_) + ) { + return Ok(false); + } - Ok(!comments.has_comments(first.syntax()) - && is_function_like - && !second_arg_is_function_like - && !can_group) + Ok(!comments.has_comments(first.syntax()) + && !can_group_expression_argument(&second, false, comments)?) + } + _ => Ok(false), + } } -/// Checks if the last group requires grouping +/// Checks if the last argument should be grouped. fn should_group_last_argument( list: &JsCallArgumentList, comments: &JsComments, ) -> SyntaxResult { - let list_len = list.len(); + use JsAnyExpression::*; + let mut iter = list.iter(); let last = iter.next_back(); - let penultimate = iter.next_back(); - - if let Some(last) = last { - let last = last?; - let check_with_penultimate = if let Some(penultimate) = penultimate { - let penultimate = penultimate?; - let different_kind = last.syntax().kind() != penultimate.syntax().kind(); - - let no_array_and_arrow_function = list_len != 2 - || !JsArrayExpression::can_cast(penultimate.syntax().kind()) - || !JsArrowFunctionExpression::can_cast(last.syntax().kind()); - - // TODO implement no poor printed array - let _no_poor_printed_array = - !list_len > 1 && JsArrayExpression::can_cast(last.syntax().kind()); - different_kind && no_array_and_arrow_function - } else { - true - }; - let can_group = match &last { - JsAnyCallArgument::JsAnyExpression(expression) => { - could_group_expression_argument(expression, false, comments)? + match last { + Some(Ok(JsAnyCallArgument::JsAnyExpression(last))) => { + if comments.has_leading_comments(last.syntax()) + || comments.has_trailing_comments(last.syntax()) + { + return Ok(false); } - _ => false, - }; - Ok(!comments.has_leading_comments(last.syntax()) - && !comments.has_trailing_comments(last.syntax()) - && can_group - && check_with_penultimate) - } else { - Ok(false) + if !can_group_expression_argument(&last, false, comments)? { + return Ok(false); + } + + let penultimate = iter.next_back(); + + if let Some(Ok(penultimate)) = &penultimate { + if penultimate.syntax().kind() == last.syntax().kind() { + return Ok(false); + } + } + + match last { + JsArrayExpression(array) if list.len() > 1 => { + // Not for `useEffect` + if list.len() == 2 + && matches!( + penultimate, + Some(Ok(JsAnyCallArgument::JsAnyExpression( + JsArrowFunctionExpression(_) + ))) + ) + { + return Ok(false); + } + + if can_concisely_print_array_list(&array.elements(), comments) { + return Ok(false); + } + + Ok(true) + } + _ => Ok(true), + } + } + _ => Ok(false), } } -/// Checks if the current argument could be grouped -fn could_group_expression_argument( +/// Checks if `argument` benefits from grouping in call arguments. +fn can_group_expression_argument( argument: &JsAnyExpression, is_arrow_recursion: bool, comments: &JsComments, ) -> SyntaxResult { + use JsAnyExpression::*; + let result = match argument { - JsAnyExpression::JsObjectExpression(object_expression) => { - object_expression.members().len() > 0 + JsObjectExpression(object_expression) => { + !object_expression.members().is_empty() || comments.has_comments(object_expression.syntax()) } - JsAnyExpression::JsArrayExpression(array_expression) => { - array_expression.elements().len() > 0 + JsArrayExpression(array_expression) => { + !array_expression.elements().is_empty() || comments.has_comments(array_expression.syntax()) } - JsAnyExpression::TsTypeAssertionExpression(assertion_expression) => { - could_group_expression_argument(&assertion_expression.expression()?, false, comments)? + + TsTypeAssertionExpression(assertion_expression) => { + can_group_expression_argument(&assertion_expression.expression()?, false, comments)? } - JsAnyExpression::TsAsExpression(as_expression) => { - could_group_expression_argument(&as_expression.expression()?, false, comments)? + TsAsExpression(as_expression) => { + can_group_expression_argument(&as_expression.expression()?, false, comments)? } - JsAnyExpression::JsArrowFunctionExpression(arrow_function) => { + + JsArrowFunctionExpression(arrow_function) => { let body = arrow_function.body()?; let return_type_annotation = arrow_function.return_type_annotation(); @@ -358,66 +890,38 @@ fn could_group_expression_argument( // ); // } let can_group_type = - !return_type_annotation + return_type_annotation .and_then(|rty| rty.ty().ok()) - .map_or(false, |any_type| { - TsReferenceType::can_cast(any_type.syntax().kind()) - || if let JsAnyFunctionBody::JsFunctionBody(function_body) = &body { - function_body - .statements() - .iter() - .any(|st| matches!(st, JsAnyStatement::JsEmptyStatement(_))) - } else { - true + .map_or(true, |any_type| match any_type { + TsAnyReturnType::TsType(TsType::TsReferenceType(_)) => match &body { + JsAnyFunctionBody::JsFunctionBody(body) => { + body.statements().iter().any(|statement| { + !matches!(statement, JsAnyStatement::JsEmptyStatement(_)) + }) || comments.has_dangling_comments(body.syntax()) } + _ => false, + }, + _ => true, }); - let expression_body = match &body { - JsAnyFunctionBody::JsFunctionBody(_) => None, - JsAnyFunctionBody::JsAnyExpression(expression) => Some(expression), + let can_group_body = match &body { + JsAnyFunctionBody::JsFunctionBody(_) + | JsAnyFunctionBody::JsAnyExpression( + JsObjectExpression(_) | JsArrayExpression(_) | JsxTagExpression(_), + ) => true, + JsAnyFunctionBody::JsAnyExpression(arrow @ JsArrowFunctionExpression(_)) => { + can_group_expression_argument(arrow, true, comments)? + } + JsAnyFunctionBody::JsAnyExpression( + JsCallExpression(_) | JsConditionalExpression(_), + ) if !is_arrow_recursion => true, + _ => false, }; - let body_is_delimited = matches!(body, JsAnyFunctionBody::JsFunctionBody(_)) - || matches!( - expression_body, - Some( - JsAnyExpression::JsObjectExpression(_) - | JsAnyExpression::JsArrayExpression(_) - ) - ); - - if let Some(any_expression) = expression_body { - let is_nested_arrow_function = - if let JsAnyExpression::JsArrowFunctionExpression(arrow_function_expression) = - &any_expression - { - arrow_function_expression - .body() - .ok() - .and_then(|body| body.as_js_any_expression().cloned()) - .and_then(|body| { - could_group_expression_argument(&body, true, comments).ok() - }) - .unwrap_or(false) - } else { - false - }; - - body_is_delimited - && is_nested_arrow_function - && can_group_type - && (!is_arrow_recursion - && (is_call_like_expression(any_expression) - || matches!( - any_expression, - JsAnyExpression::JsConditionalExpression(_) - ))) - } else { - body_is_delimited && can_group_type - } + can_group_body && can_group_type } - JsAnyExpression::JsFunctionExpression(_) => true, + JsFunctionExpression(_) => true, _ => false, }; @@ -428,13 +932,8 @@ fn could_group_expression_argument( /// or amd's [`define`](https://github.com/amdjs/amdjs-api/wiki/AMD#define-function-) function. fn is_commonjs_or_amd_call( arguments: &JsCallArguments, - call: Option<&JsCallExpression>, + call: &JsCallExpression, ) -> SyntaxResult { - let call = match call { - Some(call) => call, - None => return Ok(false), - }; - let callee = call.callee()?; Ok(match callee { @@ -506,345 +1005,78 @@ fn is_multiline_template_only_args(arguments: &JsCallArguments) -> bool { /// ```js /// useMemo(() => {}, []) /// ``` -fn is_react_hook_with_deps_array( - first_argument: &JsAnyCallArgument, - second_argument: &JsAnyCallArgument, - comments: &JsComments, -) -> SyntaxResult { - if comments.has_comments(first_argument.syntax()) - || comments.has_comments(second_argument.syntax()) - { - return Ok(false); - } - - let first_expression = match first_argument { - JsAnyCallArgument::JsAnyExpression(expression) => Some(expression), - _ => None, - }; - - let first_node_matches = if let Some(JsAnyExpression::JsArrowFunctionExpression( - arrow_function, - )) = first_expression - { - let no_parameters = arrow_function.parameters()?.is_empty(); - let body = arrow_function.body()?; - let is_block = matches!(body, JsAnyFunctionBody::JsFunctionBody(_)); - - no_parameters && is_block - } else { - false - }; - - let second_node_matches = matches!(second_argument, JsAnyCallArgument::JsAnyExpression(_)); - if first_node_matches && second_node_matches { - Ok(true) - } else { - Ok(false) - } -} - -struct IsTestFrameworkCallPayload<'a> { - first_argument: &'a JsAnyCallArgument, - second_argument: &'a JsAnyCallArgument, - third_argument: &'a Option>, - arguments_len: usize, - callee: &'a JsAnyExpression, -} - -pub(crate) fn is_test_call_expression(expression: &JsCallExpression) -> SyntaxResult { - let arguments = expression.arguments()?.args(); - let mut arguments_iter = arguments.iter(); - - let result = match ( - arguments_iter.next(), - arguments_iter.next(), - arguments_iter.next(), - ) { - (Some(first_argument), Some(second_argument), third_argument) => { - is_framework_test_call(IsTestFrameworkCallPayload { - first_argument: &first_argument?, - second_argument: &second_argument?, - third_argument: &third_argument, - arguments_len: arguments.len(), - callee: &expression.callee()?, - })? - } - (_, _, _) => false, - }; - - Ok(result) -} +fn is_react_hook_with_deps_array(arguments: &JsCallArguments, comments: &JsComments) -> bool { + use JsAnyExpression::*; + let mut args = arguments.args().iter(); + + match (args.next(), args.next()) { + ( + Some(Ok(JsAnyCallArgument::JsAnyExpression(JsArrowFunctionExpression(callback)))), + Some(Ok(JsAnyCallArgument::JsAnyExpression(JsArrayExpression(deps)))), + ) if arguments.args().len() == 2 => { + if comments.has_comments(callback.syntax()) || comments.has_comments(deps.syntax()) { + return false; + } -/// This is a specialised function that checks if the current [call expression] -/// resembles a call expression usually used by a testing frameworks. -/// -/// If the [call expression] matches the criteria, a different formatting is applied. -/// -/// To evaluable the eligibility of a [call expression] to be a test framework like, -/// we need to check its [callee] and its [arguments]. -/// -/// 1. The [callee] must contain a name or a chain of names that belongs to the -/// test frameworks, for example: `test()`, `test.only()`, etc. -/// 2. The [arguments] should be at the least 2 -/// 3. The first argument has to be a string literal -/// 4. The third argument, if present, has to be a number literal -/// 5. The second argument has to be an [arrow function expression] or [function expression] -/// 6. Both function must have zero or one parameters -/// -/// [call expression]: crate::rome_js_syntax::JsCallExpression -/// [callee]: crate::rome_js_syntax::JsAnyExpression -/// [arguments]: crate::rome_js_syntax::JsCallArgumentList -/// [arrow function expression]: crate::rome_js_syntax::JsArrowFunctionExpression -/// [function expression]: crate::rome_js_syntax::JsCallArgumentList -fn is_framework_test_call(payload: IsTestFrameworkCallPayload) -> SyntaxResult { - let IsTestFrameworkCallPayload { - first_argument, - second_argument, - third_argument, - arguments_len, - callee, - } = payload; - let first_argument_expression = first_argument.as_js_any_expression(); - let second_argument_expression = second_argument.as_js_any_expression(); - let third_argument_expression = - third_argument - .as_ref() - .and_then(|third_argument| match third_argument { - Ok(argument) => argument.as_js_any_expression(), - _ => None, - }); - - let first_argument_is_literal_like = matches!( - first_argument_expression, - Some( - JsAnyExpression::JsAnyLiteralExpression( - JsAnyLiteralExpression::JsStringLiteralExpression(_) - ) | JsAnyExpression::JsTemplate(_) - ) - ); - - if first_argument_is_literal_like && contains_a_test_pattern(callee)? { - if arguments_len == 2 { - Ok(matches!( - second_argument_expression, - Some( - JsAnyExpression::JsArrowFunctionExpression(_) - | JsAnyExpression::JsFunctionExpression(_) - ) - )) - } else { - // if the third argument is not a numeric literal, we bail - // example: `it("name", () => { ... }, 2500)` - if !matches!( - third_argument_expression, - Some(JsAnyExpression::JsAnyLiteralExpression( - JsAnyLiteralExpression::JsNumberLiteralExpression(_) - )) - ) { - return Ok(false); + if !callback + .parameters() + .map_or(false, |parameters| parameters.is_empty()) + { + return false; } - let result = match second_argument_expression { - Some(JsAnyExpression::JsFunctionExpression(node)) => { - node.parameters()?.items().len() <= 1 - } - Some(JsAnyExpression::JsArrowFunctionExpression(node)) => { - let body = node.body()?; - let has_enough_parameters = node.parameters()?.len() <= 1; - matches!(body, JsAnyFunctionBody::JsFunctionBody(_)) && has_enough_parameters - } - _ => false, - }; - Ok(result) + matches!(callback.body(), Ok(JsAnyFunctionBody::JsFunctionBody(_))) } - } else { - Ok(false) - } -} - -/// This function checks if a call expressions has one of the following members: -/// - `it` -/// - `it.only` -/// - `it.skip` -/// - `describe` -/// - `describe.only` -/// - `describe.skip` -/// - `test` -/// - `test.only` -/// - `test.skip` -/// - `test.step` -/// - `test.describe` -/// - `test.describe.only` -/// - `test.describe.parallel` -/// - `test.describe.parallel.only` -/// - `test.describe.serial` -/// - `test.describe.serial.only` -/// - `skip` -/// - `xit` -/// - `xdescribe` -/// - `xtest` -/// - `fit` -/// - `fdescribe` -/// - `ftest` -/// -/// Based on this [article] -/// -/// [article]: https://craftinginterpreters.com/scanning-on-demand.html#tries-and-state-machines -fn contains_a_test_pattern(callee: &JsAnyExpression) -> SyntaxResult { - let members: Vec<_> = matches_test_call(callee)?; - - let first = members.get(0).map(|t| t.text()); - let second = members.get(1).map(|t| t.text()); - let third = members.get(2).map(|t| t.text()); - let fourth = members.get(3).map(|t| t.text()); - let fifth = members.get(4).map(|t| t.text()); - - Ok(match first { - Some("it" | "describe") => match second { - None => true, - Some("only" | "skip") => third.is_none(), - _ => false, - }, - Some("test") => match second { - None => true, - Some("only" | "skip" | "step") => third.is_none(), - Some("describe") => match third { - None => true, - Some("only") => true, - Some("parallel" | "serial") => match fourth { - None => true, - Some("only") => fifth.is_none(), - _ => false, - }, - _ => false, - }, - _ => false, - }, - Some("skip" | "xit" | "xdescribe" | "xtest" | "fit" | "fdescribe" | "ftest") => true, _ => false, - }) + } } -/// This is particular used to identify if a [JsCallExpression] has the shape -/// of a call argument coming from a test framework. +/// Tests if a call has multiple anonymous function like (arrow or function expression) arguments. /// -/// An example are call arguments coming from Mocha, Jest, etc. +/// ## Examples /// -/// ```js -/// describe("My component", () => { -/// it("should render", () => { -/// -/// }); -/// }) -/// -/// test.only("", testSomething); +/// ```javascript +/// compose(sortBy(x => x), flatten, map(x => [x, x*2])); /// ``` -/// -/// This function should accept the `callee` of [JsCallExpression] and the -/// string pattern to test against. For example "test", "test.only" -fn matches_test_call(callee: &JsAnyExpression) -> SyntaxResult> { - // this the max depth plus one, because we want to catch cases where we have test.only.WRONG - const MAX_DEPTH: u8 = 5; - let mut test_call = Vec::with_capacity(MAX_DEPTH as usize); - let mut current_node = callee.clone(); - let mut i = 0; - - while i < MAX_DEPTH { - i += 1; - current_node = match current_node { - JsAnyExpression::JsIdentifierExpression(identifier) => { - let value_token = identifier.name()?.value_token()?; - let value = value_token.token_text_trimmed(); - test_call.push(value); - break; - } - JsAnyExpression::JsStaticMemberExpression(member_expression) => { - match member_expression.member()? { - JsAnyName::JsName(name) => { - let value = name.value_token()?; - test_call.push(value.token_text_trimmed()); - member_expression.object()? - } - _ => break, - } - } - _ => break, - }; - } - test_call.reverse(); - Ok(test_call) -} - -#[cfg(test)] -mod test { - use super::contains_a_test_pattern; - use rome_diagnostics::file::FileId; - use rome_js_parser::parse; - use rome_js_syntax::{JsCallExpression, SourceType}; - use rome_rowan::AstNodeList; - - fn extract_call_expression(src: &str) -> JsCallExpression { - let source_type = SourceType::js_module(); - let result = parse(src, FileId::zero(), source_type); - let module = result - .tree() - .as_js_module() - .unwrap() - .items() - .first() - .unwrap(); - - module - .as_js_any_statement() - .unwrap() - .as_js_expression_statement() - .unwrap() - .expression() - .unwrap() - .as_js_call_expression() - .unwrap() - .clone() - } - - #[test] - fn matches_simple_call() { - let call_expression = extract_call_expression("test();"); - assert_eq!( - contains_a_test_pattern(&call_expression.callee().unwrap()), - Ok(true) - ); +fn is_function_composition_args(arguments: &JsCallArguments) -> bool { + let args = arguments.args(); - let call_expression = extract_call_expression("it();"); - assert_eq!( - contains_a_test_pattern(&call_expression.callee().unwrap()), - Ok(true) - ); + if args.len() <= 1 { + return false; } - #[test] - fn matches_static_member_expression() { - let call_expression = extract_call_expression("test.only();"); - assert_eq!( - contains_a_test_pattern(&call_expression.callee().unwrap()), - Ok(true) - ); - } + let mut has_seen_function_like = false; - #[test] - fn matches_static_member_expression_deep() { - let call_expression = extract_call_expression("test.describe.parallel.only();"); - assert_eq!( - contains_a_test_pattern(&call_expression.callee().unwrap()), - Ok(true) - ); + for arg in args.iter().flatten() { + use JsAnyExpression::*; + match arg { + JsAnyCallArgument::JsAnyExpression( + JsFunctionExpression(_) | JsArrowFunctionExpression(_), + ) => { + if has_seen_function_like { + return true; + } + has_seen_function_like = true; + } + JsAnyCallArgument::JsAnyExpression(JsCallExpression(call)) => { + if call.arguments().map_or(false, |call_arguments| { + call_arguments.args().iter().flatten().any(|arg| { + matches!( + arg, + JsAnyCallArgument::JsAnyExpression( + JsFunctionExpression(_) | JsArrowFunctionExpression(_) + ) + ) + }) + }) { + return true; + } + } + _ => { + continue; + } + } } - #[test] - fn doesnt_static_member_expression_deep() { - let call_expression = extract_call_expression("test.describe.parallel.only.AHAHA();"); - assert_eq!( - contains_a_test_pattern(&call_expression.callee().unwrap()), - Ok(false) - ); - } + false } diff --git a/crates/rome_js_formatter/src/js/expressions/function_expression.rs b/crates/rome_js_formatter/src/js/expressions/function_expression.rs index 34710226385..2e12db42500 100644 --- a/crates/rome_js_formatter/src/js/expressions/function_expression.rs +++ b/crates/rome_js_formatter/src/js/expressions/function_expression.rs @@ -1,18 +1,31 @@ use crate::prelude::*; -use crate::js::declarations::function_declaration::FormatFunction; +use crate::js::declarations::function_declaration::{FormatFunction, FormatFunctionOptions}; use crate::parentheses::{ is_callee, is_first_in_statement, is_tag, FirstInStatementMode, NeedsParentheses, }; -use rome_formatter::write; + +use rome_formatter::FormatRuleWithOptions; use rome_js_syntax::{JsFunctionExpression, JsSyntaxNode}; -#[derive(Debug, Clone, Default)] -pub struct FormatJsFunctionExpression; +#[derive(Debug, Copy, Clone, Default)] +pub struct FormatJsFunctionExpression { + options: FormatFunctionOptions, +} + +impl FormatRuleWithOptions for FormatJsFunctionExpression { + type Options = FormatFunctionOptions; + + fn with_options(mut self, options: Self::Options) -> Self { + self.options = options; + self + } +} impl FormatNodeRule for FormatJsFunctionExpression { fn fmt_fields(&self, node: &JsFunctionExpression, f: &mut JsFormatter) -> FormatResult<()> { - write![f, [FormatFunction::from(node.clone())]] + FormatFunction::from(node.clone()).fmt_with_options(f, &self.options)?; + Ok(()) } fn needs_parentheses(&self, item: &JsFunctionExpression) -> bool { diff --git a/crates/rome_js_formatter/src/js/expressions/template_element.rs b/crates/rome_js_formatter/src/js/expressions/template_element.rs index 8c2979f4d92..2bac2a48000 100644 --- a/crates/rome_js_formatter/src/js/expressions/template_element.rs +++ b/crates/rome_js_formatter/src/js/expressions/template_element.rs @@ -1,9 +1,7 @@ use crate::prelude::*; -use rome_formatter::format_element::document::Document; use rome_formatter::prelude::tag::Tag; -use rome_formatter::printer::{PrintWidth, Printer}; use rome_formatter::{ - format_args, write, CstFormatContext, FormatOptions, FormatRuleWithOptions, VecBuffer, + format_args, write, CstFormatContext, FormatRuleWithOptions, RemoveSoftLinesBuffer, }; use crate::context::TabWidth; @@ -78,32 +76,8 @@ impl Format for FormatTemplateElement { let format_inner = format_with(|f: &mut JsFormatter| match self.options.layout { TemplateElementLayout::SingleLine => { - // The goal is to print the expression on a single line, even if it exceeds the configured print width. - // - // Ideally, it would be possible to use a custom buffer that drops all soft line breaks - // (or converts them to spaces). However, this isn't straightforward with our - // nested IR (but would be with a flat ir). - // - // That's why we write the expression into a temporary buffer and print it - // with a printer that uses a print width so large, that the expression never exceeds - // the print width. - let mut buffer = VecBuffer::new(f.state_mut()); - write!(buffer, [format_expression])?; - let root = Document::from(buffer.into_vec()); - - let print_options = f - .options() - .as_print_options() - .with_print_width(PrintWidth::infinite()); - let printed = Printer::new(print_options).print(&root)?; - - write!( - f, - [dynamic_text( - printed.as_code(), - self.element.inner_syntax()?.text_trimmed_range().start() - )] - ) + let mut buffer = RemoveSoftLinesBuffer::new(f); + write!(buffer, [format_expression]) } TemplateElementLayout::Fit => { use JsAnyExpression::*; diff --git a/crates/rome_js_formatter/src/js/lists/array_element_list.rs b/crates/rome_js_formatter/src/js/lists/array_element_list.rs index 799d705118a..1e05a0e9ae6 100644 --- a/crates/rome_js_formatter/src/js/lists/array_element_list.rs +++ b/crates/rome_js_formatter/src/js/lists/array_element_list.rs @@ -24,7 +24,7 @@ impl FormatRule for FormatJsArrayElementList { type Context = JsFormatContext; fn fmt(&self, node: &JsArrayElementList, f: &mut JsFormatter) -> FormatResult<()> { - let layout = if can_print_fill(node, f.context().comments()) { + let layout = if can_concisely_print_array_list(node, f.context().comments()) { ArrayLayout::Fill } else { ArrayLayout::OnePerLine @@ -89,7 +89,10 @@ enum ArrayLayout { /// The underlying logic only allows lists of literal expressions /// with 10 or less characters, potentially wrapped in a "short" /// unary expression (+, -, ~ or !) -fn can_print_fill(list: &JsArrayElementList, comments: &JsComments) -> bool { +pub(crate) fn can_concisely_print_array_list( + list: &JsArrayElementList, + comments: &JsComments, +) -> bool { use rome_js_syntax::JsAnyArrayElement::*; use rome_js_syntax::JsAnyExpression::*; use rome_js_syntax::JsUnaryOperator::*; diff --git a/crates/rome_js_formatter/src/lib.rs b/crates/rome_js_formatter/src/lib.rs index 562643ff6f7..6fa938b375a 100644 --- a/crates/rome_js_formatter/src/lib.rs +++ b/crates/rome_js_formatter/src/lib.rs @@ -861,12 +861,9 @@ function() { // use this test check if your snippet prints as you wish, without using a snapshot fn quick_test() { let src = r#" -new Test() - .test() - .test([, 0]) - .test(); - -"#; +function test() { +return srcPipe.pipe(generator.stream).pipe(compile()).pipe(gulp.dest(out)); +}"#; let syntax = SourceType::jsx(); let tree = parse(src, FileId::zero(), syntax); let options = JsFormatOptions::new(syntax); diff --git a/crates/rome_js_formatter/src/separated.rs b/crates/rome_js_formatter/src/separated.rs index d6584a3a2d6..216d7bb0c49 100644 --- a/crates/rome_js_formatter/src/separated.rs +++ b/crates/rome_js_formatter/src/separated.rs @@ -4,6 +4,7 @@ use rome_formatter::{write, GroupId}; use rome_js_syntax::JsLanguage; use rome_rowan::{ AstNode, AstSeparatedElement, AstSeparatedList, AstSeparatedListElementsIterator, Language, + SyntaxResult, }; use std::iter::FusedIterator; @@ -17,6 +18,13 @@ pub struct FormatSeparatedElement { options: FormatSeparatedOptions, } +impl> FormatSeparatedElement { + /// Returns the node belonging to the element. + pub fn node(&self) -> SyntaxResult<&N> { + self.element.node() + } +} + impl Format for FormatSeparatedElement where for<'a> N: AstNode + AsFormat<'a>, diff --git a/crates/rome_js_formatter/src/ts/declarations/enum_declaration.rs b/crates/rome_js_formatter/src/ts/declarations/enum_declaration.rs index f952d67fc31..b2a88756948 100644 --- a/crates/rome_js_formatter/src/ts/declarations/enum_declaration.rs +++ b/crates/rome_js_formatter/src/ts/declarations/enum_declaration.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use rome_formatter::write; +use rome_formatter::{format_args, write}; use rome_js_syntax::{TsEnumDeclaration, TsEnumDeclarationFields}; @@ -29,9 +29,29 @@ impl FormatNodeRule for FormatTsEnumDeclaration { id.format(), space(), l_curly_token.format(), - group(&soft_space_or_block_indent(&members.format())), - r_curly_token.format() ] - ) + )?; + + if members.is_empty() { + write!( + f, + [group(&format_args![ + format_dangling_comments(node.syntax()), + soft_line_break() + ])] + )?; + } else { + write!(f, [block_indent(&members.format())])?; + } + + write!(f, [r_curly_token.format()]) + } + + fn fmt_dangling_comments( + &self, + _: &TsEnumDeclaration, + _: &mut JsFormatter, + ) -> FormatResult<()> { + Ok(()) } } diff --git a/crates/rome_js_formatter/src/ts/expressions/type_arguments.rs b/crates/rome_js_formatter/src/ts/expressions/type_arguments.rs index 3ea9ff9be03..24557f45aa0 100644 --- a/crates/rome_js_formatter/src/ts/expressions/type_arguments.rs +++ b/crates/rome_js_formatter/src/ts/expressions/type_arguments.rs @@ -29,14 +29,15 @@ impl FormatNodeRule for FormatTsTypeArguments { // |_________________________| // that's where we start from let is_arrow_function_variables = { - if let Some(first_argument) = ts_type_argument_list.iter().next() { - let first_argument = first_argument?; - + match ts_type_argument_list.first() { // first argument is not mapped type or object type - if !is_object_like_type(&first_argument) { + Some(Ok(ty)) if is_object_like_type(&ty) && ts_type_argument_list.len() == 1 => { + false + } + Some(Ok(ty)) => { // we then go up until we can find a potential type annotation, // meaning four levels up - let maybe_type_annotation = first_argument.syntax().ancestors().nth(4); + let maybe_type_annotation = ty.syntax().ancestors().nth(4); let initializer = maybe_type_annotation .and_then(|maybe_type_annotation| { @@ -58,20 +59,18 @@ impl FormatNodeRule for FormatTsTypeArguments { } else { false } - } else { - false } - } else { - false + + _ => false, } }; - let first_argument_can_be_hugged_or_is_null_type = ts_type_argument_list.len() == 1 - && ts_type_argument_list.iter().next().map_or(false, |node| { - node.map_or(false, |node| { - matches!(node, TsType::TsNullLiteralType(_)) || should_hug_type(&node) - }) - }); + let first_argument_can_be_hugged_or_is_null_type = match ts_type_argument_list.first() { + _ if ts_type_argument_list.len() != 1 => false, + Some(Ok(TsType::TsNullLiteralType(_))) => true, + Some(Ok(ty)) => should_hug_type(&ty), + _ => false, + }; let should_inline = !is_arrow_function_variables && (ts_type_argument_list.len() == 0 || first_argument_can_be_hugged_or_is_null_type); diff --git a/crates/rome_js_formatter/src/ts/lists/enum_member_list.rs b/crates/rome_js_formatter/src/ts/lists/enum_member_list.rs index 5c5efd577db..57d80b51227 100644 --- a/crates/rome_js_formatter/src/ts/lists/enum_member_list.rs +++ b/crates/rome_js_formatter/src/ts/lists/enum_member_list.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::utils::node_has_leading_newline; use rome_js_syntax::TsEnumMemberList; #[derive(Debug, Clone, Default)] @@ -9,14 +8,12 @@ impl FormatRule for FormatTsEnumMemberList { type Context = JsFormatContext; fn fmt(&self, node: &TsEnumMemberList, f: &mut JsFormatter) -> FormatResult<()> { - let has_newline = node_has_leading_newline(node.syntax()); + let mut joiner = f.join_nodes_with_soft_line(); - f.join_with(&if has_newline { - hard_line_break() - } else { - soft_line_break_or_space() - }) - .entries(node.format_separated(",").nodes_grouped()) - .finish() + for variant in node.format_separated(",").nodes_grouped() { + joiner.entry(variant.node()?.syntax(), &variant) + } + + joiner.finish() } } diff --git a/crates/rome_js_formatter/src/ts/lists/type_member_list.rs b/crates/rome_js_formatter/src/ts/lists/type_member_list.rs index 0519a2584f6..556f779663a 100644 --- a/crates/rome_js_formatter/src/ts/lists/type_member_list.rs +++ b/crates/rome_js_formatter/src/ts/lists/type_member_list.rs @@ -14,21 +14,28 @@ impl FormatRule for FormatTsTypeMemberList { let items = node.iter(); let last_index = items.len().saturating_sub(1); - f.join_with(&soft_line_break_or_space()) - .entries(items.enumerate().map(|(index, member)| TsTypeMemberItem { - last: index == last_index, - member, - })) - .finish() + let mut joiner = f.join_nodes_with_soft_line(); + + for (index, member) in items.enumerate() { + joiner.entry( + member.syntax(), + &TsTypeMemberItem { + last: index == last_index, + member: &member, + }, + ) + } + + joiner.finish() } } -struct TsTypeMemberItem { +struct TsTypeMemberItem<'a> { last: bool, - member: TsAnyTypeMember, + member: &'a TsAnyTypeMember, } -impl Format for TsTypeMemberItem { +impl Format for TsTypeMemberItem<'_> { fn fmt(&self, f: &mut JsFormatter) -> FormatResult<()> { let mut is_verbatim = false; diff --git a/crates/rome_js_formatter/src/utils/assignment_like.rs b/crates/rome_js_formatter/src/utils/assignment_like.rs index d580182598d..0cb63fca0ff 100644 --- a/crates/rome_js_formatter/src/utils/assignment_like.rs +++ b/crates/rome_js_formatter/src/utils/assignment_like.rs @@ -1,4 +1,5 @@ use crate::js::auxiliary::initializer_clause::FormatJsInitializerClauseOptions; +use crate::js::expressions::arrow_function_expression::FormatJsArrowFunctionExpressionOptions; use crate::prelude::*; use crate::utils::member_chain::is_member_call_chain; use crate::utils::object::write_member_name; @@ -438,7 +439,7 @@ impl JsAnyAssignmentLike { let width = write_member_name(&name.into(), f)?; let text_width_for_break = (u8::from(f.options().tab_width()) + MIN_OVERLAP_FOR_BREAK) as usize; - width < text_width_for_break + width < text_width_for_break && property_annotation.is_none() }; write!(f, [property_annotation.format()])?; @@ -917,7 +918,7 @@ impl Format for JsAnyAssignmentLike { self.write_operator(f)?; } - match &layout { + match layout { AssignmentLikeLayout::OnlyLeft => Ok(()), AssignmentLikeLayout::Fluid => { let group_id = f.group_id("assignment_like"); @@ -1189,9 +1190,13 @@ pub(crate) fn with_assignment_layout( impl Format for WithAssignmentLayout<'_> { fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { match self.expression { - JsAnyExpression::JsArrowFunctionExpression(arrow) => { - arrow.format().with_options(self.layout).fmt(f) - } + JsAnyExpression::JsArrowFunctionExpression(arrow) => arrow + .format() + .with_options(FormatJsArrowFunctionExpressionOptions { + assignment_layout: self.layout, + ..FormatJsArrowFunctionExpressionOptions::default() + }) + .fmt(f), expression => expression.format().fmt(f), } } diff --git a/crates/rome_js_formatter/src/utils/function_body.rs b/crates/rome_js_formatter/src/utils/function_body.rs new file mode 100644 index 00000000000..d577791420c --- /dev/null +++ b/crates/rome_js_formatter/src/utils/function_body.rs @@ -0,0 +1,60 @@ +use crate::prelude::*; +use rome_formatter::write; +use rome_js_syntax::JsAnyFunctionBody; + +#[derive(Copy, Clone, Debug, Default)] +pub enum FunctionBodyCacheMode { + /// Format the body without caching it or retrieving it from the cache. + #[default] + NoCache, + + /// The body has been cached before, try to retrieve the body from the cache. + Cached, + + /// Cache the body during the next [formatting](Format::fmt). + Cache, +} + +/// Formats a [function body](JsAnyFunctionBody) with additional caching depending on [`mode`](Self::mode). +pub(crate) struct FormatMaybeCachedFunctionBody<'a> { + /// The body to format. + pub body: &'a JsAnyFunctionBody, + + /// If the body should be cached or if the formatter should try to retrieve it from the cache. + pub mode: FunctionBodyCacheMode, +} + +impl Format for FormatMaybeCachedFunctionBody<'_> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + match self.mode { + FunctionBodyCacheMode::NoCache => { + write!(f, [self.body.format()]) + } + FunctionBodyCacheMode::Cached => { + match f.context().get_cached_function_body(self.body) { + Some(cached) => f.write_element(cached), + None => { + // This can happen in the unlikely event where a function has a parameter with + // an initializer that contains a call expression with a first or last function/arrow + // ```javascript + // test(( + // problematic = test(() => body) + // ) => {}); + // ``` + // This case should be rare as it requires very specific syntax (and is rather messy to write) + // which is why it's fine to just fallback to formatting the body again in this case. + write!(f, [self.body.format()]) + } + } + } + FunctionBodyCacheMode::Cache => match f.intern(&self.body.format())? { + Some(interned) => { + f.context_mut() + .set_cached_function_body(self.body, interned.clone()); + f.write_element(interned) + } + None => Ok(()), + }, + } + } +} diff --git a/crates/rome_js_formatter/src/utils/member_chain/mod.rs b/crates/rome_js_formatter/src/utils/member_chain/mod.rs index 4093a3c66f2..59a6e72dd26 100644 --- a/crates/rome_js_formatter/src/utils/member_chain/mod.rs +++ b/crates/rome_js_formatter/src/utils/member_chain/mod.rs @@ -107,8 +107,8 @@ mod groups; mod simple_argument; use crate::context::TabWidth; -use crate::parentheses::is_callee; use crate::prelude::*; +use crate::utils::is_long_curried_call; use crate::utils::member_chain::chain_member::{CallExpressionPosition, ChainMember}; use crate::utils::member_chain::groups::{ MemberChainGroup, MemberChainGroupsBuilder, TailChainGroups, @@ -361,7 +361,7 @@ impl Format for MemberChain { }); if self.tail.len() <= 1 && !has_comments { - return if is_long_curried_call(&self.root) { + return if is_long_curried_call(Some(&self.root)) { write!(f, [format_one_line]) } else { write!(f, [group(&format_one_line)]) @@ -596,26 +596,6 @@ pub fn is_member_call_chain( Ok(chain.tail.is_member_call_chain(comments)) } -/// Tests if expression is a long curried call -/// -/// ```javascript -/// `connect(a, b, c)(d)` -/// ``` -fn is_long_curried_call(expression: &JsCallExpression) -> bool { - if let Some(parent_call) = expression.parent::() { - match (expression.arguments(), parent_call.arguments()) { - (Ok(arguments), Ok(parent_arguments)) => { - is_callee(expression.syntax(), parent_call.syntax()) - && arguments.args().len() > parent_arguments.args().len() - && !parent_arguments.args().is_empty() - } - _ => false, - } - } else { - false - } -} - fn has_short_name(identifier: &JsIdentifierExpression, tab_width: TabWidth) -> bool { identifier .name() diff --git a/crates/rome_js_formatter/src/utils/member_chain/simple_argument.rs b/crates/rome_js_formatter/src/utils/member_chain/simple_argument.rs index 0ace9ad2eca..1a5e501ffa1 100644 --- a/crates/rome_js_formatter/src/utils/member_chain/simple_argument.rs +++ b/crates/rome_js_formatter/src/utils/member_chain/simple_argument.rs @@ -127,8 +127,7 @@ impl SimpleArgument { let JsStaticMemberExpressionFields { member, object, .. } = static_expression.as_fields(); - Ok(SimpleArgument::from(member?).is_simple_impl(depth) - && SimpleArgument::from(object?).is_simple_impl(depth)) + Ok(member.is_ok() && SimpleArgument::from(object?).is_simple_impl(depth)) } else { Ok(false) } diff --git a/crates/rome_js_formatter/src/utils/mod.rs b/crates/rome_js_formatter/src/utils/mod.rs index 71f406a33a8..84d8b10bd67 100644 --- a/crates/rome_js_formatter/src/utils/mod.rs +++ b/crates/rome_js_formatter/src/utils/mod.rs @@ -5,6 +5,7 @@ mod conditional; pub mod string_utils; pub(crate) mod format_class; +pub(crate) mod function_body; pub mod jsx; pub(crate) mod member_chain; mod object; @@ -12,8 +13,10 @@ mod object_like; mod object_pattern_like; #[cfg(test)] mod quickcheck_utils; +pub(crate) mod test_call; mod typescript; +use crate::parentheses::is_callee; pub(crate) use crate::parentheses::resolve_left_most_expression; use crate::prelude::*; pub(crate) use assignment_like::{ @@ -26,7 +29,9 @@ pub(crate) use conditional::{ConditionalJsxChain, JsAnyConditional}; pub(crate) use object_like::JsObjectLike; pub(crate) use object_pattern_like::JsObjectPatternLike; use rome_formatter::{format_args, write, Buffer}; -use rome_js_syntax::{JsAnyExpression, JsAnyStatement, JsInitializerClause, JsLanguage, Modifiers}; +use rome_js_syntax::{ + JsAnyExpression, JsAnyStatement, JsCallExpression, JsInitializerClause, JsLanguage, Modifiers, +}; use rome_js_syntax::{JsSyntaxNode, JsSyntaxToken}; use rome_rowan::{AstNode, AstNodeList}; pub(crate) use string_utils::*; @@ -35,6 +40,27 @@ pub(crate) use typescript::{ TsIntersectionOrUnionTypeList, }; +/// Tests if expression is a long curried call +/// +/// ```javascript +/// `connect(a, b, c)(d)` +/// ``` +pub(crate) fn is_long_curried_call(expression: Option<&JsCallExpression>) -> bool { + if let Some(expression) = expression { + if let Some(parent_call) = expression.parent::() { + if let (Ok(arguments), Ok(parent_arguments)) = + (expression.arguments(), parent_call.arguments()) + { + return is_callee(expression.syntax(), parent_call.syntax()) + && arguments.args().len() > parent_arguments.args().len() + && !parent_arguments.args().is_empty(); + } + } + } + + false +} + /// Utility function to format the separators of the nodes that belong to the unions /// of [rome_js_syntax::TsAnyTypeMember]. /// diff --git a/crates/rome_js_formatter/src/utils/test_call.rs b/crates/rome_js_formatter/src/utils/test_call.rs new file mode 100644 index 00000000000..04c8e9f6e5e --- /dev/null +++ b/crates/rome_js_formatter/src/utils/test_call.rs @@ -0,0 +1,348 @@ +use crate::prelude::*; +use rome_js_syntax::{ + JsAnyArrowFunctionParameters, JsAnyCallArgument, JsAnyExpression, JsAnyFunctionBody, + JsAnyLiteralExpression, JsAnyName, JsCallArgumentList, JsCallArguments, JsCallExpression, +}; +use rome_rowan::{SyntaxResult, SyntaxTokenText}; + +/// This is a specialised function that checks if the current [call expression] +/// resembles a call expression usually used by a testing frameworks. +/// +/// If the [call expression] matches the criteria, a different formatting is applied. +/// +/// To evaluable the eligibility of a [call expression] to be a test framework like, +/// we need to check its [callee] and its [arguments]. +/// +/// 1. The [callee] must contain a name or a chain of names that belongs to the +/// test frameworks, for example: `test()`, `test.only()`, etc. +/// 2. The [arguments] should be at the least 2 +/// 3. The first argument has to be a string literal +/// 4. The third argument, if present, has to be a number literal +/// 5. The second argument has to be an [arrow function expression] or [function expression] +/// 6. Both function must have zero or one parameters +/// +/// [call expression]: crate::rome_js_syntax::JsCallExpression +/// [callee]: crate::rome_js_syntax::JsAnyExpression +/// [arguments]: crate::rome_js_syntax::JsCallArgumentList +/// [arrow function expression]: crate::rome_js_syntax::JsArrowFunctionExpression +/// [function expression]: crate::rome_js_syntax::JsCallArgumentList +pub(crate) fn is_test_call_expression(call_expression: &JsCallExpression) -> SyntaxResult { + use JsAnyExpression::*; + + let callee = call_expression.callee()?; + let arguments = call_expression.arguments()?; + + let mut args = arguments.args().iter(); + + match (args.next(), args.next(), args.next()) { + (Some(Ok(argument)), None, None) if arguments.args().len() == 1 => { + if is_angular_test_wrapper(&call_expression.clone().into()) + && call_expression + .parent::() + .and_then(|arguments_list| arguments_list.parent::()) + .and_then(|arguments| arguments.parent::()) + .map_or(Ok(false), |parent| is_test_call_expression(&parent))? + { + return Ok(matches!( + argument, + JsAnyCallArgument::JsAnyExpression( + JsArrowFunctionExpression(_) | JsFunctionExpression(_) + ) + )); + } + + if is_unit_test_set_up_callee(&callee) { + return Ok(argument + .as_js_any_expression() + .map_or(false, is_angular_test_wrapper)); + } + + Ok(false) + } + + // it("description", ..) + ( + Some(Ok(JsAnyCallArgument::JsAnyExpression( + JsTemplate(_) + | JsAnyLiteralExpression(self::JsAnyLiteralExpression::JsStringLiteralExpression(_)), + ))), + Some(Ok(second)), + third, + ) if arguments.args().len() <= 3 && contains_a_test_pattern(&callee)? => { + // it('name', callback, duration) + if !matches!( + third, + None | Some(Ok(JsAnyCallArgument::JsAnyExpression( + JsAnyLiteralExpression( + self::JsAnyLiteralExpression::JsNumberLiteralExpression(_) + ) + ))) + ) { + return Ok(false); + } + + if second + .as_js_any_expression() + .map_or(false, is_angular_test_wrapper) + { + return Ok(true); + } + + let (parameters, has_block_body) = match second { + JsAnyCallArgument::JsAnyExpression(JsFunctionExpression(function)) => ( + function + .parameters() + .map(JsAnyArrowFunctionParameters::from), + true, + ), + JsAnyCallArgument::JsAnyExpression(JsArrowFunctionExpression(arrow)) => ( + arrow.parameters(), + arrow.body().map_or(false, |body| { + matches!(body, JsAnyFunctionBody::JsFunctionBody(_)) + }), + ), + _ => return Ok(false), + }; + + Ok(arguments.args().len() == 2 || (parameters?.len() <= 1 && has_block_body)) + } + _ => Ok(false), + } +} + +/// Note: `inject` is used in AngularJS 1.x, `async` and `fakeAsync` in +/// Angular 2+, although `async` is deprecated and replaced by `waitForAsync` +/// since Angular 12. +/// +/// example: https://docs.angularjs.org/guide/unit-testing#using-beforeall- +/// +/// @param {CallExpression} node +/// @returns {boolean} +/// +fn is_angular_test_wrapper(expression: &JsAnyExpression) -> bool { + use JsAnyExpression::*; + match expression { + JsCallExpression(call_expression) => match call_expression.callee() { + Ok(JsIdentifierExpression(identifier)) => identifier + .name() + .and_then(|name| name.value_token()) + .map_or(false, |name| { + matches!( + name.text_trimmed(), + "async" | "inject" | "fakeAsync" | "waitForAsync" + ) + }), + _ => false, + }, + _ => false, + } +} + +/// Tests if the callee is a `beforeEach`, `beforeAll`, `afterEach` or `afterAll` identifier +/// that is commonly used in test frameworks. +fn is_unit_test_set_up_callee(callee: &JsAnyExpression) -> bool { + match callee { + JsAnyExpression::JsIdentifierExpression(identifier) => identifier + .name() + .and_then(|name| name.value_token()) + .map_or(false, |name| { + matches!( + name.text_trimmed(), + "beforeEach" | "beforeAll" | "afterEach" | "afterAll" + ) + }), + _ => false, + } +} + +/// This function checks if a call expressions has one of the following members: +/// - `it` +/// - `it.only` +/// - `it.skip` +/// - `describe` +/// - `describe.only` +/// - `describe.skip` +/// - `test` +/// - `test.only` +/// - `test.skip` +/// - `test.step` +/// - `test.describe` +/// - `test.describe.only` +/// - `test.describe.parallel` +/// - `test.describe.parallel.only` +/// - `test.describe.serial` +/// - `test.describe.serial.only` +/// - `skip` +/// - `xit` +/// - `xdescribe` +/// - `xtest` +/// - `fit` +/// - `fdescribe` +/// - `ftest` +/// +/// Based on this [article] +/// +/// [article]: https://craftinginterpreters.com/scanning-on-demand.html#tries-and-state-machines +fn contains_a_test_pattern(callee: &JsAnyExpression) -> SyntaxResult { + let mut members = CalleeNamesIterator::new(callee.clone()); + + let texts: [Option; 5] = [ + members.next(), + members.next(), + members.next(), + members.next(), + members.next(), + ]; + + let mut rev = texts.iter().rev().flatten(); + + let first = rev.next().map(|t| t.text()); + let second = rev.next().map(|t| t.text()); + let third = rev.next().map(|t| t.text()); + let fourth = rev.next().map(|t| t.text()); + let fifth = rev.next().map(|t| t.text()); + + Ok(match first { + Some("it" | "describe") => match second { + None => true, + Some("only" | "skip") => third.is_none(), + _ => false, + }, + Some("test") => match second { + None => true, + Some("only" | "skip" | "step") => third.is_none(), + Some("describe") => match third { + None => true, + Some("only") => true, + Some("parallel" | "serial") => match fourth { + None => true, + Some("only") => fifth.is_none(), + _ => false, + }, + _ => false, + }, + _ => false, + }, + Some("skip" | "xit" | "xdescribe" | "xtest" | "fit" | "fdescribe" | "ftest") => true, + _ => false, + }) +} + +/// Iterator that returns the callee names in "top down order". +/// +/// # Examples +/// +/// ```javascript +/// it.only() -> [`only`, `it`] +/// ``` +struct CalleeNamesIterator { + next: Option, +} + +impl CalleeNamesIterator { + fn new(callee: JsAnyExpression) -> Self { + Self { next: Some(callee) } + } +} + +impl Iterator for CalleeNamesIterator { + type Item = SyntaxTokenText; + + fn next(&mut self) -> Option { + use JsAnyExpression::*; + + let current = self.next.take()?; + + match current { + JsIdentifierExpression(identifier) => identifier + .name() + .and_then(|reference| reference.value_token()) + .ok() + .map(|value| value.token_text_trimmed()), + JsStaticMemberExpression(member_expression) => match member_expression.member() { + Ok(JsAnyName::JsName(name)) => { + self.next = member_expression.object().ok(); + name.value_token() + .ok() + .map(|name| name.token_text_trimmed()) + } + _ => None, + }, + _ => None, + } + } +} + +#[cfg(test)] +mod test { + use super::contains_a_test_pattern; + use rome_diagnostics::file::FileId; + use rome_js_parser::parse; + use rome_js_syntax::{JsCallExpression, SourceType}; + use rome_rowan::AstNodeList; + + fn extract_call_expression(src: &str) -> JsCallExpression { + let source_type = SourceType::js_module(); + let result = parse(src, FileId::zero(), source_type); + let module = result + .tree() + .as_js_module() + .unwrap() + .items() + .first() + .unwrap(); + + module + .as_js_any_statement() + .unwrap() + .as_js_expression_statement() + .unwrap() + .expression() + .unwrap() + .as_js_call_expression() + .unwrap() + .clone() + } + + #[test] + fn matches_simple_call() { + let call_expression = extract_call_expression("test();"); + assert_eq!( + contains_a_test_pattern(&call_expression.callee().unwrap()), + Ok(true) + ); + + let call_expression = extract_call_expression("it();"); + assert_eq!( + contains_a_test_pattern(&call_expression.callee().unwrap()), + Ok(true) + ); + } + + #[test] + fn matches_static_member_expression() { + let call_expression = extract_call_expression("test.only();"); + assert_eq!( + contains_a_test_pattern(&call_expression.callee().unwrap()), + Ok(true) + ); + } + + #[test] + fn matches_static_member_expression_deep() { + let call_expression = extract_call_expression("test.describe.parallel.only();"); + assert_eq!( + contains_a_test_pattern(&call_expression.callee().unwrap()), + Ok(true) + ); + } + + #[test] + fn doesnt_static_member_expression_deep() { + let call_expression = extract_call_expression("test.describe.parallel.only.AHAHA();"); + assert_eq!( + contains_a_test_pattern(&call_expression.callee().unwrap()), + Ok(false) + ); + } +} diff --git a/crates/rome_js_formatter/tests/specs/js/module/arrow/arrow_nested.js.snap b/crates/rome_js_formatter/tests/specs/js/module/arrow/arrow_nested.js.snap index b73bcea1176..f27451b0463 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/arrow/arrow_nested.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/arrow/arrow_nested.js.snap @@ -40,24 +40,21 @@ Line width: 80 Quote style: Double Quotes Quote properties: As needed ----- -Seq(typeDef.interface.groups).forEach( - (group) => - Seq(group.members).forEach( - (member, memberName) => - markdownDoc(member.doc, { - typePath: typePath.concat(memberName.slice(1)), - signatures: member.signatures, - }), - ), +Seq(typeDef.interface.groups).forEach((group) => + Seq(group.members).forEach((member, memberName) => + markdownDoc(member.doc, { + typePath: typePath.concat(memberName.slice(1)), + signatures: member.signatures, + }), + ), ); const promiseFromCallback = (fn) => - new Promise( - (resolve, reject) => - fn((err, result) => { - if (err) return reject(err); - return resolve(result); - }), + new Promise((resolve, reject) => + fn((err, result) => { + if (err) return reject(err); + return resolve(result); + }), ); runtimeAgent.getProperties( diff --git a/crates/rome_js_formatter/tests/specs/js/module/arrow/call.js.snap b/crates/rome_js_formatter/tests/specs/js/module/arrow/call.js.snap index c3ffef92cb1..6405084f8b2 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/arrow/call.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/arrow/call.js.snap @@ -57,8 +57,8 @@ Line width: 80 Quote style: Double Quotes Quote properties: As needed ----- -const testResults = results.testResults.map( - (testResult) => formatResult(testResult, formatter, reporter), +const testResults = results.testResults.map((testResult) => + formatResult(testResult, formatter, reporter), ); it("mocks regexp instances", () => { @@ -73,19 +73,17 @@ expect(() => asyncRequest({ url: "/test-endpoint" })); expect(() => asyncRequest({ url: "/test-endpoint-but-with-a-long-url" })); // .toThrowError(/Required parameter/); -expect( - () => - asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }), +expect(() => + asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }), ); // .toThrowError(/Required parameter/); -expect( - () => asyncRequest({ type: "foo", url: "/test-endpoint" }), +expect(() => + asyncRequest({ type: "foo", url: "/test-endpoint" }), ).not.toThrowError(); -expect( - () => - asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }), +expect(() => + asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }), ).not.toThrowError(); const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map( @@ -107,10 +105,9 @@ const composition = (ViewComponent, ContainerComponent) => static propTypes = {}; }; -romise.then( - (result) => - result.veryLongVariable.veryLongPropertyName > someOtherVariable - ? "ok" - : "fail", +romise.then((result) => + result.veryLongVariable.veryLongPropertyName > someOtherVariable + ? "ok" + : "fail", ); diff --git a/crates/rome_js_formatter/tests/specs/js/module/arrow/params.js.snap b/crates/rome_js_formatter/tests/specs/js/module/arrow/params.js.snap index 9dd0d42b729..4ce3c9ce6f2 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/arrow/params.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/arrow/params.js.snap @@ -338,21 +338,26 @@ fooooooooooooooooooooooooooooooooooooooooooooooooooo( (action) => (next) => dispatch(action), ); -foo(({ - a, +foo( + ({ + a, - b, -}) => {}); + b, + }) => {}, +); foo(({ a, b }) => {}); foo(({ a, b }) => {}); -foo(a, ({ +foo( a, + ({ + a, - b, -}) => {}); + b, + }) => {}, +); foo( ({ @@ -366,35 +371,41 @@ foo(({ a, b }) => a); foo(({ a, b }) => a); -foo(({ - a: { - a, +foo( + ({ + a: { + a, - b, - }, -}) => {}); + b, + }, + }) => {}, +); -foo(({ - a: { - b: { - c, +foo( + ({ + a: { + b: { + c, - d, + d, + }, }, - }, -}) => {}); + }) => {}, +); -foo(({ - a: { - b: { - c: { - d, +foo( + ({ + a: { + b: { + c: { + d, - e, + e, + }, }, }, - }, -}) => {}); + }) => {}, +); foo( ({ @@ -432,57 +443,65 @@ foo( }) => a, ); -foo(([ - { - a: { - b: { - c: { - d, +foo( + ([ + { + a: { + b: { + c: { + d, - e, + e, + }, }, }, }, - }, -]) => {}); + ]) => {}, +); -foo(([ - ...{ - a: { - b: { - c: { - d, +foo( + ([ + ...{ + a: { + b: { + c: { + d, - e, + e, + }, }, }, - }, - } -]) => {}); + } + ]) => {}, +); -foo(( - n = { - a: { - b: { - c: { - d, +foo( + ( + n = { + a: { + b: { + c: { + d, - e, + e, + }, }, }, }, - }, -) => {}); + ) => {}, +); -foo(({ - x: [ - { - a, +foo( + ({ + x: [ + { + a, - b, - }, - ], -}) => {}); + b, + }, + ], + }) => {}, +); foo( ( @@ -496,104 +515,124 @@ foo( ) => a, ); -foo(([ - [ - { - a, +foo( + ([ + [ + { + a, - b, - }, - ], -]) => {}); + b, + }, + ], + ]) => {}, +); -foo(([ - [ +foo( + ([ [ [ - { - a, - b: { - c, - d: { - e, - - f, + [ + { + a, + b: { + c, + d: { + e, + + f, + }, }, }, - }, + ], ], ], - ], -]) => {}); - -foo(( - ...{ - a, - - b, - } -) => {}); + ]) => {}, +); -foo(( - ...[ - { +foo( + ( + ...{ a, b, - }, - ] -) => {}); + } + ) => {}, +); -foo(([ - ...[ - { - a, +foo( + ( + ...[ + { + a, - b, - }, - ] -]) => {}); + b, + }, + ] + ) => {}, +); -foo(( - a = [ - { - a, +foo( + ([ + ...[ + { + a, - b, - }, - ], -) => {}); + b, + }, + ] + ]) => {}, +); -foo(( - a = (({ - a, +foo( + ( + a = [ + { + a, - b, - }) => {})(), -) => {}); + b, + }, + ], + ) => {}, +); -foo(( - a = f({ - a, +foo( + ( + a = (({ + a, - b, - }), -) => {}); + b, + }) => {})(), + ) => {}, +); -foo(( - a = ({ - a, +foo( + ( + a = f({ + a, - b, - }) => {}, -) => {}); + b, + }), + ) => {}, +); -foo(( - a = 1 + - f({ +foo( + ( + a = ({ a, b, - }), -) => {}); + }) => {}, + ) => {}, +); + +foo( + ( + a = 1 + + f({ + a, + + b, + }), + ) => {}, +); diff --git a/crates/rome_js_formatter/tests/specs/js/module/assignment/assignment.js.snap b/crates/rome_js_formatter/tests/specs/js/module/assignment/assignment.js.snap index 57f7ac9029e..be3a1fd3b29 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/assignment/assignment.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/assignment/assignment.js.snap @@ -344,12 +344,12 @@ dsakdljaskldjaslk = [ created: "09/01/2017 17:25", }, ]; -render = withGraphQLQuery("node(1234567890){image{uri}}", function ( - container, - data, -) { - return "image"; -}); +render = withGraphQLQuery( + "node(1234567890){image{uri}}", + function (container, data) { + return "image"; + }, +); loadNext = (stateIsOK && hasNext) || { skipNext: true, diff --git a/crates/rome_js_formatter/tests/specs/js/module/expression/member-chain/complex_arguments.js.snap b/crates/rome_js_formatter/tests/specs/js/module/expression/member-chain/complex_arguments.js.snap index 4e41bc85460..cf2f46b2f73 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/expression/member-chain/complex_arguments.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/expression/member-chain/complex_arguments.js.snap @@ -19,8 +19,6 @@ Quote style: Double Quotes Quote properties: As needed ----- client.execute( - Post.selectAll() - .where(Post.id.eq(42)) - .where(Post.published.eq(true)), + Post.selectAll().where(Post.id.eq(42)).where(Post.published.eq(true)), ); diff --git a/crates/rome_js_formatter/tests/specs/js/module/object/property_object_member.js.snap b/crates/rome_js_formatter/tests/specs/js/module/object/property_object_member.js.snap index e8b12bf9c27..d92231ac43e 100644 --- a/crates/rome_js_formatter/tests/specs/js/module/object/property_object_member.js.snap +++ b/crates/rome_js_formatter/tests/specs/js/module/object/property_object_member.js.snap @@ -246,12 +246,12 @@ const fluidObject = { created: "09/01/2017 17:25", }, ], - render: withGraphQLQuery("node(1234567890){image{uri}}", function ( - container, - data, - ) { - return "image"; - }), + render: withGraphQLQuery( + "node(1234567890){image{uri}}", + function (container, data) { + return "image"; + }, + ), loadNext: (stateIsOK && hasNext) || { skipNext: true, }, diff --git a/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap b/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap index 9878595dcc7..2a0cfd75f3e 100644 --- a/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap +++ b/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap @@ -331,12 +331,10 @@ function Tabs() { language={language} placeholder="Enter some code here" onChange={(evn) => { - setPlaygroundState( - (state) => ({ - ...state, - code: evn.target.value, - }), - ); + setPlaygroundState((state) => ({ + ...state, + code: evn.target.value, + })); }} style={{ fontSize: 12, @@ -458,15 +456,13 @@ let component = ( let bar = (
- {foo( - () => ( -
- {" "} - the quick brown fox jumps over the lazy dog and then jumps over the - lazy cat and then over the lazy fish.{" "} -
- ), - )} + {foo(() => ( +
+ {" "} + the quick brown fox jumps over the lazy dog and then jumps over the lazy + cat and then over the lazy fish.{" "} +
+ ))}
); @@ -505,9 +501,9 @@ const breadcrumbItems = [ 2:
; 7: tooltip="A very long tooltip text that would otherwise make the attribute break 14: - 126: "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace", - 147: "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace", - 160: "ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace", - 185:
-  234: 		Uncle Boonmee Who Can Recall His Past Lives dir. Apichatpong Weerasethakul{" "}
+  124: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  145: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  158: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  183: 				
+  232: 		Uncle Boonmee Who Can Recall His Past Lives dir. Apichatpong Weerasethakul{" "}
 
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/arrow-call/arrow_call.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/arrow-call/arrow_call.js.snap
deleted file mode 100644
index 24b37a5a0b2..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/arrow-call/arrow_call.js.snap
+++ /dev/null
@@ -1,175 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
----
-
-# Input
-
-```js
-const testResults = results.testResults.map(testResult =>
-  formatResult(testResult, formatter, reporter)
-);
-
-it('mocks regexp instances', () => {
-  expect(
-    () => moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)),
-  ).not.toThrow();
-});
-
-expect(() => asyncRequest({ url: "/test-endpoint" }))
-  .toThrowError(/Required parameter/);
-
-expect(() => asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }))
-  .toThrowError(/Required parameter/);
-
-expect(() => asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }))
-  .toThrowError(/Required parameter/);
-
-expect(() => asyncRequest({ type: "foo", url: "/test-endpoint" }))
-  .not.toThrowError();
-
-expect(() => asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }))
-  .not.toThrowError();
-
-const a = Observable
-  .fromPromise(axiosInstance.post('/carts/mine'))
-  .map((response) => response.data)
-
-const b = Observable.fromPromise(axiosInstance.get(url))
-  .map((response) => response.data)
-
-func(
-  veryLoooooooooooooooooooooooongName,
-  veryLooooooooooooooooooooooooongName =>
-    veryLoooooooooooooooongName.something()
-);
-
-promise.then(result => result.veryLongVariable.veryLongPropertyName > someOtherVariable ? "ok" : "fail");
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -1,10 +1,10 @@
--const testResults = results.testResults.map((testResult) =>
--  formatResult(testResult, formatter, reporter),
-+const testResults = results.testResults.map(
-+  (testResult) => formatResult(testResult, formatter, reporter),
- );
- 
- it("mocks regexp instances", () => {
--  expect(() =>
--    moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)),
-+  expect(
-+    () => moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)),
-   ).not.toThrow();
- });
- 
-@@ -12,20 +12,22 @@
-   /Required parameter/,
- );
- 
--expect(() =>
--  asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }),
-+expect(
-+  () => asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }),
- ).toThrowError(/Required parameter/);
- 
--expect(() =>
--  asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }),
-+expect(
-+  () =>
-+    asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }),
- ).toThrowError(/Required parameter/);
- 
--expect(() =>
--  asyncRequest({ type: "foo", url: "/test-endpoint" }),
-+expect(
-+  () => asyncRequest({ type: "foo", url: "/test-endpoint" }),
- ).not.toThrowError();
- 
--expect(() =>
--  asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }),
-+expect(
-+  () =>
-+    asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }),
- ).not.toThrowError();
- 
- const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map(
-@@ -42,8 +44,9 @@
-     veryLoooooooooooooooongName.something(),
- );
- 
--promise.then((result) =>
--  result.veryLongVariable.veryLongPropertyName > someOtherVariable
--    ? "ok"
--    : "fail",
-+promise.then(
-+  (result) =>
-+    result.veryLongVariable.veryLongPropertyName > someOtherVariable
-+      ? "ok"
-+      : "fail",
- );
-```
-
-# Output
-
-```js
-const testResults = results.testResults.map(
-  (testResult) => formatResult(testResult, formatter, reporter),
-);
-
-it("mocks regexp instances", () => {
-  expect(
-    () => moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)),
-  ).not.toThrow();
-});
-
-expect(() => asyncRequest({ url: "/test-endpoint" })).toThrowError(
-  /Required parameter/,
-);
-
-expect(
-  () => asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }),
-).toThrowError(/Required parameter/);
-
-expect(
-  () =>
-    asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }),
-).toThrowError(/Required parameter/);
-
-expect(
-  () => asyncRequest({ type: "foo", url: "/test-endpoint" }),
-).not.toThrowError();
-
-expect(
-  () =>
-    asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }),
-).not.toThrowError();
-
-const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map(
-  (response) => response.data,
-);
-
-const b = Observable.fromPromise(axiosInstance.get(url)).map(
-  (response) => response.data,
-);
-
-func(
-  veryLoooooooooooooooooooooooongName,
-  (veryLooooooooooooooooooooooooongName) =>
-    veryLoooooooooooooooongName.something(),
-);
-
-promise.then(
-  (result) =>
-    result.veryLongVariable.veryLongPropertyName > someOtherVariable
-      ? "ok"
-      : "fail",
-);
-```
-
-
-
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/assignment/chain.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/assignment/chain.js.snap
deleted file mode 100644
index 09676c40128..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/assignment/chain.js.snap
+++ /dev/null
@@ -1,104 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
----
-
-# Input
-
-```js
-let bifornCringerMoshedPerplexSawder=
-askTrovenaBeenaDependsRowans=
-glimseGlyphsHazardNoopsTieTie=
-averredBathersBoxroomBuggyNurl=
-anodyneCondosMalateOverateRetinol=
-annularCooeedSplicesWalksWayWay=
-kochabCooieGameOnOboleUnweave;
-
-bifornCringerMoshedPerplexSawder =
-  askTrovenaBeenaDependsRowans =
-  glimseGlyphsHazardNoopsTieTie =
-  x =
-  averredBathersBoxroomBuggyNurl =
-  anodyneCondosMal(sdsadsa,dasdas,asd(()=>sdf)).ateOverateRetinol =
-  annularCooeedSplicesWalksWayWay =
-    kochabCooieGameOnOboleUnweave;
-
-bifornCringerMoshedPerplexSawder =
-  askTrovenaBeenaDependsRowans =
-  glimseGlyphsHazardNoopsTieTie =
-  x =
-  averredBathersBoxroomBuggyNurl =
-  anodyneCondosMal(sdsadsa,dasdas,asd(()=>sdf)).ateOverateRetinol =
-  annularCooeedSplicesWalksWayWay =
-    kochabCooieGameOnOboleUnweave+kochabCooieGameOnOboleUnweave;
-
-a=b=c;
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -11,11 +11,7 @@
-   glimseGlyphsHazardNoopsTieTie =
-   x =
-   averredBathersBoxroomBuggyNurl =
--  anodyneCondosMal(
--    sdsadsa,
--    dasdas,
--    asd(() => sdf),
--  ).ateOverateRetinol =
-+  anodyneCondosMal(sdsadsa, dasdas, asd(() => sdf)).ateOverateRetinol =
-   annularCooeedSplicesWalksWayWay =
-     kochabCooieGameOnOboleUnweave;
- 
-@@ -24,11 +20,7 @@
-   glimseGlyphsHazardNoopsTieTie =
-   x =
-   averredBathersBoxroomBuggyNurl =
--  anodyneCondosMal(
--    sdsadsa,
--    dasdas,
--    asd(() => sdf),
--  ).ateOverateRetinol =
-+  anodyneCondosMal(sdsadsa, dasdas, asd(() => sdf)).ateOverateRetinol =
-   annularCooeedSplicesWalksWayWay =
-     kochabCooieGameOnOboleUnweave + kochabCooieGameOnOboleUnweave;
- 
-```
-
-# Output
-
-```js
-let bifornCringerMoshedPerplexSawder =
-  (askTrovenaBeenaDependsRowans =
-  glimseGlyphsHazardNoopsTieTie =
-  averredBathersBoxroomBuggyNurl =
-  anodyneCondosMalateOverateRetinol =
-  annularCooeedSplicesWalksWayWay =
-    kochabCooieGameOnOboleUnweave);
-
-bifornCringerMoshedPerplexSawder =
-  askTrovenaBeenaDependsRowans =
-  glimseGlyphsHazardNoopsTieTie =
-  x =
-  averredBathersBoxroomBuggyNurl =
-  anodyneCondosMal(sdsadsa, dasdas, asd(() => sdf)).ateOverateRetinol =
-  annularCooeedSplicesWalksWayWay =
-    kochabCooieGameOnOboleUnweave;
-
-bifornCringerMoshedPerplexSawder =
-  askTrovenaBeenaDependsRowans =
-  glimseGlyphsHazardNoopsTieTie =
-  x =
-  averredBathersBoxroomBuggyNurl =
-  anodyneCondosMal(sdsadsa, dasdas, asd(() => sdf)).ateOverateRetinol =
-  annularCooeedSplicesWalksWayWay =
-    kochabCooieGameOnOboleUnweave + kochabCooieGameOnOboleUnweave;
-
-a = b = c;
-```
-
-
-
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js b/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js
index 7cd432dc271..9edd24456ec 100644
--- a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js
+++ b/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js
@@ -13,7 +13,6 @@ deepCopyAndAsyncMapLeavesB(
   { valueMapper, overwriteExistingKeys }
 )
 
-// rome-ignore format: shut down regression
 deepCopyAndAsyncMapLeavesC(
   { source: sourceValue, destination: destination[sourceKey] },
   1337,
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js.snap
deleted file mode 100644
index 5824bc6a5ea..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/break.js.snap
+++ /dev/null
@@ -1,147 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
----
-
-# Input
-
-```js
-h(f(g(() => {
-  a
-})))
-
-deepCopyAndAsyncMapLeavesA(
-  { source: sourceValue, destination: destination[sourceKey] },
-  { valueMapper, overwriteExistingKeys }
-)
-
-deepCopyAndAsyncMapLeavesB(
-  1337,
-  { source: sourceValue, destination: destination[sourceKey] },
-  { valueMapper, overwriteExistingKeys }
-)
-
-// rome-ignore format: shut down regression
-deepCopyAndAsyncMapLeavesC(
-  { source: sourceValue, destination: destination[sourceKey] },
-  1337,
-  { valueMapper, overwriteExistingKeys }
-)
-
-function someFunction(url) {
-  return get(url)
-    .then(
-      json => dispatch(success(json)),
-      error => dispatch(failed(error))
-    );
-}
-
-const mapChargeItems = fp.flow(
-  l => l < 10 ? l: 1,
-  l => Immutable.Range(l).toMap()
-);
-
-expect(new LongLongLongLongLongRange([0, 0], [0, 0])).toEqualAtomLongLongLongLongRange(new LongLongLongRange([0, 0], [0, 0]));
-
-["red", "white", "blue", "black", "hotpink", "rebeccapurple"].reduce(
-  (allColors, color) => {
-    return allColors.concat(color);
-  },
-  []
-);
-
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -17,11 +17,12 @@
-   { valueMapper, overwriteExistingKeys },
- );
- 
-+// rome-ignore format: shut down regression
- deepCopyAndAsyncMapLeavesC(
-   { source: sourceValue, destination: destination[sourceKey] },
-   1337,
--  { valueMapper, overwriteExistingKeys },
--);
-+  { valueMapper, overwriteExistingKeys }
-+)
- 
- function someFunction(url) {
-   return get(url).then(
-@@ -39,9 +40,9 @@
-   new LongLongLongLongLongRange([0, 0], [0, 0]),
- ).toEqualAtomLongLongLongLongRange(new LongLongLongRange([0, 0], [0, 0]));
- 
--["red", "white", "blue", "black", "hotpink", "rebeccapurple"].reduce(
--  (allColors, color) => {
--    return allColors.concat(color);
--  },
--  [],
--);
-+["red", "white", "blue", "black", "hotpink", "rebeccapurple"].reduce((
-+  allColors,
-+  color,
-+) => {
-+  return allColors.concat(color);
-+}, []);
-```
-
-# Output
-
-```js
-h(
-  f(
-    g(() => {
-      a;
-    }),
-  ),
-);
-
-deepCopyAndAsyncMapLeavesA(
-  { source: sourceValue, destination: destination[sourceKey] },
-  { valueMapper, overwriteExistingKeys },
-);
-
-deepCopyAndAsyncMapLeavesB(
-  1337,
-  { source: sourceValue, destination: destination[sourceKey] },
-  { valueMapper, overwriteExistingKeys },
-);
-
-// rome-ignore format: shut down regression
-deepCopyAndAsyncMapLeavesC(
-  { source: sourceValue, destination: destination[sourceKey] },
-  1337,
-  { valueMapper, overwriteExistingKeys }
-)
-
-function someFunction(url) {
-  return get(url).then(
-    (json) => dispatch(success(json)),
-    (error) => dispatch(failed(error)),
-  );
-}
-
-const mapChargeItems = fp.flow(
-  (l) => (l < 10 ? l : 1),
-  (l) => Immutable.Range(l).toMap(),
-);
-
-expect(
-  new LongLongLongLongLongRange([0, 0], [0, 0]),
-).toEqualAtomLongLongLongLongRange(new LongLongLongRange([0, 0], [0, 0]));
-
-["red", "white", "blue", "black", "hotpink", "rebeccapurple"].reduce((
-  allColors,
-  color,
-) => {
-  return allColors.concat(color);
-}, []);
-```
-
-
-
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/react.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/react.js.snap
deleted file mode 100644
index 62cbdfb792e..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/react.js.snap
+++ /dev/null
@@ -1,297 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
-info:
-  test_file: js/break-calls/react.js
----
-
-# Input
-
-```js
-function helloWorld() {
-  useEffect(() => {
-    // do something
-  }, [props.value])
-  useEffect(() => {
-    // do something
-  }, [props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value])
-}
-
-function helloWorldWithReact() {
-  React.useEffect(() => {
-    // do something
-  }, [props.value])
-  React.useEffect(() => {
-    // do something
-  }, [props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value])
-}
-
-function MyComponent(props) {
-  useEffect(
-    () => {
-      console.log("some code", props.foo);
-    },
-
-    // We need to disable the eslint warning here,
-    // because of some complicated reason.
-    // eslint-disable line react-hooks/exhaustive-deps
-    []
-  );
-
-  return null;
-}
-
-function Comp1() {
-  const { firstName, lastName } = useMemo(
-    () => parseFullName(fullName),
-    [fullName],
-  );
-}
-
-function Comp2() {
-  const { firstName, lastName } = useMemo(
-    () => func(),
-    [props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value, props.value]
-  )
-}
-
-function Comp3() {
-  const { firstName, lastName } = useMemo(
-    (aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk) => func(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk),
-    [foo, bar, baz]
-  );
-}
-
-function Comp4() {
-  const { firstName, lastName } = useMemo(
-    () => foo && bar && baz || baz || foo && baz(foo) + bar(foo) + foo && bar && baz || baz || foo && baz(foo) + bar(foo),
-    [foo, bar, baz]
-  )
-}
-
-function Comp5() {
-  const { firstName, lastName } = useMemo(() => func(), [foo]);
-}
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -45,7 +45,6 @@
-     () => {
-       console.log("some code", props.foo);
-     },
--
-     // We need to disable the eslint warning here,
-     // because of some complicated reason.
-     // eslint-disable line react-hooks/exhaustive-deps
-@@ -56,49 +55,54 @@
- }
- 
- function Comp1() {
--  const { firstName, lastName } = useMemo(
--    () => parseFullName(fullName),
--    [fullName],
--  );
-+  const { firstName, lastName } = useMemo(() => parseFullName(fullName), [
-+    fullName,
-+  ]);
- }
- 
- function Comp2() {
--  const { firstName, lastName } = useMemo(
--    () => func(),
--    [
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--      props.value,
--    ],
--  );
-+  const { firstName, lastName } = useMemo(() => func(), [
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+    props.value,
-+  ]);
- }
- 
- function Comp3() {
--  const { firstName, lastName } = useMemo(
--    (aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk) =>
--      func(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk),
--    [foo, bar, baz],
--  );
-+  const { firstName, lastName } = useMemo((
-+    aaa,
-+    bbb,
-+    ccc,
-+    ddd,
-+    eee,
-+    fff,
-+    ggg,
-+    hhh,
-+    iii,
-+    jjj,
-+    kkk,
-+  ) => func(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk), [
-+    foo,
-+    bar,
-+    baz,
-+  ]);
- }
- 
- function Comp4() {
--  const { firstName, lastName } = useMemo(
--    () =>
--      (foo && bar && baz) ||
--      baz ||
--      (foo && baz(foo) + bar(foo) + foo && bar && baz) ||
--      baz ||
--      (foo && baz(foo) + bar(foo)),
--    [foo, bar, baz],
--  );
-+  const { firstName, lastName } = useMemo(() =>
-+    (foo && bar && baz) ||
-+    baz ||
-+    (foo && baz(foo) + bar(foo) + foo && bar && baz) ||
-+    baz ||
-+    (foo && baz(foo) + bar(foo)), [foo, bar, baz]);
- }
- 
- function Comp5() {
-```
-
-# Output
-
-```js
-function helloWorld() {
-  useEffect(() => {
-    // do something
-  }, [props.value]);
-  useEffect(() => {
-    // do something
-  }, [
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-  ]);
-}
-
-function helloWorldWithReact() {
-  React.useEffect(() => {
-    // do something
-  }, [props.value]);
-  React.useEffect(() => {
-    // do something
-  }, [
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-  ]);
-}
-
-function MyComponent(props) {
-  useEffect(
-    () => {
-      console.log("some code", props.foo);
-    },
-    // We need to disable the eslint warning here,
-    // because of some complicated reason.
-    // eslint-disable line react-hooks/exhaustive-deps
-    [],
-  );
-
-  return null;
-}
-
-function Comp1() {
-  const { firstName, lastName } = useMemo(() => parseFullName(fullName), [
-    fullName,
-  ]);
-}
-
-function Comp2() {
-  const { firstName, lastName } = useMemo(() => func(), [
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-    props.value,
-  ]);
-}
-
-function Comp3() {
-  const { firstName, lastName } = useMemo((
-    aaa,
-    bbb,
-    ccc,
-    ddd,
-    eee,
-    fff,
-    ggg,
-    hhh,
-    iii,
-    jjj,
-    kkk,
-  ) => func(aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk), [
-    foo,
-    bar,
-    baz,
-  ]);
-}
-
-function Comp4() {
-  const { firstName, lastName } = useMemo(() =>
-    (foo && bar && baz) ||
-    baz ||
-    (foo && baz(foo) + bar(foo) + foo && bar && baz) ||
-    baz ||
-    (foo && baz(foo) + bar(foo)), [foo, bar, baz]);
-}
-
-function Comp5() {
-  const { firstName, lastName } = useMemo(() => func(), [foo]);
-}
-```
-
-
-
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/reduce.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/reduce.js.snap
deleted file mode 100644
index d25c229a168..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/break-calls/reduce.js.snap
+++ /dev/null
@@ -1,64 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
----
-
-# Input
-
-```js
-const [ first1 ] = array.reduce(
-  () => [accumulator, element, accumulator, element],
-  [fullName]
-);
-
-const [ first2 ] = array.reduce(
-  (accumulator, element, ) => [accumulator, element],
-  [fullName]
-);
-```
-
-
-# Prettier differences
-
-```diff
---- Prettier
-+++ Rome
-@@ -1,9 +1,11 @@
--const [first1] = array.reduce(
--  () => [accumulator, element, accumulator, element],
--  [fullName],
--);
-+const [first1] = array.reduce(() => [
-+  accumulator,
-+  element,
-+  accumulator,
-+  element,
-+], [fullName]);
- 
--const [first2] = array.reduce(
--  (accumulator, element) => [accumulator, element],
--  [fullName],
--);
-+const [first2] = array.reduce((accumulator, element) => [
-+  accumulator,
-+  element,
-+], [fullName]);
-```
-
-# Output
-
-```js
-const [first1] = array.reduce(() => [
-  accumulator,
-  element,
-  accumulator,
-  element,
-], [fullName]);
-
-const [first2] = array.reduce((accumulator, element) => [
-  accumulator,
-  element,
-], [fullName]);
-```
-
-
-
diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/first-argument-expansion/test.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/first-argument-expansion/test.js.snap
deleted file mode 100644
index 6ce9f1ef7a1..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/js/first-argument-expansion/test.js.snap
+++ /dev/null
@@ -1,392 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
-info:
-  test_file: js/first-argument-expansion/test.js
----
-
-# Input
-
-```js
-setTimeout(function() {
-  thing();
-}, 500);
-
-["a","b","c"].reduce(function(item, thing) {
-  return thing + " " + item;
-}, "letters:")
-
-func(() => {
-  thing();
-}, identifier);
-
-func(function() {
-  thing();
-}, this.props.timeout * 1000);
-
-func((that) => {
-  thing();
-}, this.props.getTimeout());
-
-func(() => {
-  thing();
-}, true);
-
-func(() => {
-  thing();
-}, null);
-
-func(() => {
-  thing();
-}, undefined);
-
-func(() => {
-  thing();
-}, /regex.*?/);
-
-func(() => {
-  thing();
-}, 1 ? 2 : 3);
-
-func(function() {
-  return thing()
-}, 1 ? 2 : 3);
-
-func(() => {
-  thing();
-}, something() ? someOtherThing() : somethingElse(true, 0));
-
-
-func(() => {
-  thing();
-}, something(longArgumentName, anotherLongArgumentName) ? someOtherThing() : somethingElse(true, 0));
-
-
-func(() => {
-  thing();
-}, something(longArgumentName, anotherLongArgumentName, anotherLongArgumentName, anotherLongArgumentName) ? someOtherThing() : somethingElse(true, 0));
-
-compose((a) => {
-  return a.thing;
-}, b => b * b);
-
-somthing.reduce(function(item, thing) {
-  return thing.blah =  item;
-}, {})
-
-somthing.reduce(function(item, thing) {
-  return thing.push(item);
-}, [])
-
-reallyLongLongLongLongLongLongLongLongLongLongLongLongLongLongMethod((f, g, h) => {
-  return f.pop();
-}, true);
-
-// Don't do the rest of these
-
-func(function() {
-  thing();
-}, true, false);
-
-func(() => {
-  thing();
-}, {yes: true, cats: 5});
-
-compose((a) => {
-  return a.thing;
-}, b => {
-  return b + "";
-});
-
-compose((a) => {
-  return a.thing;
-}, b => [1, 2, 3, 4, 5]);
-
-renderThing(a =>
-  
Content. So much to say. Oh my. Are we done yet?
-,args); - -setTimeout( - // Something - function() { - thing(); - }, - 500 -); - -setTimeout(/* blip */ function() { - thing(); -}, 500); - -func((args) => { - execute(args); -}, result => result && console.log("success")) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -34,12 +34,9 @@ - thing(); - }, /regex.*?/); - --func( -- () => { -- thing(); -- }, -- 1 ? 2 : 3, --); -+func(() => { -+ thing(); -+}, 1 ? 2 : 3); - - func( - function () { -@@ -48,35 +45,26 @@ - 1 ? 2 : 3, - ); - --func( -- () => { -- thing(); -- }, -- something() ? someOtherThing() : somethingElse(true, 0), --); -+func(() => { -+ thing(); -+}, something() ? someOtherThing() : somethingElse(true, 0)); - --func( -- () => { -- thing(); -- }, -- something(longArgumentName, anotherLongArgumentName) -- ? someOtherThing() -- : somethingElse(true, 0), --); -+func(() => { -+ thing(); -+}, something(longArgumentName, anotherLongArgumentName) -+ ? someOtherThing() -+ : somethingElse(true, 0)); - --func( -- () => { -- thing(); -- }, -- something( -- longArgumentName, -- anotherLongArgumentName, -- anotherLongArgumentName, -- anotherLongArgumentName, -- ) -- ? someOtherThing() -- : somethingElse(true, 0), --); -+func(() => { -+ thing(); -+}, something( -+ longArgumentName, -+ anotherLongArgumentName, -+ anotherLongArgumentName, -+ anotherLongArgumentName, -+) -+ ? someOtherThing() -+ : somethingElse(true, 0)); - - compose( - (a) => { -@@ -93,12 +81,13 @@ - return thing.push(item); - }, []); - --reallyLongLongLongLongLongLongLongLongLongLongLongLongLongLongMethod( -- (f, g, h) => { -- return f.pop(); -- }, -- true, --); -+reallyLongLongLongLongLongLongLongLongLongLongLongLongLongLongMethod(( -+ f, -+ g, -+ h, -+) => { -+ return f.pop(); -+}, true); - - // Don't do the rest of these - -@@ -110,12 +99,9 @@ - false, - ); - --func( -- () => { -- thing(); -- }, -- { yes: true, cats: 5 }, --); -+func(() => { -+ thing(); -+}, { yes: true, cats: 5 }); - - compose( - (a) => { -``` - -# Output - -```js -setTimeout(function () { - thing(); -}, 500); - -["a", "b", "c"].reduce(function (item, thing) { - return thing + " " + item; -}, "letters:"); - -func(() => { - thing(); -}, identifier); - -func(function () { - thing(); -}, this.props.timeout * 1000); - -func((that) => { - thing(); -}, this.props.getTimeout()); - -func(() => { - thing(); -}, true); - -func(() => { - thing(); -}, null); - -func(() => { - thing(); -}, undefined); - -func(() => { - thing(); -}, /regex.*?/); - -func(() => { - thing(); -}, 1 ? 2 : 3); - -func( - function () { - return thing(); - }, - 1 ? 2 : 3, -); - -func(() => { - thing(); -}, something() ? someOtherThing() : somethingElse(true, 0)); - -func(() => { - thing(); -}, something(longArgumentName, anotherLongArgumentName) - ? someOtherThing() - : somethingElse(true, 0)); - -func(() => { - thing(); -}, something( - longArgumentName, - anotherLongArgumentName, - anotherLongArgumentName, - anotherLongArgumentName, -) - ? someOtherThing() - : somethingElse(true, 0)); - -compose( - (a) => { - return a.thing; - }, - (b) => b * b, -); - -somthing.reduce(function (item, thing) { - return (thing.blah = item); -}, {}); - -somthing.reduce(function (item, thing) { - return thing.push(item); -}, []); - -reallyLongLongLongLongLongLongLongLongLongLongLongLongLongLongMethod(( - f, - g, - h, -) => { - return f.pop(); -}, true); - -// Don't do the rest of these - -func( - function () { - thing(); - }, - true, - false, -); - -func(() => { - thing(); -}, { yes: true, cats: 5 }); - -compose( - (a) => { - return a.thing; - }, - (b) => { - return b + ""; - }, -); - -compose( - (a) => { - return a.thing; - }, - (b) => [1, 2, 3, 4, 5], -); - -renderThing( - (a) =>
Content. So much to say. Oh my. Are we done yet?
, - args, -); - -setTimeout( - // Something - function () { - thing(); - }, - 500, -); - -setTimeout( - /* blip */ function () { - thing(); - }, - 500, -); - -func( - (args) => { - execute(args); - }, - (result) => result && console.log("success"), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/function-single-destructuring/array.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/function-single-destructuring/array.js.snap deleted file mode 100644 index 651c7ec51dd..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/function-single-destructuring/array.js.snap +++ /dev/null @@ -1,144 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -function excludeFirstFiveResults([first, second, third, fourth, fifth, ...rest]) { - return rest; -} - -function excludeFirstFiveResults2([first, second, third, fourth, fifth, ...rest] = DEFAULT_FIVE_RESULTS) { - return rest; -} - -function excludeFirstFiveResults3([firstResult, secondResult, thirdResult, fourthResult, fifthResult, ...rest] = [1, 2, 3, 4, 5]) { - return rest; -} - -const excludeFirstFiveResults5 = ([first, second, third, fourth, fifth, ...rest]) => { - return rest; -} - -class A { - excludeFirstFiveResults([first, second, third, fourth, fifth, ...restOfResults]) { - return restOfResults; - } -} - -promise.then(([firstResult, secondResult, thirdResult, fourthResult, fifthResult, ...rest]) => { - return rest; -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -57,15 +57,13 @@ - } - } - --promise.then( -- ([ -- firstResult, -- secondResult, -- thirdResult, -- fourthResult, -- fifthResult, -- ...rest -- ]) => { -- return rest; -- }, --); -+promise.then(([ -+ firstResult, -+ secondResult, -+ thirdResult, -+ fourthResult, -+ fifthResult, -+ ...rest -+]) => { -+ return rest; -+}); -``` - -# Output - -```js -function excludeFirstFiveResults([ - first, - second, - third, - fourth, - fifth, - ...rest -]) { - return rest; -} - -function excludeFirstFiveResults2([ - first, - second, - third, - fourth, - fifth, - ...rest -] = DEFAULT_FIVE_RESULTS) { - return rest; -} - -function excludeFirstFiveResults3( - [ - firstResult, - secondResult, - thirdResult, - fourthResult, - fifthResult, - ...rest - ] = [1, 2, 3, 4, 5], -) { - return rest; -} - -const excludeFirstFiveResults5 = ([ - first, - second, - third, - fourth, - fifth, - ...rest -]) => { - return rest; -}; - -class A { - excludeFirstFiveResults([ - first, - second, - third, - fourth, - fifth, - ...restOfResults - ]) { - return restOfResults; - } -} - -promise.then(([ - firstResult, - secondResult, - thirdResult, - fourthResult, - fifthResult, - ...rest -]) => { - return rest; -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/functional_compose.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/functional_compose.js.snap deleted file mode 100644 index bd79c48bdf7..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/functional_compose.js.snap +++ /dev/null @@ -1,150 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/functional-composition/functional_compose.js ---- - -# Input - -```js -compose( - sortBy(x => x), - flatten, - map(x => [x, x*2]) -); - -somelib.compose( - sortBy(x => x), - flatten, - map(x => [x, x*2]) -); - -composeFlipped( - sortBy(x => x), - flatten, - map(x => [x, x*2]) -); - -somelib.composeFlipped( - sortBy(x => x), - flatten, - map(x => [x, x*2]) -); - -// no regression (#4602) -const hasValue = hasOwnProperty(a, b); - -this.compose(sortBy(x => x), flatten); -this.a.b.c.compose(sortBy(x => x), flatten); -someObj.someMethod(this.field.compose(a, b)); - -class A extends B { - compose() { - super.compose(sortBy(x => x), flatten); - } -} - -this.subscriptions.add( - this.componentUpdates - .pipe(startWith(this.props), distinctUntilChanged(isEqual)) - .subscribe(props => { - - }) - ) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,46 +1,21 @@ --compose( -- sortBy((x) => x), -- flatten, -- map((x) => [x, x * 2]), --); -+compose(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - --somelib.compose( -- sortBy((x) => x), -- flatten, -- map((x) => [x, x * 2]), --); -+somelib.compose(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - --composeFlipped( -- sortBy((x) => x), -- flatten, -- map((x) => [x, x * 2]), --); -+composeFlipped(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - --somelib.composeFlipped( -- sortBy((x) => x), -- flatten, -- map((x) => [x, x * 2]), --); -+somelib.composeFlipped(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - - // no regression (#4602) - const hasValue = hasOwnProperty(a, b); - --this.compose( -- sortBy((x) => x), -- flatten, --); --this.a.b.c.compose( -- sortBy((x) => x), -- flatten, --); -+this.compose(sortBy((x) => x), flatten); -+this.a.b.c.compose(sortBy((x) => x), flatten); - someObj.someMethod(this.field.compose(a, b)); - - class A extends B { - compose() { -- super.compose( -- sortBy((x) => x), -- flatten, -- ); -+ super.compose(sortBy((x) => x), flatten); - } - } - -``` - -# Output - -```js -compose(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - -somelib.compose(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - -composeFlipped(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - -somelib.composeFlipped(sortBy((x) => x), flatten, map((x) => [x, x * 2])); - -// no regression (#4602) -const hasValue = hasOwnProperty(a, b); - -this.compose(sortBy((x) => x), flatten); -this.a.b.c.compose(sortBy((x) => x), flatten); -someObj.someMethod(this.field.compose(a, b)); - -class A extends B { - compose() { - super.compose(sortBy((x) => x), flatten); - } -} - -this.subscriptions.add( - this.componentUpdates - .pipe(startWith(this.props), distinctUntilChanged(isEqual)) - .subscribe((props) => {}), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/ramda_compose.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/ramda_compose.js.snap deleted file mode 100644 index 0eff3325fe3..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/ramda_compose.js.snap +++ /dev/null @@ -1,133 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -var classyGreeting = (firstName, lastName) => - "The name's " + lastName + ", " + firstName + " " + lastName; -var yellGreeting = R.compose(R.toUpper, classyGreeting); -yellGreeting("James", "Bond"); //=> "THE NAME'S BOND, JAMES BOND" - -R.compose(Math.abs, R.add(1), R.multiply(2))(-4); //=> 7 - -// get :: String -> Object -> Maybe * -var get = R.curry((propName, obj) => Maybe(obj[propName])); - -// getStateCode :: Maybe String -> Maybe String -var getStateCode = R.composeK( - R.compose(Maybe.of, R.toUpper), - get("state"), - get("address"), - get("user") -); -getStateCode({ user: { address: { state: "ny" } } }); //=> Maybe.Just("NY") -getStateCode({}); //=> Maybe.Nothing() - -var db = { - users: { - JOE: { - name: "Joe", - followers: ["STEVE", "SUZY"] - } - } -}; - -// We'll pretend to do a db lookup which returns a promise -var lookupUser = userId => Promise.resolve(db.users[userId]); -var lookupFollowers = user => Promise.resolve(user.followers); -lookupUser("JOE").then(lookupFollowers); - -// followersForUser :: String -> Promise [UserId] -var followersForUser = R.composeP(lookupFollowers, lookupUser); -followersForUser("JOE").then(followers => console.log("Followers:", followers)); -// Followers: ["STEVE","SUZY"] - -const mapStateToProps = state => ({ - users: R.compose( R.filter(R.propEq('status', 'active')), - R.values)(state.users) -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -34,14 +34,13 @@ - - // followersForUser :: String -> Promise [UserId] - var followersForUser = R.composeP(lookupFollowers, lookupUser); --followersForUser("JOE").then((followers) => -- console.log("Followers:", followers), -+followersForUser("JOE").then( -+ (followers) => console.log("Followers:", followers), - ); - // Followers: ["STEVE","SUZY"] - - const mapStateToProps = (state) => ({ -- users: R.compose( -- R.filter(R.propEq("status", "active")), -- R.values, -- )(state.users), -+ users: R.compose(R.filter(R.propEq("status", "active")), R.values)( -+ state.users, -+ ), - }); -``` - -# Output - -```js -var classyGreeting = (firstName, lastName) => - "The name's " + lastName + ", " + firstName + " " + lastName; -var yellGreeting = R.compose(R.toUpper, classyGreeting); -yellGreeting("James", "Bond"); //=> "THE NAME'S BOND, JAMES BOND" - -R.compose(Math.abs, R.add(1), R.multiply(2))(-4); //=> 7 - -// get :: String -> Object -> Maybe * -var get = R.curry((propName, obj) => Maybe(obj[propName])); - -// getStateCode :: Maybe String -> Maybe String -var getStateCode = R.composeK( - R.compose(Maybe.of, R.toUpper), - get("state"), - get("address"), - get("user"), -); -getStateCode({ user: { address: { state: "ny" } } }); //=> Maybe.Just("NY") -getStateCode({}); //=> Maybe.Nothing() - -var db = { - users: { - JOE: { - name: "Joe", - followers: ["STEVE", "SUZY"], - }, - }, -}; - -// We'll pretend to do a db lookup which returns a promise -var lookupUser = (userId) => Promise.resolve(db.users[userId]); -var lookupFollowers = (user) => Promise.resolve(user.followers); -lookupUser("JOE").then(lookupFollowers); - -// followersForUser :: String -> Promise [UserId] -var followersForUser = R.composeP(lookupFollowers, lookupUser); -followersForUser("JOE").then( - (followers) => console.log("Followers:", followers), -); -// Followers: ["STEVE","SUZY"] - -const mapStateToProps = (state) => ({ - users: R.compose(R.filter(R.propEq("status", "active")), R.values)( - state.users, - ), -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/redux_connect.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/redux_connect.js.snap deleted file mode 100644 index 13a419d569e..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/redux_connect.js.snap +++ /dev/null @@ -1,37 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const ArtistInput = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,5 +1,3 @@ --const ArtistInput = connect( -- mapStateToProps, -- mapDispatchToProps, -- mergeProps, --)(Component); -+const ArtistInput = connect(mapStateToProps, mapDispatchToProps, mergeProps)( -+ Component, -+); -``` - -# Output - -```js -const ArtistInput = connect(mapStateToProps, mapDispatchToProps, mergeProps)( - Component, -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/reselect_createselector.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/reselect_createselector.js.snap deleted file mode 100644 index f661addf4f9..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/functional-composition/reselect_createselector.js.snap +++ /dev/null @@ -1,65 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -import { createSelector } from 'reselect'; - -const foo = createSelector( - getIds, - getObjects, - (ids, objects) => ids.map(id => objects[id]) -); - -const bar = createSelector( - [getIds, getObjects], - (ids, objects) => ids.map(id => objects[id]) -); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,9 +1,12 @@ - import { createSelector } from "reselect"; - --const foo = createSelector(getIds, getObjects, (ids, objects) => -- ids.map((id) => objects[id]), -+const foo = createSelector( -+ getIds, -+ getObjects, -+ (ids, objects) => ids.map((id) => objects[id]), - ); - --const bar = createSelector([getIds, getObjects], (ids, objects) => -- ids.map((id) => objects[id]), -+const bar = createSelector( -+ [getIds, getObjects], -+ (ids, objects) => ids.map((id) => objects[id]), - ); -``` - -# Output - -```js -import { createSelector } from "reselect"; - -const foo = createSelector( - getIds, - getObjects, - (ids, objects) => ids.map((id) => objects[id]), -); - -const bar = createSelector( - [getIds, getObjects], - (ids, objects) => ids.map((id) => objects[id]), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/arrow.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/arrow.js.snap deleted file mode 100644 index 4a4cad15690..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/arrow.js.snap +++ /dev/null @@ -1,93 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/last-argument-expansion/arrow.js ---- - -# Input - -```js -export default function searchUsers(action$) { - return action$.ofType(ActionTypes.SEARCHED_USERS) - .map(action => action.payload.query) - .filter(q => !!q) - .switchMap(q => - Observable.timer(800) // debounce - .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) - .mergeMap(() => Observable.merge( - Observable.of(replace(`?q=${q}`)), - ajax.getJSON(`https://api.github.com/search/users?q=${q}`) - .map(res => res.items) - .map(receiveUsers) - )) - ); -}; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -3,17 +3,19 @@ - .ofType(ActionTypes.SEARCHED_USERS) - .map((action) => action.payload.query) - .filter((q) => !!q) -- .switchMap((q) => -- Observable.timer(800) // debounce -- .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) -- .mergeMap(() => -- Observable.merge( -- Observable.of(replace(`?q=${q}`)), -- ajax -- .getJSON(`https://api.github.com/search/users?q=${q}`) -- .map((res) => res.items) -- .map(receiveUsers), -+ .switchMap( -+ (q) => -+ Observable.timer(800) // debounce -+ .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) -+ .mergeMap( -+ () => -+ Observable.merge( -+ Observable.of(replace(`?q=${q}`)), -+ ajax -+ .getJSON(`https://api.github.com/search/users?q=${q}`) -+ .map((res) => res.items) -+ .map(receiveUsers), -+ ), - ), -- ), - ); - } -``` - -# Output - -```js -export default function searchUsers(action$) { - return action$ - .ofType(ActionTypes.SEARCHED_USERS) - .map((action) => action.payload.query) - .filter((q) => !!q) - .switchMap( - (q) => - Observable.timer(800) // debounce - .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) - .mergeMap( - () => - Observable.merge( - Observable.of(replace(`?q=${q}`)), - ajax - .getJSON(`https://api.github.com/search/users?q=${q}`) - .map((res) => res.items) - .map(receiveUsers), - ), - ), - ); -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/dangling-comment-in-arrow-function.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/dangling-comment-in-arrow-function.js.snap index 31c9227e051..9e78ec61dc7 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/dangling-comment-in-arrow-function.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/dangling-comment-in-arrow-function.js.snap @@ -1,5 +1,7 @@ --- source: crates/rome_js_formatter/tests/prettier_tests.rs +info: + test_file: js/last-argument-expansion/dangling-comment-in-arrow-function.js --- # Input @@ -18,21 +20,25 @@ foo( ```diff --- Prettier +++ Rome -@@ -1,4 +1,3 @@ +@@ -1,4 +1,5 @@ -foo(() => -+foo(( - // foo +- // foo - {}, --); -+) => {}); ++foo( ++ ( ++ // foo ++ ) => {}, + ); ``` # Output ```js -foo(( - // foo -) => {}); +foo( + ( + // foo + ) => {}, +); ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/edge_case.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/edge_case.js.snap deleted file mode 100644 index 7c705ad6596..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/edge_case.js.snap +++ /dev/null @@ -1,259 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/last-argument-expansion/edge_case.js ---- - -# Input - -```js - - -a( - SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong, - [ - { - SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong: 1 - } - ] -); - -exports.examples = [ - { - render: withGraphQLQuery( - 'node(1234567890){image{uri}}', - function(container, data) { - return ( -
- - - -
- ); - } - ) - } -]; - -someReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReally.a([ - [], - // comment - [], -]); - -(function webpackUniversalModuleDefinition() {})(this, function(__WEBPACK_EXTERNAL_MODULE_85__, __WEBPACK_EXTERNAL_MODULE_115__) { -return /******/ (function(modules) { // webpackBootstrap - -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - -/***/ }, -/* 1 */ -/***/ function(module, exports, __webpack_require__) { - -/***/ }, -/* 2 */ -/***/ function(module, exports, __webpack_require__) { - -/***/ } -/******/ ]) -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -9,26 +9,26 @@ - - exports.examples = [ - { -- render: withGraphQLQuery( -- "node(1234567890){image{uri}}", -- function (container, data) { -- return ( --
-- -- -- --
-- ); -- }, -- ), -+ render: withGraphQLQuery("node(1234567890){image{uri}}", function ( -+ container, -+ data, -+ ) { -+ return ( -+
-+ -+ -+ -+
-+ ); -+ }), - }, - ]; - -@@ -40,29 +40,29 @@ - ], - ); - --(function webpackUniversalModuleDefinition() {})( -- this, -- function (__WEBPACK_EXTERNAL_MODULE_85__, __WEBPACK_EXTERNAL_MODULE_115__) { -- return /******/ (function (modules) { -- // webpackBootstrap -+(function webpackUniversalModuleDefinition() {})(this, function ( -+ __WEBPACK_EXTERNAL_MODULE_85__, -+ __WEBPACK_EXTERNAL_MODULE_115__, -+) { -+ return /******/ (function (modules) { -+ // webpackBootstrap -+ /******/ -+ })( -+ /************************************************************************/ -+ /******/ [ -+ /* 0 */ -+ /***/ function (module, exports, __webpack_require__) { -+ /***/ -+ }, -+ /* 1 */ -+ /***/ function (module, exports, __webpack_require__) { -+ /***/ -+ }, -+ /* 2 */ -+ /***/ function (module, exports, __webpack_require__) { -+ /***/ -+ }, - /******/ -- })( -- /************************************************************************/ -- /******/ [ -- /* 0 */ -- /***/ function (module, exports, __webpack_require__) { -- /***/ -- }, -- /* 1 */ -- /***/ function (module, exports, __webpack_require__) { -- /***/ -- }, -- /* 2 */ -- /***/ function (module, exports, __webpack_require__) { -- /***/ -- }, -- /******/ -- ], -- ); -- }, --); -+ ], -+ ); -+}); -``` - -# Output - -```js -a( - SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong, - [ - { - SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong: 1, - }, - ], -); - -exports.examples = [ - { - render: withGraphQLQuery("node(1234567890){image{uri}}", function ( - container, - data, - ) { - return ( -
- - - -
- ); - }), - }, -]; - -someReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReally.a( - [ - [], - // comment - [], - ], -); - -(function webpackUniversalModuleDefinition() {})(this, function ( - __WEBPACK_EXTERNAL_MODULE_85__, - __WEBPACK_EXTERNAL_MODULE_115__, -) { - return /******/ (function (modules) { - // webpackBootstrap - /******/ - })( - /************************************************************************/ - /******/ [ - /* 0 */ - /***/ function (module, exports, __webpack_require__) { - /***/ - }, - /* 1 */ - /***/ function (module, exports, __webpack_require__) { - /***/ - }, - /* 2 */ - /***/ function (module, exports, __webpack_require__) { - /***/ - }, - /******/ - ], - ); -}); -``` - - -# Lines exceeding max width of 80 characters -``` - 2: SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong, - 5: SomethingVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong: 1, - 35: someReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReally.a( -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/empty-lines.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/empty-lines.js.snap deleted file mode 100644 index d097bbe7c42..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/empty-lines.js.snap +++ /dev/null @@ -1,54 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -all_verylongcall_verylongcall_verylongcall_verylongcall_verylongcall( - (a, - - b) => { - console.log() - } -) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,9 +1,7 @@ --all_verylongcall_verylongcall_verylongcall_verylongcall_verylongcall( -- ( -- a, -+all_verylongcall_verylongcall_verylongcall_verylongcall_verylongcall(( -+ a, - -- b, -- ) => { -- console.log(); -- }, --); -+ b, -+) => { -+ console.log(); -+}); -``` - -# Output - -```js -all_verylongcall_verylongcall_verylongcall_verylongcall_verylongcall(( - a, - - b, -) => { - console.log(); -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression-issue-2239.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression-issue-2239.js.snap deleted file mode 100644 index 2c568fb6bb5..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression-issue-2239.js.snap +++ /dev/null @@ -1,44 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -someFunctionCallWithBigArgumentsAndACallback(thisArgumentIsQuiteLong, function(cool) { - return cool -}) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,6 +1,5 @@ --someFunctionCallWithBigArgumentsAndACallback( -- thisArgumentIsQuiteLong, -- function (cool) { -- return cool; -- }, --); -+someFunctionCallWithBigArgumentsAndACallback(thisArgumentIsQuiteLong, function ( -+ cool, -+) { -+ return cool; -+}); -``` - -# Output - -```js -someFunctionCallWithBigArgumentsAndACallback(thisArgumentIsQuiteLong, function ( - cool, -) { - return cool; -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression.js.snap deleted file mode 100644 index 03235a97ad4..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/function-expression.js.snap +++ /dev/null @@ -1,96 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -function* mySagas() { - yield effects.takeEvery( - rexpress.actionTypes.REQUEST_START, - function*({ id }) { - console.log(id); - yield rexpress.actions(store).writeHead(id, 400); - yield rexpress.actions(store).end(id, 'pong'); - console.log('pong'); - } - ); -} - -function mySagas2() { - return effects.takeEvery( - rexpress.actionTypes.REQUEST_START, - function({ id }) { - console.log(id); - } - ); -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,20 +1,18 @@ - function* mySagas() { -- yield effects.takeEvery( -- rexpress.actionTypes.REQUEST_START, -- function* ({ id }) { -- console.log(id); -- yield rexpress.actions(store).writeHead(id, 400); -- yield rexpress.actions(store).end(id, "pong"); -- console.log("pong"); -- }, -- ); -+ yield effects.takeEvery(rexpress.actionTypes.REQUEST_START, function* ({ -+ id, -+ }) { -+ console.log(id); -+ yield rexpress.actions(store).writeHead(id, 400); -+ yield rexpress.actions(store).end(id, "pong"); -+ console.log("pong"); -+ }); - } - - function mySagas2() { -- return effects.takeEvery( -- rexpress.actionTypes.REQUEST_START, -- function ({ id }) { -- console.log(id); -- }, -- ); -+ return effects.takeEvery(rexpress.actionTypes.REQUEST_START, function ({ -+ id, -+ }) { -+ console.log(id); -+ }); - } -``` - -# Output - -```js -function* mySagas() { - yield effects.takeEvery(rexpress.actionTypes.REQUEST_START, function* ({ - id, - }) { - console.log(id); - yield rexpress.actions(store).writeHead(id, 400); - yield rexpress.actions(store).end(id, "pong"); - console.log("pong"); - }); -} - -function mySagas2() { - return effects.takeEvery(rexpress.actionTypes.REQUEST_START, function ({ - id, - }) { - console.log(id); - }); -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/jsx.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/jsx.js.snap deleted file mode 100644 index 6e282cdc7e0..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/jsx.js.snap +++ /dev/null @@ -1,49 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const els = items.map(item => ( -
- {children} -
-)); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,5 +1,7 @@ --const els = items.map((item) => ( --
-- {children} --
--)); -+const els = items.map( -+ (item) => ( -+
-+ {children} -+
-+ ), -+); -``` - -# Output - -```js -const els = items.map( - (item) => ( -
- {children} -
- ), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/number-only-array.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/number-only-array.js.snap deleted file mode 100644 index 8102a431ab7..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/number-only-array.js.snap +++ /dev/null @@ -1,46 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -instantiate(game, [ - transform([-0.7, 0.5, 0]), - render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [1, 1, 0.3, 1]), -]); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,8 +1,6 @@ - instantiate(game, [ - transform([-0.7, 0.5, 0]), -- render_colored_diffuse( -- game.MaterialDiffuse, -- game.Meshes["monkey_flat"], -- [1, 1, 0.3, 1], -- ), -+ render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [ -+ 1, 1, 0.3, 1, -+ ]), - ]); -``` - -# Output - -```js -instantiate(game, [ - transform([-0.7, 0.5, 0]), - render_colored_diffuse(game.MaterialDiffuse, game.Meshes["monkey_flat"], [ - 1, 1, 0.3, 1, - ]), -]); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/object.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/object.js.snap deleted file mode 100644 index f372f95a334..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/last-argument-expansion/object.js.snap +++ /dev/null @@ -1,80 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const formatData = pipe( - zip, - map(([ ref, data ]) => ({ - nodeId: ref.nodeId.toString(), - ...attributeFromDataValue(ref.attributeId, data) - })), - groupBy(prop('nodeId')), - map(mergeAll), - values -); - -export const setProp = y => ({ - ...y, - a: 'very, very, very long very, very long text' -}); - -export const log = y => { - console.log('very, very, very long very, very long text') -}; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,9 +1,11 @@ - const formatData = pipe( - zip, -- map(([ref, data]) => ({ -- nodeId: ref.nodeId.toString(), -- ...attributeFromDataValue(ref.attributeId, data), -- })), -+ map( -+ ([ref, data]) => ({ -+ nodeId: ref.nodeId.toString(), -+ ...attributeFromDataValue(ref.attributeId, data), -+ }), -+ ), - groupBy(prop("nodeId")), - map(mergeAll), - values, -``` - -# Output - -```js -const formatData = pipe( - zip, - map( - ([ref, data]) => ({ - nodeId: ref.nodeId.toString(), - ...attributeFromDataValue(ref.attributeId, data), - }), - ), - groupBy(prop("nodeId")), - map(mergeAll), - values, -); - -export const setProp = (y) => ({ - ...y, - a: "very, very, very long very, very long text", -}); - -export const log = (y) => { - console.log("very, very, very long very, very long text"); -}; -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/complex-args.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/complex-args.js.snap deleted file mode 100644 index ed966660f1e..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/complex-args.js.snap +++ /dev/null @@ -1,41 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -client.execute( - Post.selectAll() - .where(Post.id.eq(42)) - .where(Post.published.eq(true)) -); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,3 +1,5 @@ - client.execute( -- Post.selectAll().where(Post.id.eq(42)).where(Post.published.eq(true)), -+ Post.selectAll() -+ .where(Post.id.eq(42)) -+ .where(Post.published.eq(true)), - ); -``` - -# Output - -```js -client.execute( - Post.selectAll() - .where(Post.id.eq(42)) - .where(Post.published.eq(true)), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/first_long.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/first_long.js.snap deleted file mode 100644 index b271e047198..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/first_long.js.snap +++ /dev/null @@ -1,126 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/method-chain/first_long.js ---- - -# Input - -```js -export default function theFunction(action$, store) { - return action$.ofType(THE_ACTION).switchMap(action => Observable - .webSocket({ - url: THE_URL, - more: stuff(), - evenMore: stuff({ - value1: true, - value2: false, - value3: false - }) - }) - .filter(data => theFilter(data)) - .map(({ theType, ...data }) => theMap(theType, data)) - .retryWhen(errors => errors)); -} - -function f() { - return this._getWorker(workerOptions)({ - filePath, - hasteImplModulePath: this._options.hasteImplModulePath, - }).then( - metadata => { - // `1` for truthy values instead of `true` to save cache space. - fileMetadata[H.VISITED] = 1; - const metadataId = metadata.id; - const metadataModule = metadata.module; - if (metadataId && metadataModule) { - fileMetadata[H.ID] = metadataId; - setModule(metadataId, metadataModule); - } - fileMetadata[H.DEPENDENCIES] = metadata.dependencies || []; - } - ); -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,17 +1,18 @@ - export default function theFunction(action$, store) { -- return action$.ofType(THE_ACTION).switchMap((action) => -- Observable.webSocket({ -- url: THE_URL, -- more: stuff(), -- evenMore: stuff({ -- value1: true, -- value2: false, -- value3: false, -- }), -- }) -- .filter((data) => theFilter(data)) -- .map(({ theType, ...data }) => theMap(theType, data)) -- .retryWhen((errors) => errors), -+ return action$.ofType(THE_ACTION).switchMap( -+ (action) => -+ Observable.webSocket({ -+ url: THE_URL, -+ more: stuff(), -+ evenMore: stuff({ -+ value1: true, -+ value2: false, -+ value3: false, -+ }), -+ }) -+ .filter((data) => theFilter(data)) -+ .map(({ theType, ...data }) => theMap(theType, data)) -+ .retryWhen((errors) => errors), - ); - } - -``` - -# Output - -```js -export default function theFunction(action$, store) { - return action$.ofType(THE_ACTION).switchMap( - (action) => - Observable.webSocket({ - url: THE_URL, - more: stuff(), - evenMore: stuff({ - value1: true, - value2: false, - value3: false, - }), - }) - .filter((data) => theFilter(data)) - .map(({ theType, ...data }) => theMap(theType, data)) - .retryWhen((errors) => errors), - ); -} - -function f() { - return this._getWorker(workerOptions)({ - filePath, - hasteImplModulePath: this._options.hasteImplModulePath, - }).then((metadata) => { - // `1` for truthy values instead of `true` to save cache space. - fileMetadata[H.VISITED] = 1; - const metadataId = metadata.id; - const metadataModule = metadata.module; - if (metadataId && metadataModule) { - fileMetadata[H.ID] = metadataId; - setModule(metadataId, metadataModule); - } - fileMetadata[H.DEPENDENCIES] = metadata.dependencies || []; - }); -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/issue-4125.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/issue-4125.js.snap index 642f3bb8987..ba061e80638 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/issue-4125.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/issue-4125.js.snap @@ -164,60 +164,7 @@ var l = base ```diff --- Prettier +++ Rome -@@ -111,18 +111,20 @@ - .ofType(ActionTypes.SEARCHED_USERS) - .map((action) => action.payload.query) - .filter((q) => !!q) -- .switchMap((q) => -- Observable.timer(800) // debounce -- .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) -- .mergeMap(() => -- Observable.merge( -- Observable.of(replace(`?q=${q}`)), -- ajax -- .getJSON(`https://api.github.com/search/users?q=${q}`) -- .map((res) => res.items) -- .map(receiveUsers), -+ .switchMap( -+ (q) => -+ Observable.timer(800) // debounce -+ .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) -+ .mergeMap( -+ () => -+ Observable.merge( -+ Observable.of(replace(`?q=${q}`)), -+ ajax -+ .getJSON(`https://api.github.com/search/users?q=${q}`) -+ .map((res) => res.items) -+ .map(receiveUsers), -+ ), - ), -- ), - ); - - window.FooClient.setVars({ -@@ -138,10 +140,18 @@ - const a1 = x.a(true).b(null).c(123); - const a2 = x.d("").e(``).f(g); - const a3 = x.d("").e(`${123}`).f(g); --const a4 = x.h(i.j).k(l()).m([n, o]); -+const a4 = x -+ .h(i.j) -+ .k(l()) -+ .m([n, o]); - class X { - y() { -- const j = x.a(this).b(super.cde()).f(/g/).h(new i()).j(); -+ const j = x -+ .a(this) -+ .b(super.cde()) -+ .f(/g/) -+ .h(new i()) -+ .j(); - } - } - -@@ -161,7 +171,4 @@ +@@ -161,7 +161,4 @@ .b() .c(a(a(b(c(d().p).p).p).p)); @@ -344,20 +291,18 @@ action$ .ofType(ActionTypes.SEARCHED_USERS) .map((action) => action.payload.query) .filter((q) => !!q) - .switchMap( - (q) => - Observable.timer(800) // debounce - .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) - .mergeMap( - () => - Observable.merge( - Observable.of(replace(`?q=${q}`)), - ajax - .getJSON(`https://api.github.com/search/users?q=${q}`) - .map((res) => res.items) - .map(receiveUsers), - ), + .switchMap((q) => + Observable.timer(800) // debounce + .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS)) + .mergeMap(() => + Observable.merge( + Observable.of(replace(`?q=${q}`)), + ajax + .getJSON(`https://api.github.com/search/users?q=${q}`) + .map((res) => res.items) + .map(receiveUsers), ), + ), ); window.FooClient.setVars({ @@ -373,18 +318,10 @@ it("gets triggered by mouseenter", () => { const a1 = x.a(true).b(null).c(123); const a2 = x.d("").e(``).f(g); const a3 = x.d("").e(`${123}`).f(g); -const a4 = x - .h(i.j) - .k(l()) - .m([n, o]); +const a4 = x.h(i.j).k(l()).m([n, o]); class X { y() { - const j = x - .a(this) - .b(super.cde()) - .f(/g/) - .h(new i()) - .j(); + const j = x.a(this).b(super.cde()).f(/g/).h(new i()).j(); } } diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/logical.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/logical.js.snap deleted file mode 100644 index 7a97dc8e1d5..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/logical.js.snap +++ /dev/null @@ -1,79 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/method-chain/logical.js ---- - -# Input - -```js -const someLongVariableName = (idx( - this.props, - props => props.someLongPropertyName -) || [] -).map(edge => edge.node); - -(veryLongVeryLongVeryLong || e).map(tickets => - TicketRecord.createFromSomeLongString()); - -(veryLongVeryLongVeryLong || e).map(tickets => - TicketRecord.createFromSomeLongString()).filter(obj => !!obj); - -(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => - TicketRecord.createFromSomeLongString()); - -(veryLongVeryLongVeryLong || anotherVeryLongVeryLongVeryLong || veryVeryVeryLongError).map(tickets => - TicketRecord.createFromSomeLongString()).filter(obj => !!obj); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -2,8 +2,8 @@ - idx(this.props, (props) => props.someLongPropertyName) || [] - ).map((edge) => edge.node); - --(veryLongVeryLongVeryLong || e).map((tickets) => -- TicketRecord.createFromSomeLongString(), -+(veryLongVeryLongVeryLong || e).map( -+ (tickets) => TicketRecord.createFromSomeLongString(), - ); - - (veryLongVeryLongVeryLong || e) -``` - -# Output - -```js -const someLongVariableName = ( - idx(this.props, (props) => props.someLongPropertyName) || [] -).map((edge) => edge.node); - -(veryLongVeryLongVeryLong || e).map( - (tickets) => TicketRecord.createFromSomeLongString(), -); - -(veryLongVeryLongVeryLong || e) - .map((tickets) => TicketRecord.createFromSomeLongString()) - .filter((obj) => !!obj); - -( - veryLongVeryLongVeryLong || - anotherVeryLongVeryLongVeryLong || - veryVeryVeryLongError -).map((tickets) => TicketRecord.createFromSomeLongString()); - -( - veryLongVeryLongVeryLong || - anotherVeryLongVeryLongVeryLong || - veryVeryVeryLongError -) - .map((tickets) => TicketRecord.createFromSomeLongString()) - .filter((obj) => !!obj); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/pr-7889.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/pr-7889.js.snap deleted file mode 100644 index cccee2fca9a..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/method-chain/pr-7889.js.snap +++ /dev/null @@ -1,76 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const Profile = view.with({ name: (state) => state.name }).as((props) => ( -
-

Hello, {props.name}

-
-)) - -const Profile2 = view.with({ name }).as((props) => ( -
-

Hello, {props.name}

-
-)) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,11 +1,15 @@ --const Profile = view.with({ name: (state) => state.name }).as((props) => ( --
--

Hello, {props.name}

--
--)); -+const Profile = view.with({ name: (state) => state.name }).as( -+ (props) => ( -+
-+

Hello, {props.name}

-+
-+ ), -+); - --const Profile2 = view.with({ name }).as((props) => ( --
--

Hello, {props.name}

--
--)); -+const Profile2 = view.with({ name }).as( -+ (props) => ( -+
-+

Hello, {props.name}

-+
-+ ), -+); -``` - -# Output - -```js -const Profile = view.with({ name: (state) => state.name }).as( - (props) => ( -
-

Hello, {props.name}

-
- ), -); - -const Profile2 = view.with({ name }).as( - (props) => ( -
-

Hello, {props.name}

-
- ), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/new-expression/with-member-expression.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/new-expression/with-member-expression.js.snap deleted file mode 100644 index c97f67a0e61..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/new-expression/with-member-expression.js.snap +++ /dev/null @@ -1,62 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -function functionName() { - // indent to make the line break - if (true) { - this._aVeryLongVariableNameToForceLineBreak = new this.Promise( - (resolve, reject) => { - // do something - } - ); - } -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,10 +1,11 @@ - function functionName() { - // indent to make the line break - if (true) { -- this._aVeryLongVariableNameToForceLineBreak = new this.Promise( -- (resolve, reject) => { -- // do something -- }, -- ); -+ this._aVeryLongVariableNameToForceLineBreak = new this.Promise(( -+ resolve, -+ reject, -+ ) => { -+ // do something -+ }); - } - } -``` - -# Output - -```js -function functionName() { - // indent to make the line break - if (true) { - this._aVeryLongVariableNameToForceLineBreak = new this.Promise(( - resolve, - reject, - ) => { - // do something - }); - } -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/objects/assignment-expression/object-value.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/objects/assignment-expression/object-value.js.snap deleted file mode 100644 index 815c446a1e1..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/objects/assignment-expression/object-value.js.snap +++ /dev/null @@ -1,52 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -a = { - resource: (this.resource = resource), -} - -map(([resource]) => ({ - resource: (this.resource = resource), -})) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -2,6 +2,8 @@ - resource: (this.resource = resource), - }; - --map(([resource]) => ({ -- resource: (this.resource = resource), --})); -+map( -+ ([resource]) => ({ -+ resource: (this.resource = resource), -+ }), -+); -``` - -# Output - -```js -a = { - resource: (this.resource = resource), -}; - -map( - ([resource]) => ({ - resource: (this.resource = resource), - }), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/objects/range.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/objects/range.js.snap deleted file mode 100644 index fc5f28071bc..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/objects/range.js.snap +++ /dev/null @@ -1,65 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -group( - concat([ - "(", - indent( - options.tabWidth, - concat([line, join(concat([",", line]), printed)]) - ), - options.trailingComma ? "," : "", - line, - ")" - ]), - {shouldBreak: true} -) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,13 +1,7 @@ --group( -- concat([ -- "(", -- indent( -- options.tabWidth, -- concat([line, join(concat([",", line]), printed)]), -- ), -- options.trailingComma ? "," : "", -- line, -- ")", -- ]), -- { shouldBreak: true }, --); -+group(concat([ -+ "(", -+ indent(options.tabWidth, concat([line, join(concat([",", line]), printed)])), -+ options.trailingComma ? "," : "", -+ line, -+ ")", -+]), { shouldBreak: true }); -``` - -# Output - -```js -group(concat([ - "(", - indent(options.tabWidth, concat([line, join(concat([",", line]), printed)])), - options.trailingComma ? "," : "", - line, - ")", -]), { shouldBreak: true }); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/performance/nested-real.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/performance/nested-real.js.snap deleted file mode 100644 index 271ccb8a7a1..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/performance/nested-real.js.snap +++ /dev/null @@ -1,301 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -tap.test("RecordImport.advance", (t) => { - const checkStates = (batches, states) => { - t.equal(batches.length, states.length); - for (const batch of batches) { - t.equal(batch.state, states.shift()); - t.ok(batch.getCurState().name(i18n)); - } - }; - - const batch = init.getRecordBatch(); - const dataFile = path.resolve(process.cwd(), "testData", "default.json"); - - const getBatches = (callback) => { - RecordImport.find({}, "", {}, (err, batches) => { - callback(null, batches.filter((batch) => (batch.state !== "error" && - batch.state !== "completed"))); - }); - }; - - mockFS((callback) => { - batch.setResults([fs.createReadStream(dataFile)], (err) => { - t.error(err, "Error should be empty."); - t.equal(batch.results.length, 6, "Check number of results"); - for (const result of batch.results) { - t.equal(result.result, "unknown"); - t.ok(result.data); - t.equal(result.data.lang, "en"); - } - - getBatches((err, batches) => { - checkStates(batches, ["started"]); - - RecordImport.advance((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, ["process.completed"]); - - // Need to manually move to the next step - batch.importRecords((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, ["import.completed"]); - - RecordImport.advance((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, - ["similarity.sync.completed"]); - - RecordImport.advance((err) => { - t.error(err, - "Error should be empty."); - - t.ok(batch.getCurState() - .name(i18n)); - - getBatches((err, batches) => { - checkStates(batches, []); - t.end(); - callback(); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - }); -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -22,63 +22,66 @@ - }; - - mockFS((callback) => { -- batch.setResults([fs.createReadStream(dataFile)], (err) => { -- t.error(err, "Error should be empty."); -- t.equal(batch.results.length, 6, "Check number of results"); -- for (const result of batch.results) { -- t.equal(result.result, "unknown"); -- t.ok(result.data); -- t.equal(result.data.lang, "en"); -- } -+ batch.setResults( -+ [fs.createReadStream(dataFile)], -+ (err) => { -+ t.error(err, "Error should be empty."); -+ t.equal(batch.results.length, 6, "Check number of results"); -+ for (const result of batch.results) { -+ t.equal(result.result, "unknown"); -+ t.ok(result.data); -+ t.equal(result.data.lang, "en"); -+ } - -- getBatches((err, batches) => { -- checkStates(batches, ["started"]); -+ getBatches((err, batches) => { -+ checkStates(batches, ["started"]); - -- RecordImport.advance((err) => { -- t.error(err, "Error should be empty."); -+ RecordImport.advance((err) => { -+ t.error(err, "Error should be empty."); - -- getBatches((err, batches) => { -- checkStates(batches, ["process.completed"]); -+ getBatches((err, batches) => { -+ checkStates(batches, ["process.completed"]); - -- // Need to manually move to the next step -- batch.importRecords((err) => { -- t.error(err, "Error should be empty."); -+ // Need to manually move to the next step -+ batch.importRecords((err) => { -+ t.error(err, "Error should be empty."); - -- getBatches((err, batches) => { -- checkStates(batches, ["import.completed"]); -+ getBatches((err, batches) => { -+ checkStates(batches, ["import.completed"]); - -- RecordImport.advance((err) => { -- t.error(err, "Error should be empty."); -+ RecordImport.advance((err) => { -+ t.error(err, "Error should be empty."); - -- getBatches((err, batches) => { -- checkStates(batches, ["similarity.sync.completed"]); -+ getBatches((err, batches) => { -+ checkStates(batches, ["similarity.sync.completed"]); - -- RecordImport.advance((err) => { -- t.error(err, "Error should be empty."); -+ RecordImport.advance((err) => { -+ t.error(err, "Error should be empty."); - -- t.ok(batch.getCurState().name(i18n)); -+ t.ok(batch.getCurState().name(i18n)); - -- getBatches((err, batches) => { -- checkStates(batches, []); -- t.end(); -- callback(); -+ getBatches((err, batches) => { -+ checkStates(batches, []); -+ t.end(); -+ callback(); -+ }); - }); -+ -+ t.ok(batch.getCurState().name(i18n)); - }); -+ }); - -- t.ok(batch.getCurState().name(i18n)); -- }); -+ t.ok(batch.getCurState().name(i18n)); - }); -- -- t.ok(batch.getCurState().name(i18n)); - }); -+ -+ t.ok(batch.getCurState().name(i18n)); - }); -- -- t.ok(batch.getCurState().name(i18n)); - }); -+ -+ t.ok(batch.getCurState().name(i18n)); - }); -- -- t.ok(batch.getCurState().name(i18n)); -- }); -- }); -+ }, -+ ); - }); - }); -``` - -# Output - -```js -tap.test("RecordImport.advance", (t) => { - const checkStates = (batches, states) => { - t.equal(batches.length, states.length); - for (const batch of batches) { - t.equal(batch.state, states.shift()); - t.ok(batch.getCurState().name(i18n)); - } - }; - - const batch = init.getRecordBatch(); - const dataFile = path.resolve(process.cwd(), "testData", "default.json"); - - const getBatches = (callback) => { - RecordImport.find({}, "", {}, (err, batches) => { - callback( - null, - batches.filter( - (batch) => batch.state !== "error" && batch.state !== "completed", - ), - ); - }); - }; - - mockFS((callback) => { - batch.setResults( - [fs.createReadStream(dataFile)], - (err) => { - t.error(err, "Error should be empty."); - t.equal(batch.results.length, 6, "Check number of results"); - for (const result of batch.results) { - t.equal(result.result, "unknown"); - t.ok(result.data); - t.equal(result.data.lang, "en"); - } - - getBatches((err, batches) => { - checkStates(batches, ["started"]); - - RecordImport.advance((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, ["process.completed"]); - - // Need to manually move to the next step - batch.importRecords((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, ["import.completed"]); - - RecordImport.advance((err) => { - t.error(err, "Error should be empty."); - - getBatches((err, batches) => { - checkStates(batches, ["similarity.sync.completed"]); - - RecordImport.advance((err) => { - t.error(err, "Error should be empty."); - - t.ok(batch.getCurState().name(i18n)); - - getBatches((err, batches) => { - checkStates(batches, []); - t.end(); - callback(); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }); - - t.ok(batch.getCurState().name(i18n)); - }); - }, - ); - }); -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/argument-list.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/argument-list.js.snap deleted file mode 100644 index 937b213a8d2..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/argument-list.js.snap +++ /dev/null @@ -1,533 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: js/preserve-line/argument-list.js ---- - -# Input - -```js -longArgNamesWithComments( - - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong1, - - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong2, - - /* Hello World */ - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong3, - - -); - -shortArgNames( - - - short, - - short2, - short3, -); - -comments( - - // Comment - - /* Some comments */ - short, - /* Another comment */ - - - short2, // Even more comments - - - /* Another comment */ - - - // Long Long Long Long Long Comment - - - - /* Long Long Long Long Long Comment */ - // Long Long Long Long Long Comment - - short3, - // More comments - - -); - -differentArgTypes( - - () => { - return true - }, - - isTrue ? - doSomething() : 12, - -); - -moreArgTypes( - - [1, 2, - 3], - - { - name: 'Hello World', - age: 29 - }, - - doSomething( - - // Hello world - - - // Hello world again - { name: 'Hello World', age: 34 }, - - - oneThing - + anotherThing, - - // Comment - - ), - -); - -evenMoreArgTypes( - doSomething( - { name: 'Hello World', age: 34 }, - - - true - - ), - - 14, - - 1 + 2 - - 90/80, - - !98 * - 60 - - 90, - - - -) - -foo.apply(null, - -// Array here -[1, 2]); - - -bar.on("readable", - -() => { - doStuff() -}); - -foo(['A, B'], - -/* function here */ -function doSomething() { return true; }); - -doSomething.apply(null, - -// Comment - -[ - 'Hello world 1', - 'Hello world 2', - 'Hello world 3', -]); - - -doAnotherThing("node", - -{ - solution_type, - time_frame -}); - -stuff.doThing(someStuff, - - -1, { - accept: node => doSomething(node) -}); - -doThing( - - someOtherStuff, - - // This is important - true, { - decline: creditCard => takeMoney(creditCard) -} - -); - -func( - () => { - thing(); - }, - - { yes: true, no: 5 } -); - -doSomething( - - { tomorrow: maybe, today: never[always] }, - - 1337, - - /* Comment */ - - // This is important - { helloWorld, someImportantStuff } - - -); - -function foo( - one, - - two, - three, - four, - - - five, - six, - seven, - eight, - nine, - ten, - - eleven - -) {} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -2,21 +2,14 @@ - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong1, -- - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong2, -- - /* Hello World */ - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong3, - ); -- --shortArgNames( -- short, - -- short2, -- short3, --); -+shortArgNames(short, short2, short3); - - comments( - // Comment -@@ -26,7 +19,6 @@ - /* Another comment */ - - short2, // Even more comments -- - /* Another comment */ - - // Long Long Long Long Long Comment -@@ -38,28 +30,21 @@ - // More comments - ); - --differentArgTypes( -- () => { -- return true; -- }, -+differentArgTypes(() => { -+ return true; -+}, isTrue ? doSomething() : 12); - -- isTrue ? doSomething() : 12, --); -- - moreArgTypes( - [1, 2, 3], -- - { - name: "Hello World", - age: 29, - }, -- - doSomething( - // Hello world - - // Hello world again - { name: "Hello World", age: 34 }, -- - oneThing + anotherThing, - - // Comment -@@ -67,37 +52,24 @@ - ); - - evenMoreArgTypes( -- doSomething( -- { name: "Hello World", age: 34 }, -- -- true, -- ), -- -+ doSomething({ name: "Hello World", age: 34 }, true), - 14, -- - 1 + 2 - 90 / 80, -- - !98 * 60 - 90, - ); - - foo.apply( - null, -- - // Array here - [1, 2], - ); - --bar.on( -- "readable", -- -- () => { -- doStuff(); -- }, --); -+bar.on("readable", () => { -+ doStuff(); -+}); - - foo( - ["A, B"], -- - /* function here */ - function doSomething() { - return true; -@@ -106,33 +78,22 @@ - - doSomething.apply( - null, -- - // Comment - - ["Hello world 1", "Hello world 2", "Hello world 3"], - ); - --doAnotherThing( -- "node", -+doAnotherThing("node", { -+ solution_type, -+ time_frame, -+}); - -- { -- solution_type, -- time_frame, -- }, --); -- --stuff.doThing( -- someStuff, -- -- -1, -- { -- accept: (node) => doSomething(node), -- }, --); -+stuff.doThing(someStuff, -1, { -+ accept: (node) => doSomething(node), -+}); - - doThing( - someOtherStuff, -- - // This is important - true, - { -@@ -140,19 +101,13 @@ - }, - ); - --func( -- () => { -- thing(); -- }, -+func(() => { -+ thing(); -+}, { yes: true, no: 5 }); - -- { yes: true, no: 5 }, --); -- - doSomething( - { tomorrow: maybe, today: never[always] }, -- - 1337, -- - /* Comment */ - - // This is important -``` - -# Output - -```js -longArgNamesWithComments( - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong1, - // Hello World - - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong2, - /* Hello World */ - longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong3, -); - -shortArgNames(short, short2, short3); - -comments( - // Comment - - /* Some comments */ - short, - /* Another comment */ - - short2, // Even more comments - /* Another comment */ - - // Long Long Long Long Long Comment - - /* Long Long Long Long Long Comment */ - // Long Long Long Long Long Comment - - short3, - // More comments -); - -differentArgTypes(() => { - return true; -}, isTrue ? doSomething() : 12); - -moreArgTypes( - [1, 2, 3], - { - name: "Hello World", - age: 29, - }, - doSomething( - // Hello world - - // Hello world again - { name: "Hello World", age: 34 }, - oneThing + anotherThing, - - // Comment - ), -); - -evenMoreArgTypes( - doSomething({ name: "Hello World", age: 34 }, true), - 14, - 1 + 2 - 90 / 80, - !98 * 60 - 90, -); - -foo.apply( - null, - // Array here - [1, 2], -); - -bar.on("readable", () => { - doStuff(); -}); - -foo( - ["A, B"], - /* function here */ - function doSomething() { - return true; - }, -); - -doSomething.apply( - null, - // Comment - - ["Hello world 1", "Hello world 2", "Hello world 3"], -); - -doAnotherThing("node", { - solution_type, - time_frame, -}); - -stuff.doThing(someStuff, -1, { - accept: (node) => doSomething(node), -}); - -doThing( - someOtherStuff, - // This is important - true, - { - decline: (creditCard) => takeMoney(creditCard), - }, -); - -func(() => { - thing(); -}, { yes: true, no: 5 }); - -doSomething( - { tomorrow: maybe, today: never[always] }, - 1337, - /* Comment */ - - // This is important - { helloWorld, someImportantStuff }, -); - -function foo( - one, - - two, - three, - four, - - five, - six, - seven, - eight, - nine, - ten, - - eleven, -) {} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/parameter-list.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/parameter-list.js.snap deleted file mode 100644 index e9059216007..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/preserve-line/parameter-list.js.snap +++ /dev/null @@ -1,327 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -class Foo { - constructor( - one, - - two, - three, - four, - - - five, - six, - seven, - eight, - nine, - ten, - - eleven - - ) {} -} - -function foo( - one, - - two, - three, - four, - - - five, - six, - seven, - eight, - nine, - ten, - - eleven - -) {} - -call((a, b) => {}); - -call(( - one, - two, - three, - four, - five, - six, - seven, - eight, - nine, - ten, - eleven -) => {}); - -call(( - one, - - two, - three, - four, - - - five, - six, - seven, - eight, - nine, - ten, - - eleven - -) => {}); - -function test({ - one, - - two, - three, - four, - - - five, - six, - seven, - eight, - nine, - ten, - - eleven - -}) {} - -function test({ - one, - two, - three, - four, -}) {} - -function test({ - one, - - two, - three, - four, - -}) {} - -function test({ one, two, three, four }, $a) {} - - -function test( - { one, two, three, four }, - - $a -) {} - -function foo( - - ...rest - -) {} - -function foo( - one, - - ...rest -) {} - -function foo(one,...rest) {} - -f( - superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong,...args -); - -it( - - "does something really long and complicated so I have to write a very long name for the test", - - function( - - done, - - foo - ) { - - console.log("hello!"); - } -); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -38,24 +38,22 @@ - - call((one, two, three, four, five, six, seven, eight, nine, ten, eleven) => {}); - --call( -- ( -- one, -+call(( -+ one, - -- two, -- three, -- four, -+ two, -+ three, -+ four, - -- five, -- six, -- seven, -- eight, -- nine, -- ten, -+ five, -+ six, -+ seven, -+ eight, -+ nine, -+ ten, - -- eleven, -- ) => {}, --); -+ eleven, -+) => {}); - - function test({ - one, -``` - -# Output - -```js -class Foo { - constructor( - one, - - two, - three, - four, - - five, - six, - seven, - eight, - nine, - ten, - - eleven, - ) {} -} - -function foo( - one, - - two, - three, - four, - - five, - six, - seven, - eight, - nine, - ten, - - eleven, -) {} - -call((a, b) => {}); - -call((one, two, three, four, five, six, seven, eight, nine, ten, eleven) => {}); - -call(( - one, - - two, - three, - four, - - five, - six, - seven, - eight, - nine, - ten, - - eleven, -) => {}); - -function test({ - one, - - two, - three, - four, - - five, - six, - seven, - eight, - nine, - ten, - - eleven, -}) {} - -function test({ one, two, three, four }) {} - -function test({ - one, - - two, - three, - four, -}) {} - -function test({ one, two, three, four }, $a) {} - -function test( - { one, two, three, four }, - - $a, -) {} - -function foo(...rest) {} - -function foo( - one, - - ...rest -) {} - -function foo(one, ...rest) {} - -f( - superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong, - ...args, -); - -it("does something really long and complicated so I have to write a very long name for the test", function (done, foo) { - console.log("hello!"); -}); -``` - - -# Lines exceeding max width of 80 characters -``` - 108: it("does something really long and complicated so I have to write a very long name for the test", function (done, foo) { -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/ternaries/binary.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/ternaries/binary.js.snap deleted file mode 100644 index 8ab3d3a33c5..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/ternaries/binary.js.snap +++ /dev/null @@ -1,80 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const funnelSnapshotCard = (report === MY_OVERVIEW && - !ReportGK.xar_metrics_active_capitol_v2) || - (report === COMPANY_OVERVIEW && - !ReportGK.xar_metrics_active_capitol_v2_company_metrics) - ? - : null; - -room = room.map((row, rowIndex) => ( - row.map((col, colIndex) => ( - (rowIndex === 0 || colIndex === 0 || rowIndex === height || colIndex === width) ? 1 : 0 - )) -)) -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -5,13 +5,15 @@ - - ) : null; - --room = room.map((row, rowIndex) => -- row.map((col, colIndex) => -- rowIndex === 0 || -- colIndex === 0 || -- rowIndex === height || -- colIndex === width -- ? 1 -- : 0, -- ), -+room = room.map( -+ (row, rowIndex) => -+ row.map( -+ (col, colIndex) => -+ rowIndex === 0 || -+ colIndex === 0 || -+ rowIndex === height || -+ colIndex === width -+ ? 1 -+ : 0, -+ ), - ); -``` - -# Output - -```js -const funnelSnapshotCard = - (report === MY_OVERVIEW && !ReportGK.xar_metrics_active_capitol_v2) || - (report === COMPANY_OVERVIEW && - !ReportGK.xar_metrics_active_capitol_v2_company_metrics) ? ( - - ) : null; - -room = room.map( - (row, rowIndex) => - row.map( - (col, colIndex) => - rowIndex === 0 || - colIndex === 0 || - rowIndex === height || - colIndex === width - ? 1 - : 0, - ), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_async.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_async.js.snap deleted file mode 100644 index d3534f830b7..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_async.js.snap +++ /dev/null @@ -1,145 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -beforeEach(async(() => { - // code -})); - -beforeEach(done => - foo() - .bar() - .bar(), -); - -afterAll(async(() => { - console.log('Hello'); -})); - -afterAll(done => - foo() - .bar() - .bar(), -); - -it('should create the app', async(() => { - //code -})); - -it("does something really long and complicated so I have to write a very long name for the test", async(() => { - // code -})); - -/* -* isTestCall(parent) should only be called when parent exists -* and parent.type is CallExpression. This test makes sure that -* no errors are thrown when calling isTestCall(parent) -*/ -function x() { async(() => {}) } -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,22 +1,32 @@ --beforeEach(async(() => { -- // code --})); -+beforeEach( -+ async(() => { -+ // code -+ }), -+); - - beforeEach((done) => foo().bar().bar()); - --afterAll(async(() => { -- console.log("Hello"); --})); -+afterAll( -+ async(() => { -+ console.log("Hello"); -+ }), -+); - - afterAll((done) => foo().bar().bar()); - --it("should create the app", async(() => { -- //code --})); -+it( -+ "should create the app", -+ async(() => { -+ //code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", async(() => { -- // code --})); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ async(() => { -+ // code -+ }), -+); - - /* - * isTestCall(parent) should only be called when parent exists -``` - -# Output - -```js -beforeEach( - async(() => { - // code - }), -); - -beforeEach((done) => foo().bar().bar()); - -afterAll( - async(() => { - console.log("Hello"); - }), -); - -afterAll((done) => foo().bar().bar()); - -it( - "should create the app", - async(() => { - //code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - async(() => { - // code - }), -); - -/* - * isTestCall(parent) should only be called when parent exists - * and parent.type is CallExpression. This test makes sure that - * no errors are thrown when calling isTestCall(parent) - */ -function x() { - async(() => {}); -} -``` - - -# Lines exceeding max width of 80 characters -``` - 25: "does something really long and complicated so I have to write a very long name for the test", -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_fakeAsync.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_fakeAsync.js.snap deleted file mode 100644 index 085068a6a9e..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_fakeAsync.js.snap +++ /dev/null @@ -1,147 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -beforeEach(fakeAsync(() => { - // code -})); - -afterAll(fakeAsync(() => { - console.log('Hello'); -})); - -it('should create the app', fakeAsync(() => { - //code -})); - -it("does something really long and complicated so I have to write a very long name for the test", fakeAsync(() => { - // code -})); - -it("does something really long and complicated so I have to write a very long name for the test", fakeAsync(() => new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS)); - -/* -* isTestCall(parent) should only be called when parent exists -* and parent.type is CallExpression. This test makes sure that -* no errors are thrown when calling isTestCall(parent) -*/ -function x() { fakeAsync(() => {}) } -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,21 +1,36 @@ --beforeEach(fakeAsync(() => { -- // code --})); -+beforeEach( -+ fakeAsync(() => { -+ // code -+ }), -+); - --afterAll(fakeAsync(() => { -- console.log("Hello"); --})); -+afterAll( -+ fakeAsync(() => { -+ console.log("Hello"); -+ }), -+); - --it("should create the app", fakeAsync(() => { -- //code --})); -+it( -+ "should create the app", -+ fakeAsync(() => { -+ //code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", fakeAsync(() => { -- // code --})); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ fakeAsync(() => { -+ // code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", fakeAsync(() => -- new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS())); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ fakeAsync( -+ () => -+ new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), -+ ), -+); - - /* - * isTestCall(parent) should only be called when parent exists -``` - -# Output - -```js -beforeEach( - fakeAsync(() => { - // code - }), -); - -afterAll( - fakeAsync(() => { - console.log("Hello"); - }), -); - -it( - "should create the app", - fakeAsync(() => { - //code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - fakeAsync(() => { - // code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - fakeAsync( - () => - new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), - ), -); - -/* - * isTestCall(parent) should only be called when parent exists - * and parent.type is CallExpression. This test makes sure that - * no errors are thrown when calling isTestCall(parent) - */ -function x() { - fakeAsync(() => {}); -} -``` - - -# Lines exceeding max width of 80 characters -``` - 21: "does something really long and complicated so I have to write a very long name for the test", - 28: "does something really long and complicated so I have to write a very long name for the test", - 31: new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_waitForAsync.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_waitForAsync.js.snap deleted file mode 100644 index 7a28521b6a1..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angular_waitForAsync.js.snap +++ /dev/null @@ -1,147 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -beforeEach(waitForAsync(() => { - // code -})); - -afterAll(waitForAsync(() => { - console.log('Hello'); -})); - -it('should create the app', waitForAsync(() => { - //code -})); - -it("does something really long and complicated so I have to write a very long name for the test", waitForAsync(() => { - // code -})); - -it("does something really long and complicated so I have to write a very long name for the test", waitForAsync(() => new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS)); - -/* -* isTestCall(parent) should only be called when parent exists -* and parent.type is CallExpression. This test makes sure that -* no errors are thrown when calling isTestCall(parent) -*/ -function x() { waitForAsync(() => {}) } -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,21 +1,36 @@ --beforeEach(waitForAsync(() => { -- // code --})); -+beforeEach( -+ waitForAsync(() => { -+ // code -+ }), -+); - --afterAll(waitForAsync(() => { -- console.log("Hello"); --})); -+afterAll( -+ waitForAsync(() => { -+ console.log("Hello"); -+ }), -+); - --it("should create the app", waitForAsync(() => { -- //code --})); -+it( -+ "should create the app", -+ waitForAsync(() => { -+ //code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", waitForAsync(() => { -- // code --})); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ waitForAsync(() => { -+ // code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", waitForAsync(() => -- new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS())); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ waitForAsync( -+ () => -+ new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), -+ ), -+); - - /* - * isTestCall(parent) should only be called when parent exists -``` - -# Output - -```js -beforeEach( - waitForAsync(() => { - // code - }), -); - -afterAll( - waitForAsync(() => { - console.log("Hello"); - }), -); - -it( - "should create the app", - waitForAsync(() => { - //code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - waitForAsync(() => { - // code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - waitForAsync( - () => - new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), - ), -); - -/* - * isTestCall(parent) should only be called when parent exists - * and parent.type is CallExpression. This test makes sure that - * no errors are thrown when calling isTestCall(parent) - */ -function x() { - waitForAsync(() => {}); -} -``` - - -# Lines exceeding max width of 80 characters -``` - 21: "does something really long and complicated so I have to write a very long name for the test", - 28: "does something really long and complicated so I have to write a very long name for the test", - 31: new SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS(), -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angularjs_inject.js.snap b/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angularjs_inject.js.snap index 7ca3bdc562c..747a5f6e7c2 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angularjs_inject.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/js/test-declarations/angularjs_inject.js.snap @@ -1,5 +1,7 @@ --- source: crates/rome_js_formatter/tests/prettier_tests.rs +info: + test_file: js/test-declarations/angularjs_inject.js --- # Input @@ -39,97 +41,42 @@ function x() { inject(() => {}) } ```diff --- Prettier +++ Rome -@@ -1,25 +1,35 @@ --beforeEach(inject(($fooService, $barService) => { -- // code --})); -+beforeEach( -+ inject(($fooService, $barService) => { -+ // code -+ }), -+); - --afterAll(inject(($fooService, $barService) => { -- console.log("Hello"); --})); -+afterAll( -+ inject(($fooService, $barService) => { -+ console.log("Hello"); -+ }), -+); - --it("should create the app", inject(($fooService, $barService) => { -- //code --})); -+it( -+ "should create the app", -+ inject(($fooService, $barService) => { -+ //code -+ }), -+); - --it("does something really long and complicated so I have to write a very long name for the test", inject(() => { -- // code --})); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ inject(() => { -+ // code -+ }), -+); +@@ -14,10 +14,7 @@ + // code + })); -it("does something really long and complicated so I have to write a very long name for the test", inject(( - $fooServiceLongName, - $barServiceLongName, -) => { -- // code --})); -+it( -+ "does something really long and complicated so I have to write a very long name for the test", -+ inject(($fooServiceLongName, $barServiceLongName) => { -+ // code -+ }), -+); ++it("does something really long and complicated so I have to write a very long name for the test", inject(($fooServiceLongName, $barServiceLongName) => { + // code + })); - /* - * isTestCall(parent) should only be called when parent exists ``` # Output ```js -beforeEach( - inject(($fooService, $barService) => { - // code - }), -); - -afterAll( - inject(($fooService, $barService) => { - console.log("Hello"); - }), -); - -it( - "should create the app", - inject(($fooService, $barService) => { - //code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - inject(() => { - // code - }), -); - -it( - "does something really long and complicated so I have to write a very long name for the test", - inject(($fooServiceLongName, $barServiceLongName) => { - // code - }), -); +beforeEach(inject(($fooService, $barService) => { + // code +})); + +afterAll(inject(($fooService, $barService) => { + console.log("Hello"); +})); + +it("should create the app", inject(($fooService, $barService) => { + //code +})); + +it("does something really long and complicated so I have to write a very long name for the test", inject(() => { + // code +})); + +it("does something really long and complicated so I have to write a very long name for the test", inject(($fooServiceLongName, $barServiceLongName) => { + // code +})); /* * isTestCall(parent) should only be called when parent exists @@ -144,7 +91,7 @@ function x() { # Lines exceeding max width of 80 characters ``` - 21: "does something really long and complicated so I have to write a very long name for the test", - 28: "does something really long and complicated so I have to write a very long name for the test", + 13: it("does something really long and complicated so I have to write a very long name for the test", inject(() => { + 17: it("does something really long and complicated so I have to write a very long name for the test", inject(($fooServiceLongName, $barServiceLongName) => { ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/argument-expansion/arrow-with-return-type.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/argument-expansion/arrow-with-return-type.ts.snap deleted file mode 100644 index 5d4ec11b8ed..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/argument-expansion/arrow-with-return-type.ts.snap +++ /dev/null @@ -1,102 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -longfunctionWithCall1("bla", foo, (thing: string): complex> => { - code(); -}); - -longfunctionWithCall12("bla", foo, (thing: string): complex> => { - code(); -}); - -longfunctionWithCallBack("blabla", foobarbazblablablablabla, (thing: string): complex> => { - code(); -}); - -longfunctionWithCallBack("blabla", foobarbazblablabla, (thing: string): complex> => { - code(); -}); - -longfunctionWithCall1("bla", foo, (thing: string): complex> => { - code(); -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,6 +1,10 @@ --longfunctionWithCall1("bla", foo, (thing: string): complex> => { -- code(); --}); -+longfunctionWithCall1( -+ "bla", -+ foo, -+ (thing: string): complex> => { -+ code(); -+ }, -+); - - longfunctionWithCall12( - "bla", -``` - -# Output - -```js -longfunctionWithCall1( - "bla", - foo, - (thing: string): complex> => { - code(); - }, -); - -longfunctionWithCall12( - "bla", - foo, - (thing: string): complex> => { - code(); - }, -); - -longfunctionWithCallBack( - "blabla", - foobarbazblablablablabla, - (thing: string): complex> => { - code(); - }, -); - -longfunctionWithCallBack( - "blabla", - foobarbazblablabla, - (thing: string): complex> => { - code(); - }, -); - -longfunctionWithCall1( - "bla", - foo, - ( - thing: string, - ): complex< - type<` -`> - > => { - code(); - }, -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/arrow/arrow_regression.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/arrow/arrow_regression.ts.snap deleted file mode 100644 index 936667d8918..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/arrow/arrow_regression.ts.snap +++ /dev/null @@ -1,62 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const bar = (...varargs:any[]) => { - console.log(varargs); -}; - -const foo = (x:string):void => ( - bar( - x, - () => {}, - () => {} - ) -); - -app.get("/", (req, res): void => { - res.send("Hello world"); -}); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -2,12 +2,7 @@ - console.log(varargs); - }; - --const foo = (x: string): void => -- bar( -- x, -- () => {}, -- () => {}, -- ); -+const foo = (x: string): void => bar(x, () => {}, () => {}); - - app.get("/", (req, res): void => { - res.send("Hello world"); -``` - -# Output - -```js -const bar = (...varargs: any[]) => { - console.log(varargs); -}; - -const foo = (x: string): void => bar(x, () => {}, () => {}); - -app.get("/", (req, res): void => { - res.send("Hello world"); -}); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/comments/interface.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/comments/interface.ts.snap deleted file mode 100644 index 8a5f92a5ac0..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/comments/interface.ts.snap +++ /dev/null @@ -1,108 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -interface Foo { - bar( - currentRequest: {a: number}, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - - ( - currentRequest: {a: number}, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - - new ( - currentRequest: {a: number}, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - - foo: { - x( - currentRequest: {a: number}, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - - y: ( - currentRequest: {a: number}, - // TODO this is a very very very very long comment that makes it go > 80 columns - ) => number; - } -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -3,23 +3,19 @@ - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; -- - ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; -- - new ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; -- - foo: { - x( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; -- - y: ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns -``` - -# Output - -```js -interface Foo { - bar( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - new ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - foo: { - x( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ): number; - y: ( - currentRequest: { a: number }, - // TODO this is a very very very very long comment that makes it go > 80 columns - ) => number; - }; -} -``` - - -# Lines exceeding max width of 80 characters -``` - 4: // TODO this is a very very very very long comment that makes it go > 80 columns - 8: // TODO this is a very very very very long comment that makes it go > 80 columns - 12: // TODO this is a very very very very long comment that makes it go > 80 columns - 17: // TODO this is a very very very very long comment that makes it go > 80 columns - 21: // TODO this is a very very very very long comment that makes it go > 80 columns -``` - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/functionOverloadsOnGenericArity1.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/functionOverloadsOnGenericArity1.ts.snap deleted file mode 100644 index 97469e25937..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/compiler/functionOverloadsOnGenericArity1.ts.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -// overloading on arity not allowed -interface C { - f(): string; - f(): string; - - (): string; - (): string; - - new (): string; - new (): string; -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -2,10 +2,8 @@ - interface C { - f(): string; - f(): string; -- - (): string; - (): string; -- - new (): string; - new (): string; - } -``` - -# Output - -```js -// overloading on arity not allowed -interface C { - f(): string; - f(): string; - (): string; - (): string; - new (): string; - new (): string; -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/constKeyword/constKeyword.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/constKeyword/constKeyword.ts.snap deleted file mode 100644 index 048c0b67ca2..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/constKeyword/constKeyword.ts.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -const enum E { A, B, C } -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,5 +1 @@ --const enum E { -- A, -- B, -- C, --} -+const enum E { A, B, C } -``` - -# Output - -```js -const enum E { A, B, C } -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/enumDeclaration/enumDeclaration.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/enumDeclaration/enumDeclaration.ts.snap deleted file mode 100644 index ca635e63638..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/conformance/types/enumDeclaration/enumDeclaration.ts.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -enum E { A, B, C } -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,5 +1 @@ --enum E { -- A, -- B, -- C, --} -+enum E { A, B, C } -``` - -# Output - -```js -enum E { A, B, C } -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/enum/computed-members.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/enum/computed-members.ts.snap index 3c1443ded3f..d94559fca9e 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/enum/computed-members.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/enum/computed-members.ts.snap @@ -28,35 +28,41 @@ enum C { ```diff --- Prettier +++ Rome -@@ -1,13 +1,7 @@ --enum A { +@@ -1,13 +1,13 @@ + enum A { - i++, --} -+enum A { [i++] } ++ [i++], + } const bar = "bar"; --enum B { + enum B { - bar = 2, --} -+enum B { [bar] = 2 } ++ [bar] = 2, + } const foo = () => "foo"; --enum C { + enum C { - foo() = 2, --} -+enum C { [foo()] = 2 } ++ [foo()] = 2, + } ``` # Output ```js -enum A { [i++] } +enum A { + [i++], +} const bar = "bar"; -enum B { [bar] = 2 } +enum B { + [bar] = 2, +} const foo = () => "foo"; -enum C { [foo()] = 2 } +enum C { + [foo()] = 2, +} ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/instantiation-expression/inferface-asi.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/instantiation-expression/inferface-asi.ts.snap deleted file mode 100644 index 8ed7fe1ae3d..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/instantiation-expression/inferface-asi.ts.snap +++ /dev/null @@ -1,39 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -interface Example { - (a: number): typeof a - - (): void -}; -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,5 +1,4 @@ - interface Example { - (a: number): typeof a; -- - (): void; - } -``` - -# Output - -```js -interface Example { - (a: number): typeof a; - (): void; -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/keywords/keywords.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/keywords/keywords.ts.snap index 53feb79b1da..35d0bc8f9b0 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/keywords/keywords.ts.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/typescript/keywords/keywords.ts.snap @@ -1,7 +1,7 @@ --- source: crates/rome_js_formatter/tests/prettier_tests.rs info: - test_file: "typescript\\keywords\\keywords.ts" + test_file: typescript/keywords/keywords.ts --- # Input @@ -53,7 +53,7 @@ module YYY4 { ```diff --- Prettier +++ Rome -@@ -1,29 +1,37 @@ +@@ -1,29 +1,40 @@ // All of these should be an error module Y3 { @@ -86,11 +86,11 @@ module YYY4 { module Y4 { - public enum Color { -- Blue, -- Red, -- } + public -+ enum Color { Blue, Red } ++ enum Color { + Blue, + Red, + } } module YY3 { @@ -100,16 +100,16 @@ module YYY4 { class A { s: string; } -@@ -31,14 +39,13 @@ +@@ -31,14 +42,16 @@ } module YY4 { - private enum Color { -- Blue, -- Red, -- } + private -+ enum Color { Blue, Red } ++ enum Color { + Blue, + Red, + } } module YYY3 { @@ -119,17 +119,16 @@ module YYY4 { class A { s: string; } -@@ -46,8 +53,6 @@ +@@ -46,7 +59,8 @@ } module YYY4 { - static enum Color { -- Blue, -- Red, -- } + static -+ enum Color { Blue, Red } - } ++ enum Color { + Blue, + Red, + } ``` # Output @@ -163,7 +162,10 @@ module Y3 { module Y4 { public - enum Color { Blue, Red } + enum Color { + Blue, + Red, + } } module YY3 { @@ -177,7 +179,10 @@ module YY3 { module YY4 { private - enum Color { Blue, Red } + enum Color { + Blue, + Red, + } } module YYY3 { @@ -191,7 +196,10 @@ module YYY3 { module YYY4 { static - enum Color { Blue, Red } + enum Color { + Blue, + Red, + } } ``` diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/last-argument-expansion/break.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/last-argument-expansion/break.ts.snap deleted file mode 100644 index b3560896379..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/last-argument-expansion/break.ts.snap +++ /dev/null @@ -1,77 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js -export default class AddAssetHtmlPlugin { - apply(compiler: WebpackCompilerType) { - compiler.plugin('compilation', (compilation: WebpackCompilationType) => { - compilation.plugin('html-webpack-plugin-before-html', (callback: Callback) => { - addAllAssetsToCompilation(this.assets, compilation, htmlPluginData, callback); - }); - }); - } -} -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,17 +1,16 @@ - export default class AddAssetHtmlPlugin { - apply(compiler: WebpackCompilerType) { - compiler.plugin("compilation", (compilation: WebpackCompilationType) => { -- compilation.plugin( -- "html-webpack-plugin-before-html", -- (callback: Callback) => { -- addAllAssetsToCompilation( -- this.assets, -- compilation, -- htmlPluginData, -- callback, -- ); -- }, -- ); -+ compilation.plugin("html-webpack-plugin-before-html", ( -+ callback: Callback, -+ ) => { -+ addAllAssetsToCompilation( -+ this.assets, -+ compilation, -+ htmlPluginData, -+ callback, -+ ); -+ }); - }); - } - } -``` - -# Output - -```js -export default class AddAssetHtmlPlugin { - apply(compiler: WebpackCompilerType) { - compiler.plugin("compilation", (compilation: WebpackCompilationType) => { - compilation.plugin("html-webpack-plugin-before-html", ( - callback: Callback, - ) => { - addAllAssetsToCompilation( - this.assets, - compilation, - htmlPluginData, - callback, - ); - }); - }); - } -} -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/method-chain/comment.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/method-chain/comment.ts.snap deleted file mode 100644 index 793bb7dfd4f..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/method-chain/comment.ts.snap +++ /dev/null @@ -1,72 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs ---- - -# Input - -```js - -this.firebase.object(`/shops/${shopLocation.shop}`) - // keep distance info - .first((shop: ShopQueryResult, index: number, source: Observable): any => { - // add distance to result - const s = shop; - s.distance = shopLocation.distance; - return s; - }); -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -1,15 +1,13 @@ - this.firebase - .object(`/shops/${shopLocation.shop}`) - // keep distance info -- .first( -- ( -- shop: ShopQueryResult, -- index: number, -- source: Observable, -- ): any => { -- // add distance to result -- const s = shop; -- s.distance = shopLocation.distance; -- return s; -- }, -- ); -+ .first(( -+ shop: ShopQueryResult, -+ index: number, -+ source: Observable, -+ ): any => { -+ // add distance to result -+ const s = shop; -+ s.distance = shopLocation.distance; -+ return s; -+ }); -``` - -# Output - -```js -this.firebase - .object(`/shops/${shopLocation.shop}`) - // keep distance info - .first(( - shop: ShopQueryResult, - index: number, - source: Observable, - ): any => { - // add distance to result - const s = shop; - s.distance = shopLocation.distance; - return s; - }); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/typescript/typeparams/class-method.ts.snap b/crates/rome_js_formatter/tests/specs/prettier/typescript/typeparams/class-method.ts.snap deleted file mode 100644 index 67d479287b2..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/typescript/typeparams/class-method.ts.snap +++ /dev/null @@ -1,311 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: typescript/typeparams/class-method.ts ---- - -# Input - -```js -// https://github.com/prettier/prettier/issues/4070 -export class Thing implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => {}); -} - -export class Thing2 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => { const someVar = doSomething(type); if (someVar) {return someVar.method()} return false;}); -} - -export class Thing3 implements OtherThing { - do: (type: Type) => Provider = memoize((type) => { const someVar = doSomething(type); if (someVar) {return someVar.method()} return false;}); -} - -export class Thing4 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => type.doSomething()); -} - -export class Thing5 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => type.doSomething()); -} - -export class Thing6 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => >type.doSomething()); -} - -export class Thing7 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType) => >type.doSomething()); -} - -export class Thing8 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType) => >type.doSomething(withArgs, soIt, does, not, fit).extraCall()); -} - -export class Thing9 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType) => type.doSomething()); -} - -export class Thing10 implements OtherThing { - do: (type: Type) => Provider = memoize((veryLongArgName: ObjectType): Provider => veryLongArgName ); -} - -export class Thing11 implements OtherThing { - do: (type: Type) => Provider = memoize((type: ObjectType): Provider => {}); -} - -// regular non-arrow functions - -export class Thing12 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider {return type}); -} - -export class Thing13 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider { const someVar = doSomething(type); if (someVar) {return someVar.method()} return false;}); -} - -export class Thing14 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type) { const someVar = doSomething(type); if (someVar) {return someVar.method()} return false;}); -} - -export class Thing15 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider {return type.doSomething()}); -} - -export class Thing16 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider {return type.doSomething()}); -} - -export class Thing17 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider {return >type.doSomething()}); -} - -export class Thing18 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType) {return >type.doSomething()}); -} - -export class Thing19 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType) { return >type.doSomething(withArgs, soIt, does, not, fit).extraCall()}); -} - -export class Thing20 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType) {return type.doSomething()}); -} - -export class Thing21 implements OtherThing { - do: (type: Type) => Provider = memoize(function(veryLongArgName: ObjectType): Provider { return veryLongArgName }); -} - -export class Thing22 implements OtherThing { - do: (type: Type) => Provider = memoize(function(type: ObjectType): Provider {}); -} - - -// case from https://github.com/prettier/prettier/issues/2581 - -const appIDs = createSelector( - PubXURLParams.APP_IDS, - (rawAppIDs): Array => deserializeList(rawAppIDs), -);``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -61,8 +61,8 @@ - } - - export class Thing9 implements OtherThing { -- do: (type: Type) => Provider = memoize((type: ObjectType) => -- type.doSomething(), -+ do: (type: Type) => Provider = memoize( -+ (type: ObjectType) => type.doSomething(), - ); - } - -``` - -# Output - -```js -// https://github.com/prettier/prettier/issues/4070 -export class Thing implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => {}, - ); -} - -export class Thing2 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => { - const someVar = doSomething(type); - if (someVar) { - return someVar.method(); - } - return false; - }, - ); -} - -export class Thing3 implements OtherThing { - do: (type: Type) => Provider = memoize((type) => { - const someVar = doSomething(type); - if (someVar) { - return someVar.method(); - } - return false; - }); -} - -export class Thing4 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => type.doSomething(), - ); -} - -export class Thing5 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => type.doSomething(), - ); -} - -export class Thing6 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => >type.doSomething(), - ); -} - -export class Thing7 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType) => >type.doSomething(), - ); -} - -export class Thing8 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType) => - >( - type.doSomething(withArgs, soIt, does, not, fit).extraCall() - ), - ); -} - -export class Thing9 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType) => type.doSomething(), - ); -} - -export class Thing10 implements OtherThing { - do: (type: Type) => Provider = memoize( - (veryLongArgName: ObjectType): Provider => - veryLongArgName, - ); -} - -export class Thing11 implements OtherThing { - do: (type: Type) => Provider = memoize( - (type: ObjectType): Provider => {}, - ); -} - -// regular non-arrow functions - -export class Thing12 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider { - return type; - }); -} - -export class Thing13 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider { - const someVar = doSomething(type); - if (someVar) { - return someVar.method(); - } - return false; - }); -} - -export class Thing14 implements OtherThing { - do: (type: Type) => Provider = memoize(function (type) { - const someVar = doSomething(type); - if (someVar) { - return someVar.method(); - } - return false; - }); -} - -export class Thing15 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider { - return type.doSomething(); - }); -} - -export class Thing16 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider { - return type.doSomething(); - }); -} - -export class Thing17 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider { - return >type.doSomething(); - }); -} - -export class Thing18 implements OtherThing { - do: (type: Type) => Provider = memoize(function (type: ObjectType) { - return >type.doSomething(); - }); -} - -export class Thing19 implements OtherThing { - do: (type: Type) => Provider = memoize(function (type: ObjectType) { - return >( - type.doSomething(withArgs, soIt, does, not, fit).extraCall() - ); - }); -} - -export class Thing20 implements OtherThing { - do: (type: Type) => Provider = memoize(function (type: ObjectType) { - return type.doSomething(); - }); -} - -export class Thing21 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - veryLongArgName: ObjectType, - ): Provider { - return veryLongArgName; - }); -} - -export class Thing22 implements OtherThing { - do: (type: Type) => Provider = memoize(function ( - type: ObjectType, - ): Provider {}); -} - -// case from https://github.com/prettier/prettier/issues/2581 - -const appIDs = createSelector( - PubXURLParams.APP_IDS, - (rawAppIDs): Array => deserializeList(rawAppIDs), -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/ts/suppressions.ts.snap b/crates/rome_js_formatter/tests/specs/ts/suppressions.ts.snap index 1c6da56df1a..4e727eefc7f 100644 --- a/crates/rome_js_formatter/tests/specs/ts/suppressions.ts.snap +++ b/crates/rome_js_formatter/tests/specs/ts/suppressions.ts.snap @@ -22,6 +22,7 @@ Quote properties: As needed interface Suppressions { // rome-ignore format: test a: void + b: void; } diff --git a/npm/backend-jsonrpc/tests/transport.test.mjs b/npm/backend-jsonrpc/tests/transport.test.mjs index 69ccbb8f675..f20362a0175 100644 --- a/npm/backend-jsonrpc/tests/transport.test.mjs +++ b/npm/backend-jsonrpc/tests/transport.test.mjs @@ -107,8 +107,8 @@ describe("Transport Layer", () => { const transport = new Transport(socket); - expect( - () => onData(Buffer.from(`Content-Type: text/plain\r\n`)), + expect(() => + onData(Buffer.from(`Content-Type: text/plain\r\n`)), ).toThrowError( 'invalid value for Content-Type expected "application/vscode-jsonrpc", got "text/plain"', ); @@ -130,8 +130,8 @@ describe("Transport Layer", () => { const transport = new Transport(socket); - expect( - () => onData(makeMessage({ jsonrpc: "2.0", id: 0, result: "result" })), + expect(() => + onData(makeMessage({ jsonrpc: "2.0", id: 0, result: "result" })), ).toThrowError( "could not find any pending request matching RPC response ID 0", ); diff --git a/npm/rome/scripts/generate-packages.mjs b/npm/rome/scripts/generate-packages.mjs index afd1b403dcf..ee53ab62da9 100644 --- a/npm/rome/scripts/generate-packages.mjs +++ b/npm/rome/scripts/generate-packages.mjs @@ -68,16 +68,17 @@ function writeManifest(packagePath) { fs.readFileSync(manifestPath).toString("utf-8"), ); - const nativePackages = PLATFORMS.flatMap( - (platform) => - ARCHITECTURES.map( - (arch) => [`@rometools/cli-${platform}-${arch}`, rootManifest.version], - ), + const nativePackages = PLATFORMS.flatMap((platform) => + ARCHITECTURES.map((arch) => [ + `@rometools/cli-${platform}-${arch}`, + rootManifest.version, + ]), ); - const wasmPackages = WASM_TARGETS.map( - (target) => [`@rometools/wasm-${target}`, rootManifest.version], - ); + const wasmPackages = WASM_TARGETS.map((target) => [ + `@rometools/wasm-${target}`, + rootManifest.version, + ]); manifestData["version"] = rootManifest.version; manifestData["optionalDependencies"] = Object.fromEntries( diff --git a/website/playground/src/App.tsx b/website/playground/src/App.tsx index 1a34319cc5d..ceec78cb07c 100644 --- a/website/playground/src/App.tsx +++ b/website/playground/src/App.tsx @@ -25,14 +25,14 @@ function App() { const [prettierOutput, setPrettierOutput] = useState({ code: "", ir: "" }); useEffect(() => { - romeWorkerRef.current = new Worker(new URL( - "./romeWorker", - import.meta.url, - ), { type: "module" }); - prettierWorkerRef.current = new Worker(new URL( - "./prettierWorker", - import.meta.url, - ), { type: "module" }); + romeWorkerRef.current = new Worker( + new URL("./romeWorker", import.meta.url), + { type: "module" }, + ); + prettierWorkerRef.current = new Worker( + new URL("./prettierWorker", import.meta.url), + { type: "module" }, + ); romeWorkerRef.current.addEventListener("message", (event) => { switch (event.data.type) { diff --git a/website/playground/src/DesktopPlayground.tsx b/website/playground/src/DesktopPlayground.tsx index 79fd5c35268..cd876d166f0 100644 --- a/website/playground/src/DesktopPlayground.tsx +++ b/website/playground/src/DesktopPlayground.tsx @@ -49,14 +49,13 @@ export default function DesktopPlayground({ const onUpdate = useCallback((viewUpdate: ViewUpdate) => { const cursorPosition = viewUpdate.state.selection.ranges[0]?.from ?? 0; - setPlaygroundState( - (state) => - state.cursorPosition !== cursorPosition - ? { - ...state, - cursorPosition, - } - : state, + setPlaygroundState((state) => + state.cursorPosition !== cursorPosition + ? { + ...state, + cursorPosition, + } + : state, ); }, []); diff --git a/website/playground/src/MobilePlayground.tsx b/website/playground/src/MobilePlayground.tsx index 16567006b94..edbafc02327 100644 --- a/website/playground/src/MobilePlayground.tsx +++ b/website/playground/src/MobilePlayground.tsx @@ -25,14 +25,13 @@ export function MobilePlayground({ const onUpdate = useCallback((viewUpdate: ViewUpdate) => { const cursorPosition = viewUpdate.state.selection.ranges[0]?.from ?? 0; - setPlaygroundState( - (state) => - state.cursorPosition !== cursorPosition - ? { - ...state, - cursorPosition, - } - : state, + setPlaygroundState((state) => + state.cursorPosition !== cursorPosition + ? { + ...state, + cursorPosition, + } + : state, ); }, []); const onChange = useCallback((value) => { diff --git a/website/src/_includes/scripts/index.js b/website/src/_includes/scripts/index.js index fe287ca880a..c35513e3eb6 100644 --- a/website/src/_includes/scripts/index.js +++ b/website/src/_includes/scripts/index.js @@ -456,9 +456,11 @@ class Manager { window.addEventListener("resize", this.refresh.bind(this), { passive: true, }); - window.addEventListener("resize", this.calculateHeadingsPositions.bind( - this, - ), { passive: true }); + window.addEventListener( + "resize", + this.calculateHeadingsPositions.bind(this), + { passive: true }, + ); document.addEventListener( "click",