UNPKG

4.56 kBJavaScriptView Raw
1/**
2 * @fileoverview A rule to set the maximum depth block can be nested in a function.
3 * @author Ian Christian Myers
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "enforce a maximum depth that blocks can be nested",
16 category: "Stylistic Issues",
17 recommended: false
18 },
19
20 schema: [
21 {
22 oneOf: [
23 {
24 type: "integer",
25 minimum: 0
26 },
27 {
28 type: "object",
29 properties: {
30 maximum: {
31 type: "integer",
32 minimum: 0
33 },
34 max: {
35 type: "integer",
36 minimum: 0
37 }
38 },
39 additionalProperties: false
40 }
41 ]
42 }
43 ]
44 },
45
46 create(context) {
47
48 //--------------------------------------------------------------------------
49 // Helpers
50 //--------------------------------------------------------------------------
51
52 const functionStack = [],
53 option = context.options[0];
54 let maxDepth = 4;
55
56 if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
57 maxDepth = option.maximum;
58 }
59 if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
60 maxDepth = option.max;
61 }
62 if (typeof option === "number") {
63 maxDepth = option;
64 }
65
66 /**
67 * When parsing a new function, store it in our function stack
68 * @returns {void}
69 * @private
70 */
71 function startFunction() {
72 functionStack.push(0);
73 }
74
75 /**
76 * When parsing is done then pop out the reference
77 * @returns {void}
78 * @private
79 */
80 function endFunction() {
81 functionStack.pop();
82 }
83
84 /**
85 * Save the block and Evaluate the node
86 * @param {ASTNode} node node to evaluate
87 * @returns {void}
88 * @private
89 */
90 function pushBlock(node) {
91 const len = ++functionStack[functionStack.length - 1];
92
93 if (len > maxDepth) {
94 context.report({ node, message: "Blocks are nested too deeply ({{depth}}).", data: { depth: len } });
95 }
96 }
97
98 /**
99 * Pop the saved block
100 * @returns {void}
101 * @private
102 */
103 function popBlock() {
104 functionStack[functionStack.length - 1]--;
105 }
106
107 //--------------------------------------------------------------------------
108 // Public API
109 //--------------------------------------------------------------------------
110
111 return {
112 Program: startFunction,
113 FunctionDeclaration: startFunction,
114 FunctionExpression: startFunction,
115 ArrowFunctionExpression: startFunction,
116
117 IfStatement(node) {
118 if (node.parent.type !== "IfStatement") {
119 pushBlock(node);
120 }
121 },
122 SwitchStatement: pushBlock,
123 TryStatement: pushBlock,
124 DoWhileStatement: pushBlock,
125 WhileStatement: pushBlock,
126 WithStatement: pushBlock,
127 ForStatement: pushBlock,
128 ForInStatement: pushBlock,
129 ForOfStatement: pushBlock,
130
131 "IfStatement:exit": popBlock,
132 "SwitchStatement:exit": popBlock,
133 "TryStatement:exit": popBlock,
134 "DoWhileStatement:exit": popBlock,
135 "WhileStatement:exit": popBlock,
136 "WithStatement:exit": popBlock,
137 "ForStatement:exit": popBlock,
138 "ForInStatement:exit": popBlock,
139 "ForOfStatement:exit": popBlock,
140
141 "FunctionDeclaration:exit": endFunction,
142 "FunctionExpression:exit": endFunction,
143 "ArrowFunctionExpression:exit": endFunction,
144 "Program:exit": endFunction
145 };
146
147 }
148};