func-style.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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",
  15. recommended: false,
  16. url: "https://eslint.org/docs/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. },
  30. additionalProperties: false
  31. }
  32. ],
  33. messages: {
  34. expression: "Expected a function expression.",
  35. declaration: "Expected a function declaration."
  36. }
  37. },
  38. create(context) {
  39. const style = context.options[0],
  40. allowArrowFunctions = context.options[1] && context.options[1].allowArrowFunctions,
  41. enforceDeclarations = (style === "declaration"),
  42. stack = [];
  43. const nodesToCheck = {
  44. FunctionDeclaration(node) {
  45. stack.push(false);
  46. if (!enforceDeclarations && node.parent.type !== "ExportDefaultDeclaration") {
  47. context.report({ node, messageId: "expression" });
  48. }
  49. },
  50. "FunctionDeclaration:exit"() {
  51. stack.pop();
  52. },
  53. FunctionExpression(node) {
  54. stack.push(false);
  55. if (enforceDeclarations && node.parent.type === "VariableDeclarator") {
  56. context.report({ node: node.parent, messageId: "declaration" });
  57. }
  58. },
  59. "FunctionExpression:exit"() {
  60. stack.pop();
  61. },
  62. ThisExpression() {
  63. if (stack.length > 0) {
  64. stack[stack.length - 1] = true;
  65. }
  66. }
  67. };
  68. if (!allowArrowFunctions) {
  69. nodesToCheck.ArrowFunctionExpression = function() {
  70. stack.push(false);
  71. };
  72. nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
  73. const hasThisExpr = stack.pop();
  74. if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
  75. context.report({ node: node.parent, messageId: "declaration" });
  76. }
  77. };
  78. }
  79. return nodesToCheck;
  80. }
  81. };