/**
							 | 
						|
								 * @fileoverview Rule to check for "block scoped" variables by binding context
							 | 
						|
								 * @author Matt DuVall <http://www.mattduvall.com>
							 | 
						|
								 */
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Rule Definition
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/** @type {import('../shared/types').Rule} */
							 | 
						|
								module.exports = {
							 | 
						|
								    meta: {
							 | 
						|
								        type: "suggestion",
							 | 
						|
								
							 | 
						|
								        docs: {
							 | 
						|
								            description: "Enforce the use of variables within the scope they are defined",
							 | 
						|
								            recommended: false,
							 | 
						|
								            url: "https://eslint.org/docs/latest/rules/block-scoped-var"
							 | 
						|
								        },
							 | 
						|
								
							 | 
						|
								        schema: [],
							 | 
						|
								
							 | 
						|
								        messages: {
							 | 
						|
								            outOfScope: "'{{name}}' declared on line {{definitionLine}} column {{definitionColumn}} is used outside of binding context."
							 | 
						|
								        }
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    create(context) {
							 | 
						|
								        let stack = [];
							 | 
						|
								        const sourceCode = context.sourceCode;
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Makes a block scope.
							 | 
						|
								         * @param {ASTNode} node A node of a scope.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function enterScope(node) {
							 | 
						|
								            stack.push(node.range);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Pops the last block scope.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function exitScope() {
							 | 
						|
								            stack.pop();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Reports a given reference.
							 | 
						|
								         * @param {eslint-scope.Reference} reference A reference to report.
							 | 
						|
								         * @param {eslint-scope.Definition} definition A definition for which to report reference.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function report(reference, definition) {
							 | 
						|
								            const identifier = reference.identifier;
							 | 
						|
								            const definitionPosition = definition.name.loc.start;
							 | 
						|
								
							 | 
						|
								            context.report({
							 | 
						|
								                node: identifier,
							 | 
						|
								                messageId: "outOfScope",
							 | 
						|
								                data: {
							 | 
						|
								                    name: identifier.name,
							 | 
						|
								                    definitionLine: definitionPosition.line,
							 | 
						|
								                    definitionColumn: definitionPosition.column + 1
							 | 
						|
								                }
							 | 
						|
								            });
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Finds and reports references which are outside of valid scopes.
							 | 
						|
								         * @param {ASTNode} node A node to get variables.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function checkForVariables(node) {
							 | 
						|
								            if (node.kind !== "var") {
							 | 
						|
								                return;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Defines a predicate to check whether or not a given reference is outside of valid scope.
							 | 
						|
								            const scopeRange = stack[stack.length - 1];
							 | 
						|
								
							 | 
						|
								            /**
							 | 
						|
								             * Check if a reference is out of scope
							 | 
						|
								             * @param {ASTNode} reference node to examine
							 | 
						|
								             * @returns {boolean} True is its outside the scope
							 | 
						|
								             * @private
							 | 
						|
								             */
							 | 
						|
								            function isOutsideOfScope(reference) {
							 | 
						|
								                const idRange = reference.identifier.range;
							 | 
						|
								
							 | 
						|
								                return idRange[0] < scopeRange[0] || idRange[1] > scopeRange[1];
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Gets declared variables, and checks its references.
							 | 
						|
								            const variables = sourceCode.getDeclaredVariables(node);
							 | 
						|
								
							 | 
						|
								            for (let i = 0; i < variables.length; ++i) {
							 | 
						|
								
							 | 
						|
								                // Reports.
							 | 
						|
								                variables[i]
							 | 
						|
								                    .references
							 | 
						|
								                    .filter(isOutsideOfScope)
							 | 
						|
								                    .forEach(ref => report(ref, variables[i].defs.find(def => def.parent === node)));
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return {
							 | 
						|
								            Program(node) {
							 | 
						|
								                stack = [node.range];
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            // Manages scopes.
							 | 
						|
								            BlockStatement: enterScope,
							 | 
						|
								            "BlockStatement:exit": exitScope,
							 | 
						|
								            ForStatement: enterScope,
							 | 
						|
								            "ForStatement:exit": exitScope,
							 | 
						|
								            ForInStatement: enterScope,
							 | 
						|
								            "ForInStatement:exit": exitScope,
							 | 
						|
								            ForOfStatement: enterScope,
							 | 
						|
								            "ForOfStatement:exit": exitScope,
							 | 
						|
								            SwitchStatement: enterScope,
							 | 
						|
								            "SwitchStatement:exit": exitScope,
							 | 
						|
								            CatchClause: enterScope,
							 | 
						|
								            "CatchClause:exit": exitScope,
							 | 
						|
								            StaticBlock: enterScope,
							 | 
						|
								            "StaticBlock:exit": exitScope,
							 | 
						|
								
							 | 
						|
								            // Finds and reports references which are outside of valid scope.
							 | 
						|
								            VariableDeclaration: checkForVariables
							 | 
						|
								        };
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								};
							 |