summaryrefslogtreecommitdiff
path: root/tools/node_modules/eslint/lib/rules/no-cond-assign.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/node_modules/eslint/lib/rules/no-cond-assign.js')
-rw-r--r--tools/node_modules/eslint/lib/rules/no-cond-assign.js139
1 files changed, 139 insertions, 0 deletions
diff --git a/tools/node_modules/eslint/lib/rules/no-cond-assign.js b/tools/node_modules/eslint/lib/rules/no-cond-assign.js
new file mode 100644
index 0000000000..7c031c13f0
--- /dev/null
+++ b/tools/node_modules/eslint/lib/rules/no-cond-assign.js
@@ -0,0 +1,139 @@
+/**
+ * @fileoverview Rule to flag assignment in a conditional statement's test expression
+ * @author Stephen Murray <spmurrayzzz>
+ */
+"use strict";
+
+const astUtils = require("../ast-utils");
+
+const NODE_DESCRIPTIONS = {
+ DoWhileStatement: "a 'do...while' statement",
+ ForStatement: "a 'for' statement",
+ IfStatement: "an 'if' statement",
+ WhileStatement: "a 'while' statement"
+};
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ docs: {
+ description: "disallow assignment operators in conditional expressions",
+ category: "Possible Errors",
+ recommended: true
+ },
+
+ schema: [
+ {
+ enum: ["except-parens", "always"]
+ }
+ ]
+ },
+
+ create(context) {
+
+ const prohibitAssign = (context.options[0] || "except-parens");
+
+ const sourceCode = context.getSourceCode();
+
+ /**
+ * Check whether an AST node is the test expression for a conditional statement.
+ * @param {!Object} node The node to test.
+ * @returns {boolean} `true` if the node is the text expression for a conditional statement; otherwise, `false`.
+ */
+ function isConditionalTestExpression(node) {
+ return node.parent &&
+ node.parent.test &&
+ node === node.parent.test;
+ }
+
+ /**
+ * Given an AST node, perform a bottom-up search for the first ancestor that represents a conditional statement.
+ * @param {!Object} node The node to use at the start of the search.
+ * @returns {?Object} The closest ancestor node that represents a conditional statement.
+ */
+ function findConditionalAncestor(node) {
+ let currentAncestor = node;
+
+ do {
+ if (isConditionalTestExpression(currentAncestor)) {
+ return currentAncestor.parent;
+ }
+ } while ((currentAncestor = currentAncestor.parent) && !astUtils.isFunction(currentAncestor));
+
+ return null;
+ }
+
+ /**
+ * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
+ * @param {!Object} node The node to test.
+ * @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`.
+ */
+ function isParenthesisedTwice(node) {
+ const previousToken = sourceCode.getTokenBefore(node, 1),
+ nextToken = sourceCode.getTokenAfter(node, 1);
+
+ return astUtils.isParenthesised(sourceCode, node) &&
+ astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
+ astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
+ }
+
+ /**
+ * Check a conditional statement's test expression for top-level assignments that are not enclosed in parentheses.
+ * @param {!Object} node The node for the conditional statement.
+ * @returns {void}
+ */
+ function testForAssign(node) {
+ if (node.test &&
+ (node.test.type === "AssignmentExpression") &&
+ (node.type === "ForStatement"
+ ? !astUtils.isParenthesised(sourceCode, node.test)
+ : !isParenthesisedTwice(node.test)
+ )
+ ) {
+
+ // must match JSHint's error message
+ context.report({
+ node,
+ loc: node.test.loc.start,
+ message: "Expected a conditional expression and instead saw an assignment."
+ });
+ }
+ }
+
+ /**
+ * Check whether an assignment expression is descended from a conditional statement's test expression.
+ * @param {!Object} node The node for the assignment expression.
+ * @returns {void}
+ */
+ function testForConditionalAncestor(node) {
+ const ancestor = findConditionalAncestor(node);
+
+ if (ancestor) {
+ context.report({
+ node: ancestor,
+ message: "Unexpected assignment within {{type}}.",
+ data: {
+ type: NODE_DESCRIPTIONS[ancestor.type] || ancestor.type
+ }
+ });
+ }
+ }
+
+ if (prohibitAssign === "always") {
+ return {
+ AssignmentExpression: testForConditionalAncestor
+ };
+ }
+
+ return {
+ DoWhileStatement: testForAssign,
+ ForStatement: testForAssign,
+ IfStatement: testForAssign,
+ WhileStatement: testForAssign
+ };
+
+ }
+};