Compare commits

...

11 Commits

Author SHA1 Message Date
Sebastian McKenzie
8e2abad41c v1.9.7 2014-10-17 21:29:39 +11:00
Sebastian McKenzie
f06901ac05 add jsx and react transformer 2014-10-17 21:28:01 +11:00
Sebastian McKenzie
531ea91a07 add support for exit traversal functions to replace the node 2014-10-17 21:20:08 +11:00
Sebastian McKenzie
0188556b36 forbid function declarations that reference block scoped variables 2014-10-17 21:19:51 +11:00
Sebastian McKenzie
aeac003dc8 add util.ensureExpressionType which will change a node from a declaration to an expression 2014-10-17 11:48:25 +11:00
Sebastian McKenzie
41ab47dde8 allow let scope access within FunctionDeclaration, add _block-hoist helper transformer - fixes #77 2014-10-17 11:09:49 +11:00
Sebastian McKenzie
112932f9ee add jsx elements to traversal visitor keys 2014-10-17 09:18:29 +11:00
Sebastian McKenzie
0efeed3d5e add destructuring no element test 2014-10-16 11:41:27 +11:00
Sebastian McKenzie
55fdf11555 add util list test 2014-10-16 11:41:13 +11:00
Sebastian McKenzie
d801c95f6e add hasType traverse test 2014-10-16 11:41:08 +11:00
Sebastian McKenzie
138d714589 add 6to5-node --extensions test 2014-10-16 11:05:35 +11:00
41 changed files with 406 additions and 39 deletions

View File

