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"
26 redundantBlock: "Block is redundant.",
27 redundantNestedBlock: "Nested block is redundant."
33 // A stack of lone blocks to be checked for block-level bindings
34 const loneBlocks = [];
38 * Reports a node as invalid.
39 * @param {ASTNode} node The node to be reported.
42 function report(node) {
43 const messageId = node.parent.type === "BlockStatement" ? "redundantNestedBlock" : "redundantBlock";
52 * Checks for any occurrence of a BlockStatement in a place where lists of statements can appear
53 * @param {ASTNode} node The node to check
54 * @returns {boolean} True if the node is a lone block.
56 function isLoneBlock(node) {
57 return node.parent.type === "BlockStatement" ||
58 node.parent.type === "Program" ||
60 // Don't report blocks in switch cases if the block is the only statement of the case.
61 node.parent.type === "SwitchCase" && !(node.parent.consequent[0] === node && node.parent.consequent.length === 1);
65 * Checks the enclosing block of the current node for block-level bindings,
66 * and "marks it" as valid if any.
69 function markLoneBlock() {
70 if (loneBlocks.length === 0) {
74 const block = context.getAncestors().pop();
76 if (loneBlocks[loneBlocks.length - 1] === block) {
81 // Default rule definition: report all lone blocks
83 BlockStatement(node) {
84 if (isLoneBlock(node)) {
90 // ES6: report blocks without block-level bindings, or that's only child of another block
91 if (context.parserOptions.ecmaVersion >= 6) {
93 BlockStatement(node) {
94 if (isLoneBlock(node)) {
95 loneBlocks.push(node);
98 "BlockStatement:exit"(node) {
99 if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
103 node.parent.type === "BlockStatement" &&
104 node.parent.body.length === 1
111 ruleDef.VariableDeclaration = function(node) {
112 if (node.kind === "let" || node.kind === "const") {
117 ruleDef.FunctionDeclaration = function() {
118 if (context.getScope().isStrict) {
123 ruleDef.ClassDeclaration = markLoneBlock;