UNPKG

3.99 kBJavaScriptView Raw
1"use strict";
2/*
3 * eslint-plugin-sonarjs
4 * Copyright (C) 2018-2021 SonarSource SA
5 * mailto:info AT sonarsource DOT com
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21// https://sonarsource.github.io/rspec/#/rspec/S1751
22const nodes_1 = require("../utils/nodes");
23const docs_url_1 = require("../utils/docs-url");
24const rule = {
25 meta: {
26 type: 'problem',
27 docs: {
28 description: 'Loops with at most one iteration should be refactored',
29 category: 'Possible Errors',
30 recommended: 'error',
31 url: docs_url_1.default(__filename),
32 },
33 },
34 create(context) {
35 const loopingNodes = new Set();
36 const loops = new Set();
37 const loopsAndTheirSegments = [];
38 const currentCodePaths = [];
39 return {
40 ForStatement(node) {
41 loops.add(node);
42 },
43 WhileStatement(node) {
44 loops.add(node);
45 },
46 DoWhileStatement(node) {
47 loops.add(node);
48 },
49 onCodePathStart(codePath) {
50 currentCodePaths.push(codePath);
51 },
52 onCodePathEnd() {
53 currentCodePaths.pop();
54 },
55 'WhileStatement > *'(node) {
56 visitLoopChild(node.parent);
57 },
58 'ForStatement > *'(node) {
59 visitLoopChild(node.parent);
60 },
61 onCodePathSegmentLoop(_, toSegment, node) {
62 if (nodes_1.isContinueStatement(node)) {
63 loopsAndTheirSegments.forEach(({ segments, loop }) => {
64 if (segments.includes(toSegment)) {
65 loopingNodes.add(loop);
66 }
67 });
68 }
69 else {
70 loopingNodes.add(node);
71 }
72 },
73 'Program:exit'() {
74 loops.forEach(loop => {
75 if (!loopingNodes.has(loop)) {
76 context.report({
77 message: 'Refactor this loop to do more than one iteration.',
78 loc: context.getSourceCode().getFirstToken(loop).loc,
79 });
80 }
81 });
82 },
83 };
84 // Required to correctly process "continue" looping.
85 // When a loop has a "continue" statement, this "continue" statement triggers a "onCodePathSegmentLoop" event,
86 // and the corresponding event node is that "continue" statement. Current implementation is based on the fact
87 // that the "onCodePathSegmentLoop" event is triggerent with a loop node. To work this special case around,
88 // we visit loop children and collect corresponding path segments as these segments are "toSegment"
89 // in "onCodePathSegmentLoop" event.
90 function visitLoopChild(parent) {
91 if (currentCodePaths.length > 0) {
92 const currentCodePath = currentCodePaths[currentCodePaths.length - 1];
93 loopsAndTheirSegments.push({ segments: currentCodePath.currentSegments, loop: parent });
94 }
95 }
96 },
97};
98module.exports = rule;
99//# sourceMappingURL=no-one-iteration-loop.js.map
\No newline at end of file