diff --git a/src/dom/components/__tests__/ReactDOMTextarea-test.js b/src/dom/components/__tests__/ReactDOMTextarea-test.js
index aaca8ea596b..70055adbb67 100644
--- a/src/dom/components/__tests__/ReactDOMTextarea-test.js
+++ b/src/dom/components/__tests__/ReactDOMTextarea-test.js
@@ -188,7 +188,7 @@ describe('ReactDOMTextarea', function() {
expect(function() {
ReactTestUtils.renderIntoDocument(
-
+
);
}).toThrow();
diff --git a/vendor/fbtransform/transforms/react.js b/vendor/fbtransform/transforms/react.js
index af5aa7dbedc..f3735a1bf92 100644
--- a/vendor/fbtransform/transforms/react.js
+++ b/vendor/fbtransform/transforms/react.js
@@ -50,6 +50,12 @@ var JSX_ATTRIBUTE_TRANSFORMS = {
}
};
+function isChildString(child) {
+ return child.type === Syntax.Literal ||
+ child.type === Syntax.XJSExpressionContainer &&
+ child.expression.raw && child.expression.raw.match(/^(|'[^']*'|"[^"]*")$/);
+}
+
function visitReactTag(traverse, object, path, state) {
var jsxObjIdent = utils.getDocblock(state).jsx;
@@ -134,18 +140,23 @@ function visitReactTag(traverse, object, path, state) {
if (childrenToRender.length > 0) {
utils.append(', ', state);
- object.children.forEach(function(child) {
- if (child.type === Syntax.Literal && !child.value.match(/\S/)) {
- return;
- }
+ childrenToRender.forEach(function(child, index) {
utils.catchup(child.range[0], state);
- var isLast = child === childrenToRender[childrenToRender.length - 1];
+ var isLast = index === childrenToRender.length - 1;
if (child.type === Syntax.Literal) {
- renderXJSLiteral(child, isLast, state);
+ var concat = !isLast && isChildString(childrenToRender[index + 1]);
+
+ renderXJSLiteral(child, isLast, state, null, null, concat);
} else if (child.type === Syntax.XJSExpressionContainer) {
- renderXJSExpressionContainer(traverse, child, isLast, path, state);
+ var concat = !isLast &&
+ isChildString(child) &&
+ isChildString(childrenToRender[index + 1]);
+
+ renderXJSExpressionContainer(
+ traverse, child, isLast, path, state, concat
+ );
} else {
traverse(child, path, state);
if (!isLast) {
diff --git a/vendor/fbtransform/transforms/xjs.js b/vendor/fbtransform/transforms/xjs.js
index faa9fb40f33..0fd4fbc6521 100644
--- a/vendor/fbtransform/transforms/xjs.js
+++ b/vendor/fbtransform/transforms/xjs.js
@@ -171,7 +171,7 @@ function trimWithSingleSpace(string) {
* "line "+
* "line"
*/
-function renderXJSLiteral(object, isLast, state, start, end) {
+function renderXJSLiteral(object, isLast, state, start, end, concat) {
/** Added blank check filtering and triming*/
var trimmedChildValue = safeTrim(object.value);
var hasFinalNewLine = false;
@@ -253,7 +253,7 @@ function renderXJSLiteral(object, isLast, state, start, end) {
// add comma before trailing whitespace
if (!isLast) {
- utils.append(',', state);
+ utils.append(concat ? '+' : ',', state);
}
// tail whitespace
@@ -264,14 +264,16 @@ function renderXJSLiteral(object, isLast, state, start, end) {
utils.move(object.range[1], state);
}
-function renderXJSExpressionContainer(traverse, object, isLast, path, state) {
+function renderXJSExpressionContainer(
+ traverse, object, isLast, path, state, concat
+) {
// Plus 1 to skip `{`.
utils.move(object.range[0] + 1, state);
traverse(object.expression, path, state);
if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) {
// If we need to append a comma, make sure to do so after the expression.
utils.catchup(object.expression.range[1], state);
- utils.append(',', state);
+ utils.append(concat ? '+' : ',', state);
}
// Minus 1 to skip `}`.