Compare commits

...

14 Commits

Author SHA1 Message Date
Sebastian McKenzie
9ff4df6dae v1.12.16 2014-11-16 14:39:15 +11:00
Sebastian McKenzie
0dbb24c922 remove unused i variable in default parameters transformer 2014-11-16 14:37:26 +11:00
Sebastian McKenzie
a027d2b9cf add 1.12.16 changelog 2014-11-16 14:34:42 +11:00
Sebastian McKenzie
e290990371 scope: remove unused references instance property 2014-11-16 14:34:29 +11:00
Sebastian McKenzie
d0a2bd170e clean up constants transformer 2014-11-16 14:33:37 +11:00
Sebastian McKenzie
69db46f96b move down and clump constants and let scoping transformer positions 2014-11-16 14:33:29 +11:00
Sebastian McKenzie
27ba4b2bba scope: switch over declaration building to info so we can build multiple things 2014-11-16 14:33:16 +11:00
Sebastian McKenzie
b337c1ab06 test/transformation: use full location as filename 2014-11-16 14:32:40 +11:00
Sebastian McKenzie
a1895b4bb4 implement temporal dead zone for default parameters - fixes #169 2014-11-16 14:32:03 +11:00
Sebastian McKenzie
00483917f0 fix comments not being retained from MethodDefinition in classes 2014-11-16 11:30:05 +11:00
Sebastian McKenzie
d09bafaf8c Merge pull request #172 from thejameskyle/docs-whitespace
Add newline to keep marked from parsing incorrectly
2014-11-16 10:32:04 +11:00
James Kyle
a7ef02c781 Add newline to keep marked from parsing incorrectly 2014-11-15 15:31:16 -08:00
Sebastian McKenzie
94cd45c269 v1.12.15 2014-11-15 11:42:06 +11:00
Sebastian McKenzie
424bab97d0 update acorn-6to5 - fixes #165 2014-11-15 11:40:34 +11:00
18 changed files with 164 additions and 61 deletions

View File

@@ -1,3 +1,12 @@
# 1.12.16
* Fix comments not being retained from `MethodDefinition` in classes.
* Add temporal dead zone in default parameters.
# 1.12.15
* Update `acorn-6to5`.
# 1.12.14
* Fix duplicate let scoping in functions.

View File

