90 lines
2.2 KiB
JavaScript
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);
|
|
};
|