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 |
|
39 | var assert = require('assert');
|
40 |
|
41 | module.exports = function() {};
|
42 |
|
43 | module.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 | };
|