UNPKG

4.74 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 "asyncFunctions",
28 "asyncMethods"
29]);
30
31/**
32 * Gets the kind of a given function node.
33 * @param {ASTNode} node A function node to get. This is one of
34 * an ArrowFunctionExpression, a FunctionDeclaration, or a
35 * FunctionExpression.
36 * @returns {string} The kind of the function. This is one of "functions",
37 * "arrowFunctions", "generatorFunctions", "asyncFunctions", "methods",
38 * "generatorMethods", "asyncMethods", "getters", "setters", and
39 * "constructors".
40 */
41function getKind(node) {
42 const parent = node.parent;
43 let kind = "";
44
45 if (node.type === "ArrowFunctionExpression") {
46 return "arrowFunctions";
47 }
48
49 // Detects main kind.
50 if (parent.type === "Property") {
51 if (parent.kind === "get") {
52 return "getters";
53 }
54 if (parent.kind === "set") {
55 return "setters";
56 }
57 kind = parent.method ? "methods" : "functions";
58
59 } else if (parent.type === "MethodDefinition") {
60 if (parent.kind === "get") {
61 return "getters";
62 }
63 if (parent.kind === "set") {
64 return "setters";
65 }
66 if (parent.kind === "constructor") {
67 return "constructors";
68 }
69 kind = "methods";
70
71 } else {
72 kind = "functions";
73 }
74
75 // Detects prefix.
76 let prefix = "";
77
78 if (node.generator) {
79 prefix = "generator";
80 } else if (node.async) {
81 prefix = "async";
82 } else {
83 return kind;
84 }
85 return prefix + kind[0].toUpperCase() + kind.slice(1);
86}
87
88//------------------------------------------------------------------------------
89// Rule Definition
90//------------------------------------------------------------------------------
91
92module.exports = {
93 meta: {
94 type: "suggestion",
95
96 docs: {
97 description: "disallow empty functions",
98 category: "Best Practices",
99 recommended: false,
100 url: "https://eslint.org/docs/rules/no-empty-function"
101 },
102
103 schema: [
104 {
105 type: "object",
106 properties: {
107 allow: {
108 type: "array",
109 items: { enum: ALLOW_OPTIONS },
110 uniqueItems: true
111 }
112 },
113 additionalProperties: false
114 }
115 ],
116
117 messages: {
118 unexpected: "Unexpected empty {{name}}."
119 }
120 },
121
122 create(context) {
123 const options = context.options[0] || {};
124 const allowed = options.allow || [];
125
126 const sourceCode = context.getSourceCode();
127
128 /**
129 * Reports a given function node if the node matches the following patterns.
130 *
131 * - Not allowed by options.
132 * - The body is empty.
133 * - The body doesn't have any comments.
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,
155 messageId: "unexpected",
156 data: { name }
157 });
158 }
159 }
160
161 return {
162 ArrowFunctionExpression: reportIfEmpty,
163 FunctionDeclaration: reportIfEmpty,
164 FunctionExpression: reportIfEmpty
165 };
166 }
167};