UNPKG

2.74 kBJavaScriptView Raw
1/**
2 * Requires to return early in a function.
3 *
4 * Types: `Boolean`
5 *
6 * Values:
7 * - `true`: disallow to use of else if the corresponding `if` block contain a return.
8 *
9 * #### Example
10 *
11 * ```js
12 * "requireEarlyReturn": true
13 * ```
14 *
15 * ##### Valid
16 *
17 * ```js
18 * function test() {
19 * if (x) {
20 * return x;
21 * }
22 * return y;
23 * }
24 * ```
25 *
26 * ##### Invalid
27 *
28 * ```js
29 * function test() {
30 * if (x) {
31 * return x;
32 * } else {
33 * return y;
34 * }
35 * }
36 * ```
37 */
38
39var assert = require('assert');
40
41module.exports = function() {};
42
43module.exports.prototype = {
44 configure: function(options) {
45 assert(
46 options === true,
47 this.getOptionName() + ' option allow only the `true` value'
48 );
49 },
50
51 getOptionName: function() {
52 return 'requireEarlyReturn';
53 },
54
55 check: function(file, errors) {
56 function addError(entity) {
57 errors.add(
58 'Use of else after return',
59 entity
60 );
61 }
62
63 // Check if the IfStatement node contain a ReturnStatement.
64 // If the node has a block, check all the statements in backward order to see if there is one.
65 // This is to ensure that code like this will still return true:
66 //
67 // if (true) {
68 // return;
69 // eval();
70 // }
71 function hasNodeReturn(node) {
72 if (node.type === 'BlockStatement') {
73 for (var i = node.body.length - 1; i >= 0; i--) {
74 if (node.body[i].type === 'ReturnStatement') {
75 return true;
76 }
77 }
78 return false;
79 }
80 return node.type === 'ReturnStatement';
81 }
82
83 file.iterateNodesByType('IfStatement', function(node) {
84 if (!node.alternate) {
85 return;
86 }
87
88 // Check if all the parents have a return statement, if not continue to the following IfStatement node.
89 //
90 // Example:
91 //
92 // if (foo) {
93 // return;
94 // } else if (bar) { <-- error
95 // bar();
96 // } else if (baz) { <-- safe
97 // return baz();
98 // } else { <-- safe
99 // bas();
100 // }
101 for (var nodeIf = node; nodeIf && nodeIf.type === 'IfStatement'; nodeIf = nodeIf.parentElement) {
102 if (nodeIf.alternate && !hasNodeReturn(nodeIf.consequent)) {
103 return;
104 }
105 }
106
107 return addError(file.getPrevToken(file.getFirstNodeToken(node.alternate)));
108 });
109 }
110};