|                                                                                                                                                  |  | /** * @fileoverview Rule to check for implicit global variables, functions and classes. * @author Joshua Peek */
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",
        docs: {            description: "Disallow declarations in the global scope",            recommended: false,            url: "https://eslint.org/docs/latest/rules/no-implicit-globals"        },
        schema: [{            type: "object",            properties: {                lexicalBindings: {                    type: "boolean",                    default: false                }            },            additionalProperties: false        }],
        messages: {            globalNonLexicalBinding: "Unexpected {{kind}} declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable.",            globalLexicalBinding: "Unexpected {{kind}} declaration in the global scope, wrap in a block or in an IIFE.",            globalVariableLeak: "Global variable leak, declare the variable if it is intended to be local.",            assignmentToReadonlyGlobal: "Unexpected assignment to read-only global variable.",            redeclarationOfReadonlyGlobal: "Unexpected redeclaration of read-only global variable."        }    },
    create(context) {
        const checkLexicalBindings = context.options[0] && context.options[0].lexicalBindings === true;        const sourceCode = context.sourceCode;
        /**         * Reports the node.         * @param {ASTNode} node Node to report.         * @param {string} messageId Id of the message to report.         * @param {string|undefined} kind Declaration kind, can be 'var', 'const', 'let', function or class.         * @returns {void}         */        function report(node, messageId, kind) {            context.report({                node,                messageId,                data: {                    kind                }            });        }
        return {            Program(node) {                const scope = sourceCode.getScope(node);
                scope.variables.forEach(variable => {
                    // Only ESLint global variables have the `writable` key.
                    const isReadonlyEslintGlobalVariable = variable.writeable === false;                    const isWritableEslintGlobalVariable = variable.writeable === true;
                    if (isWritableEslintGlobalVariable) {
                        // Everything is allowed with writable ESLint global variables.
                        return;                    }
                    // Variables exported by "exported" block comments
                    if (variable.eslintExported) {                        return;                    }
                    variable.defs.forEach(def => {                        const defNode = def.node;
                        if (def.type === "FunctionName" || (def.type === "Variable" && def.parent.kind === "var")) {                            if (isReadonlyEslintGlobalVariable) {                                report(defNode, "redeclarationOfReadonlyGlobal");                            } else {                                report(                                    defNode,                                    "globalNonLexicalBinding",                                    def.type === "FunctionName" ? "function" : `'${def.parent.kind}'`                                );                            }                        }
                        if (checkLexicalBindings) {                            if (def.type === "ClassName" ||                                    (def.type === "Variable" && (def.parent.kind === "let" || def.parent.kind === "const"))) {                                if (isReadonlyEslintGlobalVariable) {                                    report(defNode, "redeclarationOfReadonlyGlobal");                                } else {                                    report(                                        defNode,                                        "globalLexicalBinding",                                        def.type === "ClassName" ? "class" : `'${def.parent.kind}'`                                    );                                }                            }                        }                    });                });
                // Undeclared assigned variables.
                scope.implicit.variables.forEach(variable => {                    const scopeVariable = scope.set.get(variable.name);                    let messageId;
                    if (scopeVariable) {
                        // ESLint global variable
                        if (scopeVariable.writeable) {                            return;                        }                        messageId = "assignmentToReadonlyGlobal";
                    } else {
                        // Reference to an unknown variable, possible global leak.
                        messageId = "globalVariableLeak";                    }
                    // def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
                    variable.defs.forEach(def => {                        report(def.node, messageId);                    });                });            }        };
    }};
 |