You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.7 KiB
149 lines
4.7 KiB
/** |
|
* @fileoverview Rule to flag use constant conditions |
|
* @author Christian Schulz <http://rndm.de> |
|
*/ |
|
|
|
"use strict"; |
|
|
|
const { isConstant } = require("./utils/ast-utils"); |
|
|
|
//------------------------------------------------------------------------------ |
|
// Helpers |
|
//------------------------------------------------------------------------------ |
|
|
|
//------------------------------------------------------------------------------ |
|
// Rule Definition |
|
//------------------------------------------------------------------------------ |
|
|
|
/** @type {import('../shared/types').Rule} */ |
|
module.exports = { |
|
meta: { |
|
type: "problem", |
|
|
|
docs: { |
|
description: "Disallow constant expressions in conditions", |
|
recommended: true, |
|
url: "https://eslint.org/docs/rules/no-constant-condition" |
|
}, |
|
|
|
schema: [ |
|
{ |
|
type: "object", |
|
properties: { |
|
checkLoops: { |
|
type: "boolean", |
|
default: true |
|
} |
|
}, |
|
additionalProperties: false |
|
} |
|
], |
|
|
|
messages: { |
|
unexpected: "Unexpected constant condition." |
|
} |
|
}, |
|
|
|
create(context) { |
|
const options = context.options[0] || {}, |
|
checkLoops = options.checkLoops !== false, |
|
loopSetStack = []; |
|
|
|
let loopsInCurrentScope = new Set(); |
|
|
|
//-------------------------------------------------------------------------- |
|
// Helpers |
|
//-------------------------------------------------------------------------- |
|
|
|
/** |
|
* Tracks when the given node contains a constant condition. |
|
* @param {ASTNode} node The AST node to check. |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function trackConstantConditionLoop(node) { |
|
if (node.test && isConstant(context.getScope(), node.test, true)) { |
|
loopsInCurrentScope.add(node); |
|
} |
|
} |
|
|
|
/** |
|
* Reports when the set contains the given constant condition node |
|
* @param {ASTNode} node The AST node to check. |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function checkConstantConditionLoopInSet(node) { |
|
if (loopsInCurrentScope.has(node)) { |
|
loopsInCurrentScope.delete(node); |
|
context.report({ node: node.test, messageId: "unexpected" }); |
|
} |
|
} |
|
|
|
/** |
|
* Reports when the given node contains a constant condition. |
|
* @param {ASTNode} node The AST node to check. |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function reportIfConstant(node) { |
|
if (node.test && isConstant(context.getScope(), node.test, true)) { |
|
context.report({ node: node.test, messageId: "unexpected" }); |
|
} |
|
} |
|
|
|
/** |
|
* Stores current set of constant loops in loopSetStack temporarily |
|
* and uses a new set to track constant loops |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function enterFunction() { |
|
loopSetStack.push(loopsInCurrentScope); |
|
loopsInCurrentScope = new Set(); |
|
} |
|
|
|
/** |
|
* Reports when the set still contains stored constant conditions |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function exitFunction() { |
|
loopsInCurrentScope = loopSetStack.pop(); |
|
} |
|
|
|
/** |
|
* Checks node when checkLoops option is enabled |
|
* @param {ASTNode} node The AST node to check. |
|
* @returns {void} |
|
* @private |
|
*/ |
|
function checkLoop(node) { |
|
if (checkLoops) { |
|
trackConstantConditionLoop(node); |
|
} |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// Public |
|
//-------------------------------------------------------------------------- |
|
|
|
return { |
|
ConditionalExpression: reportIfConstant, |
|
IfStatement: reportIfConstant, |
|
WhileStatement: checkLoop, |
|
"WhileStatement:exit": checkConstantConditionLoopInSet, |
|
DoWhileStatement: checkLoop, |
|
"DoWhileStatement:exit": checkConstantConditionLoopInSet, |
|
ForStatement: checkLoop, |
|
"ForStatement > .test": node => checkLoop(node.parent), |
|
"ForStatement:exit": checkConstantConditionLoopInSet, |
|
FunctionDeclaration: enterFunction, |
|
"FunctionDeclaration:exit": exitFunction, |
|
FunctionExpression: enterFunction, |
|
"FunctionExpression:exit": exitFunction, |
|
YieldExpression: () => loopsInCurrentScope.clear() |
|
}; |
|
|
|
} |
|
};
|
|
|