.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-fallthrough.js
1 /**
2  * @fileoverview Rule to flag fall-through cases in switch statements.
3  * @author Matt DuVall <http://mattduvall.com/>
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const lodash = require("lodash");
12
13 //------------------------------------------------------------------------------
14 // Helpers
15 //------------------------------------------------------------------------------
16
17 const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
18
19 /**
20  * Checks whether or not a given node has a fallthrough comment.
21  * @param {ASTNode} node A SwitchCase node to get comments.
22  * @param {RuleContext} context A rule context which stores comments.
23  * @param {RegExp} fallthroughCommentPattern A pattern to match comment to.
24  * @returns {boolean} `true` if the node has a valid fallthrough comment.
25  */
26 function hasFallthroughComment(node, context, fallthroughCommentPattern) {
27     const sourceCode = context.getSourceCode();
28     const comment = lodash.last(sourceCode.getCommentsBefore(node));
29
30     return Boolean(comment && fallthroughCommentPattern.test(comment.value));
31 }
32
33 /**
34  * Checks whether or not a given code path segment is reachable.
35  * @param {CodePathSegment} segment A CodePathSegment to check.
36  * @returns {boolean} `true` if the segment is reachable.
37  */
38 function isReachable(segment) {
39     return segment.reachable;
40 }
41
42 /**
43  * Checks whether a node and a token are separated by blank lines
44  * @param {ASTNode} node The node to check
45  * @param {Token} token The token to compare against
46  * @returns {boolean} `true` if there are blank lines between node and token
47  */
48 function hasBlankLinesBetween(node, token) {
49     return token.loc.start.line > node.loc.end.line + 1;
50 }
51
52 //------------------------------------------------------------------------------
53 // Rule Definition
54 //------------------------------------------------------------------------------
55
56 module.exports = {
57     meta: {
58         type: "problem",
59
60         docs: {
61             description: "disallow fallthrough of `case` statements",
62             category: "Best Practices",
63             recommended: true,
64             url: "https://eslint.org/docs/rules/no-fallthrough"
65         },
66
67         schema: [
68             {
69                 type: "object",
70                 properties: {
71                     commentPattern: {
72                         type: "string",
73                         default: ""
74                     }
75                 },
76                 additionalProperties: false
77             }
78         ],
79         messages: {
80             case: "Expected a 'break' statement before 'case'.",
81             default: "Expected a 'break' statement before 'default'."
82         }
83     },
84
85     create(context) {
86         const options = context.options[0] || {};
87         let currentCodePath = null;
88         const sourceCode = context.getSourceCode();
89
90         /*
91          * We need to use leading comments of the next SwitchCase node because
92          * trailing comments is wrong if semicolons are omitted.
93          */
94         let fallthroughCase = null;
95         let fallthroughCommentPattern = null;
96
97         if (options.commentPattern) {
98             fallthroughCommentPattern = new RegExp(options.commentPattern, "u");
99         } else {
100             fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT;
101         }
102
103         return {
104             onCodePathStart(codePath) {
105                 currentCodePath = codePath;
106             },
107             onCodePathEnd() {
108                 currentCodePath = currentCodePath.upper;
109             },
110
111             SwitchCase(node) {
112
113                 /*
114                  * Checks whether or not there is a fallthrough comment.
115                  * And reports the previous fallthrough node if that does not exist.
116                  */
117                 if (fallthroughCase && !hasFallthroughComment(node, context, fallthroughCommentPattern)) {
118                     context.report({
119                         messageId: node.test ? "case" : "default",
120                         node
121                     });
122                 }
123                 fallthroughCase = null;
124             },
125
126             "SwitchCase:exit"(node) {
127                 const nextToken = sourceCode.getTokenAfter(node);
128
129                 /*
130                  * `reachable` meant fall through because statements preceded by
131                  * `break`, `return`, or `throw` are unreachable.
132                  * And allows empty cases and the last case.
133                  */
134                 if (currentCodePath.currentSegments.some(isReachable) &&
135                     (node.consequent.length > 0 || hasBlankLinesBetween(node, nextToken)) &&
136                     lodash.last(node.parent.cases) !== node) {
137                     fallthroughCase = node;
138                 }
139             }
140         };
141     }
142 };