hoist var declarations to before function definition when let block scoping

This commit is contained in:
Sebastian McKenzie 2014-09-29 13:36:39 +10:00
parent 74f831bd39
commit fd932e20e9
9 changed files with 86 additions and 7 deletions

View File

@ -0,0 +1 @@
KEY = VALUE;

View File

@ -0,0 +1 @@
var KEY;

View File

@ -5,6 +5,7 @@ var _ = require("lodash");
var isLet = function (node) {
if (node.type === "VariableDeclaration" && node.kind === "let") {
node.kind = "var";
node._ignoreBlockBindingHoist = true;
return true;
}
};
@ -21,7 +22,7 @@ var hasLet = function (nodes) {
exports.Program = function (node) {
if (hasLet(node.body)) {
node.body = [buildNode(node.body)];
node.body = buildNode(node.body);
}
};
@ -31,7 +32,7 @@ exports.BlockStatement = function (node, parent) {
// ignore if we're the body of a closure already
if (parent.type === "FunctionExpression") return;
node.body = [buildNode(node.body)];
node.body = buildNode(node.body);
};
exports.ForInStatement = function (node) {
@ -43,13 +44,47 @@ exports.ForStatement = function (node) {
};
var buildNode = function (node) {
var nodes = [];
// hoist normal variable declarations
node = [].concat(node);
node = node.map(function (node) {
if (node._ignoreBlockBindingHoist) return node;
if (node.type === "VariableDeclaration" && node.kind === "var") {
_.each(node.declarations, function (declar) {
nodes.push(util.template("variable-declare", {
KEY: declar.id
}));
});
return node.declarations.map(function (declar) {
return util.template("assign", {
KEY: declar.id,
VALUE: declar.init
}, true);
});
} else if (node.type === "ForInStatement" && !node.left._ignoreBlockBindingHoist) {
var id = node.left.declarations[0].id;
node.left = id;
nodes.push(util.template("variable-declare", {
KEY: id
}));
}
return node;
});
//
var func = {
type: "FunctionExpression",
params: [],
defaults: [],
body: {
type: "BlockStatement",
body: [].concat(node)
body: node
}
};
@ -58,7 +93,11 @@ var buildNode = function (node) {
templateName = "function-call-this";
}
return util.template(templateName, {
//
nodes.push(util.template(templateName, {
FUNCTION: func
}, true);
}, true));
return nodes;
};

View File

@ -30,11 +30,17 @@ var traverse = module.exports = function (parent, callback) {
_.each(nodes, function (node, i) {
handle(nodes, i);
});
parent[key] = _.flatten(nodes).filter(function (node) {
parent[key] = _.flatten(parent[key]).filter(function (node) {
return node !== traverse.Delete;
});
} else {
handle(parent, key);
if (parent[key] === traverse.Delete) {
throw new Error("trying to delete property " + key + " from " +
parent.type + " but can't because it's required");
}
}
});
};
@ -66,3 +72,18 @@ traverse.replace = function (node, callback) {
if (result != null) obj[key] = result;
});
};
traverse.replace.shallow = function (node, callback) {
traverse(node, function (node, parent, obj, key) {
var result = callback(node, parent);
if (result != null) obj[key] = result;
return false;
});
};
traverse.shallow = function (node, callback) {
traverse(node, function () {
callback.apply(this, arguments);
return false;
});
};

View File

@ -0,0 +1,2 @@
let MULTIPLIER = 5;
var foo = "bar", bar = "foo";

View File

@ -0,0 +1,7 @@
var foo;
var bar;
(function () {
var MULTIPLIER = 5;
foo = "bar";
bar = "foo";
})();

View File

@ -0,0 +1,2 @@
let MULTIPLIER = 5;
var foo = "bar";

View File

@ -0,0 +1,5 @@
var foo;
(function () {
var MULTIPLIER = 5;
foo = "bar";
})();

View File

@ -1,6 +1,7 @@
var i;
(function () {
var MULTIPLIER = 5;
for (var i in arr) {
for (i in arr) {
console.log(arr[i] * MULTIPLIER);
}
}());