max-statements.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /**
  2. * @fileoverview A rule to set the maximum number of statements in a function.
  3. * @author Ian Christian Myers
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const lodash = require("lodash");
  10. const astUtils = require("../ast-utils");
  11. //------------------------------------------------------------------------------
  12. // Rule Definition
  13. //------------------------------------------------------------------------------
  14. module.exports = {
  15. meta: {
  16. docs: {
  17. description: "enforce a maximum number of statements allowed in function blocks",
  18. category: "Stylistic Issues",
  19. recommended: false,
  20. url: "https://eslint.org/docs/rules/max-statements"
  21. },
  22. schema: [
  23. {
  24. oneOf: [
  25. {
  26. type: "integer",
  27. minimum: 0
  28. },
  29. {
  30. type: "object",
  31. properties: {
  32. maximum: {
  33. type: "integer",
  34. minimum: 0
  35. },
  36. max: {
  37. type: "integer",
  38. minimum: 0
  39. }
  40. },
  41. additionalProperties: false
  42. }
  43. ]
  44. },
  45. {
  46. type: "object",
  47. properties: {
  48. ignoreTopLevelFunctions: {
  49. type: "boolean"
  50. }
  51. },
  52. additionalProperties: false
  53. }
  54. ]
  55. },
  56. create(context) {
  57. //--------------------------------------------------------------------------
  58. // Helpers
  59. //--------------------------------------------------------------------------
  60. const functionStack = [],
  61. option = context.options[0],
  62. ignoreTopLevelFunctions = context.options[1] && context.options[1].ignoreTopLevelFunctions || false,
  63. topLevelFunctions = [];
  64. let maxStatements = 10;
  65. if (typeof option === "object" && option.hasOwnProperty("maximum") && typeof option.maximum === "number") {
  66. maxStatements = option.maximum;
  67. }
  68. if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
  69. maxStatements = option.max;
  70. }
  71. if (typeof option === "number") {
  72. maxStatements = option;
  73. }
  74. /**
  75. * Reports a node if it has too many statements
  76. * @param {ASTNode} node node to evaluate
  77. * @param {int} count Number of statements in node
  78. * @param {int} max Maximum number of statements allowed
  79. * @returns {void}
  80. * @private
  81. */
  82. function reportIfTooManyStatements(node, count, max) {
  83. if (count > max) {
  84. const name = lodash.upperFirst(astUtils.getFunctionNameWithKind(node));
  85. context.report({
  86. node,
  87. message: "{{name}} has too many statements ({{count}}). Maximum allowed is {{max}}.",
  88. data: { name, count, max }
  89. });
  90. }
  91. }
  92. /**
  93. * When parsing a new function, store it in our function stack
  94. * @returns {void}
  95. * @private
  96. */
  97. function startFunction() {
  98. functionStack.push(0);
  99. }
  100. /**
  101. * Evaluate the node at the end of function
  102. * @param {ASTNode} node node to evaluate
  103. * @returns {void}
  104. * @private
  105. */
  106. function endFunction(node) {
  107. const count = functionStack.pop();
  108. if (ignoreTopLevelFunctions && functionStack.length === 0) {
  109. topLevelFunctions.push({ node, count });
  110. } else {
  111. reportIfTooManyStatements(node, count, maxStatements);
  112. }
  113. }
  114. /**
  115. * Increment the count of the functions
  116. * @param {ASTNode} node node to evaluate
  117. * @returns {void}
  118. * @private
  119. */
  120. function countStatements(node) {
  121. functionStack[functionStack.length - 1] += node.body.length;
  122. }
  123. //--------------------------------------------------------------------------
  124. // Public API
  125. //--------------------------------------------------------------------------
  126. return {
  127. FunctionDeclaration: startFunction,
  128. FunctionExpression: startFunction,
  129. ArrowFunctionExpression: startFunction,
  130. BlockStatement: countStatements,
  131. "FunctionDeclaration:exit": endFunction,
  132. "FunctionExpression:exit": endFunction,
  133. "ArrowFunctionExpression:exit": endFunction,
  134. "Program:exit"() {
  135. if (topLevelFunctions.length === 1) {
  136. return;
  137. }
  138. topLevelFunctions.forEach(element => {
  139. const count = element.count;
  140. const node = element.node;
  141. reportIfTooManyStatements(node, count, maxStatements);
  142. });
  143. }
  144. };
  145. }
  146. };