make scope tracker more reliable to handle all edgecases

This commit is contained in:
Sebastian McKenzie
2014-11-14 23:13:58 +11:00
parent e5a8c95b62
commit 37f360c72d
5 changed files with 70 additions and 20 deletions

View File

@@ -4,6 +4,8 @@ var traverse = require("./index");
var t = require("../types");
var _ = require("lodash");
var FOR_KEYS = ["left", "init"];
function Scope(parent, block) {
this.parent = parent;
this.block = block;
@@ -19,29 +21,59 @@ Scope.prototype.getIds = function () {
var self = this;
var ids = block._scopeIds = {};
if (t.isBlockStatement(block)) {
_.each(block.body, function (node) {
if (t.isVariableDeclaration(node) && node.kind !== "var") {
self.add(node, ids);
}
});
} else if (t.isProgram(block) || t.isFunction(block)) {
traverse(block, function (node, parent) {
if (parent !== block && t.isVariableDeclaration(node) && node.kind !== "var") {
return;
}
// ForStatement - left, init
if (t.isDeclaration(node)) {
self.add(node, ids);
} else if (t.isFunction(node)) {
return false;
}
if (t.isFor(block)) {
_.each(FOR_KEYS, function (key) {
var node = block[key];
if (t.isLet(node)) self.add(node, ids);
});
} else if (t.isCatchClause(block)) {
block = block.body;
}
// Program, BlockStatement - let variables
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);
});
}
// CatchClause - param
if (t.isCatchClause(block)) {
self.add(block.param, ids);
}
// Program, Function - var variables
if (t.isProgram(block) || t.isFunction(block)) {
traverse(block, function (node) {
if (t.isFor(node)) {
_.each(FOR_KEYS, function (key) {
var declar = node[key];
if (t.isVar(declar)) self.add(declar, ids);
});
}
// this block is a function so we'll stop since none of the variables
// declared within are accessible
if (t.isFunction(node)) return false;
// 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);
}
});
}
// Function - params
if (t.isFunction(block)) {
this.add(block.rest, ids);
_.each(block.params, function (param) {
self.add(param, ids);
});
@@ -51,6 +83,7 @@ Scope.prototype.getIds = function () {
};
Scope.prototype.add = function (node, ids) {
if (!node) return;
_.merge(ids || this.ids, t.getIds(node, true));
};

View File

@@ -35,9 +35,9 @@
"ClassDeclaration": ["Statement", "Declaration", "Class"],
"ClassExpression": ["Class"],
"ForOfStatement": ["Statement", "For"],
"ForInStatement": ["Statement", "For"],
"ForStatement": ["Statement", "For"],
"ForOfStatement": ["Statement", "For", "Scope"],
"ForInStatement": ["Statement", "For", "Scope"],
"ForStatement": ["Statement", "For", "Scope"],
"ObjectPattern": ["Pattern"],
"ArrayPattern": ["Pattern"],

View File

@@ -185,6 +185,14 @@ 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",