func-style.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /**
  2. * @fileoverview Rule to enforce a particular function style
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. /** @type {import('../shared/types').Rule} */
  10. module.exports = {
  11. meta: {
  12. type: "suggestion",
  13. docs: {
  14. description: "Enforce the consistent use of either `function` declarations or expressions assigned to variables",
  15. recommended: false,
  16. url: "https://eslint.org/docs/latest/rules/func-style"
  17. },
  18. schema: [
  19. {
  20. enum: ["declaration", "expression"]
  21. },
  22. {
  23. type: "object",
  24. properties: {
  25. allowArrowFunctions: {
  26. type: "boolean",
  27. default: false
  28. },
  29. overrides: {
  30. type: "object",
  31. properties: {
  32. namedExports: {
  33. enum: ["declaration", "expression", "ignore"]
  34. }
  35. },
  36. additionalProperties: false
  37. }
  38. },
  39. additionalProperties: false
  40. }
  41. ],
  42. messages: {
  43. expression: "Expected a function expression.",
  44. declaration: "Expected a function declaration."
  45. }
  46. },
  47. create(context) {
  48. const style = context.options[0],
  49. allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions,
  50. enforceDeclarations = (style === "declaration"),
  51. exportFunctionStyle = context.options[1] && context.options[1].overrides && context.options[1].overrides.namedExports,
  52. stack = [];
  53. const nodesToCheck = {
  54. FunctionDeclaration(node) {
  55. stack.push(false);
  56. if (
  57. !enforceDeclarations &&
  58. node.parent.type !== "ExportDefaultDeclaration" &&
  59. (typeof exportFunctionStyle === "undefined" || node.parent.type !== "ExportNamedDeclaration")
  60. ) {
  61. context.report({ node, messageId: "expression" });
  62. }
  63. if (node.parent.type === "ExportNamedDeclaration" && exportFunctionStyle === "expression") {
  64. context.report({ node, messageId: "expression" });
  65. }
  66. },
  67. "FunctionDeclaration:exit"() {
  68. stack.pop();
  69. },
  70. FunctionExpression(node) {
  71. stack.push(false);
  72. if (
  73. enforceDeclarations &&
  74. node.parent.type === "VariableDeclarator" &&
  75. (typeof exportFunctionStyle === "undefined" || node.parent.parent.parent.type !== "ExportNamedDeclaration")
  76. ) {
  77. context.report({ node: node.parent, messageId: "declaration" });
  78. }
  79. if (
  80. node.parent.type === "VariableDeclarator" && node.parent.parent.parent.type === "ExportNamedDeclaration" &&
  81. exportFunctionStyle === "declaration"
  82. ) {
  83. context.report({ node: node.parent, messageId: "declaration" });
  84. }
  85. },
  86. "FunctionExpression:exit"() {
  87. stack.pop();
  88. },
  89. "ThisExpression, Super"() {
  90. if (stack.length > 0) {
  91. stack[stack.length - 1] = true;
  92. }
  93. }
  94. };
  95. if (!allowArrowFunctions) {
  96. nodesToCheck.ArrowFunctionExpression = function() {
  97. stack.push(false);
  98. };
  99. nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
  100. const hasThisOrSuperExpr = stack.pop();
  101. if (!hasThisOrSuperExpr && node.parent.type === "VariableDeclarator") {
  102. if (
  103. enforceDeclarations &&
  104. (typeof exportFunctionStyle === "undefined" || node.parent.parent.parent.type !== "ExportNamedDeclaration")
  105. ) {
  106. context.report({ node: node.parent, messageId: "declaration" });
  107. }
  108. if (node.parent.parent.parent.type === "ExportNamedDeclaration" && exportFunctionStyle === "declaration") {
  109. context.report({ node: node.parent, messageId: "declaration" });
  110. }
  111. }
  112. };
  113. }
  114. return nodesToCheck;
  115. }
  116. };