From 60d7a02d44d8ce893e338f0ff6ae4812c9b5331a Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Fri, 24 Jan 2014 21:46:16 +0100 Subject: [PATCH] Normalize whitespace for transformed JSX code --- vendor/fbtransform/transforms/react.js | 50 +++++++++++++------------- vendor/fbtransform/transforms/xjs.js | 22 ++++++++---- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/vendor/fbtransform/transforms/react.js b/vendor/fbtransform/transforms/react.js index 1d5536c1455..03d4880b826 100644 --- a/vendor/fbtransform/transforms/react.js +++ b/vendor/fbtransform/transforms/react.js @@ -25,6 +25,8 @@ var renderXJSExpressionContainer = var renderXJSLiteral = require('./xjs').renderXJSLiteral; var quoteAttrName = require('./xjs').quoteAttrName; +var trimLeft = require('./xjs').trimLeft; + /** * Customized desugar processor. * @@ -53,7 +55,7 @@ function visitReactTag(traverse, object, path, state) { var nameObject = openingElement.name; var attributesObject = openingElement.attributes; - utils.catchup(openingElement.range[0], state); + utils.catchup(openingElement.range[0], state, trimLeft); if (nameObject.namespace) { throw new Error( @@ -68,44 +70,43 @@ function visitReactTag(traverse, object, path, state) { utils.move(nameObject.range[1], state); + var hasAttributes = attributesObject.length; + // if we don't have any attributes, pass in null - if (attributesObject.length === 0) { + if (hasAttributes) { + utils.append('{', state); + } else { utils.append('null', state); } // write attributes attributesObject.forEach(function(attr, index) { - utils.catchup(attr.range[0], state); if (attr.name.namespace) { throw new Error( 'Namespace attributes are not supported. ReactJSX is not XML.'); } var name = attr.name.name; - var isFirst = index === 0; var isLast = index === attributesObject.length - 1; - if (isFirst) { - utils.append('{', state); - } - + utils.catchup(attr.range[0], state, trimLeft); utils.append(quoteAttrName(name), state); - utils.append(':', state); + utils.append(': ', state); if (!attr.value) { state.g.buffer += 'true'; state.g.position = attr.name.range[1]; if (!isLast) { - utils.append(',', state); + utils.append(', ', state); } } else { utils.move(attr.name.range[1], state); - // Use catchupWhiteSpace to skip over the '=' in the attribute - utils.catchupWhiteSpace(attr.value.range[0], state); + // Use catchupNewlines to skip over the '=' in the attribute + utils.catchupNewlines(attr.value.range[0], state); if (JSX_ATTRIBUTE_TRANSFORMS.hasOwnProperty(attr.name.name)) { utils.append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state); utils.move(attr.value.range[1], state); if (!isLast) { - utils.append(',', state); + utils.append(', ', state); } } else if (attr.value.type === Syntax.Literal) { renderXJSLiteral(attr.value, isLast, state); @@ -114,18 +115,18 @@ function visitReactTag(traverse, object, path, state) { } } - if (isLast) { - utils.append('}', state); - } - - utils.catchup(attr.range[1], state); + utils.catchup(attr.range[1], state, trimLeft); }); if (!openingElement.selfClosing) { - utils.catchup(openingElement.range[1] - 1, state); + utils.catchup(openingElement.range[1] - 1, state, trimLeft); utils.move(openingElement.range[1], state); } + if (hasAttributes) { + utils.append('}', state); + } + // filter out whitespace var childrenToRender = object.children.filter(function(child) { return !(child.type === Syntax.Literal @@ -147,7 +148,7 @@ function visitReactTag(traverse, object, path, state) { } childrenToRender.forEach(function(child, index) { - utils.catchup(child.range[0], state); + utils.catchup(child.range[0], state, trimLeft); var isLast = index >= lastRenderableIndex; @@ -158,22 +159,21 @@ function visitReactTag(traverse, object, path, state) { } else { traverse(child, path, state); if (!isLast) { - utils.append(',', state); - state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1'); + utils.append(', ', state); } } - utils.catchup(child.range[1], state); + utils.catchup(child.range[1], state, trimLeft); }); } if (openingElement.selfClosing) { // everything up to /> - utils.catchup(openingElement.range[1] - 2, state); + utils.catchup(openingElement.range[1] - 2, state, trimLeft); utils.move(openingElement.range[1], state); } else { // everything up to - utils.catchup(object.closingElement.range[0], state); + utils.catchup(object.closingElement.range[0], state, trimLeft); utils.move(object.closingElement.range[1], state); } diff --git a/vendor/fbtransform/transforms/xjs.js b/vendor/fbtransform/transforms/xjs.js index 27a8020f5ce..69f5118c4b1 100644 --- a/vendor/fbtransform/transforms/xjs.js +++ b/vendor/fbtransform/transforms/xjs.js @@ -180,12 +180,14 @@ function renderXJSLiteral(object, isLast, state, start, end) { trimmedLine = trimmedLine.replace(/[ ]+$/, ''); } - utils.append(line.match(/^[ \t]*/)[0], state); + if (!isFirstLine) { + utils.append(line.match(/^[ \t]*/)[0], state); + } if (trimmedLine || isLastNonEmptyLine) { utils.append( JSON.stringify(trimmedLine) + - (!isLastNonEmptyLine ? "+' '+" : ''), + (!isLastNonEmptyLine ? " + ' ' +" : ''), state); if (isLastNonEmptyLine) { @@ -193,12 +195,12 @@ function renderXJSLiteral(object, isLast, state, start, end) { utils.append(end, state); } if (!isLast) { - utils.append(',', state); + utils.append(', ', state); } } // only restore tail whitespace if line had literals - if (trimmedLine) { + if (trimmedLine && !isLastLine) { utils.append(line.match(/[ \t]*$/)[0], state); } } @@ -215,14 +217,15 @@ function renderXJSExpressionContainer(traverse, object, isLast, path, state) { // 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.catchup(object.expression.range[1], state, trimLeft); + utils.append(', ', state); } // Minus 1 to skip `}`. - utils.catchup(object.range[1] - 1, state); + utils.catchup(object.range[1] - 1, state, trimLeft); utils.move(object.range[1], state); return false; } @@ -235,7 +238,12 @@ function quoteAttrName(attr) { return attr; } +function trimLeft(value) { + return value.replace(/^[ ]+/, ''); +} + exports.knownTags = knownTags; exports.renderXJSExpressionContainer = renderXJSExpressionContainer; exports.renderXJSLiteral = renderXJSLiteral; exports.quoteAttrName = quoteAttrName; +exports.trimLeft = trimLeft;