block scope constants

This commit is contained in:
Sebastian McKenzie
2014-12-10 23:49:13 +11:00
parent 2a0b63f3bb
commit c7d69b2f92
3 changed files with 30 additions and 10 deletions

View File

@@ -9,11 +9,21 @@ exports.ForOfStatement =
exports.ForStatement = function (node, parent, file) {
var constants = {};
var check = function (parent, names) {
/**
* Check the results of `util.getIds` as `names` generated from a
* node against it's parent.
*/
var check = function (parent, names, scope) {
_.each(names, function (nameNode, name) {
if (!_.has(constants, name)) return;
if (parent && t.isBlockStatement(parent) && parent !== constants[name]) return;
if (scope) {
var defined = scope.get(name);
if (defined && defined === nameNode) return;
}
throw file.errorWithNode(nameNode, name + " is read-only");
});
};
@@ -22,6 +32,10 @@ exports.ForStatement = function (node, parent, file) {
return t.getIds(node, true, ["MemberExpression"]);
};
/**
* Collect all constants in this scope.
*/
_.each(node.body, function (child, parent) {
if (child && t.isVariableDeclaration(child, { kind: "const" })) {
_.each(child.declarations, function (declar) {
@@ -43,12 +57,12 @@ exports.ForStatement = function (node, parent, file) {
if (_.isEmpty(constants)) return;
traverse(node, function (child, parent) {
traverse(node, function (child, parent, scope) {
if (child._ignoreConstant) return;
if (t.isVariableDeclaration(child)) return;
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
check(parent, getIds(child));
check(parent, getIds(child), scope);
}
});
};

View File

@@ -27,12 +27,12 @@ Scope.add = function (node, references) {
};
Scope.prototype.generateTemp = function (file, name) {
var id = file.generateUidIdentifier(name || "temp", this);
this.push({
key: id.name,
id: id
});
return id;
var id = file.generateUidIdentifier(name || "temp", this);
this.push({
key: id.name,
id: id
});
return id;
};
Scope.prototype.getReferences = function () {
@@ -86,12 +86,15 @@ Scope.prototype.getReferences = function () {
// declared within are accessible
if (t.isFunction(node)) return false;
// function identifier doesn't belong to this scope
if (block.id && node === block.id) return;
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
add(node);
}
// we've ran into a declaration!
// we'll let the BlockStatement scope deal with `let` declarations
// we'll let the BlockStatement scope deal with `let` declarations unless
if (t.isDeclaration(node) && !t.isLet(node)) {
add(node);
}