/**
							 | 
						|
								 * @fileoverview Rule to enforce var declarations are only at the top of a function.
							 | 
						|
								 * @author Danny Fritz
							 | 
						|
								 * @author Gyandeep Singh
							 | 
						|
								 */
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Rule Definition
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/** @type {import('../shared/types').Rule} */
							 | 
						|
								module.exports = {
							 | 
						|
								    meta: {
							 | 
						|
								        type: "suggestion",
							 | 
						|
								
							 | 
						|
								        docs: {
							 | 
						|
								            description: "Require `var` declarations be placed at the top of their containing scope",
							 | 
						|
								            recommended: false,
							 | 
						|
								            url: "https://eslint.org/docs/latest/rules/vars-on-top"
							 | 
						|
								        },
							 | 
						|
								
							 | 
						|
								        schema: [],
							 | 
						|
								        messages: {
							 | 
						|
								            top: "All 'var' declarations must be at the top of the function scope."
							 | 
						|
								        }
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    create(context) {
							 | 
						|
								
							 | 
						|
								        //--------------------------------------------------------------------------
							 | 
						|
								        // Helpers
							 | 
						|
								        //--------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Has AST suggesting a directive.
							 | 
						|
								         * @param {ASTNode} node any node
							 | 
						|
								         * @returns {boolean} whether the given node structurally represents a directive
							 | 
						|
								         */
							 | 
						|
								        function looksLikeDirective(node) {
							 | 
						|
								            return node.type === "ExpressionStatement" &&
							 | 
						|
								                node.expression.type === "Literal" && typeof node.expression.value === "string";
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Check to see if its a ES6 import declaration
							 | 
						|
								         * @param {ASTNode} node any node
							 | 
						|
								         * @returns {boolean} whether the given node represents a import declaration
							 | 
						|
								         */
							 | 
						|
								        function looksLikeImport(node) {
							 | 
						|
								            return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" ||
							 | 
						|
								                node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier";
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether a given node is a variable declaration or not.
							 | 
						|
								         * @param {ASTNode} node any node
							 | 
						|
								         * @returns {boolean} `true` if the node is a variable declaration.
							 | 
						|
								         */
							 | 
						|
								        function isVariableDeclaration(node) {
							 | 
						|
								            return (
							 | 
						|
								                node.type === "VariableDeclaration" ||
							 | 
						|
								                (
							 | 
						|
								                    node.type === "ExportNamedDeclaration" &&
							 | 
						|
								                    node.declaration &&
							 | 
						|
								                    node.declaration.type === "VariableDeclaration"
							 | 
						|
								                )
							 | 
						|
								            );
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether this variable is on top of the block body
							 | 
						|
								         * @param {ASTNode} node The node to check
							 | 
						|
								         * @param {ASTNode[]} statements collection of ASTNodes for the parent node block
							 | 
						|
								         * @returns {boolean} True if var is on top otherwise false
							 | 
						|
								         */
							 | 
						|
								        function isVarOnTop(node, statements) {
							 | 
						|
								            const l = statements.length;
							 | 
						|
								            let i = 0;
							 | 
						|
								
							 | 
						|
								            // Skip over directives and imports. Static blocks don't have either.
							 | 
						|
								            if (node.parent.type !== "StaticBlock") {
							 | 
						|
								                for (; i < l; ++i) {
							 | 
						|
								                    if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            for (; i < l; ++i) {
							 | 
						|
								                if (!isVariableDeclaration(statements[i])) {
							 | 
						|
								                    return false;
							 | 
						|
								                }
							 | 
						|
								                if (statements[i] === node) {
							 | 
						|
								                    return true;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return false;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether variable is on top at the global level
							 | 
						|
								         * @param {ASTNode} node The node to check
							 | 
						|
								         * @param {ASTNode} parent Parent of the node
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function globalVarCheck(node, parent) {
							 | 
						|
								            if (!isVarOnTop(node, parent.body)) {
							 | 
						|
								                context.report({ node, messageId: "top" });
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether variable is on top at functional block scope level
							 | 
						|
								         * @param {ASTNode} node The node to check
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function blockScopeVarCheck(node) {
							 | 
						|
								            const { parent } = node;
							 | 
						|
								
							 | 
						|
								            if (
							 | 
						|
								                parent.type === "BlockStatement" &&
							 | 
						|
								                /Function/u.test(parent.parent.type) &&
							 | 
						|
								                isVarOnTop(node, parent.body)
							 | 
						|
								            ) {
							 | 
						|
								                return;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (
							 | 
						|
								                parent.type === "StaticBlock" &&
							 | 
						|
								                isVarOnTop(node, parent.body)
							 | 
						|
								            ) {
							 | 
						|
								                return;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            context.report({ node, messageId: "top" });
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        //--------------------------------------------------------------------------
							 | 
						|
								        // Public API
							 | 
						|
								        //--------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								        return {
							 | 
						|
								            "VariableDeclaration[kind='var']"(node) {
							 | 
						|
								                if (node.parent.type === "ExportNamedDeclaration") {
							 | 
						|
								                    globalVarCheck(node.parent, node.parent.parent);
							 | 
						|
								                } else if (node.parent.type === "Program") {
							 | 
						|
								                    globalVarCheck(node, node.parent);
							 | 
						|
								                } else {
							 | 
						|
								                    blockScopeVarCheck(node);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        };
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								};
							 |