Skip to content
Permalink
9bfb9ba527
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
174 lines (148 sloc) 5.67 KB
/**
* @fileoverview Rule to flag when the same variable is declared more then once.
* @author Ilya Volodin
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Disallow variable redeclaration",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-redeclare"
},
messages: {
redeclared: "'{{id}}' is already defined.",
redeclaredAsBuiltin: "'{{id}}' is already defined as a built-in global variable.",
redeclaredBySyntax: "'{{id}}' is already defined by a variable declaration."
},
schema: [
{
type: "object",
properties: {
builtinGlobals: { type: "boolean", default: true }
},
additionalProperties: false
}
]
},
create(context) {
const options = {
builtinGlobals: Boolean(
context.options.length === 0 ||
context.options[0].builtinGlobals
)
};
const sourceCode = context.sourceCode;
/**
* Iterate declarations of a given variable.
* @param {escope.variable} variable The variable object to iterate declarations.
* @returns {IterableIterator<{type:string,node:ASTNode,loc:SourceLocation}>} The declarations.
*/
function *iterateDeclarations(variable) {
if (options.builtinGlobals && (
variable.eslintImplicitGlobalSetting === "readonly" ||
variable.eslintImplicitGlobalSetting === "writable"
)) {
yield { type: "builtin" };
}
for (const id of variable.identifiers) {
yield { type: "syntax", node: id, loc: id.loc };
}
if (variable.eslintExplicitGlobalComments) {
for (const comment of variable.eslintExplicitGlobalComments) {
yield {
type: "comment",
node: comment,
loc: astUtils.getNameLocationInGlobalDirectiveComment(
sourceCode,
comment,
variable.name
)
};
}
}
}
/**
* Find variables in a given scope and flag redeclared ones.
* @param {Scope} scope An eslint-scope scope object.
* @returns {void}
* @private
*/
function findVariablesInScope(scope) {
for (const variable of scope.variables) {
const [
declaration,
...extraDeclarations
] = iterateDeclarations(variable);
if (extraDeclarations.length === 0) {
continue;
}
/*
* If the type of a declaration is different from the type of
* the first declaration, it shows the location of the first
* declaration.
*/
const detailMessageId = declaration.type === "builtin"
? "redeclaredAsBuiltin"
: "redeclaredBySyntax";
const data = { id: variable.name };
// Report extra declarations.
for (const { type, node, loc } of extraDeclarations) {
const messageId = type === declaration.type
? "redeclared"
: detailMessageId;
context.report({ node, loc, messageId, data });
}
}
}
/**
* Find variables in the current scope.
* @param {ASTNode} node The node of the current scope.
* @returns {void}
* @private
*/
function checkForBlock(node) {
const scope = sourceCode.getScope(node);
/*
* In ES5, some node type such as `BlockStatement` doesn't have that scope.
* `scope.block` is a different node in such a case.
*/
if (scope.block === node) {
findVariablesInScope(scope);
}
}
return {
Program(node) {
const scope = sourceCode.getScope(node);
findVariablesInScope(scope);
// Node.js or ES modules has a special scope.
if (
scope.type === "global" &&
scope.childScopes[0] &&
// The special scope's block is the Program node.
scope.block === scope.childScopes[0].block
) {
findVariablesInScope(scope.childScopes[0]);
}
},
FunctionDeclaration: checkForBlock,
FunctionExpression: checkForBlock,
ArrowFunctionExpression: checkForBlock,
StaticBlock: checkForBlock,
BlockStatement: checkForBlock,
ForStatement: checkForBlock,
ForInStatement: checkForBlock,
ForOfStatement: checkForBlock,
SwitchStatement: checkForBlock
};
}
};