combine jsx and react transformer so we can make the jsx output correct - #143

This commit is contained in:
Sebastian McKenzie 2014-11-11 19:11:30 +11:00
parent b9f3f1e2a9
commit 9e08a6f084
66 changed files with 229 additions and 209 deletions

View File

@ -49,7 +49,6 @@ _.each({
numericLiterals: require("./transformers/numeric-literals"),
react: require("./transformers/react"),
jsx: require("./transformers/jsx"),
_aliasFunctions: require("./transformers/_alias-functions"),
_blockHoist: require("./transformers/_block-hoist"),

View File

@ -1,101 +0,0 @@
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
// https://github.com/RReverser/jsx-transpiler
var esutils = require("esutils");
var t = require("../../types");
var _ = require("lodash");
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;
exports.Program = function (node, parent, file) {
var jsx = "React.DOM";
// looking for namespace annotation
_.each(node.leadingComments, function (comment) {
var matches = JSX_ANNOTATION_REGEX.exec(comment.value);
if (matches) jsx = matches[1];
});
// prebuilding AST node
file.jsx = jsx.split(".").map(t.identifier).reduce(function (object, property) {
return t.memberExpression(object, property);
});
};
exports.XJSIdentifier = function (node) {
if (esutils.keyword.isIdentifierName(node.name)) {
node.type = "Identifier";
} else {
return t.literal(node.name);
}
};
exports.XJSNamespacedName = function () {
throw new Error("Namespace tags are not supported. ReactJSX is not XML.");
};
exports.XJSMemberExpression = {
exit: function (node) {
node.computed = t.isLiteral(node.property);
node.type = "MemberExpression";
}
};
exports.XJSExpressionContainer = function (node) {
return node.expression;
};
exports.XJSAttribute = {
exit: function (node) {
var value = node.value || t.literal(true);
return t.property("init", node.name, value);
}
};
exports.XJSOpeningElement = {
exit: function (node, parent, file) {
var tagExpr = node.name;
if (t.isIdentifier(tagExpr)) {
var tagName = tagExpr.name;
if (/[a-z]/.exec(tagName[0]) || _.contains(tagName, "-")) {
tagExpr = t.memberExpression(file.jsx, tagExpr);
}
}
var props = node.attributes;
if (props.length) {
props = t.objectExpression(props);
} else {
props = t.literal(null);
}
return t.callExpression(tagExpr, [props]);
}
};
exports.XJSElement = {
exit: function (node) {
var callExpr = node.openingElement;
var children = node.children;
_.each(children, function (child, i) {
var val = child.value;
if (t.isLiteral(child) && _.isString(val)) {
val = val.replace(/\n(\s+)/g, " ");
i = +i;
if (i === 0) val = val.trimLeft();
if (i === children.length - 1) val = val.trimRight();
if (!val) return;
child.value = val;
}
callExpr.arguments.push(child);
});
return t.inherits(callExpr, node);
}
};

View File

@ -1,5 +1,101 @@
var t = require("../../types");
var _ = require("lodash");
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
// https://github.com/RReverser/jsx-transpiler
// jsx
var esutils = require("esutils");
var t = require("../../types");
var _ = require("lodash");
exports.XJSIdentifier = function (node) {
if (esutils.keyword.isIdentifierName(node.name)) {
node.type = "Identifier";
} else {
return t.literal(node.name);
}
};
exports.XJSNamespacedName = function (node, parent, file) {
throw file.errorWithNode(node, "Namespace tags are not supported. ReactJSX is not XML.");
};
exports.XJSMemberExpression = {
exit: function (node) {
node.computed = t.isLiteral(node.property);
node.type = "MemberExpression";
}
};
exports.XJSExpressionContainer = function (node) {
return node.expression;
};
exports.XJSAttribute = {
exit: function (node) {
var value = node.value || t.literal(true);
return t.property("init", node.name, value);
}
};
exports.XJSOpeningElement = {
exit: function (node, parent, file) {
var tagExpr = node.name;
var args = [];
var tagName;
if (t.isIdentifier(tagExpr)) {
tagName = tagExpr.name;
} else if (t.isLiteral(tagExpr)) {
tagName = tagExpr.value;
}
if (tagName && (/[a-z]/.exec(tagName[0]) || _.contains(tagName, "-"))) {
args.push(t.literal(tagName));
} else {
args.push(tagExpr);
}
var props = node.attributes;
if (props.length) {
var first = props[0];
if (t.isXJSSpreadAttribute(first)) {
props.shift();
props = t.callExpression(
t.memberExpression(t.identifier("React"), t.identifier("__spread")),
[t.objectExpression([]), first.argument, t.objectExpression(props)]
);
} else {
props = t.objectExpression(props);
}
} else {
props = t.literal(null);
}
args.push(props);
tagExpr = t.memberExpression(t.identifier("React"), t.identifier("createElement"));
return t.callExpression(tagExpr, args);
}
};
exports.XJSElement = {
exit: function (node) {
var callExpr = node.openingElement;
var children = node.children;
var childrenToRender = node.children.filter(function(child) {
return !(t.isLiteral(child) && _.isString(child.value) && child.value.match(/^[ \t]*[\r\n][ \t\r\n]*$/));
});
_.each(childrenToRender, function (child, i) {
callExpr.arguments.push(child);
});
return t.inherits(callExpr, node);
}
};
// display names
var addDisplayName = function (id, call) {
if (!call || !t.isCallExpression(call)) return;

View File

@ -71,6 +71,6 @@
"XJSMemberExpression": ["object", "property"],
"XJSNamespacedName": ["namespace", "name"],
"XJSOpeningElement": ["name", "attributes"],
"XJSSpreadAttribute": [],
"XJSSpreadAttribute": ["argument"],
"YieldExpression": ["argument"]
}

View File

@ -1,3 +0,0 @@
/** @jsx CUSTOM_DOM */
<a></a>

View File

@ -1,5 +0,0 @@
/** @jsx CUSTOM_DOM */
"use strict";
CUSTOM_DOM.a(null);

View File

@ -1 +0,0 @@
<X>{}</X>

View File

@ -1,3 +0,0 @@
"use strict";
X(null, null);

View File

@ -1,2 +0,0 @@
<X data-prop={x ? <Y prop={2} /> : <Z>
</Z>}></X>

View File

@ -1,7 +0,0 @@
"use strict";
X({
"data-prop": x ? Y({
prop: 2
}) : Z(null)
});

View File

@ -1,5 +0,0 @@
(<X>{a}</X>);
(<X>{a} {b}</X>);
(<X prop={a} yes></X>);

View File

@ -1,10 +0,0 @@
"use strict";
(X(null, a));
(X(null, a, " ", b));
(X({
prop: a,
yes: true
}));

View File

@ -1 +0,0 @@
<a></a>

View File

@ -1,3 +0,0 @@
"use strict";
React.DOM.a(null);

View File

@ -1 +0,0 @@
<Test.X></Test.X>

View File

@ -1,3 +0,0 @@
"use strict";
Test.X(null);

View File

@ -1 +0,0 @@
<Test:X></Test:X>

View File

@ -1,3 +0,0 @@
(<X />);
(<X prop="1" />);

View File

@ -1,7 +0,0 @@
"use strict";
(X(null));
(X({
prop: "1"
}));

View File

@ -1 +0,0 @@
<X></X>

View File

@ -1,3 +0,0 @@
"use strict";
X(null);

View File

@ -1,3 +0,0 @@
(<X prop="2"><Y /></X>);
(<X prop="2"><Y /><Z /></X>);

View File

@ -1,9 +0,0 @@
"use strict";
(X({
prop: "2"
}, Y(null)));
(X({
prop: "2"
}, Y(null), Z(null)));

View File

@ -1,13 +0,0 @@
(<X> </X>);
(<X>
</X>);
(<X>
string
</X>);
(<X>
string
string
</X>);

View File

@ -1,9 +0,0 @@
"use strict";
(X(null));
(X(null));
(X(null, "string"));
(X(null, "string string"));

View File

@ -0,0 +1 @@
<div>&nbsp; </div>;

View File

@ -0,0 +1 @@
React.createElement("div", null, "\u00A0 ");

View File

@ -0,0 +1 @@
<div>&nbsp;</div>;

View File

@ -0,0 +1 @@
React.createElement("div", null, "\u00A0");

View File

@ -0,0 +1,13 @@
var x = (
<div>
{/* A comment at the beginning */}
{/* A second comment at the beginning */}
<span>
{/* A nested comment */}
</span>
{/* A sandwiched comment */}
<br />
{/* A comment at the end */}
{/* A second comment at the end */}
</div>
);

View File

@ -0,0 +1,11 @@
var x = (React.createElement("div", null,
/* A comment at the beginning */
/* A second comment at the beginning */
React.createElement("span", null
/* A nested comment */
),
/* A sandwiched comment */
React.createElement("br", null)
/* A comment at the end */
/* A second comment at the end */
));

View File

@ -0,0 +1,10 @@
var x = (
<div
/* a multi-line
comment */
attr1="foo">
<span // a double-slash comment
attr2="bar"
/>
</div>
);

View File

@ -0,0 +1,8 @@
var x = (React.createElement("div", {
/* a multi-line
comment */
attr1: "foo"},
React.createElement("span", {// a double-slash comment
attr2: "bar"}
)
));

View File

@ -0,0 +1,3 @@
<Component
{...this.props}
sound="moo" />

View File

@ -0,0 +1,3 @@
React.createElement(Component, React.__spread({}, this.props, {
sound: "moo"
}));

View File

@ -1,5 +1,3 @@
"use strict";
var Component;
Component = React.createClass({
displayName: "Component",

View File

@ -1,8 +1,6 @@
"use strict";
var Whateva = React.createClass({
displayName: "Whatever",
render: function () {
return null;
}
});
});

View File

@ -1,5 +1,3 @@
"use strict";
exports = {
Component: React.createClass({
displayName: "Component",

View File

@ -1,5 +1,3 @@
"use strict";
exports.Component = React.createClass({
displayName: "Component",

View File

@ -1,5 +1,3 @@
"use strict";
var Component = React.createClass({
displayName: "Component",

View File

@ -0,0 +1,3 @@
{
"blacklist": ["useStrict"]
}

View File

@ -0,0 +1 @@
<Component constructor="foo" />;

View File

@ -0,0 +1,3 @@
React.createElement(Component, {
constructor: "foo"
});

View File

@ -0,0 +1 @@
<Namespace.DeepNamespace.Component />;

View File

@ -0,0 +1 @@
React.createElement(Namespace.DeepNamespace.Component, null);

View File

@ -0,0 +1 @@
<Namespace.Component />;

View File

@ -0,0 +1 @@
React.createElement(Namespace.Component, null);

View File

@ -0,0 +1 @@
React.createElement(Namespace.Component, null);

View File

@ -0,0 +1,15 @@
var x = <div>
<Component />
</div>;
var x = <div>
{this.props.children}
</div>;
var x = <Composite>
{this.props.children}
</Composite>;
var x = <Composite>
<Composite2 />
</Composite>;

View File

@ -0,0 +1,7 @@
var x = React.createElement("div", null, React.createElement(Component, null));
var x = React.createElement("div", null, this.props.children);
var x = React.createElement(Composite, null, this.props.children);
var x = React.createElement(Composite, null, React.createElement(Composite2, null));

View File

@ -0,0 +1 @@
var x = <div></div>;

View File

@ -0,0 +1 @@
var x = React.createElement("div", null);

View File

@ -0,0 +1 @@
var x = <div>text</div>;

View File

@ -0,0 +1 @@
var x = React.createElement("div", null, "text");

View File

@ -0,0 +1 @@
<Namespace:Component />;

View File

@ -0,0 +1 @@
<hasOwnProperty>testing</hasOwnProperty>;

View File

@ -0,0 +1 @@
React.createElement("hasOwnProperty", null, "testing");

View File

@ -0,0 +1,5 @@
var x = <div>
<div><br /></div>
<Component>{foo}<br />{bar}</Component>
<br />
</div>;

View File

@ -0,0 +1 @@
var x = React.createElement("div", null, React.createElement("div", null, React.createElement("br", null)), React.createElement(Component, null, foo, React.createElement("br", null), bar), React.createElement("br", null));

View File

@ -0,0 +1,16 @@
var x =
<div
attr1={
"foo" + "bar"
}
attr2={
"foo" + "bar" +
"baz" + "bug"
}
attr3={
"foo" + "bar" +
"baz" + "bug"
}
attr4="baz">
</div>

View File

@ -0,0 +1,6 @@
var x = React.createElement("div", {
attr1: "foo" + "bar",
attr2: "foo" + "bar" + "baz" + "bug",
attr3: "foo" + "bar" + "baz" + "bug",
attr4: "baz"
});

View File

@ -0,0 +1 @@
<font-face />;

View File

@ -0,0 +1 @@
React.createElement("font-face", null);

View File

@ -0,0 +1,2 @@
<Component { ... x } y
={2 } z />

View File

@ -0,0 +1,4 @@
React.createElement(Component, React.__spread({}, x, {
y: 2,
z: true
}));