/**
							 | 
						|
								 * @fileoverview Rule to flag blocks with no reason to exist
							 | 
						|
								 * @author Brandon Mills
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Rule Definition
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/** @type {import('../shared/types').Rule} */
							 | 
						|
								module.exports = {
							 | 
						|
								    meta: {
							 | 
						|
								        type: "suggestion",
							 | 
						|
								
							 | 
						|
								        docs: {
							 | 
						|
								            description: "Disallow unnecessary nested blocks",
							 | 
						|
								            recommended: false,
							 | 
						|
								            url: "https://eslint.org/docs/latest/rules/no-lone-blocks"
							 | 
						|
								        },
							 | 
						|
								
							 | 
						|
								        schema: [],
							 | 
						|
								
							 | 
						|
								        messages: {
							 | 
						|
								            redundantBlock: "Block is redundant.",
							 | 
						|
								            redundantNestedBlock: "Nested block is redundant."
							 | 
						|
								        }
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    create(context) {
							 | 
						|
								
							 | 
						|
								        // A stack of lone blocks to be checked for block-level bindings
							 | 
						|
								        const loneBlocks = [];
							 | 
						|
								        let ruleDef;
							 | 
						|
								        const sourceCode = context.sourceCode;
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Reports a node as invalid.
							 | 
						|
								         * @param {ASTNode} node The node to be reported.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function report(node) {
							 | 
						|
								            const messageId = node.parent.type === "BlockStatement" || node.parent.type === "StaticBlock"
							 | 
						|
								                ? "redundantNestedBlock"
							 | 
						|
								                : "redundantBlock";
							 | 
						|
								
							 | 
						|
								            context.report({
							 | 
						|
								                node,
							 | 
						|
								                messageId
							 | 
						|
								            });
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks for any occurrence of a BlockStatement in a place where lists of statements can appear
							 | 
						|
								         * @param {ASTNode} node The node to check
							 | 
						|
								         * @returns {boolean} True if the node is a lone block.
							 | 
						|
								         */
							 | 
						|
								        function isLoneBlock(node) {
							 | 
						|
								            return node.parent.type === "BlockStatement" ||
							 | 
						|
								                node.parent.type === "StaticBlock" ||
							 | 
						|
								                node.parent.type === "Program" ||
							 | 
						|
								
							 | 
						|
								                // Don't report blocks in switch cases if the block is the only statement of the case.
							 | 
						|
								                node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks the enclosing block of the current node for block-level bindings,
							 | 
						|
								         * and "marks it" as valid if any.
							 | 
						|
								         * @param {ASTNode} node The current node to check.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         */
							 | 
						|
								        function markLoneBlock(node) {
							 | 
						|
								            if (loneBlocks.length === 0) {
							 | 
						|
								                return;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            const block = node.parent;
							 | 
						|
								
							 | 
						|
								            if (loneBlocks[loneBlocks.length - 1] === block) {
							 | 
						|
								                loneBlocks.pop();
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Default rule definition: report all lone blocks
							 | 
						|
								        ruleDef = {
							 | 
						|
								            BlockStatement(node) {
							 | 
						|
								                if (isLoneBlock(node)) {
							 | 
						|
								                    report(node);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        };
							 | 
						|
								
							 | 
						|
								        // ES6: report blocks without block-level bindings, or that's only child of another block
							 | 
						|
								        if (context.languageOptions.ecmaVersion >= 2015) {
							 | 
						|
								            ruleDef = {
							 | 
						|
								                BlockStatement(node) {
							 | 
						|
								                    if (isLoneBlock(node)) {
							 | 
						|
								                        loneBlocks.push(node);
							 | 
						|
								                    }
							 | 
						|
								                },
							 | 
						|
								                "BlockStatement:exit"(node) {
							 | 
						|
								                    if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
							 | 
						|
								                        loneBlocks.pop();
							 | 
						|
								                        report(node);
							 | 
						|
								                    } else if (
							 | 
						|
								                        (
							 | 
						|
								                            node.parent.type === "BlockStatement" ||
							 | 
						|
								                            node.parent.type === "StaticBlock"
							 | 
						|
								                        ) &&
							 | 
						|
								                        node.parent.body.length === 1
							 | 
						|
								                    ) {
							 | 
						|
								                        report(node);
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            };
							 | 
						|
								
							 | 
						|
								            ruleDef.VariableDeclaration = function(node) {
							 | 
						|
								                if (node.kind === "let" || node.kind === "const") {
							 | 
						|
								                    markLoneBlock(node);
							 | 
						|
								                }
							 | 
						|
								            };
							 | 
						|
								
							 | 
						|
								            ruleDef.FunctionDeclaration = function(node) {
							 | 
						|
								                if (sourceCode.getScope(node).isStrict) {
							 | 
						|
								                    markLoneBlock(node);
							 | 
						|
								                }
							 | 
						|
								            };
							 | 
						|
								
							 | 
						|
								            ruleDef.ClassDeclaration = markLoneBlock;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return ruleDef;
							 | 
						|
								    }
							 | 
						|
								};
							 |