add default initializer to let variables within loop bodies and fix excessive break replacement inside of switches in let scoping - fixes #255
This commit is contained in:
@@ -91,6 +91,9 @@ 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();
|
||||
|
||||
@@ -106,7 +109,7 @@ LetScoping.prototype.run = function () {
|
||||
|
||||
// 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();
|
||||
this.has = this.checkLoop();
|
||||
|
||||
// hoist var references to retain scope
|
||||
this.hoistVarDeclarations();
|
||||
@@ -244,6 +247,30 @@ 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)) {
|
||||
_.each(node.declarations, function (declar) {
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* If we're inside of a `For*Statement` then traverse it and check if it has one
|
||||
* of the following node types `ReturnStatement`, `BreakStatement`,
|
||||
@@ -253,22 +280,26 @@ LetScoping.prototype.getInfo = function () {
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.checkFor = function () {
|
||||
LetScoping.prototype.checkLoop = function () {
|
||||
var has = {
|
||||
hasContinue: false,
|
||||
hasReturn: false,
|
||||
hasBreak: false,
|
||||
};
|
||||
|
||||
traverse(this.block, function (node) {
|
||||
var loopParent = this.loopParent;
|
||||
|
||||
traverse(this.block, function (node, parent) {
|
||||
var replace;
|
||||
|
||||
if (t.isFunction(node) || t.isLoop(node) || t.isSwitchStatement(node)) {
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node && !node.label) {
|
||||
if (t.isBreakStatement(node)) {
|
||||
if (t.isSwitchCase(parent)) return;
|
||||
|
||||
has.hasBreak = true;
|
||||
replace = t.returnStatement(t.literal("break"));
|
||||
} else if (t.isContinueStatement(node)) {
|
||||
|
||||
Reference in New Issue
Block a user