@samitouri / QOS-React-2 / commits / f66f8f0310

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;