max-depth.js 4.5 KB

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