]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-constant-condition.js
import 8.23.1 source
[pve-eslint.git] / eslint / lib / rules / no-constant-condition.js
1 /**
2 * @fileoverview Rule to flag use constant conditions
3 * @author Christian Schulz <http://rndm.de>
4 */
5
6 "use strict";
7
8 const { isConstant } = require("./utils/ast-utils");
9
10 //------------------------------------------------------------------------------
11 // Helpers
12 //------------------------------------------------------------------------------
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 /** @type {import('../shared/types').Rule} */
19 module.exports = {
20 meta: {
21 type: "problem",
22
23 docs: {
24 description: "Disallow constant expressions in conditions",
25 recommended: true,
26 url: "https://eslint.org/docs/rules/no-constant-condition"
27 },
28
29 schema: [
30 {
31 type: "object",
32 properties: {
33 checkLoops: {
34 type: "boolean",
35 default: true
36 }
37 },
38 additionalProperties: false
39 }
40 ],
41
42 messages: {
43 unexpected: "Unexpected constant condition."
44 }
45 },
46
47 create(context) {
48 const options = context.options[0] || {},
49 checkLoops = options.checkLoops !== false,
50 loopSetStack = [];
51
52 let loopsInCurrentScope = new Set();
53
54 //--------------------------------------------------------------------------
55 // Helpers
56 //--------------------------------------------------------------------------
57
58 /**
59 * Tracks when the given node contains a constant condition.
60 * @param {ASTNode} node The AST node to check.
61 * @returns {void}
62 * @private
63 */
64 function trackConstantConditionLoop(node) {
65 if (node.test && isConstant(context.getScope(), node.test, true)) {
66 loopsInCurrentScope.add(node);
67 }
68 }
69
70 /**
71 * Reports when the set contains the given constant condition node
72 * @param {ASTNode} node The AST node to check.
73 * @returns {void}
74 * @private
75 */
76 function checkConstantConditionLoopInSet(node) {
77 if (loopsInCurrentScope.has(node)) {
78 loopsInCurrentScope.delete(node);
79 context.report({ node: node.test, messageId: "unexpected" });
80 }
81 }
82
83 /**
84 * Reports when the given node contains a constant condition.
85 * @param {ASTNode} node The AST node to check.
86 * @returns {void}
87 * @private
88 */
89 function reportIfConstant(node) {
90 if (node.test && isConstant(context.getScope(), node.test, true)) {
91 context.report({ node: node.test, messageId: "unexpected" });
92 }
93 }
94
95 /**
96 * Stores current set of constant loops in loopSetStack temporarily
97 * and uses a new set to track constant loops
98 * @returns {void}
99 * @private
100 */
101 function enterFunction() {
102 loopSetStack.push(loopsInCurrentScope);
103 loopsInCurrentScope = new Set();
104 }
105
106 /**
107 * Reports when the set still contains stored constant conditions
108 * @returns {void}
109 * @private
110 */
111 function exitFunction() {
112 loopsInCurrentScope = loopSetStack.pop();
113 }
114
115 /**
116 * Checks node when checkLoops option is enabled
117 * @param {ASTNode} node The AST node to check.
118 * @returns {void}
119 * @private
120 */
121 function checkLoop(node) {
122 if (checkLoops) {
123 trackConstantConditionLoop(node);
124 }
125 }
126
127 //--------------------------------------------------------------------------
128 // Public
129 //--------------------------------------------------------------------------
130
131 return {
132 ConditionalExpression: reportIfConstant,
133 IfStatement: reportIfConstant,
134 WhileStatement: checkLoop,
135 "WhileStatement:exit": checkConstantConditionLoopInSet,
136 DoWhileStatement: checkLoop,
137 "DoWhileStatement:exit": checkConstantConditionLoopInSet,
138 ForStatement: checkLoop,
139 "ForStatement > .test": node => checkLoop(node.parent),
140 "ForStatement:exit": checkConstantConditionLoopInSet,
141 FunctionDeclaration: enterFunction,
142 "FunctionDeclaration:exit": exitFunction,
143 FunctionExpression: enterFunction,
144 "FunctionExpression:exit": exitFunction,
145 YieldExpression: () => loopsInCurrentScope.clear()
146 };
147
148 }
149 };