@@ -94,7 +94,11 @@ transform.transformers = {
unicodeRegex: require("./transformers/unicode-regex"),
generators: require("./transformers/generators"),
_aliasFunctions: require("./transformers/_alias-functions")
react: require("./transformers/react"),
jsx: require("./transformers/jsx"),
_aliasFunctions: require("./transformers/_alias-functions"),
_blockHoist: require("./transformers/_block-hoist")
};
_.each(transform.transformers, function (transformer, key) {

View File

@@ -0,0 +1,17 @@
exports.BlockStatement =
exports.Program = {
exit: function (node) {
var unshift = [];
node.body = node.body.filter(function (bodyNode) {
if (bodyNode._blockHoist) {
unshift.push(bodyNode);
return false;
} else {
return true;
}
});
node.body = unshift.concat(node.body);
}
};

View File

@@ -0,0 +1,99 @@
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
// https://github.com/RReverser/jsx-transpiler
var esutils = require("esutils");
var b = require("recast").types.builders;
var _ = require("lodash");
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;
var KNOWN_TAGS = require("./known-tags");
exports.Program = function (node, parent, file) {
var jsx = "React.DOM";
// looking for namespace annotation
_.each(node.comments, function (comment) {
if (!comment.possiblyLeading) return;
var matches = JSX_ANNOTATION_REGEX.exec(comment.value);
if (matches) jsx = matches[1];
});
// prebuilding AST node
file.jsx = jsx.split(".").map(b.identifier).reduce(function (object, property) {
return b.memberExpression(object, property, false);
});
};
exports.XJSIdentifier = function (node) {
if (esutils.keyword.isIdentifierName(node.name)) {
node.type = "Identifier";
} else {
return b.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 = node.property.type === "Literal";
node.type = "MemberExpression";
}
};
exports.XJSEmptyExpression = function (node) {
node.value = null;
node.type = "Literal";
};
exports.XJSExpressionContainer = function (node) {
return node.expression;
};
exports.XJSAttribute = {
exit: function (node) {
var value = node.value || b.literal(true);
var propNode = b.property("init", node.name, value);
propNode.loc = node.loc;
return propNode;
}
};
exports.XJSOpeningElement = {
exit: function (node, parent, file) {
var tagExpr = node.name;
if (_.contains(KNOWN_TAGS, tagExpr.name)) {
tagExpr = b.memberExpression(file.jsx, tagExpr, false);
}
var props = node.attributes;
if (props.length) {
props = b.objectExpression(props);
} else {
props = b.literal(null);
}
return b.callExpression(tagExpr, [props]);
}
};
exports.XJSElement = {
exit: function (node) {
var callExpr = node.openingElement;
var children = node.children;
var args = callExpr.arguments;
switch (children.length) {
case 0: break;
case 1: args.push(children[0]); break;
default: args.push(b.arrayExpression(children));
}
callExpr.loc = node.loc;
return callExpr;
}
};

View File

@@ -0,0 +1,132 @@
[
"a",
"abbr",
"address",
"applet",
"area",
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"big",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"circle",
"cite",
"code",
"col",
"colgroup",
"command",
"data",
"datalist",
"dd",
"defs",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"ellipse",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"g",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"keygen",
"label",
"legend",
"li",
"line",
"linearGradient",
"link",
"main",
"map",
"mark",
"marquee",
"menu",
"menuitem",
"meta",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"path",
"polygon",
"polyline",
"pre",
"progress",
"q",
"radialGradient",
"rect",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"small",
"source",
"span",
"stop",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"text",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tspan",
"u",
"ul",
"var",
"video",
"wbr"
]

View File

@@ -26,8 +26,10 @@ exports.VariableDeclaration = function (node, parent, file) {
if (util.isReferenced(node, parent)) return id;
};
var isProgram = parent.type === "Program";
var replace = function (node, parent) {
if (_.contains(traverse.FUNCTION_TYPES, node.type)) {
if (!isProgram && _.contains(traverse.FUNCTION_TYPES, node.type)) {
var letReferences = [];
traverse(node, function (node, parent) {
@@ -37,9 +39,13 @@ exports.VariableDeclaration = function (node, parent, file) {
});
if (letReferences.length) {
return b.callExpression(b.functionExpression(null, letReferences, b.blockStatement([
b.returnStatement(node)
])), letReferences);
if (node.type === "FunctionDeclaration") {
throw new Error("`FunctionDeclaration`s that use `let` and `constant` references aren't allowed outside of the root scope");
} else {
return b.callExpression(b.functionExpression(null, letReferences, b.blockStatement([
b.returnStatement(node)
])), letReferences);
}
} else {
return false;
}

View File

@@ -72,11 +72,7 @@ var pushExportDeclaration = function (node, parent, nodes) {
var declar = node.declaration;
if (node.default) {
if (declar.type === "FunctionDeclaration") {
declar.type = "FunctionExpression";
} else if (declar.type === "ClassDeclaration") {
declar.type = "ClassExpression";
}
util.ensureExpressionType(declar);
nodes.push(util.template("exports-default", {
VALUE: declar
@@ -95,30 +91,13 @@ var pushExportDeclaration = function (node, parent, nodes) {
nodes.push(declar);
if (declar.type === "FunctionDeclaration") {
assign._modulesHoist = true;
assign._blockHoist = true;
}
nodes.push(assign);
}
};
exports.Program = {
exit: function (node) {
var unshift = [];
node.body = node.body.filter(function (bodyNode) {
if (bodyNode._modulesHoist) {
unshift.push(bodyNode);
return false;
} else {
return true;
}
});
node.body = unshift.concat(node.body);
}
};
exports.ExportDeclaration = function (node, parent) {
var nodes = [];

0
lib/6to5/transformers/react.js vendored Normal file
View File

View File

@@ -34,20 +34,30 @@ var traverse = module.exports = function (parent, callbacks, blacklistTypes) {
// type is blacklisted
if (_.contains(blacklistTypes, node.type)) return;
// enter
var result = callbacks.enter(node, parent, obj, key);
// stop iteration
if (result === false) return;
var result;
// replace node
if (result != null) node = obj[key] = result;
var maybeReplace = function (result) {
if (result != null) obj[key] = result;
};
// enter
if (callbacks.enter) {
result = callbacks.enter(node, parent, obj, key);
// stop iteration
if (result === false) return;
maybeReplace(result);
}
// traverse node
traverse(node, callbacks, blacklistTypes);
// exit
if (callbacks.exit) callbacks.exit(node, parent, obj, key);
if (callbacks.exit) {
maybeReplace(callbacks.exit(node, parent, obj, key));
}
};
if (_.isArray(nodes)) {

View File

@@ -72,5 +72,15 @@
"VoidTypeAnnotation": [],
"WhileStatement": ["test", "body"],
"WithStatement": ["object", "body"],
"XJSIdentifier": [],
"XJSNamespacedName": ["namespace", "name"],
"XJSMemberExpression": ["object", "property"],
"XJSEmptyExpression": [],
"XJSExpressionContainer": ["expression"],
"XJSElement": ["openingElement", "closingElement", "children"],
"XJSClosingElement": ["name"],
"XJSOpeningElement": ["name", "attributes"],
"XJSAttribute": ["name", "value"],
"XJSText": [],
"YieldExpression": ["argument"]
}

View File

@@ -24,6 +24,14 @@ exports.list = function (val) {
return val ? val.split(",") : [];
};
exports.ensureExpressionType = function (node) {
node.type = {
FunctionDeclaration: "FunctionExpression",
ClassDeclaration: "ClassExpression"
}[node.type] || node.type;
return node;
};
exports.getUid = function (parent, file) {
var node;

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.9.6",
"version": "1.9.7",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/sebmck/6to5",
"repository": {
@@ -45,7 +45,8 @@
"source-map": "0.1.40",
"regenerator": "0.6.7",
"chokidar": "^0.9.0",
"source-map-support": "^0.2.7"
"source-map-support": "^0.2.7",
"esutils": "^1.1.4"
},
"devDependencies": {
"es6-transpiler": "0.7.17",

View File

@@ -0,0 +1 @@
console.log([1, 2, 3].map(x => x * x));

View File

@@ -0,0 +1,4 @@
{
"args": ["foo", "--extensions", ".bar"],
"stdout": "[ 1, 4, 9 ]"
}

View File

@@ -0,0 +1 @@
var [, a, [b], [c], d] = ["foo", "hello", [", ", "junk"], ["world"]];

View File

@@ -0,0 +1,5 @@
var _ref = ["foo", "hello", [", ", "junk"], ["world"]];
var a = _ref[1];
var b = _ref[2][0];
var c = _ref[3][0];
var d = _ref[4];

View File

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

View File

@@ -0,0 +1,3 @@
/** @jsx CUSTOM_DOM */
CUSTOM_DOM.a(null);

View File

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

View File

@@ -0,0 +1 @@
x(null, null);

View File

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

View File

@@ -0,0 +1,3 @@
X({
"data-prop": x ? Y({ prop: 2 }) : Z(null, "\n")
});

View File

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

View File

@@ -0,0 +1,3 @@
X(null, a);
X(null, [a, ' ', b]);
X({ prop: a, yes: true });

View File

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

View File

@@ -0,0 +1 @@
React.DOM.a(null);

View File

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

View File

@@ -0,0 +1 @@
Test.X(null);

View File

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

View File

@@ -0,0 +1,3 @@
{
"throws": "Namespace tags are not supported. ReactJSX is not XML."
}

View File

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

View File

@@ -0,0 +1,2 @@
X(null);
X({ prop: '1' });

View File

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

View File

@@ -0,0 +1 @@
X(null);

View File

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

View File

@@ -0,0 +1,2 @@
X({ prop: '2' }, Y(null));
X({ prop: '2' }, [Y(null), Z(null)]);

View File

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

View File

@@ -0,0 +1,4 @@
X(null, ' ');
X(null, '\n');
X(null, '\n string\n');
X(null, '\n string\n string\n ');

View File

@@ -0,0 +1,7 @@
var numbers = [1, 2, 3];
for (let i in numbers) {
function foo() {
return i;
}
}

View File

@@ -0,0 +1,3 @@
{
"throws": "`FunctionDeclaration`s that use `let` and `constant` references aren't allowed outside of the root scope"
}

View File

@@ -1,5 +1,6 @@
var traverse = require("../lib/6to5/traverse");
var assert = require("assert");
var b = require("recast").types.builders;
var _ = require("lodash");
suite("traverse", function () {
@@ -137,9 +138,21 @@ suite("traverse", function () {
}, /trying to delete property object from MemberExpression but can't because it's required/);
});
test("hasType");
test("hasType", function () {
assert.ok(traverse.hasType(ast, "ThisExpression"));
assert.ok(traverse.hasType(ast, "Program"));
assert.ok(!traverse.hasType(ast, "ThisExpression", ["MemberExpression"]));
assert.ok(!traverse.hasType(ast, "ThisExpression", ["Program"]));
assert.ok(!traverse.hasType(ast, "ArrowFunctionExpression"));
});
test("isPattern");
test("isFunction");
test("isFunction", function () {
//assert.ok(traverse.isFunction(b.arrowFunctionExpression());
//assert.ok(traverse.isFunction(b.functionExpression()));
//assert.ok(traverse.isFunction(b.functionDeclaration()));
});
});

View File

@@ -45,6 +45,15 @@ suite("util", function () {
assert.ok(!util.isAbsolute("test/test.js"));
});
test("list", function () {
assert.deepEqual(util.list(undefined), []);
assert.deepEqual(util.list(false), []);
assert.deepEqual(util.list(null), []);
assert.deepEqual(util.list(""), []);
assert.deepEqual(util.list("foo"), ["foo"]);
assert.deepEqual(util.list("foo,bar"), ["foo", "bar"]);
});
test("getIds");
test("isReferenced");