minor adjustment to readme
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-unreachable.js
1 /**
2  * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
3  * @author Joel Feenstra
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Helpers
9 //------------------------------------------------------------------------------
10
11 /**
12  * Checks whether or not a given variable declarator has the initializer.
13  * @param {ASTNode} node A VariableDeclarator node to check.
14  * @returns {boolean} `true` if the node has the initializer.
15  */
16 function isInitialized(node) {
17     return Boolean(node.init);
18 }
19
20 /**
21  * Checks whether or not a given code path segment is unreachable.
22  * @param {CodePathSegment} segment A CodePathSegment to check.
23  * @returns {boolean} `true` if the segment is unreachable.
24  */
25 function isUnreachable(segment) {
26     return !segment.reachable;
27 }
28
29 /**
30  * The class to distinguish consecutive unreachable statements.
31  */
32 class ConsecutiveRange {
33     constructor(sourceCode) {
34         this.sourceCode = sourceCode;
35         this.startNode = null;
36         this.endNode = null;
37     }
38
39     /**
40      * The location object of this range.
41      * @type {Object}
42      */
43     get location() {
44         return {
45             start: this.startNode.loc.start,
46             end: this.endNode.loc.end
47         };
48     }
49
50     /**
51      * `true` if this range is empty.
52      * @type {boolean}
53      */
54     get isEmpty() {
55         return !(this.startNode && this.endNode);
56     }
57
58     /**
59      * Checks whether the given node is inside of this range.
60      * @param {ASTNode|Token} node The node to check.
61      * @returns {boolean} `true` if the node is inside of this range.
62      */
63     contains(node) {
64         return (
65             node.range[0] >= this.startNode.range[0] &&
66             node.range[1] <= this.endNode.range[1]
67         );
68     }
69
70     /**
71      * Checks whether the given node is consecutive to this range.
72      * @param {ASTNode} node The node to check.
73      * @returns {boolean} `true` if the node is consecutive to this range.
74      */
75     isConsecutive(node) {
76         return this.contains(this.sourceCode.getTokenBefore(node));
77     }
78
79     /**
80      * Merges the given node to this range.
81      * @param {ASTNode} node The node to merge.
82      * @returns {void}
83      */
84     merge(node) {
85         this.endNode = node;
86     }
87
88     /**
89      * Resets this range by the given node or null.
90      * @param {ASTNode|null} node The node to reset, or null.
91      * @returns {void}
92      */
93     reset(node) {
94         this.startNode = this.endNode = node;
95     }
96 }
97
98 //------------------------------------------------------------------------------
99 // Rule Definition
100 //------------------------------------------------------------------------------
101
102 module.exports = {
103     meta: {
104         type: "problem",
105
106         docs: {
107             description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
108             category: "Possible Errors",
109             recommended: true,
110             url: "https://eslint.org/docs/rules/no-unreachable"
111         },
112
113         schema: []
114     },
115
116     create(context) {
117         let currentCodePath = null;
118
119         const range = new ConsecutiveRange(context.getSourceCode());
120
121         /**
122          * Reports a given node if it's unreachable.
123          * @param {ASTNode} node A statement node to report.
124          * @returns {void}
125          */
126         function reportIfUnreachable(node) {
127             let nextNode = null;
128
129             if (node && currentCodePath.currentSegments.every(isUnreachable)) {
130
131                 // Store this statement to distinguish consecutive statements.
132                 if (range.isEmpty) {
133                     range.reset(node);
134                     return;
135                 }
136
137                 // Skip if this statement is inside of the current range.
138                 if (range.contains(node)) {
139                     return;
140                 }
141
142                 // Merge if this statement is consecutive to the current range.
143                 if (range.isConsecutive(node)) {
144                     range.merge(node);
145                     return;
146                 }
147
148                 nextNode = node;
149             }
150
151             /*
152              * Report the current range since this statement is reachable or is
153              * not consecutive to the current range.
154              */
155             if (!range.isEmpty) {
156                 context.report({
157                     message: "Unreachable code.",
158                     loc: range.location,
159                     node: range.startNode
160                 });
161             }
162
163             // Update the current range.
164             range.reset(nextNode);
165         }
166
167         return {
168
169             // Manages the current code path.
170             onCodePathStart(codePath) {
171                 currentCodePath = codePath;
172             },
173
174             onCodePathEnd() {
175                 currentCodePath = currentCodePath.upper;
176             },
177
178             // Registers for all statement nodes (excludes FunctionDeclaration).
179             BlockStatement: reportIfUnreachable,
180             BreakStatement: reportIfUnreachable,
181             ClassDeclaration: reportIfUnreachable,
182             ContinueStatement: reportIfUnreachable,
183             DebuggerStatement: reportIfUnreachable,
184             DoWhileStatement: reportIfUnreachable,
185             ExpressionStatement: reportIfUnreachable,
186             ForInStatement: reportIfUnreachable,
187             ForOfStatement: reportIfUnreachable,
188             ForStatement: reportIfUnreachable,
189             IfStatement: reportIfUnreachable,
190             ImportDeclaration: reportIfUnreachable,
191             LabeledStatement: reportIfUnreachable,
192             ReturnStatement: reportIfUnreachable,
193             SwitchStatement: reportIfUnreachable,
194             ThrowStatement: reportIfUnreachable,
195             TryStatement: reportIfUnreachable,
196
197             VariableDeclaration(node) {
198                 if (node.kind !== "var" || node.declarations.some(isInitialized)) {
199                     reportIfUnreachable(node);
200                 }
201             },
202
203             WhileStatement: reportIfUnreachable,
204             WithStatement: reportIfUnreachable,
205             ExportNamedDeclaration: reportIfUnreachable,
206             ExportDefaultDeclaration: reportIfUnreachable,
207             ExportAllDeclaration: reportIfUnreachable,
208
209             "Program:exit"() {
210                 reportIfUnreachable();
211             }
212         };
213     }
214 };