massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / consistent-return.js
1 /**
2  * @fileoverview Rule to flag consistent return values
3  * @author Nicholas C. Zakas
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12 const { upperCaseFirst } = require("../shared/string-utils");
13
14 //------------------------------------------------------------------------------
15 // Helpers
16 //------------------------------------------------------------------------------
17
18 /**
19  * Checks whether or not a given code path segment is unreachable.
20  * @param {CodePathSegment} segment A CodePathSegment to check.
21  * @returns {boolean} `true` if the segment is unreachable.
22  */
23 function isUnreachable(segment) {
24     return !segment.reachable;
25 }
26
27 /**
28  * Checks whether a given node is a `constructor` method in an ES6 class
29  * @param {ASTNode} node A node to check
30  * @returns {boolean} `true` if the node is a `constructor` method
31  */
32 function isClassConstructor(node) {
33     return node.type === "FunctionExpression" &&
34         node.parent &&
35         node.parent.type === "MethodDefinition" &&
36         node.parent.kind === "constructor";
37 }
38
39 //------------------------------------------------------------------------------
40 // Rule Definition
41 //------------------------------------------------------------------------------
42
43 module.exports = {
44     meta: {
45         type: "suggestion",
46
47         docs: {
48             description: "require `return` statements to either always or never specify values",
49             category: "Best Practices",
50             recommended: false,
51             url: "https://eslint.org/docs/rules/consistent-return"
52         },
53
54         schema: [{
55             type: "object",
56             properties: {
57                 treatUndefinedAsUnspecified: {
58                     type: "boolean",
59                     default: false
60                 }
61             },
62             additionalProperties: false
63         }],
64
65         messages: {
66             missingReturn: "Expected to return a value at the end of {{name}}.",
67             missingReturnValue: "{{name}} expected a return value.",
68             unexpectedReturnValue: "{{name}} expected no return value."
69         }
70     },
71
72     create(context) {
73         const options = context.options[0] || {};
74         const treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true;
75         let funcInfo = null;
76
77         /**
78          * Checks whether of not the implicit returning is consistent if the last
79          * code path segment is reachable.
80          * @param {ASTNode} node A program/function node to check.
81          * @returns {void}
82          */
83         function checkLastSegment(node) {
84             let loc, name;
85
86             /*
87              * Skip if it expected no return value or unreachable.
88              * When unreachable, all paths are returned or thrown.
89              */
90             if (!funcInfo.hasReturnValue ||
91                 funcInfo.codePath.currentSegments.every(isUnreachable) ||
92                 astUtils.isES5Constructor(node) ||
93                 isClassConstructor(node)
94             ) {
95                 return;
96             }
97
98             // Adjust a location and a message.
99             if (node.type === "Program") {
100
101                 // The head of program.
102                 loc = { line: 1, column: 0 };
103                 name = "program";
104             } else if (node.type === "ArrowFunctionExpression") {
105
106                 // `=>` token
107                 loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc;
108             } else if (
109                 node.parent.type === "MethodDefinition" ||
110                 (node.parent.type === "Property" && node.parent.method)
111             ) {
112
113                 // Method name.
114                 loc = node.parent.key.loc;
115             } else {
116
117                 // Function name or `function` keyword.
118                 loc = (node.id || context.getSourceCode().getFirstToken(node)).loc;
119             }
120
121             if (!name) {
122                 name = astUtils.getFunctionNameWithKind(node);
123             }
124
125             // Reports.
126             context.report({
127                 node,
128                 loc,
129                 messageId: "missingReturn",
130                 data: { name }
131             });
132         }
133
134         return {
135
136             // Initializes/Disposes state of each code path.
137             onCodePathStart(codePath, node) {
138                 funcInfo = {
139                     upper: funcInfo,
140                     codePath,
141                     hasReturn: false,
142                     hasReturnValue: false,
143                     messageId: "",
144                     node
145                 };
146             },
147             onCodePathEnd() {
148                 funcInfo = funcInfo.upper;
149             },
150
151             // Reports a given return statement if it's inconsistent.
152             ReturnStatement(node) {
153                 const argument = node.argument;
154                 let hasReturnValue = Boolean(argument);
155
156                 if (treatUndefinedAsUnspecified && hasReturnValue) {
157                     hasReturnValue = !astUtils.isSpecificId(argument, "undefined") && argument.operator !== "void";
158                 }
159
160                 if (!funcInfo.hasReturn) {
161                     funcInfo.hasReturn = true;
162                     funcInfo.hasReturnValue = hasReturnValue;
163                     funcInfo.messageId = hasReturnValue ? "missingReturnValue" : "unexpectedReturnValue";
164                     funcInfo.data = {
165                         name: funcInfo.node.type === "Program"
166                             ? "Program"
167                             : upperCaseFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
168                     };
169                 } else if (funcInfo.hasReturnValue !== hasReturnValue) {
170                     context.report({
171                         node,
172                         messageId: funcInfo.messageId,
173                         data: funcInfo.data
174                     });
175                 }
176             },
177
178             // Reports a given program/function if the implicit returning is not consistent.
179             "Program:exit": checkLastSegment,
180             "FunctionDeclaration:exit": checkLastSegment,
181             "FunctionExpression:exit": checkLastSegment,
182             "ArrowFunctionExpression:exit": checkLastSegment
183         };
184     }
185 };