|                                                                                                                                                                              |  | /** * @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        };    }};
 |