]> git.proxmox.com Git - pve-eslint.git/blame - eslint/lib/rules/func-names.js
change from CLIEngine to ESLint
[pve-eslint.git] / eslint / lib / rules / func-names.js
CommitLineData
eb39fafa
DC
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
12const 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 */
19function isFunctionName(variable) {
20 return variable && variable.defs[0].type === "FunctionName";
21}
22
23//------------------------------------------------------------------------------
24// Rule Definition
25//------------------------------------------------------------------------------
26
27module.exports = {
28 meta: {
29 type: "suggestion",
30
31 docs: {
32 description: "require or disallow named `function` expressions",
eb39fafa
DC
33 recommended: false,
34 url: "https://eslint.org/docs/rules/func-names"
35 },
36
37 schema: {
38 definitions: {
39 value: {
40 enum: [
41 "always",
42 "as-needed",
43 "never"
44 ]
45 }
46 },
47 items: [
48 {
49 $ref: "#/definitions/value"
50 },
51 {
52 type: "object",
53 properties: {
54 generators: {
55 $ref: "#/definitions/value"
56 }
57 },
58 additionalProperties: false
59 }
60 ]
61 },
62
63 messages: {
64 unnamed: "Unexpected unnamed {{name}}.",
65 named: "Unexpected named {{name}}."
66 }
67 },
68
69 create(context) {
70
71 const sourceCode = context.getSourceCode();
72
73 /**
74 * Returns the config option for the given node.
75 * @param {ASTNode} node A node to get the config for.
76 * @returns {string} The config option.
77 */
78 function getConfigForNode(node) {
79 if (
80 node.generator &&
81 context.options.length > 1 &&
82 context.options[1].generators
83 ) {
84 return context.options[1].generators;
85 }
86
87 return context.options[0] || "always";
88 }
89
90 /**
91 * Determines whether the current FunctionExpression node is a get, set, or
92 * shorthand method in an object literal or a class.
93 * @param {ASTNode} node A node to check.
94 * @returns {boolean} True if the node is a get, set, or shorthand method.
95 */
96 function isObjectOrClassMethod(node) {
97 const parent = node.parent;
98
99 return (parent.type === "MethodDefinition" || (
100 parent.type === "Property" && (
101 parent.method ||
102 parent.kind === "get" ||
103 parent.kind === "set"
104 )
105 ));
106 }
107
108 /**
109 * Determines whether the current FunctionExpression node has a name that would be
110 * inferred from context in a conforming ES6 environment.
111 * @param {ASTNode} node A node to check.
112 * @returns {boolean} True if the node would have a name assigned automatically.
113 */
114 function hasInferredName(node) {
115 const parent = node.parent;
116
117 return isObjectOrClassMethod(node) ||
118 (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) ||
119 (parent.type === "Property" && parent.value === node) ||
609c276f 120 (parent.type === "PropertyDefinition" && parent.value === node) ||
eb39fafa
DC
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};