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