max-statements.js 5.4 KB

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