Compare commits

...

30 Commits

Author SHA1 Message Date
Sebastian McKenzie
e13ed39567 v1.12.3 2014-11-12 18:43:39 +11:00
Sebastian McKenzie
bb00f641b7 remove unused variables in spread transformer 2014-11-12 18:42:24 +11:00
Sebastian McKenzie
25b466a627 remove unused variables 2014-11-12 18:39:50 +11:00
Sebastian McKenzie
ac231f2987 add 1.12.3 changelog 2014-11-12 18:38:39 +11:00
Sebastian McKenzie
458e3d48f6 use Array.from instead of Array.prototype.slice in spread transformer and support NewExpression spreads - fixes #148 2014-11-12 18:38:30 +11:00
Sebastian McKenzie
c235780611 move down 6to5-node util declaration 2014-11-12 18:37:32 +11:00
Sebastian McKenzie
56b858ccb1 add generator comprehension transformer 2014-11-12 18:29:41 +11:00
Sebastian McKenzie
d42351bb02 add default parameters existence change to well... the defaultParameters transformer 2014-11-12 18:29:27 +11:00
Sebastian McKenzie
ed7378cc2d add apply-constructor declaration and add support for not returning generated code in opts.code 2014-11-12 18:29:03 +11:00
Sebastian McKenzie
a47a7dc347 rename util.parseNoProperties to util.parseTemplate 2014-11-12 18:28:11 +11:00
Sebastian McKenzie
2c82b5a4b0 add generator option to FunctionExpression builder keys 2014-11-12 18:27:56 +11:00
Sebastian McKenzie
3578135b90 add spread caveat and add generator comprehension and react/jsx to features 2014-11-12 18:27:05 +11:00
Sebastian McKenzie
5f3408b2a2 upgrade regenerator-6to5 2014-11-12 18:26:29 +11:00
Sebastian McKenzie
9e3f9fda6b add support for generator comprehensions - fixes #149 2014-11-12 18:26:22 +11:00
Sebastian McKenzie
7f425d2c6e v1.12.2 2014-11-12 12:22:03 +11:00
Sebastian McKenzie
311a8e042b add missing semicolon 2014-11-12 12:19:25 +11:00
Sebastian McKenzie
27d30329fd add more react spread tests 2014-11-12 12:18:16 +11:00
Sebastian McKenzie
12c5a3e73b add 1.12.2 changelog 2014-11-12 12:17:59 +11:00
Sebastian McKenzie
2a166a6ed1 support jsx spread attributes that aren't the first - fixes #146 2014-11-12 12:17:45 +11:00
Sebastian McKenzie
896929378e add util.trimRight method - fixes #147 2014-11-12 12:17:26 +11:00
Sebastian McKenzie
ae439d27b9 update mocha and browserify 2014-11-12 12:08:33 +11:00
Sebastian McKenzie
e22798261a change useless self references to this 2014-11-12 02:03:46 +11:00
Sebastian McKenzie
d0af8b8d0a remove numeric literals transformer 2014-11-12 02:03:25 +11:00
Sebastian McKenzie
beaa2fa540 add async functions to features 2014-11-12 02:03:11 +11:00
Sebastian McKenzie
b8cac9787e produce new MemberExpression in a CallExpression super identifier instead of mutating the property 2014-11-12 01:51:57 +11:00
Sebastian McKenzie
64f6e4a0c5 clean up classes transformer and add comments 2014-11-12 01:48:55 +11:00
Sebastian McKenzie
c4a7ac5a8b turn classes transformer into a class like let scoping 2014-11-12 01:39:35 +11:00
Sebastian McKenzie
1ed682fa76 fix up jsdoc in let-scoping transformer 2014-11-12 01:39:02 +11:00
Sebastian McKenzie
9987e7fe0e add 1.12.1 changelog 2014-11-12 01:38:50 +11:00
Sebastian McKenzie
e74c7cb0b7 turn the let scoping transformer into a class because it's quite complicated and the logic needs to be WAY more organised 2014-11-12 01:20:51 +11:00
50 changed files with 619 additions and 335 deletions

View File

@@ -1,3 +1,19 @@
# 1.12.3
* Support generator comprehensions.
* Use `Array.from` instead of `Array.prototype.slice` in spread transformer.
* Support spread in `NewExpression`s.
# 1.12.2
* Upgrade `matcha` to `0.6.0` and `browserify` to `6.3.2`.
* Add own `trimRight` helper instead of relying on the string instance method.
* Support JSX spreads that aren't the first.
# 1.12.1
* Fix `this` and `arguments` mapping in the `_aliasFunctions` transformer.
# 1.12.0
* Combine `jsx` and `react` transformers to `react`.

View File

