Pull in syranides jsx whitespace codemod transform fixes
JeffMo committed
Feb 15, 2014 at 11:20 UTC
f66f8f03102d6af083890d11dbeff7dd02db093e
1 file changed
+99
-22
npm-jsx_whitespace_transform/transforms/react.js
+99
-22
@@ -18,35 +18,31 @@
18
var Syntax = require('esprima-fb').Syntax;
19
var utils = require('jstransform/src/utils');
20
21
-var renderXJSExpressionContainer =
22
- require('./xjs').renderXJSExpressionContainer;
23
-var renderXJSLiteral = require('./xjs').renderXJSLiteral;
24
-
21
function visitReactTag(traverse, object, path, state) {
26
- if (object.name.namespace) {
27
- throw new Error(
28
- 'Namespace tags are not supported. ReactJSX is not XML.');
29
- }
30
-
31
- object.children.forEach(function(child, ii) {
22
+ object.attributes.forEach(function(attr, index) {
23
+ traverse(attr.value, path, state);
24
+ });
25
+
26
+ object.children.forEach(function(child, index) {
27
if (child.type === Syntax.Literal) {
33
- renderXJSLiteral(child, state);
28
+ codemodXJSLiteral(child, state);
29
} else if (child.type === Syntax.XJSExpressionContainer) {
35
-
30
var isNotAfterLiteral =
37
- ii == 0 ||
38
- object.children[ii - 1].type !== Syntax.Literal;
39
-
31
+ index == 0 ||
32
+ object.children[index - 1].type !== Syntax.Literal;
33
+
34
var isNotBeforeLiteral =
41
- ii == object.children.length - 1 ||
42
- object.children[ii + 1].type !== Syntax.Literal;
43
-
44
- renderXJSExpressionContainer(
45
- traverse, child,
35
+ index == object.children.length - 1 ||
36
+ object.children[index + 1].type !== Syntax.Literal;
37
+
38
+ codemodXJSExpressionContainer(
39
+ traverse,
40
+ child,
41
isNotAfterLiteral,
42
isNotBeforeLiteral,
48
- path, state);
49
-
43
+ path,
44
+ state
45
+ );
46
} else {
47
traverse(child, path, state);
48
}
@@ -61,4 +57,85 @@ visitReactTag.test = function(object, path, state) {
57
return object.type === Syntax.XJSElement && jsx && jsx.length;
58
};
59
60
+function codemodXJSLiteral(object, state) {
61
+ var value = object.raw;
62
+
63
+ utils.catchup(object.range[0], state);
64
+
65
+ /*
66
+ This can be used to "annotate spaces" inserted by this transformation,
67
+ so that they can be more easily recognized as such in the final code
68
+
69
+ {' '}
70
+ {'\\x20'}
71
+ {(' ')}
72
+ {' '||0}
73
+ {' '||AnyTextYouLike}
74
+ {' '||'AnyTextYouLike'}
75
+ {GlobalVariableWithASpace}
76
+ */
77
+
78
+ var space = "{' '}";
79
+
80
+ /*
81
+ · space
82
+ ¬ newline
83
+ {expr} = <tag>
84
+
85
+ Old whitespace rules:
86
+ {1}··Aaa··Bbb··{2}··{3} → {1}·Aaa··Bbb·{2}{3}
87
+ {1}¬¬Aaa¬¬Bbb¬¬{2}¬¬{3} → {1}·Aaa·Bbb·{2}{3}
88
+
89
+ New whitespace rules:
90
+ {1}··Aaa··Bbb··{2}··{3} → {1}··Aaa··Bbb··{2}··{3}
91
+ {1}¬¬Aaa¬¬Bbb¬¬{2}¬¬{3} → {1}Aaa·Bbb{2}{3}
92
+
93
+ Required transformation:
94
+ {1}··{2} = {1}··{2} → {1}{2}
95
+ {1}··Aaa··{2} = {1}··Aaa··{2} → {1}·Aaa·{2}
96
+ {1}¬¬Aaa¬¬{2} = {1}Aaa{2} → {1}·Aaa·{2}
97
+ */
98
+
99
+ // {1}··{2} = {1}··{2} → {1}{2}
100
+ value = value.replace(/^[ \t]+$/, '');
101
+
102
+ // {1}··Aaa··{2} = {1}··Aaa··{2} → {1}·Aaa·{2}
103
+ value = value.replace(/^[ \t]+([^ \t\r\n])/, " $1");
104
+ value = value.replace(/([^ \t\r\n])[ \t]+$/, "$1 ");
105
+
106
+ // {1}¬¬Aaa¬¬{2} = {1}Aaa{2} → {1}·Aaa·{2}
107
+ value = value.replace(/^([ \t]*[\r\n][ \t\r\n]*)([^ \t\r\n].*)/, "$1" + space + "$2");
108
+ value = value.replace(/([^ \t\r\n])([ \t]*[\r\n][ \t\r\n]*)$/, "$1" + space + "$2");
109
+
110
+ // Rendered whitespace tabs are replaced with spaces
111
+ value = value.replace(/[^ \t\r\n][ ]*[\t][ \t]*[^ \t\r\n]/, function(match) {
112
+ return match.replace(/\t/g, ' ');
113
+ });
114
+
115
+ utils.append(value, state);
116
+ utils.move(object.range[1], state);
117
+}
118
+
119
+function codemodXJSExpressionContainer(
120
+ traverse,
121
+ object,
122
+ isNotAfterLiteral,
123
+ isNotBeforeLiteral,
124
+ path,
125
+ state) {
126
+ utils.catchup(object.range[0], state);
127
+ traverse(object.expression, path, state);
128
+
129
+ // Unbox the previously required {' '}-workaround
130
+ var raw = object.expression.raw;
131
+ var isSpace = raw === "' '" || raw === '" "';
132
+
133
+ if (isNotAfterLiteral && isNotBeforeLiteral && isSpace) {
134
+ utils.append(' ', state);
135
+ utils.move(object.range[1], state);
136
+ } else {
137
+ utils.catchup(object.range[1], state);
138
+ }
139
+}
140
+
141
exports.visitReactTag = visitReactTag;