Skip to content

Commit

Permalink
Merge pull request #480 from syranide/whitespace
Browse files Browse the repository at this point in the history
JSX whitespace coalescing rules
  • Loading branch information
Jeff Morrison authored and Jeff Morrison committed Jan 23, 2014
2 parents 38491c7 + c16b565 commit db04043
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 119 deletions.
10 changes: 5 additions & 5 deletions src/core/__tests__/ReactRenderDocument-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe('rendering React components at document', function() {
React.renderComponentToString(<Root />, function(markup) {
testDocument = getTestDocument(markup);
var component = React.renderComponent(<Root />, testDocument);
expect(testDocument.body.innerHTML).toBe(' Hello world ');
expect(testDocument.body.innerHTML).toBe('Hello world');

var componentID = ReactMount.getReactRootID(testDocument);
expect(componentID).toBe(component._rootNodeID);
Expand Down Expand Up @@ -95,13 +95,13 @@ describe('rendering React components at document', function() {
React.renderComponentToString(<Root />, function(markup) {
testDocument = getTestDocument(markup);
React.renderComponent(<Root />, testDocument);
expect(testDocument.body.innerHTML).toBe(' Hello world ');
expect(testDocument.body.innerHTML).toBe('Hello world');

expect(function() {
React.unmountComponentAtNode(testDocument);
}).toThrow(UNMOUNT_INVARIANT_MESSAGE);

expect(testDocument.body.innerHTML).toBe(' Hello world ');
expect(testDocument.body.innerHTML).toBe('Hello world');
});
});

Expand Down Expand Up @@ -143,14 +143,14 @@ describe('rendering React components at document', function() {

React.renderComponent(<Component />, testDocument);

expect(testDocument.body.innerHTML).toBe(' Hello world ');
expect(testDocument.body.innerHTML).toBe('Hello world');

// Reactive update
expect(function() {
React.renderComponent(<Component2 />, testDocument);
}).toThrow(UNMOUNT_INVARIANT_MESSAGE);

expect(testDocument.body.innerHTML).toBe(' Hello world ');
expect(testDocument.body.innerHTML).toBe('Hello world');
});
});

Expand Down
16 changes: 7 additions & 9 deletions vendor/fbtransform/transforms/react.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ function visitReactTag(traverse, object, path, state) {

utils.move(object.name.range[1], state);

var childrenToRender = object.children.filter(function(child) {
return !(child.type === Syntax.Literal && !child.value.match(/\S/));
});

// if we don't have any attributes, pass in null
if (object.attributes.length === 0) {
utils.append('null', state);
Expand Down Expand Up @@ -131,16 +127,18 @@ function visitReactTag(traverse, object, path, state) {
}

// filter out whitespace
var childrenToRender = object.children.filter(function(child) {
return !(child.type === Syntax.Literal &&
child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/));
});

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);
Expand Down
157 changes: 52 additions & 105 deletions vendor/fbtransform/transforms/xjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,118 +149,65 @@ var knownTags = {
wbr: true
};

function safeTrim(string) {
return string.replace(/^[ \t]+/, '').replace(/[ \t]+$/, '');
}

// Replace all trailing whitespace characters with a single space character
function trimWithSingleSpace(string) {
return string.replace(/^[ \t\xA0]{2,}/, ' ').
replace(/[ \t\xA0]{2,}$/, ' ').replace(/^\s+$/, '');
}

/**
* Special handling for multiline string literals
* print lines:
*
* line
* line
*
* as:
*
* "line "+
* "line"
*/
function renderXJSLiteral(object, isLast, state, start, end) {
/** Added blank check filtering and triming*/
var trimmedChildValue = safeTrim(object.value);
var hasFinalNewLine = false;

if (trimmedChildValue) {
// head whitespace
utils.append(object.value.match(/^[\t ]*/)[0], state);
if (start) {
utils.append(start, state);
var lines = object.value.split(/\r\n|\n|\r/);

if (start) {
utils.append(start, state);
}

var lastNonEmptyLine = 0;

lines.forEach(function (line, index) {
if (line.match(/[^ \t]/)) {
lastNonEmptyLine = index;
}

var trimmedChildValueWithSpace = trimWithSingleSpace(object.value);

/**
*/
var initialLines = trimmedChildValue.split(/\r\n|\n|\r/);

var lines = initialLines.filter(function(line) {
return safeTrim(line).length > 0;
});

var hasInitialNewLine = initialLines[0] !== lines[0];
hasFinalNewLine =
initialLines[initialLines.length - 1] !== lines[lines.length - 1];

var numLines = lines.length;
lines.forEach(function (line, ii) {
var lastLine = ii === numLines - 1;
var trimmedLine = safeTrim(line);
if (trimmedLine === '' && !lastLine) {
utils.append(line, state);
} else {
var preString = '';
var postString = '';
var leading = line.match(/^[ \t]*/)[0];

if (ii === 0) {
if (hasInitialNewLine) {
preString = ' ';
leading = '\n' + leading;
}
if (trimmedChildValueWithSpace.substring(0, 1) === ' ') {
// If this is the first line, and the original content starts with
// whitespace, place a single space at the beginning.
preString = ' ';
}
});

lines.forEach(function (line, index) {
var isFirstLine = index === 0;
var isLastLine = index === lines.length - 1;
var isLastNonEmptyLine = index === lastNonEmptyLine;

// replace rendered whitespace tabs with spaces
var trimmedLine = line.replace(/\t/g, ' ');

// trim whitespace touching a newline
if (!isFirstLine) {
trimmedLine = trimmedLine.replace(/^[ ]+/, '');
}
if (!isLastLine) {
trimmedLine = trimmedLine.replace(/[ ]+$/, '');
}

utils.append(line.match(/^[ \t]*/)[0], state);

if (trimmedLine || isLastNonEmptyLine) {
utils.append(
JSON.stringify(trimmedLine) +
(!isLastNonEmptyLine ? "+' '+" : ''),
state);

if (isLastNonEmptyLine) {
if (end) {
utils.append(end, state);
}
if (!lastLine || trimmedChildValueWithSpace.substr(
trimmedChildValueWithSpace.length - 1, 1) === ' ' ||
hasFinalNewLine
) {
// If either not on the last line, or the original content ends with
// whitespace, place a single character at the end.
postString = ' ';
if (!isLast) {
utils.append(',', state);
}

utils.append(
leading +
JSON.stringify(
preString + trimmedLine + postString
) +
(lastLine ? '' : '+') +
line.match(/[ \t]*$/)[0],
state);
}
if (!lastLine) {
utils.append('\n', state);

// only restore tail whitespace if line had literals
if (trimmedLine) {
utils.append(line.match(/[ \t]*$/)[0], state);
}
});
} else {
if (start) {
utils.append(start, state);
}
utils.append('""', state);
}
if (end) {
utils.append(end, state);
}

// add comma before trailing whitespace
if (!isLast) {
utils.append(',', state);
}

// tail whitespace
if (hasFinalNewLine) {
utils.append('\n', state);
}
utils.append(object.value.match(/[ \t]*$/)[0], state);

if (!isLastLine) {
utils.append('\n', state);
}
});

utils.move(object.range[1], state);
}

Expand Down

0 comments on commit db04043

Please sign in to comment.