@@ -133,11 +133,13 @@ for (var i of [1, 2, 3]) {
## Generators
```javascript
```
## Generator comprehension
```javascript
```
## Let scoping
@@ -151,6 +153,7 @@ for (let i in arr) {
## Modules
```javascript
```
## Numeric literals

View File

@@ -29,7 +29,6 @@ transform.moduleFormatters = {
_.each({
modules: require("./transformers/modules"),
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"),
@@ -45,9 +44,11 @@ _.each({
restParameters: require("./transformers/rest-parameters"),
destructuring: require("./transformers/destructuring"),
forOf: require("./transformers/for-of"),
letScoping: require("./transformers/let-scoping"),
unicodeRegex: require("./transformers/unicode-regex"),
constants: require("./transformers/constants"),
letScoping: require("./transformers/let-scoping"),
react: require("./transformers/react"),
_aliasFunctions: require("./transformers/_alias-functions"),

View File

@@ -254,6 +254,7 @@ Class.prototype.pushConstructor = function (method) {
this.hasConstructor = true;
t.inherits(construct, fn);
t.inheritsComments(construct, method);
construct.defaults = fn.defaults;
construct.params = fn.params;

View File

@@ -9,24 +9,27 @@ exports.ForOfStatement =
exports.ForStatement = function (node, parent, file) {
var constants = {};
var check = function (node, names, parent) {
_.each(names, function (name) {
var check = function (parent, names) {
_.each(names, function (nameNode, name) {
if (!_.has(constants, name)) return;
if (parent && t.isBlockStatement(parent) && parent !== constants[name]) return;
throw file.errorWithNode(node, name + " is read-only");
throw file.errorWithNode(nameNode, name + " is read-only");
});
};
var getIds = function (node) {
return t.getIds(node, false, ["MemberExpression"]);
return t.getIds(node, true, ["MemberExpression"]);
};
_.each(node.body, function (child, parent) {
if (child && t.isVariableDeclaration(child, { kind: "const" })) {
_.each(child.declarations, function (declar) {
_.each(getIds(declar), function (name) {
check(declar, [name], parent);
_.each(getIds(declar), function (nameNode, name) {
var names = {};
names[name] = nameNode;
check(parent, names);
constants[name] = parent;
});
@@ -42,9 +45,10 @@ exports.ForStatement = function (node, parent, file) {
traverse(node, function (child, parent) {
if (child._ignoreConstant) return;
if (t.isVariableDeclaration(child)) return;
if (t.isDeclaration(child) || t.isAssignmentExpression(child)) {
check(child, getIds(child), parent);
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
check(parent, getIds(child));
}
});
};

View File

@@ -1,21 +1,70 @@
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
var traverse = require("../../traverse");
var util = require("../../util");
var t = require("../../types");
var _ = require("lodash");
exports.Function = function (node) {
exports.Function = function (node, parent, file, scope) {
if (!node.defaults || !node.defaults.length) return;
t.ensureBlock(node);
var ids = node.params.map(function (param) {
return t.getIds(param);
});
var closure = false;
_.each(node.defaults, function (def, i) {
if (!def) return;
var param = node.params[i];
node.body.body.unshift(util.template("if-undefined-set-to", {
VARIABLE: param,
DEFAULT: def
// temporal dead zone check - here we prevent accessing of params that
// are to the right - ie. uninitialized parameters
_.each(ids.slice(i), function (ids) {
var check = function (node, parent) {
if (!t.isIdentifier(node) || !t.isReferenced(node, parent)) return;
if (_.contains(ids, node.name)) {
throw file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
}
if (scope.has(node.name)) {
closure = true;
}
};
check(def, node);
traverse(def, check);
});
// we're accessing a variable that's already defined within this function
var has = scope.get(param.name);
if (has && !_.contains(node.params, has)) {
closure = true;
}
});
var body = [];
_.each(node.defaults, function (def, i) {
if (!def) return;
body.push(util.template("if-undefined-set-to", {
VARIABLE: node.params[i],
DEFAULT: def
}, true));
});
if (closure) {
var container = t.functionExpression(null, [], node.body, node.generator);
container._aliasFunction = true;
body.push(t.returnStatement(t.callExpression(container, [])));
node.body = t.blockStatement(body);
} else {
node.body.body = body.concat(node.body.body);
}
node.defaults = [];
};

View File

@@ -9,24 +9,30 @@ var FOR_KEYS = ["left", "init"];
function Scope(parent, block) {
this.parent = parent;
this.block = block;
this.ids = this.getIds();
this.getIds();
this.info = this.getInfo();
this.declarations = this.info.declarations;
}
Scope.prototype.getIds = function () {
Scope.prototype.getInfo = function () {
var block = this.block;
if (block._scopeIds) return block._scopeIds;
if (block._scope) return block._scope;
var self = this;
var ids = block._scopeIds = {};
var info = block._scope = {
declarations: {}
};
var add = function (node) {
self.addDeclaration(node, info.declarations);
};
// ForStatement - left, init
if (t.isFor(block)) {
_.each(FOR_KEYS, function (key) {
var node = block[key];
if (t.isLet(node)) self.add(node, ids);
if (t.isLet(node)) add(node);
});
block = block.body;
@@ -37,14 +43,14 @@ Scope.prototype.getIds = function () {
if (t.isBlockStatement(block) || t.isProgram(block)) {
_.each(block.body, function (node) {
// check for non-var `VariableDeclaration`s
if (t.isLet(node)) self.add(node, ids);
if (t.isLet(node)) add(node);
});
}
// CatchClause - param
if (t.isCatchClause(block)) {
self.add(block.param, ids);
add(block.param);
}
// Program, Function - var variables
@@ -54,7 +60,7 @@ Scope.prototype.getIds = function () {
if (t.isFor(node)) {
_.each(FOR_KEYS, function (key) {
var declar = node[key];
if (t.isVar(declar)) self.add(declar, ids);
if (t.isVar(declar)) add(declar);
});
}
@@ -65,26 +71,26 @@ Scope.prototype.getIds = function () {
// we've ran into a declaration!
// we'll let the BlockStatement scope deal with `let` declarations
if (t.isDeclaration(node) && !t.isLet(node)) {
self.add(node, ids);
add(node);
}
});
}
// Function - params
// Function - params, rest
if (t.isFunction(block)) {
this.add(block.rest, ids);
add(block.rest);
_.each(block.params, function (param) {
self.add(param, ids);
add(param);
});
}
return ids;
return info;
};
Scope.prototype.add = function (node, ids) {
Scope.prototype.addDeclaration = function (node, declarations) {
if (!node) return;
_.merge(ids || this.ids, t.getIds(node, true));
_.merge(declarations || this.declarations, t.getIds(node, true));
};
Scope.prototype.get = function (id) {
@@ -92,7 +98,7 @@ Scope.prototype.get = function (id) {
};
Scope.prototype.getOwn = function (id) {
return _.has(this.ids, id) && this.ids[id];
return _.has(this.declarations, id) && this.declarations[id];
};
Scope.prototype.parentGet = function (id) {

View File

@@ -70,6 +70,9 @@ t.isReferenced = function (node, parent) {
// we're a property key so we aren't referenced
if (t.isProperty(parent) && parent.key === node) return false;
// we're a variable declarator id so we aren't referenced
if (t.isVariableDeclarator(parent) && parent.id === node) return false;
var isMemberExpression = t.isMemberExpression(parent);
// we're in a member expression and we're the computed property so we're referenced
@@ -161,7 +164,7 @@ t.toBlock = function (node, parent) {
t.getIds = function (node, map, ignoreTypes) {
ignoreTypes = ignoreTypes || [];
var search = [node];
var search = [].concat(node);
var ids = {};
while (search.length) {
@@ -185,14 +188,6 @@ t.getIds = function (node, map, ignoreTypes) {
return ids;
};
t.isLet = function (node) {
return t.isVariableDeclaration(node) && (node.kind !== "var" || node._let);
};
t.isVar = function (node) {
return t.isVariableDeclaration(node, { kind: "var" }) && !node._let;
};
t.getIds.nodes = {
AssignmentExpression: "left",
ImportSpecifier: "id",
@@ -214,13 +209,32 @@ t.getIds.arrays = {
ObjectPattern: "properties"
};
t.isLet = function (node) {
return t.isVariableDeclaration(node) && (node.kind !== "var" || node._let);
};
t.isVar = function (node) {
return t.isVariableDeclaration(node, { kind: "var" }) && !node._let;
};
t.removeComments = function (child) {
delete child.leadingComments;
delete child.trailingComments;
return child;
};
t.inheritsComments = function (child, parent) {
child.leadingComments = _.compact([].concat(child.leadingComments, parent.leadingComments));
child.trailingComments = _.compact([].concat(child.trailingComments, parent.trailingComments));
return child;
};
t.inherits = function (child, parent) {
child.loc = parent.loc;
child.end = parent.end;
child.range = parent.range;
child.start = parent.start;
child.leadingComments = parent.leadingComments;
child.trailingComments = parent.trailingComments;
child.loc = parent.loc;
child.end = parent.end;
child.range = parent.range;
child.start = parent.start;
t.inheritsComments(child, parent);
return child;
};

View File

@@ -106,8 +106,13 @@ exports.buildDefineProperties = function (mutatorMap) {
if (key[0] === "_") return;
node = _.clone(node);
var inheritNode = node;
if (t.isMethodDefinition(node)) node = node.value;
mapNode.properties.push(t.property("init", t.identifier(key), node));
var prop = t.property("init", t.identifier(key), node);
t.inheritsComments(prop, inheritNode);
t.removeComments(inheritNode);
mapNode.properties.push(prop);
});
objExpr.properties.push(propNode);

View File

@@ -1,7 +1,7 @@
{
"name": "6to5",
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
"version": "1.12.14",
"version": "1.12.16",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://github.com/6to5/6to5",
"repository": {
@@ -48,7 +48,7 @@
"chokidar": "0.10.5",
"source-map-support": "0.2.8",
"esutils": "1.1.4",
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/a6c34ba73e215bd16ee585f6794f6a6587820c58.tar.gz",
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/74d8e9bed20ba302d3504f53d0b1c649968959e1.tar.gz",
"estraverse": "^1.7.0"
},
"devDependencies": {

View File

@@ -48,8 +48,8 @@ exports.get = function (entryName) {
var execLoc = taskDir + "/exec.js";
var taskOpts = _.merge({
filename: actualLocAlias,
sourceMapName: expectLocAlias
sourceFileName: actualLocAlias,
sourceMapName: expectLocAlias
}, _.cloneDeep(suite.options));
var taskOptsLoc = taskDir + "/options.json";

View File

@@ -1,8 +1,8 @@
"use strict";
var t = function (t, f) {
if (f === undefined) f = 5;
if (t === undefined) t = "foo";
if (f === undefined) f = 5;
return t + " bar " + f;
};

View File

@@ -0,0 +1 @@
function foo(a=b, b) {}

View File

@@ -0,0 +1,3 @@
{
"throws": "Temporal dead zone - accessing a variable before it's initialized"
}

View File

@@ -0,0 +1,4 @@
assert.equal((function(a, b=a++){
function b(){}
return a;
})(1), 2);

View File

@@ -0,0 +1 @@
function foo(a=a) {}

View File

@@ -0,0 +1,3 @@
{
"throws": "Temporal dead zone - accessing a variable before it's initialized"
}

View File

@@ -9,21 +9,20 @@ var _ = require("lodash");
var run = function (task) {
var actual = task.actual;
var expect = task.expect;
var opts = task.options;
var exec = task.exec;
var getOpts = function (filename) {
var getOpts = function (self) {
return _.merge({
whtiespace: true,
filename: filename
}, opts);
filename: self.loc
}, task.options);
};
var execCode = exec.code;
var result;
if (execCode) {
result = transform(execCode, getOpts(exec.filename));
result = transform(execCode, getOpts(exec));
execCode = result.code;
require("../lib/6to5/polyfill");
@@ -39,7 +38,7 @@ var run = function (task) {
var actualCode = actual.code;
var expectCode = expect.code;
result = transform(actualCode, getOpts(actual.filename));
result = transform(actualCode, getOpts(actual));
actualCode = result.code;
chai.expect(actualCode).to.be.equal(expectCode, actual.loc + " !== " + expect.loc);