An error occurred while loading the file. Please try again.
no-redeclare.js 5.60 KiB
/**
 * @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
//------------------------------------------------------------------------------
module.exports = {
    meta: {
        type: "suggestion",
        docs: {
            description: "disallow variable redeclaration",
            category: "Best Practices",
            recommended: true,
            url: "https://eslint.org/docs/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.getSourceCode();
        /**
         * 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 = context.getScope(); /* * 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() { const scope = context.getScope(); 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, BlockStatement: checkForBlock, ForStatement: checkForBlock, ForInStatement: checkForBlock, ForOfStatement: checkForBlock, SwitchStatement: checkForBlock }; } };