From 5831a07da59ae13ad5cca28e8b5ec82f34da2ed2 Mon Sep 17 00:00:00 2001 From: Denis Bezrukov <6227442+denbezrukov@users.noreply.github.com> Date: Mon, 19 Sep 2022 10:59:00 +0300 Subject: [PATCH] fix(rome_js_formatter): in JSX, some spaces are removed #3211 --- .../src/jsx/lists/child_list.rs | 87 +++-- crates/rome_js_formatter/src/lib.rs | 13 +- crates/rome_js_formatter/src/utils/jsx.rs | 110 +++++- .../tests/specs/jsx/element.jsx | 64 ++++ .../tests/specs/jsx/element.jsx.snap | 129 ++++++- .../jsx/significant-space/test.js.snap | 290 ---------------- .../jsx/stateless-arrow-fn/test.js.snap | 300 ---------------- .../specs/prettier/jsx/text-wrap/test.js.snap | 326 +++--------------- 8 files changed, 407 insertions(+), 912 deletions(-) delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/jsx/significant-space/test.js.snap delete mode 100644 crates/rome_js_formatter/tests/specs/prettier/jsx/stateless-arrow-fn/test.js.snap diff --git a/crates/rome_js_formatter/src/jsx/lists/child_list.rs b/crates/rome_js_formatter/src/jsx/lists/child_list.rs index d36811fbdd2..ff42a88eeeb 100644 --- a/crates/rome_js_formatter/src/jsx/lists/child_list.rs +++ b/crates/rome_js_formatter/src/jsx/lists/child_list.rs @@ -108,7 +108,11 @@ impl FormatJsxChildList { ), }), - _ => None, + Some(JsxChild::Newline | JsxChild::Whitespace | JsxChild::EmptyLine) => { + None + } + + None => None, }; child_breaks = separator.map_or(false, |separator| separator.will_break()); @@ -116,9 +120,10 @@ impl FormatJsxChildList { flat.write(&format_args![word, separator], f); if let Some(separator) = separator { - multiline.write(word, &separator, f); + multiline.write_with_separator(word, &separator, f); } else { - multiline.write_with_empty_separator(word, f); + // it's safe to write without a separator because None means that next element is a separator or end of the iterator + multiline.write_content(word, f); } } @@ -139,7 +144,7 @@ impl FormatJsxChildList { let is_trailing_or_only_whitespace = children_iter.peek().is_none(); if is_trailing_or_only_whitespace || is_after_line_break { - multiline.write_with_empty_separator(&JsxRawSpace, f); + multiline.write_separator(&JsxRawSpace, f); } // Leading whitespace. Only possible if used together with a expression child // @@ -151,9 +156,9 @@ impl FormatJsxChildList { // // ``` else if last.is_none() { - multiline.write(&JsxRawSpace, &hard_line_break(), f); + multiline.write_with_separator(&JsxRawSpace, &hard_line_break(), f); } else { - multiline.write_with_empty_separator(&JsxSpace, f); + multiline.write_separator(&JsxSpace, f); } } @@ -161,20 +166,20 @@ impl FormatJsxChildList { JsxChild::Newline => { child_breaks = true; - multiline.write_with_empty_separator(&hard_line_break(), f); + multiline.write_separator(&hard_line_break(), f); } // An empty line between some JSX text and an element JsxChild::EmptyLine => { child_breaks = true; - multiline.write_with_empty_separator(&empty_line(), f); + multiline.write_separator(&empty_line(), f); } // Any child that isn't text JsxChild::NonText(non_text) => { let line_mode = match children_iter.peek() { - Some(JsxChild::Newline | JsxChild::Word(_) | JsxChild::Whitespace) => { + Some(JsxChild::Word(word)) => { // Break if the current or next element is a self closing element // ```javascript //
adefg
@@ -184,7 +189,9 @@ impl FormatJsxChildList {
                             // 
                             // adefg
                             // ```
-                            if matches!(non_text, JsxAnyChild::JsxSelfClosingElement(_)) {
+                            if matches!(non_text, JsxAnyChild::JsxSelfClosingElement(_))
+                                && !word.is_ascii_punctuation()
+                            {
                                 Some(LineMode::Hard)
                             } else {
                                 Some(LineMode::Soft)
@@ -192,28 +199,44 @@ impl FormatJsxChildList {
                         }
 
                         // Add a hard line break if what comes after the element is not a text or is all whitespace
-                        Some(_) => Some(LineMode::Hard),
+                        Some(JsxChild::NonText(_)) => Some(LineMode::Hard),
 
+                        Some(JsxChild::Newline | JsxChild::Whitespace | JsxChild::EmptyLine) => {
+                            None
+                        }
                         // Don't insert trailing line breaks
                         None => None,
                     };
 
                     child_breaks = line_mode.map_or(false, |mode| mode.is_hard());
 
-                    let format_separator = format_with(|f| match line_mode {
-                        Some(mode) => f.write_element(FormatElement::Line(mode)),
-                        None => Ok(()),
+                    let format_separator = line_mode.map(|mode| {
+                        format_with(move |f| f.write_element(FormatElement::Line(mode)))
                     });
 
                     if force_multiline {
-                        multiline.write(&non_text.format(), &format_separator, f);
+                        if let Some(format_separator) = format_separator {
+                            multiline.write_with_separator(
+                                &non_text.format(),
+                                &format_separator,
+                                f,
+                            );
+                        } else {
+                            // it's safe to write without a separator because None means that next element is a separator or end of the iterator
+                            multiline.write_content(&non_text.format(), f);
+                        }
                     } else {
                         let mut memoized = non_text.format().memoized();
 
                         force_multiline = memoized.inspect(f)?.will_break();
-
                         flat.write(&format_args![memoized, format_separator], f);
-                        multiline.write(&memoized, &format_separator, f);
+
+                        if let Some(format_separator) = format_separator {
+                            multiline.write_with_separator(&memoized, &format_separator, f);
+                        } else {
+                            // it's safe to write without a separator because None means that next element is a separator or end of the iterator
+                            multiline.write_content(&memoized, f);
+                        }
                     }
                 }
             }
@@ -476,18 +499,30 @@ impl MultilineBuilder {
     }
 
     /// Formats an element that does not require a separator
-    fn write_with_empty_separator(
+    /// It is safe to omit the separator because at the call side we must guarantee that we have reached the end of the iterator
+    /// or the next element is a space/newline that should be written into the separator "slot".
+    fn write_content(&mut self, content: &dyn Format, f: &mut JsFormatter) {
+        self.write(content, None, f);
+    }
+
+    /// Formatting a separator does not require any element in the separator slot
+    fn write_separator(&mut self, separator: &dyn Format, f: &mut JsFormatter) {
+        self.write(separator, None, f);
+    }
+
+    fn write_with_separator(
         &mut self,
         content: &dyn Format,
+        separator: &dyn Format,
         f: &mut JsFormatter,
     ) {
-        self.write(content, &format_with(|_| Ok(())), f)
+        self.write(content, Some(separator), f);
     }
 
     fn write(
         &mut self,
         content: &dyn Format,
-        separator: &dyn Format,
+        separator: Option<&dyn Format>,
         f: &mut JsFormatter,
     ) {
         let result = std::mem::replace(&mut self.result, Ok(Vec::new()));
@@ -502,12 +537,18 @@ impl MultilineBuilder {
                         write!(buffer, [content])?;
                         buffer.write_element(FormatElement::Tag(Tag::EndEntry))?;
 
-                        buffer.write_element(FormatElement::Tag(Tag::StartEntry))?;
-                        write!(buffer, [separator])?;
-                        buffer.write_element(FormatElement::Tag(Tag::EndEntry))?;
+                        if let Some(separator) = separator {
+                            buffer.write_element(FormatElement::Tag(Tag::StartEntry))?;
+                            write!(buffer, [separator])?;
+                            buffer.write_element(FormatElement::Tag(Tag::EndEntry))?;
+                        }
                     }
                     MultilineLayout::NoFill => {
                         write!(buffer, [content, separator])?;
+
+                        if let Some(separator) = separator {
+                            write!(buffer, [separator])?;
+                        }
                     }
                 };
                 buffer.into_vec()
diff --git a/crates/rome_js_formatter/src/lib.rs b/crates/rome_js_formatter/src/lib.rs
index 6fa938b375a..84058088124 100644
--- a/crates/rome_js_formatter/src/lib.rs
+++ b/crates/rome_js_formatter/src/lib.rs
@@ -861,9 +861,16 @@ function() {
     // use this test check if your snippet prints as you wish, without using a snapshot
     fn quick_test() {
         let src = r#"
-function test() {
-return srcPipe.pipe(generator.stream).pipe(compile()).pipe(gulp.dest(out));
-}"#;
+const b4 = (
+	
+ Text + some link + {" "} + | some other text,{" "} +
+); + +"#; let syntax = SourceType::jsx(); let tree = parse(src, FileId::zero(), syntax); let options = JsFormatOptions::new(syntax); diff --git a/crates/rome_js_formatter/src/utils/jsx.rs b/crates/rome_js_formatter/src/utils/jsx.rs index 5e37f437f4e..44ce824d0f7 100644 --- a/crates/rome_js_formatter/src/utils/jsx.rs +++ b/crates/rome_js_formatter/src/utils/jsx.rs @@ -223,7 +223,7 @@ pub(crate) fn jsx_split_children( where I: IntoIterator, { - let mut result = Vec::new(); + let mut builder = JsxSplitChildrenBuilder::new(); for child in children.into_iter() { match child { @@ -253,15 +253,15 @@ where // // ``` if newlines > 1 { - result.push(JsxChild::EmptyLine); + builder.entry(JsxChild::EmptyLine); } continue; } - result.push(JsxChild::Newline) - } else if !matches!(result.last(), Some(JsxChild::Whitespace)) { - result.push(JsxChild::Whitespace) + builder.entry(JsxChild::Newline) + } else { + builder.entry(JsxChild::Whitespace) } } _ => unreachable!(), @@ -274,15 +274,15 @@ where // Only handle trailing whitespace. Words must always be joined by new lines if chunks.peek().is_none() { if whitespace.contains('\n') { - result.push(JsxChild::Newline); + builder.entry(JsxChild::Newline); } else { - result.push(JsxChild::Whitespace) + builder.entry(JsxChild::Whitespace) } } } (relative_start, JsxTextChunk::Word(word)) => { - result.push(JsxChild::Word(JsxWord { + builder.entry(JsxChild::Word(JsxWord { text: value_token .token_text() .slice(TextRange::at(relative_start, word.text_len())), @@ -295,23 +295,50 @@ where JsxAnyChild::JsxExpressionChild(child) => { if is_whitespace_jsx_expression(&child, comments) { - match result.last() { - Some(JsxChild::Whitespace) => { - // Ignore - } - _ => result.push(JsxChild::Whitespace), - } + builder.entry(JsxChild::Whitespace) } else { - result.push(JsxChild::NonText(child.into())) + builder.entry(JsxChild::NonText(child.into())) } } child => { - result.push(JsxChild::NonText(child)); + builder.entry(JsxChild::NonText(child)); + } + } + } + + Ok(builder.finish()) +} + +/// The builder is used to: +/// 1. Remove [JsxChild::EmptyLine], [JsxChild::Newline], [JsxChild::Whitespace] if a next element is [JsxChild::Whitespace] +/// 2. Don't push a new element [JsxChild::EmptyLine], [JsxChild::Newline], [JsxChild::Whitespace] if previous one is [JsxChild::EmptyLine], [JsxChild::Newline], [JsxChild::Whitespace] +/// [Prettier applies]: https://github.com/prettier/prettier/blob/b0d9387b95cdd4e9d50f5999d3be53b0b5d03a97/src/language-js/print/jsx.js#L144-L180 +#[derive(Debug)] +struct JsxSplitChildrenBuilder { + buffer: Vec, +} + +impl JsxSplitChildrenBuilder { + fn new() -> Self { + JsxSplitChildrenBuilder { buffer: vec![] } + } + + fn entry(&mut self, child: JsxChild) { + match self.buffer.last_mut() { + Some(last @ (JsxChild::EmptyLine | JsxChild::Newline | JsxChild::Whitespace)) => { + if matches!(child, JsxChild::Whitespace) { + *last = child; + } else if matches!(child, JsxChild::NonText(_) | JsxChild::Word(_)) { + self.buffer.push(child); + } } + _ => self.buffer.push(child), } } - Ok(result) + fn finish(self) -> Vec { + self.buffer + } } #[derive(Debug, Clone, Eq, PartialEq)] @@ -378,6 +405,17 @@ pub(crate) struct JsxWord { source_position: TextSize, } +impl JsxWord { + pub fn is_ascii_punctuation(&self) -> bool { + self.text.chars().count() == 1 + && self + .text + .chars() + .next() + .map_or(false, |char| char.is_ascii_punctuation()) + } +} + impl Format for JsxWord { fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { f.write_element(FormatElement::Text(Text::SyntaxTokenTextSlice { @@ -645,6 +683,44 @@ mod tests { assert_eq!(children[3], JsxChild::Whitespace); } + #[test] + fn split_children_remove_in_row_jsx_whitespaces() { + let child_list = parse_jsx_children(r#"a{' '}{' '}{' '}c{" "}{' '}{" "}"#); + + let children = jsx_split_children(&child_list, &Comments::default()).unwrap(); + + assert_eq!( + 4, + children.len(), + "Expected to contain four elements. Actual:\n{children:#?} " + ); + assert_word(&children[0], "a"); + assert_eq!(children[1], JsxChild::Whitespace); + assert_word(&children[2], "c"); + assert_eq!(children[3], JsxChild::Whitespace); + } + + #[test] + fn split_children_remove_new_line_before_jsx_whitespaces() { + let child_list = parse_jsx_children( + r#"a + {' '}c{" "} + "#, + ); + + let children = jsx_split_children(&child_list, &Comments::default()).unwrap(); + + assert_eq!( + 4, + children.len(), + "Expected to contain four elements. Actual:\n{children:#?} " + ); + assert_word(&children[0], "a"); + assert_eq!(children[1], JsxChild::Whitespace); + assert_word(&children[2], "c"); + assert_eq!(children[3], JsxChild::Whitespace); + } + fn assert_word(child: &JsxChild, text: &str) { match child { JsxChild::Word(word) => { diff --git a/crates/rome_js_formatter/tests/specs/jsx/element.jsx b/crates/rome_js_formatter/tests/specs/jsx/element.jsx index 77f6f14a310..67406ac84d0 100644 --- a/crates/rome_js_formatter/tests/specs/jsx/element.jsx +++ b/crates/rome_js_formatter/tests/specs/jsx/element.jsx @@ -41,6 +41,70 @@ c =
a{' '}{' '}{' '}{' '}{' '}{' '}{' '}{' '}b{' '}{' '}{' '}{' '}{' '}{' ' c2 =
a{' '}{' '}{' '}{' '}{' '}{' '}{' '}{' '}
content{' '}{' '}{' '}{' '}{' '}{' '}
; +// this group should fit one line jsx whitespaces are hidden +b = +
+ + + {' '} + + + + {' '} + 1 +
; + +// this group should break first tag and show only first jsx whitespace +b1 = +
+ + {` +12312 +12312 + `} + + + {' '} + + + + {' '} + 1 +
; + +// this group fit one line and hide jsx whitespace +b2 = + <> + 123 + + + {' '} + 1 + ; + +// this group break group and show jsx whitespace +b3 = + <> + {` +123`} + + + {' '} + 1 + ; + +const b4 =
+ Text + some link +{' '} + | some other text,{' '} +
; + +b5 = +
+
long text long text long text long text long text long text long text long texturl long text long text +
; + ; const Essay = () =>
The films of Wong Kar-Wai exemplify the synthesis of French New Wave cinema—specifically the unrelenting 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 2a0cfd75f3e..b85d4017f44 100644 --- a/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap +++ b/crates/rome_js_formatter/tests/specs/jsx/element.jsx.snap @@ -46,6 +46,70 @@ c =
a{' '}{' '}{' '}{' '}{' '}{' '}{' '}{' '}b{' '}{' '}{' '}{' '}{' '}{' ' c2 =
a{' '}{' '}{' '}{' '}{' '}{' '}{' '}{' '}
content{' '}{' '}{' '}{' '}{' '}{' '}
; +// this group should fit one line jsx whitespaces are hidden +b = +
+ + + {' '} + + + + {' '} + 1 +
; + +// this group should break first tag and show only first jsx whitespace +b1 = +
+ + {` +12312 +12312 + `} + + + {' '} + + + + {' '} + 1 +
; + +// this group fit one line and hide jsx whitespace +b2 = + <> + 123 + + + {' '} + 1 + ; + +// this group break group and show jsx whitespace +b3 = + <> + {` +123`} + + + {' '} + 1 + ; + +const b4 =
+ Text + some link +{' '} + | some other text,{' '} +
; + +b5 = +
+
long text long text long text long text long text long text long text long texturl long text long text +
; + ; const Essay = () =>
The films of Wong Kar-Wai exemplify the synthesis of French New Wave cinema—specifically the unrelenting @@ -296,6 +360,61 @@ c2 = (
); +// this group should fit one line jsx whitespaces are hidden +b = ( +
+ 1 +
+); + +// this group should break first tag and show only first jsx whitespace +b1 = ( + +); + +// this group fit one line and hide jsx whitespace +b2 = ( + <> + 123 1 + +); + +// this group break group and show jsx whitespace +b3 = ( + <> + + {` +123`} + {" "} + 1 + +); + +const b4 = ( +
+ Text{" "} + + some link + {" "} + | some other text,{" "} +
+); + +b5 = ( +
+
long text long text long text long text long text long text long text + long texturl long text long text +
+); +
jumps over the lazy dog @@ -501,9 +620,9 @@ const breadcrumbItems = [ 2:
; 7: tooltip="A very long tooltip text that would otherwise make the attribute break 14: - 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{" "}
+  179: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  200: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  213: 							"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
+  238: 				
+  287: 		Uncle Boonmee Who Can Recall His Past Lives dir. Apichatpong Weerasethakul{" "}
 
diff --git a/crates/rome_js_formatter/tests/specs/prettier/jsx/significant-space/test.js.snap b/crates/rome_js_formatter/tests/specs/prettier/jsx/significant-space/test.js.snap
deleted file mode 100644
index 054555963c5..00000000000
--- a/crates/rome_js_formatter/tests/specs/prettier/jsx/significant-space/test.js.snap
+++ /dev/null
@@ -1,290 +0,0 @@
----
-source: crates/rome_js_formatter/tests/prettier_tests.rs
-info:
-  test_file: jsx/significant-space/test.js
----
-
-# Input
-
-```js
-after =
-  
-      foo bar
-  
-
-before =
-  
-    bar foo
-  
-
-before_break1 =
-  
-     foo
-  
-
-before_break2 =
-  
-     foo
-  
-
-after_break =
-  
-    foo 
-  
-
-within =
-  
-    foo  bar 
-  
-
-break_components =
-  
- - -

foobar bar bar

yep

-
-

nope

-
- -var x =
- hello hi sdkflsdfjk -
; - -nest_plz = -
-
-
-
-
- -regression_not_transformed_1 = - ; - -regression_not_transformed_2 = - ; - -similar_1 = - ; - -similar_2 = - ; - -similar_3 = - ; - -not_broken_end = -
- long text long text long text long text long text long text long text long text url long text long text -
- -not_broken_begin = -
-
long text long text long text long text long text long text long text long texturl long text long text -
-``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -12,7 +12,7 @@ - - before_break1 = ( - -- {" "} -+ - foo - - ); -@@ -21,15 +21,16 @@ - - {" "} -+ /> - foo - - ); - - after_break = ( - -- foo{" "} -- -+ foo - - ); - -@@ -79,7 +80,8 @@ - - regression_not_transformed_2 = ( - -- {" "} -+ -+ {" "} - - ); - -@@ -92,13 +94,15 @@ - - similar_2 = ( - -- {" "} -+ -+ {" "} - - ); - - similar_3 = ( - -- -+ -+ - - ); - -@@ -111,7 +115,8 @@ - - not_broken_begin = ( -
--
long text long text long text long text long text long text long text -- long texturl long text long text -+
-+ long text long text long text long text long text long text long text long -+ texturl long text long text -
- ); -``` - -# Output - -```js -after = ( - - foo bar - -); - -before = ( - - bar foo - -); - -before_break1 = ( - - - foo - -); - -before_break2 = ( - - - foo - -); - -after_break = ( - - foo - -); - -within = ( - - foo bar - -); - -break_components = ( -
- - -

- foobar bar bar -

-

- - yep - -

-
-

nope

-
-); - -var x = ( -
- hello hi sdkflsdfjk -
-); - -nest_plz = ( -
-
-
-
-
-); - -regression_not_transformed_1 = ( - - {" "} - - -); - -regression_not_transformed_2 = ( - - - {" "} - -); - -similar_1 = ( - - {" "} - - -); - -similar_2 = ( - - - {" "} - -); - -similar_3 = ( - - - - -); - -not_broken_end = ( -
- long text long text long text long text long text long text long text long - text url long text long text -
-); - -not_broken_begin = ( -
-
- long text long text long text long text long text long text long text long - texturl long text long text -
-); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/jsx/stateless-arrow-fn/test.js.snap b/crates/rome_js_formatter/tests/specs/prettier/jsx/stateless-arrow-fn/test.js.snap deleted file mode 100644 index bd71e968e67..00000000000 --- a/crates/rome_js_formatter/tests/specs/prettier/jsx/stateless-arrow-fn/test.js.snap +++ /dev/null @@ -1,300 +0,0 @@ ---- -source: crates/rome_js_formatter/tests/prettier_tests.rs -info: - test_file: jsx/stateless-arrow-fn/test.js ---- - -# Input - -```js -const render1 = ({ styles }) => ( -
- Keep the wrapping parens. Put each key on its own line. -
-); - -const render2 = ({ styles }) =>
- Create wrapping parens. -
; - -const render3 = ({ styles }) =>
Create wrapping parens.
; - -const render4 = ({ styles }) =>
Create wrapping parens and indent all the things.
; - -const render5 = ({ styles }) =>
Keep it on one line.
; - -const render6 = ({ styles }) => ( -
-
ddd d dd d d dddd dddd hello
-
ddd d dd d d dddd dddd hello
-
-
ddd d dd d d dddd dddd hello
hello
-
-) - -const render7 = () => -
- Dont break each elem onto its own line. -
-
- -const render7A = () => ( -
-
-
-) - -const render7B = () => ( -
- Dont break plz - Dont break plz - Dont break plz -
-) - -const render8 = (props) =>
{props.text}
-const render9 = (props) =>
{props.looooooooooooooooooooooooooooooong_text}
-const render10 = (props) =>
{props.even_looooooooooooooooooooooooooooooooooooooooooonger_contents}
- -const notJSX = (aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) => this.someLongCallWithParams(aaaaaa, bbbbbbb).anotherLongCallWithParams(cccccccccccc, dddddddddddddddddddddd) - -React.render( - - , document.querySelector('#react-root') -) - - -const renderTernary = (props) => - - {props.showTheThing ? - Hello world - : "hello " + "howdy! "} - {props.showTheThing ? - Hello world - : - null - } - {props.showTheThing ? null : - Hello world - } - {props.showTheOtherThing ?
I am here
:
} - {props.showTheOtherThing ?
I am here!!
: null} - -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Rome -@@ -55,7 +55,7 @@ - attr4 - > - ddd d dd d d dddd dddd hello --
{" "} -+
- hello -
-
-@@ -65,7 +65,8 @@ -
- - Dont break each elem onto its own line. --
-+
-+
-
- ); - -@@ -81,7 +82,8 @@ -
- - {" "} -- Dont break plz -+ -+ Dont break plz - - - -``` - -# Output - -```js -const render1 = ({ styles }) => ( -
- Keep the wrapping parens. Put each key on its own line. -
-); - -const render2 = ({ styles }) => ( -
- Create wrapping parens. -
-); - -const render3 = ({ styles }) => ( -
- Create wrapping parens. -
-); - -const render4 = ({ styles }) => ( -
- Create wrapping parens and indent all the things. -
-); - -const render5 = ({ styles }) =>
Keep it on one line.
; - -const render6 = ({ styles }) => ( -
-
- ddd d dd d d dddd dddd hello -
-
- ddd d dd d d dddd dddd hello -
-
-
- ddd d dd d d dddd dddd hello -
- hello -
-
-); - -const render7 = () => ( -
- - Dont break each elem onto its own line. -
-
-
-); - -const render7A = () => ( -
-
-
-
-
-); - -const render7B = () => ( -
- - {" "} - - Dont break plz - - - - Dont break plz - - - Dont break plz - - -
-); - -const render8 = (props) =>
{props.text}
; -const render9 = (props) => ( -
{props.looooooooooooooooooooooooooooooong_text}
-); -const render10 = (props) => ( -
- {props.even_looooooooooooooooooooooooooooooooooooooooooonger_contents} -
-); - -const notJSX = (aaaaaaaaaaaaaaaaa, bbbbbbbbbbb) => - this.someLongCallWithParams(aaaaaa, bbbbbbb).anotherLongCallWithParams( - cccccccccccc, - dddddddddddddddddddddd, - ); - -React.render( - , - document.querySelector("#react-root"), -); - -const renderTernary = (props) => ( - - {props.showTheThing ? ( - - Hello world - - ) : ( - "hello " + "howdy! " - )} - {props.showTheThing ? ( - - Hello world - - ) : null} - {props.showTheThing ? null : ( - - Hello world - - )} - {props.showTheOtherThing ?
I am here
:
} - {props.showTheOtherThing ?
I am here!!
: null} - -); -``` - - - diff --git a/crates/rome_js_formatter/tests/specs/prettier/jsx/text-wrap/test.js.snap b/crates/rome_js_formatter/tests/specs/prettier/jsx/text-wrap/test.js.snap index 03eb8021691..93f108aa333 100644 --- a/crates/rome_js_formatter/tests/specs/prettier/jsx/text-wrap/test.js.snap +++ b/crates/rome_js_formatter/tests/specs/prettier/jsx/text-wrap/test.js.snap @@ -473,147 +473,7 @@ let myDiv = ReactTestUtils.renderIntoDocument( ```diff --- Prettier +++ Rome -@@ -9,8 +9,10 @@ - // Wrapping tags - x = ( -
-- f f f f{" "} -- f f -+ f f f f -+ f -+ -+ f -
- ); - -@@ -32,15 +34,16 @@ - - - -- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{" "} -- f -+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+ f -+ -
- ); - - // Wrapping tags - x = ( -
-- {" "} -+ - f -
- ); -@@ -66,15 +69,19 @@ - - x = ( -
-- before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after{" "} -- {stuff} {stuff} {stuff} after {stuff} after -+ before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after { -+ stuff -+ } -+ {stuff} {stuff} after {stuff} after -
- ); - - x = ( -
-- Please state your name and occupation for the board of{" "} -- school directors. -+ Please state your name and occupation for the board of -+ school -+ -+ directors. -
- ); - -@@ -101,9 +108,10 @@ - x = ( - - -- Starting at minute {graphActivity.startTime}, running for{" "} -- {graphActivity.length} to minute{" "} -- {graphActivity.startTime + graphActivity.length} -+ Starting at minute {graphActivity.startTime}, running for { -+ graphActivity.length -+ } -+ to minute {graphActivity.startTime + graphActivity.length} - - - ); -@@ -176,19 +184,17 @@ - - unstable_before = ( -
-- Your score:{" "} -- {`${mini.crosstable.users[sessionUserId]} - ${ -- mini.crosstable.users[user.id] -- }`} -+ Your score: {`${ -+ mini.crosstable.users[sessionUserId] -+ } - ${mini.crosstable.users[user.id]}`} -
- ); - - unstable_after_first_run = ( -
-- Your score:{" "} -- {`${mini.crosstable.users[sessionUserId]} - ${ -- mini.crosstable.users[user.id] -- }`} -+ Your score: {`${ -+ mini.crosstable.users[sessionUserId] -+ } - ${mini.crosstable.users[user.id]}`} -
- ); - -@@ -213,24 +219,22 @@ - - jsx_around_multiline_element = ( -
-- Before{" "} --
-+ Before
- { - "Enough text to make this element wrap on to multiple lines when formatting" - } --
{" "} -+
- After -
- ); - - jsx_around_multiline_element_second_pass = ( -
-- Before{" "} --
-+ Before
- { - "Enough text to make this element wrap on to multiple lines when formatting" - } --
{" "} -+
- After -
- ); -@@ -251,8 +255,11 @@ - const Abc = () => { - return ( -
-- Please state your name and occupation for the board of -- directors. -+ Please state your -+ {" "}name -+ and -+ {" "}occupation -+ for the board of directors. -
- ); - }; -@@ -318,19 +325,25 @@ +@@ -318,7 +318,11 @@ line_after_br_2 = (
@@ -626,14 +486,7 @@ let myDiv = ReactTestUtils.renderIntoDocument(
); - br_followed_by_whitespace = ( -
--
text -+
-+ text -
- ); - +@@ -331,6 +335,7 @@ dont_preserve_blank_lines_when_jsx_contains_text = (
Zeroth
@@ -641,71 +494,18 @@ let myDiv = ReactTestUtils.renderIntoDocument(
First
Second
-@@ -346,15 +359,18 @@ - - single_expression_child_tags = ( -
-- You currently have {dashboardStr} and{" "} -- {userStr} -+ You currently have {dashboardStr} and -+ {userStr} -+ -
- ); - - expression_does_not_break = ( -
-- texty text text text text text text text text text text text{" "} -- {this.props.type}{" "} -+ texty text text text text text text text text text text text { -+ this.props.type -+ } -+ {" "} -
- ); - -@@ -362,9 +378,8 @@ +@@ -362,9 +367,7 @@ br_triggers_expression_break = (

- text text text text text text text text text text text { - this.props.type - }{" "} -+ text text text text text text text text text text text {this.props.type} -+ {" "} ++ text text text text text text text text text text text {this.props.type}{" "}
); -@@ -372,14 +387,14 @@ -
- - {variable} -- {" "} -+ - ({variable}) -
- ); - - x = ( -
-- ENDS IN
text text text text text text text text text text text
{" "} -+ ENDS IN
text text text text text text text text text text text
- HRS -
- ); -@@ -404,8 +419,9 @@ -
-
-
-- Line {startRange.row + 1}:{startRange.column + 1} -{" "} -- {endRange.row + 1}:{endRange.column + 1} -+ Line {startRange.row + 1}:{startRange.column + 1} - {endRange.row + -+ 1} -+ :{endRange.column + 1} - {caller} -
-
-@@ -436,13 +452,16 @@ +@@ -436,13 +439,16 @@ x = (
@@ -724,7 +524,7 @@ let myDiv = ReactTestUtils.renderIntoDocument(
); -@@ -496,19 +515,26 @@ +@@ -496,19 +502,26 @@ x = (
@@ -754,7 +554,7 @@ let myDiv = ReactTestUtils.renderIntoDocument(
); -@@ -528,7 +554,8 @@ +@@ -528,7 +541,8 @@ {name}’s{" "} @@ -764,16 +564,6 @@ let myDiv = ReactTestUtils.renderIntoDocument( You {type}ed this shipment to
); -@@ -564,7 +591,8 @@ - - let myDiv = ReactTestUtils.renderIntoDocument( -
--
, -+ ); // Wrapping tags x = (
- + {" "} f
); @@ -850,19 +637,15 @@ x = ( x = (
- before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after { - stuff - } - {stuff} {stuff} after {stuff} after + before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after{" "} + {stuff} {stuff} {stuff} after {stuff} after
); x = (
- Please state your name and occupation for the board of - school - - directors. + Please state your name and occupation for the board of{" "} + school directors.
); @@ -889,10 +672,9 @@ function DiffOverview(props) { x = ( - Starting at minute {graphActivity.startTime}, running for { - graphActivity.length - } - to minute {graphActivity.startTime + graphActivity.length} + Starting at minute {graphActivity.startTime}, running for{" "} + {graphActivity.length} to minute{" "} + {graphActivity.startTime + graphActivity.length} ); @@ -965,17 +747,19 @@ this_really_should_split_across_lines = ( unstable_before = (
- Your score: {`${ - mini.crosstable.users[sessionUserId] - } - ${mini.crosstable.users[user.id]}`} + Your score:{" "} + {`${mini.crosstable.users[sessionUserId]} - ${ + mini.crosstable.users[user.id] + }`}
); unstable_after_first_run = (
- Your score: {`${ - mini.crosstable.users[sessionUserId] - } - ${mini.crosstable.users[user.id]}`} + Your score:{" "} + {`${mini.crosstable.users[sessionUserId]} - ${ + mini.crosstable.users[user.id] + }`}
); @@ -1000,22 +784,24 @@ jsx_whitespace_on_newline = ( jsx_around_multiline_element = (
- Before
+ Before{" "} +
{ "Enough text to make this element wrap on to multiple lines when formatting" } -
+
{" "} After
); jsx_around_multiline_element_second_pass = (
- Before
+ Before{" "} +
{ "Enough text to make this element wrap on to multiple lines when formatting" } -
+
{" "} After
); @@ -1036,11 +822,8 @@ x = ( const Abc = () => { return (
- Please state your - {" "}name - and - {" "}occupation - for the board of directors. + Please state your name and occupation for the board of + directors.
); }; @@ -1116,8 +899,7 @@ line_after_br_2 = ( br_followed_by_whitespace = (
-
- text +
text
); @@ -1140,18 +922,15 @@ multiple_expressions = ( single_expression_child_tags = (
- You currently have {dashboardStr} and - {userStr} - + You currently have {dashboardStr} and{" "} + {userStr}
); expression_does_not_break = (
- texty text text text text text text text text text text text { - this.props.type - } - {" "} + texty text text text text text text text text text text text{" "} + {this.props.type}{" "}
); @@ -1159,8 +938,7 @@ expression_does_not_break = ( br_triggers_expression_break = (

- text text text text text text text text text text text {this.props.type} - {" "} + text text text text text text text text text text text {this.props.type}{" "}
); @@ -1168,14 +946,14 @@ jsx_whitespace_after_tag = (
{variable} - + {" "} ({variable})
); x = (
- ENDS IN
text text text text text text text text text text text
+ ENDS IN
text text text text text text text text text text text
{" "} HRS
); @@ -1200,9 +978,8 @@ x = (
- Line {startRange.row + 1}:{startRange.column + 1} - {endRange.row + - 1} - :{endRange.column + 1} + Line {startRange.row + 1}:{startRange.column + 1} -{" "} + {endRange.row + 1}:{endRange.column + 1} {caller}
@@ -1372,8 +1149,7 @@ this_really_should_split_across_lines = ( let myDiv = ReactTestUtils.renderIntoDocument(
-
- , +
,
, ); @@ -1382,9 +1158,11 @@ let myDiv = ReactTestUtils.renderIntoDocument( # Lines exceeding max width of 80 characters ``` - 72: before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after { - 122:
- 224: "Enough text to make this element wrap on to multiple lines when formatting" - 235: "Enough text to make this element wrap on to multiple lines when formatting" + 69: before {stuff} after {stuff} after {stuff} after {stuff} after {stuff} after{" "} + 114:
+ 219: "Enough text to make this element wrap on to multiple lines when formatting" + 231: "Enough text to make this element wrap on to multiple lines when formatting" + 370: text text text text text text text text text text text {this.props.type}{" "} + 385: ENDS IN
text text text text text text text text text text text
{" "} ```