.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / func-names.js
1 /**
2  * @fileoverview Rule to warn when a function expression does not have a name.
3  * @author Kyle T. Nunery
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 /**
15  * Checks whether or not a given variable is a function name.
16  * @param {eslint-scope.Variable} variable A variable to check.
17  * @returns {boolean} `true` if the variable is a function name.
18  */
19 function isFunctionName(variable) {
20     return variable && variable.defs[0].type === "FunctionName";
21 }
22
23 //------------------------------------------------------------------------------
24 // Rule Definition
25 //------------------------------------------------------------------------------
26
27 module.exports = {
28     meta: {
29         type: "suggestion",
30
31         docs: {
32             description: "require or disallow named `function` expressions",
33             category: "Stylistic Issues",
34             recommended: false,
35             url: "https://eslint.org/docs/rules/func-names"
36         },
37
38         schema: {
39             definitions: {
40                 value: {
41                     enum: [
42                         "always",
43                         "as-needed",
44                         "never"
45                     ]
46                 }
47             },
48             items: [
49                 {
50                     $ref: "#/definitions/value"
51                 },
52                 {
53                     type: "object",
54                     properties: {
55                         generators: {
56                             $ref: "#/definitions/value"
57                         }
58                     },
59                     additionalProperties: false
60                 }
61             ]
62         },
63
64         messages: {
65             unnamed: "Unexpected unnamed {{name}}.",
66             named: "Unexpected named {{name}}."
67         }
68     },
69
70     create(context) {
71
72         const sourceCode = context.getSourceCode();
73
74         /**
75          * Returns the config option for the given node.
76          * @param {ASTNode} node A node to get the config for.
77          * @returns {string} The config option.
78          */
79         function getConfigForNode(node) {
80             if (
81                 node.generator &&
82                 context.options.length > 1 &&
83                 context.options[1].generators
84             ) {
85                 return context.options[1].generators;
86             }
87
88             return context.options[0] || "always";
89         }
90
91         /**
92          * Determines whether the current FunctionExpression node is a get, set, or
93          * shorthand method in an object literal or a class.
94          * @param {ASTNode} node A node to check.
95          * @returns {boolean} True if the node is a get, set, or shorthand method.
96          */
97         function isObjectOrClassMethod(node) {
98             const parent = node.parent;
99
100             return (parent.type === "MethodDefinition" || (
101                 parent.type === "Property" && (
102                     parent.method ||
103                     parent.kind === "get" ||
104                     parent.kind === "set"
105                 )
106             ));
107         }
108
109         /**
110          * Determines whether the current FunctionExpression node has a name that would be
111          * inferred from context in a conforming ES6 environment.
112          * @param {ASTNode} node A node to check.
113          * @returns {boolean} True if the node would have a name assigned automatically.
114          */
115         function hasInferredName(node) {
116             const parent = node.parent;
117
118             return isObjectOrClassMethod(node) ||
119                 (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) ||
120                 (parent.type === "Property" && parent.value === node) ||
121                 (parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) ||
122                 (parent.type === "AssignmentPattern" && parent.left.type === "Identifier" && parent.right === node);
123         }
124
125         /**
126          * Reports that an unnamed function should be named
127          * @param {ASTNode} node The node to report in the event of an error.
128          * @returns {void}
129          */
130         function reportUnexpectedUnnamedFunction(node) {
131             context.report({
132                 node,
133                 messageId: "unnamed",
134                 loc: astUtils.getFunctionHeadLoc(node, sourceCode),
135                 data: { name: astUtils.getFunctionNameWithKind(node) }
136             });
137         }
138
139         /**
140          * Reports that a named function should be unnamed
141          * @param {ASTNode} node The node to report in the event of an error.
142          * @returns {void}
143          */
144         function reportUnexpectedNamedFunction(node) {
145             context.report({
146                 node,
147                 messageId: "named",
148                 loc: astUtils.getFunctionHeadLoc(node, sourceCode),
149                 data: { name: astUtils.getFunctionNameWithKind(node) }
150             });
151         }
152
153         /**
154          * The listener for function nodes.
155          * @param {ASTNode} node function node
156          * @returns {void}
157          */
158         function handleFunction(node) {
159
160             // Skip recursive functions.
161             const nameVar = context.getDeclaredVariables(node)[0];
162
163             if (isFunctionName(nameVar) && nameVar.references.length > 0) {
164                 return;
165             }
166
167             const hasName = Boolean(node.id && node.id.name);
168             const config = getConfigForNode(node);
169
170             if (config === "never") {
171                 if (hasName && node.type !== "FunctionDeclaration") {
172                     reportUnexpectedNamedFunction(node);
173                 }
174             } else if (config === "as-needed") {
175                 if (!hasName && !hasInferredName(node)) {
176                     reportUnexpectedUnnamedFunction(node);
177                 }
178             } else {
179                 if (!hasName && !isObjectOrClassMethod(node)) {
180                     reportUnexpectedUnnamedFunction(node);
181                 }
182             }
183         }
184
185         return {
186             "FunctionExpression:exit": handleFunction,
187             "ExportDefaultDeclaration > FunctionDeclaration": handleFunction
188         };
189     }
190 };