You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.9 KiB

/**
* @fileoverview A rule to suggest using of const declaration for variables that are never modified after declared.
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = function(context) {
/**
* Checks whether a reference is the initializer.
* @param {Reference} reference - A reference to check.
* @returns {boolean} Whether or not the reference is the initializer.
*/
function isInitializer(reference) {
return reference.init === true;
}
/**
* Checks whether a reference is read-only or the initializer.
* @param {Reference} reference - A reference to check.
* @returns {boolean} Whether or not the reference is read-only or the initializer.
*/
function isReadOnlyOrInitializer(reference) {
return reference.isReadOnly() || reference.init === true;
}
/**
* Searches and reports variables that are never modified after declared.
* @param {Scope} scope - A scope of the search domain.
* @returns {void}
*/
function checkForVariables(scope) {
// Skip the TDZ type.
if (scope.type === "TDZ") {
return;
}
var variables = scope.variables;
for (var i = 0, end = variables.length; i < end; ++i) {
var variable = variables[i];
var def = variable.defs[0];
var declaration = def && def.parent;
var statement = declaration && declaration.parent;
var references = variable.references;
var identifier = variable.identifiers[0];
if (statement != null &&
identifier != null &&
declaration.type === "VariableDeclaration" &&
declaration.kind === "let" &&
(statement.type !== "ForStatement" || statement.init !== declaration) &&
references.some(isInitializer) &&
references.every(isReadOnlyOrInitializer)
) {
context.report(
identifier,
"`{{name}}` is never modified, use `const` instead.",
{name: identifier.name});
}
}
}
/**
* Adds multiple items to the tail of an array.
* @param {any[]} array - A destination to add.
* @param {any[]} values - Items to be added.
* @returns {void}
*/
var pushAll = Function.apply.bind(Array.prototype.push);
return {
"Program:exit": function () {
var stack = [context.getScope()];
while (stack.length) {
var scope = stack.pop();
pushAll(stack, scope.childScopes);
checkForVariables(scope);
}
}
};
};
module.exports.schema = [];