source: imaps-frontend/node_modules/eslint/lib/rules/no-fallthrough.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 6.9 KB
RevLine 
[d565449]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
11const { directivesPattern } = require("../shared/directives");
12
13//------------------------------------------------------------------------------
14// Helpers
15//------------------------------------------------------------------------------
16
17const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
18
19/**
20 * Checks all segments in a set and returns true if any are reachable.
21 * @param {Set<CodePathSegment>} segments The segments to check.
22 * @returns {boolean} True if any segment is reachable; false otherwise.
23 */
24function isAnySegmentReachable(segments) {
25
26 for (const segment of segments) {
27 if (segment.reachable) {
28 return true;
29 }
30 }
31
32 return false;
33}
34
35/**
36 * Checks whether or not a given comment string is really a fallthrough comment and not an ESLint directive.
37 * @param {string} comment The comment string to check.
38 * @param {RegExp} fallthroughCommentPattern The regular expression used for checking for fallthrough comments.
39 * @returns {boolean} `true` if the comment string is truly a fallthrough comment.
40 */
41function isFallThroughComment(comment, fallthroughCommentPattern) {
42 return fallthroughCommentPattern.test(comment) && !directivesPattern.test(comment.trim());
43}
44
45/**
46 * Checks whether or not a given case has a fallthrough comment.
47 * @param {ASTNode} caseWhichFallsThrough SwitchCase node which falls through.
48 * @param {ASTNode} subsequentCase The case after caseWhichFallsThrough.
49 * @param {RuleContext} context A rule context which stores comments.
50 * @param {RegExp} fallthroughCommentPattern A pattern to match comment to.
51 * @returns {boolean} `true` if the case has a valid fallthrough comment.
52 */
53function hasFallthroughComment(caseWhichFallsThrough, subsequentCase, context, fallthroughCommentPattern) {
54 const sourceCode = context.sourceCode;
55
56 if (caseWhichFallsThrough.consequent.length === 1 && caseWhichFallsThrough.consequent[0].type === "BlockStatement") {
57 const trailingCloseBrace = sourceCode.getLastToken(caseWhichFallsThrough.consequent[0]);
58 const commentInBlock = sourceCode.getCommentsBefore(trailingCloseBrace).pop();
59
60 if (commentInBlock && isFallThroughComment(commentInBlock.value, fallthroughCommentPattern)) {
61 return true;
62 }
63 }
64
65 const comment = sourceCode.getCommentsBefore(subsequentCase).pop();
66
67 return Boolean(comment && isFallThroughComment(comment.value, fallthroughCommentPattern));
68}
69
70/**
71 * Checks whether a node and a token are separated by blank lines
72 * @param {ASTNode} node The node to check
73 * @param {Token} token The token to compare against
74 * @returns {boolean} `true` if there are blank lines between node and token
75 */
76function hasBlankLinesBetween(node, token) {
77 return token.loc.start.line > node.loc.end.line + 1;
78}
79
80//------------------------------------------------------------------------------
81// Rule Definition
82//------------------------------------------------------------------------------
83
84/** @type {import('../shared/types').Rule} */
85module.exports = {
86 meta: {
87 type: "problem",
88
89 docs: {
90 description: "Disallow fallthrough of `case` statements",
91 recommended: true,
92 url: "https://eslint.org/docs/latest/rules/no-fallthrough"
93 },
94
95 schema: [
96 {
97 type: "object",
98 properties: {
99 commentPattern: {
100 type: "string",
101 default: ""
102 },
103 allowEmptyCase: {
104 type: "boolean",
105 default: false
106 }
107 },
108 additionalProperties: false
109 }
110 ],
111 messages: {
112 case: "Expected a 'break' statement before 'case'.",
113 default: "Expected a 'break' statement before 'default'."
114 }
115 },
116
117 create(context) {
118 const options = context.options[0] || {};
119 const codePathSegments = [];
120 let currentCodePathSegments = new Set();
121 const sourceCode = context.sourceCode;
122 const allowEmptyCase = options.allowEmptyCase || false;
123
124 /*
125 * We need to use leading comments of the next SwitchCase node because
126 * trailing comments is wrong if semicolons are omitted.
127 */
128 let fallthroughCase = null;
129 let fallthroughCommentPattern = null;
130
131 if (options.commentPattern) {
132 fallthroughCommentPattern = new RegExp(options.commentPattern, "u");
133 } else {
134 fallthroughCommentPattern = DEFAULT_FALLTHROUGH_COMMENT;
135 }
136 return {
137
138 onCodePathStart() {
139 codePathSegments.push(currentCodePathSegments);
140 currentCodePathSegments = new Set();
141 },
142
143 onCodePathEnd() {
144 currentCodePathSegments = codePathSegments.pop();
145 },
146
147 onUnreachableCodePathSegmentStart(segment) {
148 currentCodePathSegments.add(segment);
149 },
150
151 onUnreachableCodePathSegmentEnd(segment) {
152 currentCodePathSegments.delete(segment);
153 },
154
155 onCodePathSegmentStart(segment) {
156 currentCodePathSegments.add(segment);
157 },
158
159 onCodePathSegmentEnd(segment) {
160 currentCodePathSegments.delete(segment);
161 },
162
163
164 SwitchCase(node) {
165
166 /*
167 * Checks whether or not there is a fallthrough comment.
168 * And reports the previous fallthrough node if that does not exist.
169 */
170
171 if (fallthroughCase && (!hasFallthroughComment(fallthroughCase, node, context, fallthroughCommentPattern))) {
172 context.report({
173 messageId: node.test ? "case" : "default",
174 node
175 });
176 }
177 fallthroughCase = null;
178 },
179
180 "SwitchCase:exit"(node) {
181 const nextToken = sourceCode.getTokenAfter(node);
182
183 /*
184 * `reachable` meant fall through because statements preceded by
185 * `break`, `return`, or `throw` are unreachable.
186 * And allows empty cases and the last case.
187 */
188 if (isAnySegmentReachable(currentCodePathSegments) &&
189 (node.consequent.length > 0 || (!allowEmptyCase && hasBlankLinesBetween(node, nextToken))) &&
190 node.parent.cases[node.parent.cases.length - 1] !== node) {
191 fallthroughCase = node;
192 }
193 }
194 };
195 }
196};
Note: See TracBrowser for help on using the repository browser.