UNPKG

4.72 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to disallow empty functions.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const astUtils = require("./utils/ast-utils");
13
14//------------------------------------------------------------------------------
15// Helpers
16//------------------------------------------------------------------------------
17
18const ALLOW_OPTIONS = Object.freeze([
19 "functions",
20 "arrowFunctions",
21 "generatorFunctions",
22 "methods",
23 "generatorMethods",
24 "getters",
25 "setters",
26 "constructors"
27]);
28
29/**
30 * Gets the kind of a given function node.
31 *
32 * @param {ASTNode} node - A function node to get. This is one of
33 * an ArrowFunctionExpression, a FunctionDeclaration, or a
34 * FunctionExpression.
35 * @returns {string} The kind of the function. This is one of "functions",
36 * "arrowFunctions", "generatorFunctions", "asyncFunctions", "methods",
37 * "generatorMethods", "asyncMethods", "getters", "setters", and
38 * "constructors".
39 */
40function getKind(node) {
41 const parent = node.parent;
42 let kind = "";
43
44 if (node.type === "ArrowFunctionExpression") {
45 return "arrowFunctions";
46 }
47
48 // Detects main kind.
49 if (parent.type === "Property") {
50 if (parent.kind === "get") {
51 return "getters";
52 }
53 if (parent.kind === "set") {
54 return "setters";
55 }
56 kind = parent.method ? "methods" : "functions";
57
58 } else if (parent.type === "MethodDefinition") {
59 if (parent.kind === "get") {
60 return "getters";
61 }
62 if (parent.kind === "set") {
63 return "setters";
64 }
65 if (parent.kind === "constructor") {
66 return "constructors";
67 }
68 kind = "methods";
69
70 } else {
71 kind = "functions";
72 }
73
74 // Detects prefix.
75 let prefix = "";
76
77 if (node.generator) {
78 prefix = "generator";
79 } else if (node.async) {
80 prefix = "async";
81 } else {
82 return kind;
83 }
84 return prefix + kind[0].toUpperCase() + kind.slice(1);
85}
86
87//------------------------------------------------------------------------------
88// Rule Definition
89//------------------------------------------------------------------------------
90
91module.exports = {
92 meta: {
93 type: "suggestion",
94
95 docs: {
96 description: "disallow empty functions",
97 category: "Best Practices",
98 recommended: false,
99 url: "https://eslint.org/docs/rules/no-empty-function"
100 },
101
102 schema: [
103 {
104 type: "object",
105 properties: {
106 allow: {
107 type: "array",
108 items: { enum: ALLOW_OPTIONS },
109 uniqueItems: true
110 }
111 },
112 additionalProperties: false
113 }
114 ],
115
116 messages: {
117 unexpected: "Unexpected empty {{name}}."
118 }
119 },
120
121 create(context) {
122 const options = context.options[0] || {};
123 const allowed = options.allow || [];
124
125 const sourceCode = context.getSourceCode();
126
127 /**
128 * Reports a given function node if the node matches the following patterns.
129 *
130 * - Not allowed by options.
131 * - The body is empty.
132 * - The body doesn't have any comments.
133 *
134 * @param {ASTNode} node - A function node to report. This is one of
135 * an ArrowFunctionExpression, a FunctionDeclaration, or a
136 * FunctionExpression.
137 * @returns {void}
138 */
139 function reportIfEmpty(node) {
140 const kind = getKind(node);
141 const name = astUtils.getFunctionNameWithKind(node);
142 const innerComments = sourceCode.getTokens(node.body, {
143 includeComments: true,
144 filter: astUtils.isCommentToken
145 });
146
147 if (allowed.indexOf(kind) === -1 &&
148 node.body.type === "BlockStatement" &&
149 node.body.body.length === 0 &&
150 innerComments.length === 0
151 ) {
152 context.report({
153 node,
154 loc: node.body.loc.start,
155 messageId: "unexpected",
156 data: { name }
157 });
158 }
159 }
160
161 return {
162 ArrowFunctionExpression: reportIfEmpty,
163 FunctionDeclaration: reportIfEmpty,
164 FunctionExpression: reportIfEmpty
165 };
166 }
167};