Repository: prettier/prettier (JavaScript)
Date: 2018-01-03 14:23:15+00:00
Task type: Bug Fix

Issue:
Long JSX elements as attribute values have invalid output
**Prettier 1.9.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAfAHSgAh6gMQgmzz0lgRgF5UATASwDctcy97mcB6V91boxakerEYWIjy0eLFp92+IaKn5eI9VAHoQAGhAQADjAbQAzslABDAE42IAdwAKthBZRWmEBnT0grZjDIAGZWADZmcPoARjZWYADWcDAAyobxDFAA5sgwNgCuUSB0EGAh4ZH6mZE2ME5xWQC2VuURRQBWZgAeAEJxickpVo1wADKZcK2VBvkwhrMATLkFRek2Ncgg0VbRAJ5h0H6GNpkwAOo+MAAWyAAcAAz6xxCRZ3GGm8dwNUyT+jZwACO+QYAPqViaLSQoTa+kijQYy0KcMyWTCcAAivkIPApkUYDsLnRrsgFvo8lYGGFUQBhCCNZqbKDQP4gfKRAAqO3cMMiAF8+UA)

**Input:**
```jsx
<>
  <Foo
    content=<div>
      <div />
    </div>
  />

  <Foo
    content=<>
      <div />
    </>
  />
</>
```

**Output:**
```jsx
<>
  <Foo
    content=(
      <div>
        <div />
      </div>
    )
  />

  <Foo
    content=(
      <>
        <div />
      </>
    )
  />
</>;

```

**Second Output:**
```
SyntaxError: JSX value should be either an expression or a quoted JSX text (3:13)
  1 | <>
  2 |   <Foo
> 3 |     content=(
    |             ^
  4 |       <div>
  5 |         <div />
  6 |       </div>

SyntaxError: JSX value should be either an expression or a quoted JSX text (11:13)
   9 | 
  10 |   <Foo
> 11 |     content=(
     |             ^
  12 |       <>
  13 |         <div />
  14 |       </>
```

**Expected behavior:**
Same as input?

I’m honestly surprised that this is valid. However, here’s [the spec](http://facebook.github.io/jsx/#syntax):

> JSXAttributeValue:
> 
> - `"` JSXDoubleStringCharacters<sub>opt</sub> `"`
> - `'` JSXSingleStringCharacters<sub>opt</sub> `'`
> - `{` AssignmentExpression `}`
> - **JSXElement**
> - **JSXFragment**

<sup>(emphasis mine)</sup>

Ref https://github.com/facebook/jsx/issues/53 (issue about removing this) and https://github.com/facebook/jsx/pull/15 (PR adding this). It’s currently [broken](http://babeljs.io/repl#?babili=false&browsers=&build=&builtIns=false&code_lz=DwMQ9mAEBGCGBOBeYAhWAvSB6AfNnQA&debug=false&circleciRepo=&evaluate=false&lineWrap=false&presets=react&prettier=false&targets=&version=6.26.0) in Babel.

Maybe we should just change it to the normal `{}` form, which is semantically equivalent as far as I can tell and looks less awful.


Issue discussion:
Should we change `<Foo bar=<Baz /> />` to `<Foo bar={<Baz />} />` or keep it as-is?
I guess that would be an AST change, so I'd keep it as-is?
On the other hand, it’s ugly and confusing IMO, and they appear to be converted to the same `React.createElement` calls.
I don't think anyone uses the element in an attribute construction... I didn't even know it existed. So long as we re-print it as valid code I don't think it matters much.
The React Babel transform doesn't currently support the no-braces version. Probably better to add braces for now.
@sophiebits if code was written without braces, it should be fair to assume that it was able to run in an environment that supported this syntax and there's no risk of printing it without braces right?
I guess so.

Solution patch:
diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js
index fd52d8d2caa8..447c012a63d6 100644
--- a/src/language-js/printer-estree.js
+++ b/src/language-js/printer-estree.js
@@ -4477,6 +4477,7 @@ function maybeWrapJSXElementInParens(path, elem) {
 
   const NO_WRAP_PARENTS = {
     ArrayExpression: true,
+    JSXAttribute: true,
     JSXElement: true,
     JSXExpressionContainer: true,
     JSXFragment: true,


Test patch:
diff --git a/tests/jsx-attr-element/__snapshots__/jsfmt.spec.js.snap b/tests/jsx-attr-element/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..c1ec5a95e6d8
--- /dev/null
+++ b/tests/jsx-attr-element/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,20 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`attr-element.js 1`] = `
+<Foo prop=<Bar><Baz /></Bar> />;
+<Foo prop=<><Bar><Baz /></Bar></> />;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<Foo
+  prop=<Bar>
+    <Baz />
+  </Bar>
+/>;
+<Foo
+  prop=<>
+    <Bar>
+      <Baz />
+    </Bar>
+  </>
+/>;
+
+`;
diff --git a/tests/jsx-attr-element/attr-element.js b/tests/jsx-attr-element/attr-element.js
new file mode 100644
index 000000000000..f31bd2306ced
--- /dev/null
+++ b/tests/jsx-attr-element/attr-element.js
@@ -0,0 +1,2 @@
+<Foo prop=<Bar><Baz /></Bar> />;
+<Foo prop=<><Bar><Baz /></Bar></> />;
diff --git a/tests/jsx-attr-element/jsfmt.spec.js b/tests/jsx-attr-element/jsfmt.spec.js
new file mode 100644
index 000000000000..ad02d22b7053
--- /dev/null
+++ b/tests/jsx-attr-element/jsfmt.spec.js
@@ -0,0 +1,2 @@
+// Flow and TypeScript don't support JSX elements as attribute values
+run_spec(__dirname, ["babylon"]);