.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-useless-constructor.js
1 /**
2  * @fileoverview Rule to flag the use of redundant constructors in classes.
3  * @author Alberto Rodríguez
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Helpers
9 //------------------------------------------------------------------------------
10
11 /**
12  * Checks whether a given array of statements is a single call of `super`.
13  * @param {ASTNode[]} body An array of statements to check.
14  * @returns {boolean} `true` if the body is a single call of `super`.
15  */
16 function isSingleSuperCall(body) {
17     return (
18         body.length === 1 &&
19         body[0].type === "ExpressionStatement" &&
20         body[0].expression.type === "CallExpression" &&
21         body[0].expression.callee.type === "Super"
22     );
23 }
24
25 /**
26  * Checks whether a given node is a pattern which doesn't have any side effects.
27  * Default parameters and Destructuring parameters can have side effects.
28  * @param {ASTNode} node A pattern node.
29  * @returns {boolean} `true` if the node doesn't have any side effects.
30  */
31 function isSimple(node) {
32     return node.type === "Identifier" || node.type === "RestElement";
33 }
34
35 /**
36  * Checks whether a given array of expressions is `...arguments` or not.
37  * `super(...arguments)` passes all arguments through.
38  * @param {ASTNode[]} superArgs An array of expressions to check.
39  * @returns {boolean} `true` if the superArgs is `...arguments`.
40  */
41 function isSpreadArguments(superArgs) {
42     return (
43         superArgs.length === 1 &&
44         superArgs[0].type === "SpreadElement" &&
45         superArgs[0].argument.type === "Identifier" &&
46         superArgs[0].argument.name === "arguments"
47     );
48 }
49
50 /**
51  * Checks whether given 2 nodes are identifiers which have the same name or not.
52  * @param {ASTNode} ctorParam A node to check.
53  * @param {ASTNode} superArg A node to check.
54  * @returns {boolean} `true` if the nodes are identifiers which have the same
55  *      name.
56  */
57 function isValidIdentifierPair(ctorParam, superArg) {
58     return (
59         ctorParam.type === "Identifier" &&
60         superArg.type === "Identifier" &&
61         ctorParam.name === superArg.name
62     );
63 }
64
65 /**
66  * Checks whether given 2 nodes are a rest/spread pair which has the same values.
67  * @param {ASTNode} ctorParam A node to check.
68  * @param {ASTNode} superArg A node to check.
69  * @returns {boolean} `true` if the nodes are a rest/spread pair which has the
70  *      same values.
71  */
72 function isValidRestSpreadPair(ctorParam, superArg) {
73     return (
74         ctorParam.type === "RestElement" &&
75         superArg.type === "SpreadElement" &&
76         isValidIdentifierPair(ctorParam.argument, superArg.argument)
77     );
78 }
79
80 /**
81  * Checks whether given 2 nodes have the same value or not.
82  * @param {ASTNode} ctorParam A node to check.
83  * @param {ASTNode} superArg A node to check.
84  * @returns {boolean} `true` if the nodes have the same value or not.
85  */
86 function isValidPair(ctorParam, superArg) {
87     return (
88         isValidIdentifierPair(ctorParam, superArg) ||
89         isValidRestSpreadPair(ctorParam, superArg)
90     );
91 }
92
93 /**
94  * Checks whether the parameters of a constructor and the arguments of `super()`
95  * have the same values or not.
96  * @param {ASTNode} ctorParams The parameters of a constructor to check.
97  * @param {ASTNode} superArgs The arguments of `super()` to check.
98  * @returns {boolean} `true` if those have the same values.
99  */
100 function isPassingThrough(ctorParams, superArgs) {
101     if (ctorParams.length !== superArgs.length) {
102         return false;
103     }
104
105     for (let i = 0; i < ctorParams.length; ++i) {
106         if (!isValidPair(ctorParams[i], superArgs[i])) {
107             return false;
108         }
109     }
110
111     return true;
112 }
113
114 /**
115  * Checks whether the constructor body is a redundant super call.
116  * @param {Array} body constructor body content.
117  * @param {Array} ctorParams The params to check against super call.
118  * @returns {boolean} true if the constructor body is redundant
119  */
120 function isRedundantSuperCall(body, ctorParams) {
121     return (
122         isSingleSuperCall(body) &&
123         ctorParams.every(isSimple) &&
124         (
125             isSpreadArguments(body[0].expression.arguments) ||
126             isPassingThrough(ctorParams, body[0].expression.arguments)
127         )
128     );
129 }
130
131 //------------------------------------------------------------------------------
132 // Rule Definition
133 //------------------------------------------------------------------------------
134
135 module.exports = {
136     meta: {
137         type: "suggestion",
138
139         docs: {
140             description: "disallow unnecessary constructors",
141             category: "ECMAScript 6",
142             recommended: false,
143             url: "https://eslint.org/docs/rules/no-useless-constructor"
144         },
145
146         schema: [],
147
148         messages: {
149             noUselessConstructor: "Useless constructor."
150         }
151     },
152
153     create(context) {
154
155         /**
156          * Checks whether a node is a redundant constructor
157          * @param {ASTNode} node node to check
158          * @returns {void}
159          */
160         function checkForConstructor(node) {
161             if (node.kind !== "constructor") {
162                 return;
163             }
164
165             /*
166              * Prevent crashing on parsers which do not require class constructor
167              * to have a body, e.g. typescript and flow
168              */
169             if (!node.value.body) {
170                 return;
171             }
172
173             const body = node.value.body.body;
174             const ctorParams = node.value.params;
175             const superClass = node.parent.parent.superClass;
176
177             if (superClass ? isRedundantSuperCall(body, ctorParams) : (body.length === 0)) {
178                 context.report({
179                     node,
180                     messageId: "noUselessConstructor"
181                 });
182             }
183         }
184
185         return {
186             MethodDefinition: checkForConstructor
187         };
188     }
189 };