fix let variable declaration hoisting bug. All let variable declarators now have a default initializer of undefined unless they're the left of a ForIn or ForOf
This commit is contained in:
@@ -3,18 +3,25 @@ var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var isLet = function (node) {
|
||||
var isLet = function (node, parent) {
|
||||
if (!t.isVariableDeclaration(node)) return false;
|
||||
if (node._let) return true;
|
||||
if (node.kind !== "let") return false;
|
||||
|
||||
// https://github.com/6to5/6to5/issues/255
|
||||
if (!t.isFor(parent) || t.isFor(parent) && parent.left !== node) {
|
||||
_.each(node.declarations, function (declar) {
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
});
|
||||
}
|
||||
|
||||
node._let = true;
|
||||
node.kind = "var";
|
||||
return true;
|
||||
};
|
||||
|
||||
var isVar = function (node) {
|
||||
return t.isVariableDeclaration(node, { kind: "var" }) && !isLet(node);
|
||||
var isVar = function (node, parent) {
|
||||
return t.isVariableDeclaration(node, { kind: "var" }) && !isLet(node, parent);
|
||||
};
|
||||
|
||||
var standardiseLets = function (declars) {
|
||||
@@ -23,13 +30,13 @@ var standardiseLets = function (declars) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.VariableDeclaration = function (node) {
|
||||
isLet(node);
|
||||
exports.VariableDeclaration = function (node, parent) {
|
||||
isLet(node, parent);
|
||||
};
|
||||
|
||||
exports.Loop = function (node, parent, file, scope) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init)) {
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
node.body._letDeclars = [init];
|
||||
}
|
||||
@@ -91,9 +98,6 @@ LetScoping.prototype.run = function () {
|
||||
// remap all let references that exist in upper scopes to their uid
|
||||
this.remap();
|
||||
|
||||
// add default initializer to let variables in loop bodys
|
||||
this.initialiseLoopLets();
|
||||
|
||||
// this is a block within a `Function` so we can safely leave it be
|
||||
if (t.isFunction(this.parent)) return this.noClosure();
|
||||
|
||||
@@ -242,7 +246,7 @@ LetScoping.prototype.getInfo = function () {
|
||||
|
||||
for (var i in block.body) {
|
||||
var declar = block.body[i];
|
||||
if (!isLet(declar)) continue;
|
||||
if (!isLet(declar, block)) continue;
|
||||
|
||||
_.each(t.getIds(declar, true), function (id, key) {
|
||||
duplicates(id, key);
|
||||
@@ -253,31 +257,6 @@ LetScoping.prototype.getInfo = function () {
|
||||
return opts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Any let variable declared within a loop body need to have an initializer or
|
||||
* else they'll be hoisted and subsequent iterations of the loop will have a
|
||||
* previous state. This function adds a default initializer of `undefined` to
|
||||
* those variables.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.initialiseLoopLets = function () {
|
||||
var loopParent = this.loopParent;
|
||||
if (!loopParent) return;
|
||||
|
||||
traverse(this.block, function (node) {
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLet(node)) {
|
||||
for (var i in node.declarations) {
|
||||
var declar = node.declarations[i];
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* If we're inside of a loop then traverse it and check if it has one of
|
||||
* the following node types `ReturnStatement`, `BreakStatement`,
|
||||
@@ -333,16 +312,16 @@ LetScoping.prototype.checkLoop = function () {
|
||||
|
||||
LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
var self = this;
|
||||
traverse(this.block, function (node) {
|
||||
traverse(this.block, function (node, parent) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
if (isVar(node.left)) {
|
||||
if (isVar(node.left, node)) {
|
||||
node.left = node.left.declarations[0].id;
|
||||
}
|
||||
} else if (isVar(node)) {
|
||||
} else if (isVar(node, parent)) {
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
} else if (t.isFunction(node)) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user