UNPKG

3.23 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag blocks with no reason to exist
3 * @author Brandon Mills
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "disallow unnecessary nested blocks",
16 category: "Best Practices",
17 recommended: false
18 },
19
20 schema: []
21 },
22
23 create(context) {
24
25 // A stack of lone blocks to be checked for block-level bindings
26 const loneBlocks = [];
27 let ruleDef;
28
29 /**
30 * Reports a node as invalid.
31 * @param {ASTNode} node - The node to be reported.
32 * @returns {void}
33 */
34 function report(node) {
35 const parent = context.getAncestors().pop();
36
37 context.report(node, parent.type === "Program" ?
38 "Block is redundant." :
39 "Nested block is redundant."
40 );
41 }
42
43 /**
44 * Checks for any ocurrence of BlockStatement > BlockStatement or Program > BlockStatement
45 * @returns {boolean} True if the current node is a lone block.
46 */
47 function isLoneBlock() {
48 const parent = context.getAncestors().pop();
49
50 return parent.type === "BlockStatement" || parent.type === "Program";
51 }
52
53 /**
54 * Checks the enclosing block of the current node for block-level bindings,
55 * and "marks it" as valid if any.
56 * @returns {void}
57 */
58 function markLoneBlock() {
59 if (loneBlocks.length === 0) {
60 return;
61 }
62
63 const block = context.getAncestors().pop();
64
65 if (loneBlocks[loneBlocks.length - 1] === block) {
66 loneBlocks.pop();
67 }
68 }
69
70 // Default rule definition: report all lone blocks
71 ruleDef = {
72 BlockStatement(node) {
73 if (isLoneBlock(node)) {
74 report(node);
75 }
76 }
77 };
78
79 // ES6: report blocks without block-level bindings
80 if (context.parserOptions.ecmaVersion >= 6) {
81 ruleDef = {
82 BlockStatement(node) {
83 if (isLoneBlock(node)) {
84 loneBlocks.push(node);
85 }
86 },
87 "BlockStatement:exit"(node) {
88 if (loneBlocks.length > 0 && loneBlocks[loneBlocks.length - 1] === node) {
89 loneBlocks.pop();
90 report(node);
91 }
92 }
93 };
94
95 ruleDef.VariableDeclaration = function(node) {
96 if (node.kind === "let" || node.kind === "const") {
97 markLoneBlock(node);
98 }
99 };
100
101 ruleDef.FunctionDeclaration = function(node) {
102 if (context.getScope().isStrict) {
103 markLoneBlock(node);
104 }
105 };
106
107 ruleDef.ClassDeclaration = markLoneBlock;
108 }
109
110 return ruleDef;
111 }
112};