Normalize whitespace for transformed JSX code
Andreas Svensson committed
Jan 24, 2014 at 21:46 UTC
60d7a02d44d8ce893e338f0ff6ae4812c9b5331a
2 files changed
+40
-32
vendor/fbtransform/transforms/react.js
+25
-25
@@ -25,6 +25,8 @@ var renderXJSExpressionContainer =
25
var renderXJSLiteral = require('./xjs').renderXJSLiteral;
26
var quoteAttrName = require('./xjs').quoteAttrName;
27
28
+var trimLeft = require('./xjs').trimLeft;
29
+
30
/**
31
* Customized desugar processor.
32
*
@@ -53,7 +55,7 @@ function visitReactTag(traverse, object, path, state) {
55
var nameObject = openingElement.name;
56
var attributesObject = openingElement.attributes;
57
56
- utils.catchup(openingElement.range[0], state);
58
+ utils.catchup(openingElement.range[0], state, trimLeft);
59
60
if (nameObject.namespace) {
61
throw new Error(
@@ -68,44 +70,43 @@ function visitReactTag(traverse, object, path, state) {
70
71
utils.move(nameObject.range[1], state);
72
73
+ var hasAttributes = attributesObject.length;
74
+
75
// if we don't have any attributes, pass in null
72
- if (attributesObject.length === 0) {
76
+ if (hasAttributes) {
77
+ utils.append('{', state);
78
+ } else {
79
utils.append('null', state);
80
}
81
82
// write attributes
83
attributesObject.forEach(function(attr, index) {
78
- utils.catchup(attr.range[0], state);
84
if (attr.name.namespace) {
85
throw new Error(
86
'Namespace attributes are not supported. ReactJSX is not XML.');
87
}
88
var name = attr.name.name;
84
- var isFirst = index === 0;
89
var isLast = index === attributesObject.length - 1;
90
87
- if (isFirst) {
88
- utils.append('{', state);
89
- }
90
-
91
+ utils.catchup(attr.range[0], state, trimLeft);
92
utils.append(quoteAttrName(name), state);
92
- utils.append(':', state);
93
+ utils.append(': ', state);
94
95
if (!attr.value) {
96
state.g.buffer += 'true';
97
state.g.position = attr.name.range[1];
98
if (!isLast) {
98
- utils.append(',', state);
99
+ utils.append(', ', state);
100
}
101
} else {
102
utils.move(attr.name.range[1], state);
102
- // Use catchupWhiteSpace to skip over the '=' in the attribute
103
- utils.catchupWhiteSpace(attr.value.range[0], state);
103
+ // Use catchupNewlines to skip over the '=' in the attribute
104
+ utils.catchupNewlines(attr.value.range[0], state);
105
if (JSX_ATTRIBUTE_TRANSFORMS.hasOwnProperty(attr.name.name)) {
106
utils.append(JSX_ATTRIBUTE_TRANSFORMS[attr.name.name](attr), state);
107
utils.move(attr.value.range[1], state);
108
if (!isLast) {
108
- utils.append(',', state);
109
+ utils.append(', ', state);
110
}
111
} else if (attr.value.type === Syntax.Literal) {
112
renderXJSLiteral(attr.value, isLast, state);
@@ -114,18 +115,18 @@ function visitReactTag(traverse, object, path, state) {
115
}
116
}
117
117
- if (isLast) {
118
- utils.append('}', state);
119
- }
120
-
121
- utils.catchup(attr.range[1], state);
118
+ utils.catchup(attr.range[1], state, trimLeft);
119
});
120
121
if (!openingElement.selfClosing) {
125
- utils.catchup(openingElement.range[1] - 1, state);
122
+ utils.catchup(openingElement.range[1] - 1, state, trimLeft);
123
utils.move(openingElement.range[1], state);
124
}
125
126
+ if (hasAttributes) {
127
+ utils.append('}', state);
128
+ }
129
+
130
// filter out whitespace
131
var childrenToRender = object.children.filter(function(child) {
132
return !(child.type === Syntax.Literal
@@ -147,7 +148,7 @@ function visitReactTag(traverse, object, path, state) {
148
}
149
150
childrenToRender.forEach(function(child, index) {
150
- utils.catchup(child.range[0], state);
151
+ utils.catchup(child.range[0], state, trimLeft);
152
153
var isLast = index >= lastRenderableIndex;
154
@@ -158,22 +159,21 @@ function visitReactTag(traverse, object, path, state) {
159
} else {
160
traverse(child, path, state);
161
if (!isLast) {
161
- utils.append(',', state);
162
- state.g.buffer = state.g.buffer.replace(/(\s*),$/, ',$1');
162
+ utils.append(', ', state);
163
}
164
}
165
166
- utils.catchup(child.range[1], state);
166
+ utils.catchup(child.range[1], state, trimLeft);
167
});
168
}
169
170
if (openingElement.selfClosing) {
171
// everything up to />
172
- utils.catchup(openingElement.range[1] - 2, state);
172
+ utils.catchup(openingElement.range[1] - 2, state, trimLeft);
173
utils.move(openingElement.range[1], state);
174
} else {
175
// everything up to </ sdflksjfd>
176
- utils.catchup(object.closingElement.range[0], state);
176
+ utils.catchup(object.closingElement.range[0], state, trimLeft);
177
utils.move(object.closingElement.range[1], state);
178
}
179
vendor/fbtransform/transforms/xjs.js
+15
-7
@@ -180,12 +180,14 @@ function renderXJSLiteral(object, isLast, state, start, end) {
180
trimmedLine = trimmedLine.replace(/[ ]+$/, '');
181
}
182
183
- utils.append(line.match(/^[ \t]*/)[0], state);
183
+ if (!isFirstLine) {
184
+ utils.append(line.match(/^[ \t]*/)[0], state);
185
+ }
186
187
if (trimmedLine || isLastNonEmptyLine) {
188
utils.append(
189
JSON.stringify(trimmedLine) +
188
- (!isLastNonEmptyLine ? "+' '+" : ''),
190
+ (!isLastNonEmptyLine ? " + ' ' +" : ''),
191
state);
192
193
if (isLastNonEmptyLine) {
@@ -193,12 +195,12 @@ function renderXJSLiteral(object, isLast, state, start, end) {
195
utils.append(end, state);
196
}
197
if (!isLast) {
196
- utils.append(',', state);
198
+ utils.append(', ', state);
199
}
200
}
201
202
// only restore tail whitespace if line had literals
201
- if (trimmedLine) {
203
+ if (trimmedLine && !isLastLine) {
204
utils.append(line.match(/[ \t]*$/)[0], state);
205
}
206
}
@@ -215,14 +217,15 @@ function renderXJSExpressionContainer(traverse, object, isLast, path, state) {
217
// Plus 1 to skip `{`.
218
utils.move(object.range[0] + 1, state);
219
traverse(object.expression, path, state);
220
+
221
if (!isLast && object.expression.type !== Syntax.XJSEmptyExpression) {
222
// If we need to append a comma, make sure to do so after the expression.
220
- utils.catchup(object.expression.range[1], state);
221
- utils.append(',', state);
223
+ utils.catchup(object.expression.range[1], state, trimLeft);
224
+ utils.append(', ', state);
225
}
226
227
// Minus 1 to skip `}`.
225
- utils.catchup(object.range[1] - 1, state);
228
+ utils.catchup(object.range[1] - 1, state, trimLeft);
229
utils.move(object.range[1], state);
230
return false;
231
}
@@ -235,7 +238,12 @@ function quoteAttrName(attr) {
238
return attr;
239
}
240
241
+function trimLeft(value) {
242
+ return value.replace(/^[ ]+/, '');
243
+}
244
+
245
exports.knownTags = knownTags;
246
exports.renderXJSExpressionContainer = renderXJSExpressionContainer;
247
exports.renderXJSLiteral = renderXJSLiteral;
248
exports.quoteAttrName = quoteAttrName;
249
+exports.trimLeft = trimLeft;