| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 | /** * @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/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;        /**         * 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.         * @returns {void}         */        function markLoneBlock() {            if (loneBlocks.length === 0) {                return;            }            const block = context.getAncestors().pop();            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();                }            };            ruleDef.FunctionDeclaration = function() {                if (context.getScope().isStrict) {                    markLoneBlock();                }            };            ruleDef.ClassDeclaration = markLoneBlock;        }        return ruleDef;    }};
 |