2015-01-21 23:04:31 +11:00

90 lines
2.2 KiB
JavaScript

"use strict";
var traverse = require("../../../traverse");
var t = require("../../../types");
var _ = require("lodash");
exports.Program =
exports.BlockStatement =
exports.ForInStatement =
exports.ForOfStatement =
exports.ForStatement = function (node, parent, scope, context, file) {
var hasConstants = false;
var constants = {};
/**
* Check the results of `util.getIds` as `names` generated from a
* node against it's parent.
*/
var check = function (parent, names, scope) {
for (var name in names) {
var nameNode = names[name];
if (!_.has(constants, name)) continue;
if (parent && t.isBlockStatement(parent) && parent !== constants[name]) continue;
if (scope) {
var defined = scope.get(name);
if (defined && defined === nameNode) continue;
}
throw file.errorWithNode(nameNode, name + " is read-only");
}
};
var getIds = function (node) {
return t.getIds(node, true, ["MemberExpression"]);
};
/**
* Collect all constants in this scope.
*/
_.each(node.body, function (child, parent) {
if (t.isExportDeclaration(child)) {
child = child.declaration;
}
if (t.isVariableDeclaration(child, { kind: "const" })) {
for (var i = 0; i < child.declarations.length; i++) {
var declar = child.declarations[i];
var ids = getIds(declar);
for (var name in ids) {
var nameNode = ids[name];
var names = {};
names[name] = nameNode;
check(parent, names);
constants[name] = parent;
hasConstants = true;
}
declar._ignoreConstant = true;
}
child._ignoreConstant = true;
child.kind = "let";
}
});
if (!hasConstants) return;
var state = {
check: check,
getIds: getIds
};
traverse(node, {
enter: function (child, parent, scope, context, state) {
if (child._ignoreConstant) return;
if (t.isVariableDeclaration(child)) return;
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
state.check(parent, state.getIds(child), scope);
}
}
}, null, state);
};