@@ -6,6 +6,16 @@
[for (i of [1, 2, 3]) i * i]; // [1, 4, 9]
```
## Async functions
```javascript
async function chainAnimationsAsync(elem, animations) {
for (var anim of animations) {
await anim(elem);
}
}
```
## Arrow functions
```javascript
@@ -85,6 +95,11 @@ for (var i of [1, 2, 3]) {
```javascript
```
## Generator comprehension
```javascript
```
## Modules
```javascript

View File

@@ -55,6 +55,7 @@ It's as easy as:
## [Features](FEATURES.md)
- [Array comprehension](FEATURES.md#array-comprehension)
- [Async functions](FEATURES.md#async-functions) via [regenerator](https://github.com/facebook/regenerator)
- [Arrow functions](FEATURES.md#arrow-functions)
- [Classes](FEATURES.md#classes)
- [Computed property names](FEATURES.md#computed-property-names)
@@ -63,11 +64,13 @@ It's as easy as:
- [Destructuring](FEATURES.md#destructuring)
- [For-of](FEATURES.md#for-of)
- [Generators](FEATURES.md#generators) via [regenerator](https://github.com/facebook/regenerator)
- [Generator comprehension](FEATURES.md#generator-comprehension)
- [Let scoping](FEATURES.md#let-scoping)
- [Modules](FEATURES.md#modules)
- [Numeric literals](FEATURES.md#numeric-literals)
- [Property method assignment](FEATURES.md#property-method-assignment)
- [Property name shorthand](FEATURES.md#property-name-shorthand)
- [React/JSX](#reactjsx)
- [Rest parameters](FEATURES.md#rest-parameters)
- [Spread](FEATURES.md#spread)
- [Template literals](FEATURES.md#template-literals)
@@ -330,6 +333,11 @@ class Bar extends Foo {
}
```
### Spread
An [ES6 polyfill](#polyfill) is required in order for spread to work. More
specifically a polyfill for `Array.from`.
### Generators
The [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env node
var commander = require("commander");
var util = require("../lib/6to5/util");
var path = require("path");
var repl = require("repl");
var to5 = require("../lib/6to5");
var util = require("../lib/6to5/util");
var vm = require("vm");
var _ = require("lodash");

View File

@@ -18,7 +18,7 @@ function File(opts) {
this.ast = {};
}
File.declarations = ["extends", "class-props", "slice"];
File.declarations = ["extends", "class-props", "slice", "apply-constructor"];
File.normaliseOptions = function (opts) {
opts = _.cloneDeep(opts || {});
@@ -30,7 +30,8 @@ File.normaliseOptions = function (opts) {
sourceMap: false,
filename: "unknown",
modules: "common",
runtime: false
runtime: false,
code: true
});
// normalise windows path separators to unix
@@ -142,6 +143,14 @@ File.prototype.generate = function () {
var opts = this.opts;
var ast = this.ast;
if (!opts.code) {
return {
code: "",
map: null,
ast: ast
};
}
var result = generate(ast, opts, this.code);
if (this.shebang) {
@@ -153,6 +162,8 @@ File.prototype.generate = function () {
result.code += "\n" + util.sourceMapToComment(result.map);
}
result.ast = result;
return result;
};

View File

@@ -11,7 +11,7 @@ function Buffer(position, format) {
}
Buffer.prototype.get = function () {
return this.buf.trimRight();
return util.trimRight(this.buf);
};
Buffer.prototype.getIndent = function () {
@@ -116,7 +116,7 @@ Buffer.prototype.endsWith = function (str) {
Buffer.prototype.isLast = function (cha, trimRight) {
var buf = this.buf;
if (trimRight) buf = buf.trimRight();
if (trimRight) buf = util.trimRight(buf);
var chars = [].concat(cha);
return _.contains(chars, _.last(buf));

View File

@@ -53,16 +53,16 @@ CodeGenerator.normaliseOptions = function (opts) {
};
CodeGenerator.generators = {
arrayComprehensions: require("./generators/array-comprehensions"),
templateLiterals: require("./generators/template-literals"),
expressions: require("./generators/expressions"),
statements: require("./generators/statements"),
classes: require("./generators/classes"),
methods: require("./generators/methods"),
modules: require("./generators/modules"),
types: require("./generators/types"),
base: require("./generators/base"),
jsx: require("./generators/jsx")
templateLiterals: require("./generators/template-literals"),
comprehensions: require("./generators/comprehensions"),
expressions: require("./generators/expressions"),
statements: require("./generators/statements"),
classes: require("./generators/classes"),
methods: require("./generators/methods"),
modules: require("./generators/modules"),
types: require("./generators/types"),
base: require("./generators/base"),
jsx: require("./generators/jsx")
};
_.each(CodeGenerator.generators, function (generator) {
@@ -76,7 +76,6 @@ CodeGenerator.prototype.generate = function () {
return {
map: this.map.get(),
ast: ast,
code: this.buffer.get()
};
};

View File

@@ -8,7 +8,8 @@ exports.ComprehensionBlock = function (node, print) {
};
exports.ComprehensionExpression = function (node, print) {
this.push("[");
this.push(node.generator ? "(" : "[");
print.join(node.blocks, { separator: " " });
this.space();
@@ -21,5 +22,6 @@ exports.ComprehensionExpression = function (node, print) {
}
print(node.body);
this.push("]");
this.push(node.generator ? ")" : "]");
};

View File

@@ -36,6 +36,7 @@ var blacklistTest = function (transformer, code) {
};
blacklistTest("arrayComprehension", "var foo = [for (foo of bar) foo * foo];");
//blacklistTest("generatorComprehension", "");
blacklistTest("arrowFunctions", "var foo = x => x * x;");
blacklistTest("classes", "class Foo {}");
blacklistTest("computedPropertyNames", "var foo = { [foo]: bar };");

View File

@@ -0,0 +1,5 @@
(function (Constructor, args) {
var bindArgs = [null].concat(args);
var Factory = Constructor.bind.apply(Constructor, bindArgs);
return new Factory;
});

View File

@@ -31,6 +31,7 @@ _.each({
propertyNameShorthand: require("./transformers/property-name-shorthand"),
constants: require("./transformers/constants"),
arrayComprehension: require("./transformers/array-comprehension"),
generatorComprehension: require("./transformers/generator-comprehension"),
arrowFunctions: require("./transformers/arrow-functions"),
classes: require("./transformers/classes"),
@@ -46,7 +47,6 @@ _.each({
letScoping: require("./transformers/let-scoping"),
forOf: require("./transformers/for-of"),
unicodeRegex: require("./transformers/unicode-regex"),
numericLiterals: require("./transformers/numeric-literals"),
react: require("./transformers/react"),

View File

@@ -15,6 +15,7 @@ Transformer.normalise = function (transformer) {
}
_.each(transformer, function (fns, type) {
if (type[0] === "_") return;
if (_.isFunction(fns)) fns = { enter: fns };
transformer[type] = fns;
});

View File

@@ -37,39 +37,42 @@ var multiple = function (node, file) {
var returnStatement = body.pop();
var build = function () {
var self = node.blocks.shift();
if (!self) return;
var child = build();
if (!child) {
// last item
child = util.template("array-push", {
STATEMENT: node.body,
KEY: uid
}, true);
// add a filter as this is our final stop
if (node.filter) {
child = t.ifStatement(node.filter, t.blockStatement([child]));
}
}
return t.forOfStatement(
t.variableDeclaration("var", [t.variableDeclarator(self.left)]),
self.right,
t.blockStatement([child])
);
};
body.push(build());
body.push(exports._build(node, function () {
return util.template("array-push", {
STATEMENT: node.body,
KEY: uid
}, true);
}));
body.push(returnStatement);
return container;
};
exports._build = function (node, buildBody) {
var self = node.blocks.shift();
if (!self) return;
var child = exports._build(node, buildBody);
if (!child) {
// last item
child = buildBody();
// add a filter as this is our final stop
if (node.filter) {
child = t.ifStatement(node.filter, t.blockStatement([child]));
}
}
return t.forOfStatement(
t.variableDeclaration("var", [t.variableDeclarator(self.left)]),
self.right,
t.blockStatement([child])
);
};
exports.ComprehensionExpression = function (node, parent, file) {
if (node.generator) return;
if (node.blocks.length === 1 && t.isArrayExpression(node.blocks[0].right)) {
return singleArrayExpression(node);
} else {

View File

@@ -5,12 +5,12 @@ var _ = require("lodash");
exports.ClassDeclaration = function (node, parent, file, scope) {
return t.variableDeclaration("var", [
t.variableDeclarator(node.id, buildClass(node, file, scope))
t.variableDeclarator(node.id, new Class(node, file, scope).run())
]);
};
exports.ClassExpression = function (node, parent, file, scope) {
return buildClass(node, file, scope);
return new Class(node, file, scope).run();
};
var getMemberExpressionObject = function (node) {
@@ -20,31 +20,59 @@ var getMemberExpressionObject = function (node) {
return node;
};
var buildClass = function (node, file, scope) {
var superName = node.superClass;
var className = node.id || t.identifier(file.generateUid("class", scope));
/**
* Description
*
* @param {Node} node
* @param {File} file
* @param {Scope} scope
*/
var superClassArgument = node.superClass;
var superClassCallee = node.superClass;
function Class(node, file, scope) {
this.scope = scope;
this.node = node;
this.file = file;
this.instanceMutatorMap = {};
this.staticMutatorMap = {};
this.hasConstructor = false;
this.className = node.id || t.identifier(file.generateUid("class", scope));
this.superName = node.superClass;
}
/**
* Description
*
* @returns {Array}
*/
Class.prototype.run = function () {
var superClassArgument = this.superName;
var superClassCallee = this.superName;
var superName = this.superName;
var className = this.className;
var file = this.file;
if (superName) {
if (t.isMemberExpression(superName)) {
superClassArgument = superClassCallee = getMemberExpressionObject(superName);
} else if (!t.isIdentifier(superName)) {
superClassArgument = superName;
superClassCallee = superName = t.identifier(file.generateUid("ref", scope));
superClassCallee = superName = t.identifier(file.generateUid("ref", this.scope));
}
}
this.superName = superName;
var container = util.template("class", {
CLASS_NAME: className
});
var block = container.callee.expression.body;
var body = block.body;
var constructor = body[0].declarations[0].init;
var body = this.body = block.body;
var constructor = this.constructor = body[0].declarations[0].init;
if (node.id) constructor.id = className;
if (this.node.id) constructor.id = className;
var returnStatement = body.pop();
@@ -55,14 +83,7 @@ var buildClass = function (node, file, scope) {
container.callee.expression.params.push(superClassCallee);
}
buildClassBody({
file: file,
body: body,
node: node,
className: className,
superName: superName,
constructor: constructor,
});
this.buildBody();
if (body.length === 1) {
// only a constructor so no need for a closure container
@@ -73,49 +94,29 @@ var buildClass = function (node, file, scope) {
}
};
var buildClassBody = function (opts) {
var file = opts.file;
var body = opts.body;
var node = opts.node;
var constructor = opts.constructor;
var className = opts.className;
var superName = opts.superName;
/**
* Description
*/
var instanceMutatorMap = {};
var staticMutatorMap = {};
var hasConstructor = false;
var classBody = node.body.body;
Class.prototype.buildBody = function () {
var constructor = this.constructor;
var className = this.className;
var superName = this.superName;
var classBody = this.node.body.body;
var body = this.body;
var self = this;
_.each(classBody, function (node) {
var methodName = node.key;
var method = node.value;
replaceInstanceSuperReferences(superName, node);
self.replaceInstanceSuperReferences(node);
if (node.key.name === "constructor") {
if (node.kind === "") {
hasConstructor = true;
addConstructor(constructor, method);
} else {
throw file.errorWithNode(node, "illegal kind for constructor method");
}
self.pushConstructor(node);
} else {
var mutatorMap = instanceMutatorMap;
if (node.static) mutatorMap = staticMutatorMap;
var kind = node.kind;
if (kind === "") {
kind = "value";
util.pushMutatorMap(mutatorMap, methodName, "writable", t.identifier("true"));
}
util.pushMutatorMap(mutatorMap, methodName, kind, node);
self.pushMethod(node);
}
});
if (!hasConstructor && superName) {
if (!this.hasConstructor && superName) {
constructor.body.body.push(util.template("class-super-constructor-call", {
SUPER_NAME: superName
}, true));
@@ -124,16 +125,16 @@ var buildClassBody = function (opts) {
var instanceProps;
var staticProps;
if (!_.isEmpty(instanceMutatorMap)) {
if (!_.isEmpty(this.instanceMutatorMap)) {
var protoId = util.template("prototype-identifier", {
CLASS_NAME: className
});
instanceProps = util.buildDefineProperties(instanceMutatorMap, protoId);
instanceProps = util.buildDefineProperties(this.instanceMutatorMap, protoId);
}
if (!_.isEmpty(staticMutatorMap)) {
staticProps = util.buildDefineProperties(staticMutatorMap, className);
if (!_.isEmpty(this.staticMutatorMap)) {
staticProps = util.buildDefineProperties(this.staticMutatorMap, className);
}
if (instanceProps || staticProps) {
@@ -143,17 +144,50 @@ var buildClassBody = function (opts) {
if (instanceProps) args.push(instanceProps);
body.push(t.expressionStatement(
t.callExpression(file.addDeclaration("class-props"), args)
t.callExpression(this.file.addDeclaration("class-props"), args)
));
}
};
var superIdentifier = function (superName, methodNode, node, parent) {
var methodName = methodNode.key;
/**
* Push a method to it's respective mutatorMap.
*
* @param {Node} node MethodDefinition
*/
if (parent.property === node) {
Class.prototype.pushMethod = function (node) {
var methodName = node.key;
var mutatorMap = this.instanceMutatorMap;
if (node.static) mutatorMap = this.staticMutatorMap;
var kind = node.kind;
if (kind === "") {
kind = "value";
util.pushMutatorMap(mutatorMap, methodName, "writable", t.identifier("true"));
}
util.pushMutatorMap(mutatorMap, methodName, kind, node);
};
/**
* Given a `methodNode`, produce a `MemberExpression` super class reference.
*
* @param {Node} methodNode MethodDefinition
* @param {Node} node Identifier
* @param {Node} parent
*
* @returns {Node}
*/
Class.prototype.superIdentifier = function (methodNode, id, parent) {
var methodName = methodNode.key;
var superName = this.superName || t.identifier("Function");
if (parent.property === id) {
return;
} else if (t.isCallExpression(parent, { callee: node })) {
} else if (t.isCallExpression(parent, { callee: id })) {
// super(); -> ClassName.prototype.MethodName.call(this);
parent.arguments.unshift(t.thisExpression());
@@ -161,15 +195,15 @@ var superIdentifier = function (superName, methodNode, node, parent) {
// constructor() { super(); }
return t.memberExpression(superName, t.identifier("call"));
} else {
node = superName;
id = superName;
// foo() { super(); }
if (!methodNode.static) {
node = t.memberExpression(node, t.identifier("prototype"));
id = t.memberExpression(id, t.identifier("prototype"));
}
node = t.memberExpression(node, methodName, methodNode.computed);
return t.memberExpression(node, t.identifier("call"));
id = t.memberExpression(id, methodName, methodNode.computed);
return t.memberExpression(id, t.identifier("call"));
}
} else if (t.isMemberExpression(parent) && !methodNode.static) {
// super.test -> ClassName.prototype.test
@@ -179,31 +213,50 @@ var superIdentifier = function (superName, methodNode, node, parent) {
}
};
var replaceInstanceSuperReferences = function (superName, methodNode) {
var method = methodNode.value;
/**
* Replace all `super` references with a reference to our `superClass`.
*
* @param {Node} methodNode MethodDefinition
*/
superName = superName || t.identifier("Function");
Class.prototype.replaceInstanceSuperReferences = function (methodNode) {
var method = methodNode.value;
var self = this;
traverse(method, function (node, parent) {
if (t.isIdentifier(node, { name: "super" })) {
return superIdentifier(superName, methodNode, node, parent);
return self.superIdentifier(methodNode, node, parent);
} else if (t.isCallExpression(node)) {
var callee = node.callee;
if (!t.isMemberExpression(callee)) return;
if (callee.object.name !== "super") return;
// super.test(); -> ClassName.prototype.MethodName.call(this);
callee.property.name = callee.property.name + ".call";
// super.test(); -> ClassName.prototype.MethodName.call(this);
callee.property = t.memberExpression(callee.property, t.identifier("call"));
node.arguments.unshift(t.thisExpression());
}
});
};
var addConstructor = function (construct, method) {
construct.defaults = method.defaults;
construct.params = method.params;
construct.body = method.body;
construct.rest = method.rest;
/**
* Replace the constructor body of our class.
*
* @param {Node} method MethodDefinition
*/
t.inherits(construct, method);
Class.prototype.pushConstructor = function (method) {
if (method.kind !== "") {
throw this.file.errorWithNode(method, "illegal kind for constructor method");
}
var construct = this.constructor;
var fn = method.value;
this.hasConstructor = true;
t.inherits(construct, fn);
construct.defaults = fn.defaults;
construct.params = fn.params;
construct.body = fn.body;
construct.rest = fn.rest;
};

View File

@@ -3,7 +3,7 @@ var t = require("../../types");
var _ = require("lodash");
exports.Function = function (node) {
if (!node.defaults.length) return;
if (!node.defaults || !node.defaults.length) return;
t.ensureBlock(node);
_.each(node.defaults, function (def, i) {

View File

@@ -0,0 +1,15 @@
var arrayComprehension = require("./array-comprehension");
var t = require("../../types");
exports.ComprehensionExpression = function (node) {
if (!node.generator) return;
var body = [];
var container = t.functionExpression(null, [], t.blockStatement(body), true);
body.push(arrayComprehension._build(node, function () {
return t.expressionStatement(t.yieldExpression(node.body));
}));
return t.callExpression(container, []);
};

View File

@@ -17,6 +17,12 @@ var isVar = function (node) {
return t.isVariableDeclaration(node, { kind: "var" }) && !isLet(node);
};
var standardiseLets = function (declars) {
_.each(declars, function (declar) {
delete declar._let;
});
};
exports.VariableDeclaration = function (node) {
isLet(node);
};
@@ -33,7 +39,8 @@ exports.For = function (node, parent, file, scope) {
node.label = parent.label;
}
run(node, node.body, parent, file, scope);
var letScoping = new LetScoping(node, node.body, parent, file, scope);
letScoping.run();
if (node.label && !t.isLabeledStatement(parent)) {
// we've been given a label so let's wrap ourselves
@@ -43,12 +50,98 @@ exports.For = function (node, parent, file, scope) {
exports.BlockStatement = function (block, parent, file, scope) {
if (!t.isFor(parent)) {
run(false, block, parent, file, scope);
var letScoping = new LetScoping(false, block, parent, file, scope);
letScoping.run();
}
};
var noClosure = function (letDeclars, block, replacements) {
standardiseLets(letDeclars);
/**
* Description
*
* @param {Boolean|Node} forParent
* @param {Node} block
* @param {Node} parent
* @param {File} file
* @param {Scope} scope
*/
function LetScoping(forParent, block, parent, file, scope) {
this.forParent = forParent;
this.parent = parent;
this.scope = scope;
this.block = block;
this.file = file;
this.letReferences = {};
this.body = [];
this.info = this.getInfo();
}
/**
* Start the ball rolling.
*/
LetScoping.prototype.run = function () {
var block = this.block;
if (block._letDone) return;
block._letDone = true;
// this is a block within a `Function` so we can safely leave it be
if (t.isFunction(this.parent)) return;
// this block has no let references so let's clean up
if (!this.info.keys.length) return this.noClosure();
// returns whether or not there are any outside let references within any
// functions
var referencesInClosure = this.getLetReferences();
// no need for a closure so let's clean up
if (!referencesInClosure) return this.noClosure();
// if we're inside of a for loop then we search to see if there are any
// `break`s, `continue`s, `return`s etc
this.has = this.checkFor();
// hoist var references to retain scope
this.hoistVarDeclarations();
// set let references to plain var references
standardiseLets(this.info.declarators);
// turn letReferences into an array
var letReferences = _.values(this.letReferences);
// build the closure that we're going to wrap the block with
var fn = t.functionExpression(null, letReferences, t.blockStatement(block.body));
fn._aliasFunction = true;
// replace the current block body with the one we're going to build
block.body = this.body;
// change upper scope references with their uid if they have one
var params = this.getParams(letReferences);
// build a call and a unique id that we can assign the return value to
var call = t.callExpression(fn, params);
var ret = t.identifier(this.file.generateUid("ret", this.scope));
this.build(ret, call);
};
/**
* There are no let references accessed within a closure so we can just traverse
* through this block and replace all references that exist in a high scope to
* their uids.
*/
LetScoping.prototype.noClosure = function () {
var replacements = this.info.duplicates;
var declarators = this.info.declarators;
var block = this.block;
standardiseLets(declarators);
if (_.isEmpty(replacements)) return;
@@ -59,13 +152,17 @@ var noClosure = function (letDeclars, block, replacements) {
});
};
var standardiseLets = function (declars) {
_.each(declars, function (declar) {
delete declar._let;
});
};
/**
* Description
*
* @returns {Object}
*/
LetScoping.prototype.getInfo = function () {
var block = this.block;
var scope = this.scope;
var file = this.file;
var getInfo = function (block, file, scope) {
var opts = {
// array of `Identifier` names of let variables that appear lexically out of
// this scope but should be accessible - eg. `ForOfStatement`.left
@@ -111,15 +208,23 @@ var getInfo = function (block, file, scope) {
return opts;
};
var checkFor = function (forParent, block) {
/**
* If we're inside of a `For*Statement` then traverse it and check if it has one
* of the following node types `ReturnStatement`, `BreakStatement`,
* `ContinueStatement` and replace it with a return value we can track later on.
*
* @returns {Object}
*/
LetScoping.prototype.checkFor = function () {
var has = {
hasContinue: false,
hasReturn: false,
hasBreak: false,
};
if (forParent) {
traverse(block, function (node) {
if (this.forParent) {
traverse(this.block, function (node) {
var replace;
if (t.isFunction(node) || t.isFor(node)) {
@@ -144,38 +249,59 @@ var checkFor = function (forParent, block) {
return has;
};
var hoistVarDeclarations = function (block, pushDeclar) {
traverse(block, function (node) {
/**
* Hoist all var declarations in this block to before it so they retain scope
* once we wrap everything is in a closure.
*/
LetScoping.prototype.hoistVarDeclarations = function () {
var self = this;
traverse(this.block, function (node) {
if (t.isForStatement(node)) {
if (isVar(node.init)) {
node.init = t.sequenceExpression(pushDeclar(node.init));
node.init = t.sequenceExpression(self.pushDeclar(node.init));
}
} else if (t.isFor(node)) {
if (isVar(node.left)) {
node.left = node.left.declarations[0].id;
}
} else if (isVar(node)) {
return pushDeclar(node).map(t.expressionStatement);
return self.pushDeclar(node).map(t.expressionStatement);
} else if (t.isFunction(node)) {
return false;
}
});
};
var getParams = function (info, letReferences) {
var params = _.cloneDeep(letReferences);
/**
* Build up a parameter list that we'll call our closure wrapper with, replacing
* all duplicate ids with their uid.
*
* @param {Array} params
* @returns {Array}
*/
LetScoping.prototype.getParams = function (params) {
var info = this.info;
params = _.cloneDeep(params);
_.each(params, function (param) {
param.name = info.duplicates[param.name] || param.name;
});
return params;
};
var getLetReferences = function (block, info, letReferences) {
/**
* Get all let references within this block. Stopping whenever we reach another
* block.
*/
LetScoping.prototype.getLetReferences = function () {
var closurify = false;
var self = this;
// traverse through this block, stopping on functions and checking if they
// contain any outside let references
traverse(block, function (node, parent, scope) {
traverse(this.block, function (node, parent, scope) {
if (t.isFunction(node)) {
traverse(node, function (node, parent) {
// not an identifier so we have no use
@@ -191,10 +317,10 @@ var getLetReferences = function (block, info, letReferences) {
closurify = true;
// this key doesn't appear just outside our scope
if (!_.contains(info.outsideKeys, node.name)) return;
if (!_.contains(self.info.outsideKeys, node.name)) return;
// push this badboy
letReferences[node.name] = node;
self.letReferences[node.name] = node;
});
return false;
@@ -206,125 +332,100 @@ var getLetReferences = function (block, info, letReferences) {
return closurify;
};
var buildPushDeclar = function (body) {
return function (node) {
body.push(t.variableDeclaration(node.kind, node.declarations.map(function (declar) {
return t.variableDeclarator(declar.id);
})));
/**
* Turn a `VariableDeclaration` into an array of `AssignmentExpressions` with
* their declarations hoisted to before the closure wrapper.
*
* @param {Node} node VariableDeclaration
* @returns {Array}
*/
var replace = [];
LetScoping.prototype.buildPushDeclar = function (node) {
this.body.push(t.variableDeclaration(node.kind, node.declarations.map(function (declar) {
return t.variableDeclarator(declar.id);
})));
_.each(node.declarations, function (declar) {
if (!declar.init) return;
var replace = [];
var expr = t.assignmentExpression("=", declar.id, declar.init);
replace.push(t.inherits(expr, declar));
});
_.each(node.declarations, function (declar) {
if (!declar.init) return;
return replace;
};
var expr = t.assignmentExpression("=", declar.id, declar.init);
replace.push(t.inherits(expr, declar));
});
return replace;
};
var run = function (forParent, block, parent, file, scope) {
if (block._letDone) return;
block._letDone = true;
var info = getInfo(block, file, scope);
var declarators = info.declarators;
var letKeys = info.keys;
// this is a block within a `Function` so we can safely leave it be
if (t.isFunction(parent)) return;
// this block has no let references so let's clean up
if (!letKeys.length) return noClosure(declarators, block, info.duplicates);
// outside let references that we need to wrap
var letReferences = {};
// returns whether or not there are any outside let references within any
// functions
var closurify = getLetReferences(block, info, letReferences);
letReferences = _.values(letReferences);
// no need for a closure so let's clean up
if (!closurify) return noClosure(declarators, block, info.duplicates);
// if we're inside of a for loop then we search to see if there are any
// `break`s, `continue`s, `return`s etc
var has = checkFor(forParent, block);
var body = [];
// hoist a `VariableDeclaration` and add `AssignmentExpression`s in it's place
var pushDeclar = buildPushDeclar(body);
// hoist var references to retain scope
hoistVarDeclarations(block, pushDeclar);
// set let references to plain var references
standardiseLets(declarators);
// build the closure that we're going to wrap the block with
var fn = t.functionExpression(null, letReferences, t.blockStatement(block.body));
fn._aliasFunction = true;
// replace the current block body with the one we've built
block.body = body;
// change duplicate let references to their uid if they have one
var params = getParams(info, letReferences);
var call = t.callExpression(fn, params);
var ret = t.identifier(file.generateUid("ret", scope));
/**
* Push the closure to the body.
*
* @param {Node} ret Identifier
* @param {Node} call CallExpression
*/
LetScoping.prototype.build = function (ret, call) {
var has = this.has;
if (has.hasReturn || has.hasBreak || has.hasContinue) {
body.push(t.variableDeclaration("var", [
t.variableDeclarator(ret, call)
]));
var retCheck;
var cases = [];
if (has.hasReturn) {
// typeof ret === "object"
retCheck = util.template("let-scoping-return", {
RETURN: ret,
});
}
if (has.hasBreak || has.hasContinue) {
// ensure that the parent has a label as we're building a switch and we
// need to be able to access it
var label = forParent.label = forParent.label || t.identifier(file.generateUid("loop", scope));
if (has.hasBreak) {
cases.push(t.switchCase(t.literal("break"), [t.breakStatement(label)]));
}
if (has.hasContinue) {
cases.push(t.switchCase(t.literal("continue"), [t.continueStatement(label)]));
}
if (has.hasReturn) {
cases.push(t.switchCase(null, [retCheck]));
}
if (cases.length === 1) {
var single = cases[0];
body.push(t.ifStatement(
t.binaryExpression("===", ret, single.test),
single.consequent[0]
));
} else {
body.push(t.switchStatement(ret, cases));
}
} else {
if (has.hasReturn) body.push(retCheck);
}
this.buildHas(ret, call);
} else {
body.push(t.expressionStatement(call));
this.body.push(t.expressionStatement(call));
}
};
/**
* Description
*
* @param {Node} ret Identifier
* @param {Node} call CallExpression
*/
LetScoping.prototype.buildHas = function (ret, call) {
var body = this.body;
body.push(t.variableDeclaration("var", [
t.variableDeclarator(ret, call)
]));
var forParent = this.forParent;
var retCheck;
var has = this.has;
var cases = [];
if (has.hasReturn) {
// typeof ret === "object"
retCheck = util.template("let-scoping-return", {
RETURN: ret
});
}
if (has.hasBreak || has.hasContinue) {
// ensure that the parent has a label as we're building a switch and we
// need to be able to access it
var label = forParent.label = forParent.label || t.identifier(this.file.generateUid("loop", this.scope));
if (has.hasBreak) {
cases.push(t.switchCase(t.literal("break"), [t.breakStatement(label)]));
}
if (has.hasContinue) {
cases.push(t.switchCase(t.literal("continue"), [t.continueStatement(label)]));
}
if (has.hasReturn) {
cases.push(t.switchCase(null, [retCheck]));
}
if (cases.length === 1) {
var single = cases[0];
body.push(t.ifStatement(
t.binaryExpression("===", ret, single.test),
single.consequent[0]
));
} else {
body.push(t.switchStatement(ret, cases));
}
} else {
if (has.hasReturn) body.push(retCheck);
}
};

View File

@@ -1,6 +0,0 @@
var _ = require("lodash");
exports.Literal = function (node) {
// TODO: remove this when the new code generator is released
if (_.isNumber(node.value)) delete node.raw;
};

View File

@@ -57,15 +57,39 @@ exports.XJSOpeningElement = {
var props = node.attributes;
if (props.length) {
var first = props[0];
if (t.isXJSSpreadAttribute(first)) {
props.shift();
var _props = [];
var objs = [];
var pushProps = function () {
if (!_props.length) return;
objs.push(t.objectExpression(_props));
_props = [];
};
while (props.length) {
var prop = props.shift();
if (t.isXJSSpreadAttribute(prop)) {
pushProps();
objs.push(prop.argument);
} else {
_props.push(prop);
}
}
pushProps();
if (objs.length === 1) {
props = objs[0];
} else {
if (!t.isObjectExpression(objs[0])) {
objs.unshift(t.objectExpression([]));
}
props = t.callExpression(
t.memberExpression(t.identifier("React"), t.identifier("__spread")),
[t.objectExpression([]), first.argument, t.objectExpression(props)]
objs
);
} else {
props = t.objectExpression(props);
}
} else {
props = t.literal(null);

View File

@@ -1,14 +1,13 @@
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
var t = require("../../types");
var _ = require("lodash");
var getSpreadLiteral = function (spread, file) {
var getSpreadLiteral = function (spread) {
var literal = spread.argument;
if (!t.isArrayExpression(literal)) {
literal = util.template("call", {
OBJECT: file.addDeclaration("slice"),
CONTEXT: literal
});
literal = t.callExpression(
t.memberExpression(t.identifier("Array"), t.identifier("from")),
[literal]
);
}
return literal;
};
@@ -24,7 +23,7 @@ var hasSpread = function (nodes) {
return has;
};
var build = function (props, file) {
var build = function (props) {
var nodes = [];
var _props = [];
@@ -38,7 +37,7 @@ var build = function (props, file) {
_.each(props, function (prop) {
if (t.isSpreadElement(prop)) {
push();
nodes.push(getSpreadLiteral(prop, file));
nodes.push(getSpreadLiteral(prop));
} else {
_props.push(prop);
}
@@ -49,11 +48,11 @@ var build = function (props, file) {
return nodes;
};
exports.ArrayExpression = function (node, parent, file) {
exports.ArrayExpression = function (node) {
var elements = node.elements;
if (!hasSpread(elements)) return;
var nodes = build(elements, file);
var nodes = build(elements);
var first = nodes.shift();
if (!nodes.length) return first;
@@ -61,7 +60,7 @@ exports.ArrayExpression = function (node, parent, file) {
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
};
exports.CallExpression = function (node, parent, file) {
exports.CallExpression = function (node) {
var args = node.arguments;
if (!hasSpread(args)) return;
@@ -69,7 +68,7 @@ exports.CallExpression = function (node, parent, file) {
node.arguments = [];
var nodes = build(args, file);
var nodes = build(args);
var first = nodes.shift();
if (nodes.length) {
@@ -96,3 +95,19 @@ exports.CallExpression = function (node, parent, file) {
node.arguments.unshift(contextLiteral);
};
exports.NewExpression = function (node, parent, file) {
var args = node.arguments;
if (!hasSpread(args)) return;
var nodes = build(args);
var first = nodes.shift();
if (nodes.length) {
args = t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
} else {
args = first;
}
return t.callExpression(file.addDeclaration("apply-constructor"), [node.callee, args]);
};

View File

@@ -7,11 +7,12 @@
"ConditionalExpression": ["test", "consequent", "alternate"],
"ExpressionStatement": ["expression"],
"File": ["program", "comments", "tokens"],
"FunctionExpression": ["id", "params", "body"],
"FunctionExpression": ["id", "params", "body", "generator"],
"Identifier": ["name"],
"IfStatement": ["test", "consequent", "alternate"],
"Literal": ["value"],
"MemberExpression": ["object", "property", "computed"],
"NewExpression": ["callee", "arguments"],
"ObjectExpression": ["properties"],
"ParenthesizedExpression": ["expression"],
"Program": ["body"],

View File

@@ -25,6 +25,10 @@ exports.resolve = function (loc) {
}
};
exports.trimRight = function (str) {
return str.replace(/[\n\s]+$/g, "");
};
exports.list = function (val) {
return val ? val.split(",") : [];
};
@@ -240,7 +244,7 @@ exports.parse = function (opts, code, callback) {
}
};
exports.parseNoProperties = function (loc, code) {
exports.parseTemplate = function (loc, code) {
var ast = exports.parse({ filename: loc }, code).program;
return traverse.removeProperties(ast);
};
@@ -262,7 +266,7 @@ var loadTemplates = function () {
var loc = templatesLoc + "/" + name;
var code = fs.readFileSync(loc, "utf8");
templates[key] = exports.parseNoProperties(loc, code);
templates[key] = exports.parseTemplate(loc, code);
});
return templates;

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.12.1",
"version": "1.12.3",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/6to5/6to5",
"repository": {
@@ -44,7 +44,7 @@
"es6-symbol": "0.1.1",
"regexpu": "0.3.0",
"source-map": "0.1.40",
"regenerator-6to5": "https://github.com/6to5/regenerator-6to5/archive/62d1bfcb331dcf0bbcdbbee8043da0c6408f09cf.tar.gz",
"regenerator-6to5": "https://github.com/6to5/regenerator-6to5/archive/75925940a7bb67d1ee8afec36b6d6eec072fb47c.tar.gz",
"chokidar": "0.10.5",
"source-map-support": "0.2.8",
"esutils": "1.1.4",
@@ -53,10 +53,10 @@
},
"devDependencies": {
"istanbul": "0.3.2",
"matcha": "0.5.0",
"matcha": "0.6.0",
"mocha": "2.0.1",
"uglify-js": "2.4.15",
"browserify": "6.2.0",
"browserify": "6.3.2",
"rimraf": "2.2.8",
"jshint": "2.5.10",
"chai": "^1.9.2"

View File

@@ -1,6 +1,5 @@
"use strict";
var _slice = Array.prototype.slice;
var _classProps = function (child, staticProps, instanceProps) {
if (staticProps) Object.defineProperties(child, staticProps);
@@ -26,11 +25,11 @@ var Test = (function (Foo) {
Foo.prototype.test.call(this);
foob(Foo);
Foo.call.apply(Foo, [this].concat(_slice.call(arguments)));
Foo.call.apply(Foo, [this, "test"].concat(_slice.call(arguments)));
Foo.call.apply(Foo, [this].concat(Array.from(arguments)));
Foo.call.apply(Foo, [this, "test"].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this].concat(_slice.call(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this, "test"].concat(_slice.call(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype, [this, "test"].concat(Array.from(arguments)));
};
_extends(Test, Foo);
@@ -40,8 +39,8 @@ var Test = (function (Foo) {
writable: true,
value: function () {
Foo.foo.call(this);
Foo.foo.call.apply(Foo.foo, [this].concat(_slice.call(arguments)));
Foo.foo.call.apply(Foo.foo, [this, "test"].concat(_slice.call(arguments)));
Foo.foo.call.apply(Foo.foo, [this].concat(Array.from(arguments)));
Foo.foo.call.apply(Foo.foo, [this, "test"].concat(Array.from(arguments)));
}
}
}, {
@@ -49,8 +48,8 @@ var Test = (function (Foo) {
writable: true,
value: function () {
Foo.prototype.test.call(this);
Foo.prototype.test.call.apply(Foo.prototype.test, [this].concat(_slice.call(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this, "test"].concat(_slice.call(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this].concat(Array.from(arguments)));
Foo.prototype.test.call.apply(Foo.prototype.test, [this, "test"].concat(Array.from(arguments)));
}
}
});

View File

@@ -0,0 +1,6 @@
var nums = [1, 2, 3, 4, 5, 6];
var multiples = (for (i of nums) if (i % 2) i * i);
assert.equal(multiples.next().value, 1);
assert.equal(multiples.next().value, 9);
assert.equal(multiples.next().value, 25);
assert.ok(multiples.next().done);

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,4 +3,4 @@
var _slice = Array.prototype.slice;
var concat = function () {
var arrs = _slice.call(arguments);
};
};

View File

@@ -7,4 +7,4 @@ var t = function (f) {
function t(f) {
var items = _slice.call(arguments, 1);
}
}

View File

@@ -7,4 +7,4 @@ var t = function () {
function t() {
var items = _slice.call(arguments);
}
}

View File

@@ -1,12 +1,11 @@
"use strict";
var _slice = Array.prototype.slice;
function foo() {
return bar.apply(null, ["test"].concat(_slice.call(arguments)));
return bar.apply(null, ["test"].concat(Array.from(arguments)));
}
function bar(one, two, three) {
return [one, two, three];
}
foo("foo", "bar");
foo("foo", "bar");

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
var lyrics = _slice.call(parts).concat(["head", "and", "toes"]);
var lyrics = Array.from(parts).concat(["head", "and", "toes"]);

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
var a = [b].concat(_slice.call(c), [d]);
var a = [b].concat(Array.from(c), [d]);

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
var a = [b].concat(_slice.call(c), [d, e], _slice.call(f));
var a = [b].concat(Array.from(c), [d, e], Array.from(f));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
var lyrics = ["head", "and", "toes"].concat(_slice.call(parts));
var lyrics = ["head", "and", "toes"].concat(Array.from(parts));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
obj[method].apply(obj, [foo, bar].concat(_slice.call(args)));
obj[method].apply(obj, [foo, bar].concat(Array.from(args)));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
obj[method].apply(obj, _slice.call(args));
obj[method].apply(obj, Array.from(args));

View File

@@ -1,5 +1,4 @@
"use strict";
var _slice = Array.prototype.slice;
foob.add.apply(foob, [foo, bar].concat(_slice.call(numbers)));
foob.test.add.apply(foob.test, [foo, bar].concat(_slice.call(numbers)));
foob.add.apply(foob, [foo, bar].concat(Array.from(numbers)));
foob.test.add.apply(foob.test, [foo, bar].concat(Array.from(numbers)));

View File

@@ -1,5 +1,4 @@
"use strict";
var _slice = Array.prototype.slice;
foob.add.apply(foob, _slice.call(numbers));
foob.test.add.apply(foob.test, _slice.call(numbers));
foob.add.apply(foob, Array.from(numbers));
foob.test.add.apply(foob.test, Array.from(numbers));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
add.apply(null, _slice.call(numbers).concat([foo, bar]));
add.apply(null, Array.from(numbers).concat([foo, bar]));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
add.apply(null, [foo].concat(_slice.call(numbers), [bar]));
add.apply(null, [foo].concat(Array.from(numbers), [bar]));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
add.apply(null, [foo, bar].concat(_slice.call(numbers)));
add.apply(null, [foo, bar].concat(Array.from(numbers)));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
add.apply(null, [foo].concat(_slice.call(numbers), [bar, what], _slice.call(test)));
add.apply(null, [foo].concat(Array.from(numbers), [bar, what], Array.from(test)));

View File

@@ -1,4 +1,3 @@
"use strict";
var _slice = Array.prototype.slice;
add.apply(null, _slice.call(numbers));
add.apply(null, Array.from(numbers));

View File

@@ -0,0 +1,2 @@
new Numbers(...nums);
new Numbers(1, ...nums);

View File

@@ -0,0 +1,12 @@
"use strict";
var _applyConstructor = function (Constructor, args) {
var bindArgs = [null].concat(args);
var Factory = Constructor.bind.apply(Constructor, bindArgs);
return new Factory();
};
_applyConstructor(Numbers, Array.from(nums));
_applyConstructor(Numbers, [1].concat(Array.from(nums)));