2 * @fileoverview Rule to flag blocks with no reason to exist
3 * @author Brandon Mills
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
17 description: "disallow unnecessary nested blocks",
18 category: "Best Practices",
20 url: "https://eslint.org/docs/rules/no-lone-blocks"
28 // A stack of lone blocks to be checked for block-level bindings
29 const loneBlocks = [];
33 * Reports a node as invalid.
34 * @param {ASTNode} node The node to be reported.
37 function report(node) {
38 const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant.";
40 context.report({ node, message });
44 * Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
45 * @param {ASTNode} node The node to check
46 * @returns {boolean} True if the node is a lone block.
48 function isLoneBlock(node) {
49 return node.parent.type === "BlockStatement" ||
50 node.parent.type === "Program" ||
52 // Don't report blocks in switch cases if the block is the only statement of the case.
53 node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
57 * Checks the enclosing block of the current node for block-level bindings,
58 * and "marks it" as valid if any.
61 function markLoneBlock() {
62 if (loneBlocks.length === 0) {
66 const block = context.getAncestors().pop();
68 if (loneBlocks[loneBlocks.length - 1] === block) {
73 // Default rule definition: report all lone blocks
75 BlockStatement(node) {
76 if (isLoneBlock(node)) {
82 // ES6: report blocks without block-level bindings, or that's only child of another block
83 if (context.parserOptions.ecmaVersion >= 6) {
85 BlockStatement(node) {
86 if (isLoneBlock(node)) {
87 loneBlocks.push(node);
90 "BlockStatement:exit"(node) {
91 if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
95 node.parent.type === "BlockStatement" &&
96 node.parent.body.length === 1
103 ruleDef.VariableDeclaration = function(node) {
104 if (node.kind === "let" || node.kind === "const") {
109 ruleDef.FunctionDeclaration = function() {
110 if (context.getScope().isStrict) {
115 ruleDef.ClassDeclaration = markLoneBlock;