diff --git a/lib/rules/yoda.js b/lib/rules/yoda.js index c4ff3f81938..f1159e5255d 100644 --- a/lib/rules/yoda.js +++ b/lib/rules/yoda.js @@ -20,7 +20,7 @@ const astUtils = require("./utils/ast-utils"); * @returns {boolean} Whether or not it is a comparison operator. */ function isComparisonOperator(operator) { - return (/^(==|===|!=|!==|<|>|<=|>=)$/u).test(operator); + return /^(==|===|!=|!==|<|>|<=|>=)$/u.test(operator); } /** @@ -29,7 +29,7 @@ function isComparisonOperator(operator) { * @returns {boolean} Whether or not it is an equality operator. */ function isEqualityOperator(operator) { - return (/^(==|===)$/u).test(operator); + return /^(==|===)$/u.test(operator); } /** @@ -50,10 +50,12 @@ function isRangeTestOperator(operator) { * real literal and should be treated as such. */ function isNegativeNumericLiteral(node) { - return (node.type === "UnaryExpression" && + return ( + node.type === "UnaryExpression" && node.operator === "-" && node.prefix && - astUtils.isNumericLiteral(node.argument)); + astUtils.isNumericLiteral(node.argument) + ); } /** @@ -71,25 +73,21 @@ function isStaticTemplateLiteral(node) { * @returns {boolean} True if the node should be treated as a single Literal node. */ function looksLikeLiteral(node) { - return isNegativeNumericLiteral(node) || - isStaticTemplateLiteral(node); + return isNegativeNumericLiteral(node) || isStaticTemplateLiteral(node); } /** * Attempts to derive a Literal node from nodes that are treated like literals. * @param {ASTNode} node Node to normalize. - * @param {number} [defaultValue] The default value to be returned if the node - * is not a Literal. * @returns {ASTNode} One of the following options. * 1. The original node if the node is already a Literal * 2. A normalized Literal node with the negative number as the value if the * node represents a negative number literal. * 3. A normalized Literal node with the string as the value if the node is * a Template Literal without expression. - * 4. The Literal node which has the `defaultValue` argument if it exists. - * 5. Otherwise `null`. + * 4. Otherwise `null`. */ -function getNormalizedLiteral(node, defaultValue) { +function getNormalizedLiteral(node) { if (node.type === "Literal") { return node; } @@ -110,14 +108,6 @@ function getNormalizedLiteral(node, defaultValue) { }; } - if (defaultValue) { - return { - type: "Literal", - value: defaultValue, - raw: String(defaultValue) - }; - } - return null; } @@ -183,7 +173,7 @@ module.exports = { type: "suggestion", docs: { - description: "require or disallow \"Yoda\" conditions", + description: 'require or disallow "Yoda" conditions', category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/yoda" @@ -211,16 +201,19 @@ module.exports = { fixable: "code", messages: { - expected: "Expected literal to be on the {{expectedSide}} side of {{operator}}." + expected: + "Expected literal to be on the {{expectedSide}} side of {{operator}}." } }, create(context) { // Default to "never" (!always) if no option - const always = (context.options[0] === "always"); - const exceptRange = (context.options[1] && context.options[1].exceptRange); - const onlyEquality = (context.options[1] && context.options[1].onlyEquality); + const always = context.options[0] === "always"; + const exceptRange = + context.options[1] && context.options[1].exceptRange; + const onlyEquality = + context.options[1] && context.options[1].onlyEquality; const sourceCode = context.getSourceCode(); @@ -243,13 +236,23 @@ module.exports = { * @returns {boolean} Whether node is a "between" range test. */ function isBetweenTest() { - let leftLiteral, rightLiteral; + if (node.operator === "&&" && same(left.right, right.left)) { + const leftLiteral = getNormalizedLiteral(left.left); + const rightLiteral = getNormalizedLiteral(right.right); + + if (leftLiteral === null && rightLiteral === null) { + return false; + } - return (node.operator === "&&" && - (leftLiteral = getNormalizedLiteral(left.left)) && - (rightLiteral = getNormalizedLiteral(right.right, Number.POSITIVE_INFINITY)) && - leftLiteral.value <= rightLiteral.value && - same(left.right, right.left)); + if (rightLiteral === null || leftLiteral === null) { + return true; + } + + if (leftLiteral.value <= rightLiteral.value) { + return true; + } + } + return false; } /** @@ -257,13 +260,24 @@ module.exports = { * @returns {boolean} Whether node is an "outside" range test. */ function isOutsideTest() { - let leftLiteral, rightLiteral; + if (node.operator === "||" && same(left.left, right.right)) { + const leftLiteral = getNormalizedLiteral(left.right); + const rightLiteral = getNormalizedLiteral(right.left); + + if (leftLiteral === null && rightLiteral === null) { + return false; + } + + if (rightLiteral === null || leftLiteral === null) { + return true; + } + + if (leftLiteral.value <= rightLiteral.value) { + return true; + } + } - return (node.operator === "||" && - (leftLiteral = getNormalizedLiteral(left.right, Number.NEGATIVE_INFINITY)) && - (rightLiteral = getNormalizedLiteral(right.left)) && - leftLiteral.value <= rightLiteral.value && - same(left.left, right.right)); + return false; } /** @@ -276,13 +290,15 @@ module.exports = { return astUtils.isParenthesised(sourceCode, node); } - return (node.type === "LogicalExpression" && + return ( + node.type === "LogicalExpression" && left.type === "BinaryExpression" && right.type === "BinaryExpression" && isRangeTestOperator(left.operator) && isRangeTestOperator(right.operator) && (isBetweenTest() || isOutsideTest()) && - isParenWrapped()); + isParenWrapped() + ); } const OPERATOR_FLIP_MAP = { @@ -303,21 +319,52 @@ module.exports = { */ function getFlippedString(node) { const tokenBefore = sourceCode.getTokenBefore(node); - const operatorToken = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator); - const textBeforeOperator = sourceCode.getText().slice(sourceCode.getTokenBefore(operatorToken).range[1], operatorToken.range[0]); - const textAfterOperator = sourceCode.getText().slice(operatorToken.range[1], sourceCode.getTokenAfter(operatorToken).range[0]); - const leftText = sourceCode.getText().slice(node.range[0], sourceCode.getTokenBefore(operatorToken).range[1]); + const operatorToken = sourceCode.getFirstTokenBetween( + node.left, + node.right, + token => token.value === node.operator + ); + const textBeforeOperator = sourceCode + .getText() + .slice( + sourceCode.getTokenBefore(operatorToken).range[1], + operatorToken.range[0] + ); + const textAfterOperator = sourceCode + .getText() + .slice( + operatorToken.range[1], + sourceCode.getTokenAfter(operatorToken).range[0] + ); + const leftText = sourceCode + .getText() + .slice( + node.range[0], + sourceCode.getTokenBefore(operatorToken).range[1] + ); const firstRightToken = sourceCode.getTokenAfter(operatorToken); - const rightText = sourceCode.getText().slice(firstRightToken.range[0], node.range[1]); + const rightText = sourceCode + .getText() + .slice(firstRightToken.range[0], node.range[1]); let prefix = ""; - if (tokenBefore && tokenBefore.range[1] === node.range[0] && - !astUtils.canTokensBeAdjacent(tokenBefore, firstRightToken)) { + if ( + tokenBefore && + tokenBefore.range[1] === node.range[0] && + !astUtils.canTokensBeAdjacent(tokenBefore, firstRightToken) + ) { prefix = " "; } - return prefix + rightText + textBeforeOperator + OPERATOR_FLIP_MAP[operatorToken.value] + textAfterOperator + leftText; + return ( + prefix + + rightText + + textBeforeOperator + + OPERATOR_FLIP_MAP[operatorToken.value] + + textAfterOperator + + leftText + ); } //-------------------------------------------------------------------------- @@ -331,8 +378,12 @@ module.exports = { // If `expectedLiteral` is not a literal, and `expectedNonLiteral` is a literal, raise an error. if ( - (expectedNonLiteral.type === "Literal" || looksLikeLiteral(expectedNonLiteral)) && - !(expectedLiteral.type === "Literal" || looksLikeLiteral(expectedLiteral)) && + (expectedNonLiteral.type === "Literal" || + looksLikeLiteral(expectedNonLiteral)) && + !( + expectedLiteral.type === "Literal" || + looksLikeLiteral(expectedLiteral) + ) && !(!isEqualityOperator(node.operator) && onlyEquality) && isComparisonOperator(node.operator) && !(exceptRange && isRangeTest(context.getAncestors().pop())) @@ -344,12 +395,11 @@ module.exports = { operator: node.operator, expectedSide: always ? "left" : "right" }, - fix: fixer => fixer.replaceText(node, getFlippedString(node)) + fix: fixer => + fixer.replaceText(node, getFlippedString(node)) }); } - } }; - } }; diff --git a/tests/lib/rules/yoda.js b/tests/lib/rules/yoda.js index c0d76ca9b7c..43449401873 100644 --- a/tests/lib/rules/yoda.js +++ b/tests/lib/rules/yoda.js @@ -21,148 +21,314 @@ ruleTester.run("yoda", rule, { valid: [ // "never" mode - { code: "if (value === \"red\") {}", options: ["never"] }, + { code: 'if (value === "red") {}', options: ["never"] }, { code: "if (value === value) {}", options: ["never"] }, { code: "if (value != 5) {}", options: ["never"] }, { code: "if (5 & foo) {}", options: ["never"] }, { code: "if (5 === 4) {}", options: ["never"] }, - { code: "if (value === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`red` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`${foo}` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`${\"\"}` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`${\"red\"}` === foo) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (b > `a` && b > `a`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`b` > `a` && \"b\" > \"a\") {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } }, + { + code: "if (value === `red`) {}", + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (`red` === `red`) {}", + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (`${foo}` === `red`) {}", + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (`${""}` === `red`) {}', + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (`${"red"}` === foo) {}', + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (b > `a` && b > `a`) {}", + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (`b` > `a` && "b" > "a") {}', + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, // "always" mode - { code: "if (\"blue\" === value) {}", options: ["always"] }, + { code: 'if ("blue" === value) {}', options: ["always"] }, { code: "if (value === value) {}", options: ["always"] }, { code: "if (4 != value) {}", options: ["always"] }, { code: "if (foo & 4) {}", options: ["always"] }, { code: "if (5 === 4) {}", options: ["always"] }, - { code: "if (`red` === value) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`red` === `red`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`red` === `${foo}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`red` === `${\"\"}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (foo === `${\"red\"}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`a` > b && `a` > b) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (`b` > `a` && \"b\" > \"a\") {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } }, + { + code: "if (`red` === value) {}", + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (`red` === `red`) {}", + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (`red` === `${foo}`) {}", + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (`red` === `${""}`) {}', + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (foo === `${"red"}`) {}', + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (`a` > b && `a` > b) {}", + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: 'if (`b` > `a` && "b" > "a") {}', + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, // Range exception { - code: "if (0 < x && x <= 1) {}", + code: 'if ("a" < x && x < MAX ) {}', options: ["never", { exceptRange: true }] - }, { - code: "if (x < 0 || 1 <= x) {}", + }, + { + code: "if (1 < x && x < MAX ) {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if ('a' < x && x < MAX ) {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if (x < `x` || `x` <= x) {}", + options: ["never", { exceptRange: true }], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (0 < x && x <= 1) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (0 <= x && x < 1) {}", options: ["always", { exceptRange: true }] - }, { - code: "if (x <= 'bar' || 'foo' < x) {}", - options: ["always", { exceptRange: true }] - }, { + }, + { code: "if ('blue' < x.y && x.y < 'green') {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (0 < x[``] && x[``] < 100) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { + }, + { code: "if (0 < x[''] && x[``] < 100) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { + }, + { + code: + "if (a < 4 || (b[c[0]].d['e'] < 0 || 1 <= b[c[0]].d['e'])) {}", + options: ["never", { exceptRange: true }] + }, + { code: "if (0 <= x['y'] && x['y'] <= 100) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (a < 0 && (0 < b && b < 1)) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if ((0 < a && a < 1) && b < 0) {}", options: ["never", { exceptRange: true }] - }, { - code: "if (a < 4 || (b[c[0]].d['e'] < 0 || 1 <= b[c[0]].d['e'])) {}", - options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (-1 < x && x < 0) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (0 <= this.prop && this.prop <= 1) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (0 <= index && index < list.length) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (ZERO <= index && index < 100) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (value <= MIN || 10 < value) {}", options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (value <= 0 || MAX < value) {}", options: ["never", { exceptRange: true }] - }, { - code: "if (0 <= a.b && a[\"b\"] <= 100) {}", + }, + { + code: 'if (0 <= a.b && a["b"] <= 100) {}', options: ["never", { exceptRange: true }] - }, { + }, + { code: "if (0 <= a.b && a[`b`] <= 100) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { + }, + { code: "if (-1n < x && x <= 1n) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2020 } - }, { - code: "if (x < -1n || 1n <= x) {}", - options: ["never", { exceptRange: true }], - parserOptions: { ecmaVersion: 2020 } - }, { + }, + { code: "if (-1n <= x && x < 1n) {}", options: ["always", { exceptRange: true }], parserOptions: { ecmaVersion: 2020 } - }, { - code: "if (x < -1n || 1n <= x) {}", - options: ["always", { exceptRange: true }], - parserOptions: { ecmaVersion: 2020 } - }, { + }, + { code: "if (x < `1` || `1` < x) {}", options: ["always", { exceptRange: true }], parserOptions: { ecmaVersion: 2020 } - }, { + }, + { code: "if (1 <= a['/(?0)/'] && a[/(?0)/] <= 100) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2018 } - }, { + }, + { code: "if (x <= `bar` || `foo` < x) {}", options: ["always", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { + }, + { + code: "if ('a' < x && x < MAX ) {}", + options: ["always", { exceptRange: true }], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if ('a' < x && x < MAX ) {}", + options: ["always"], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (MIN < x && x < 'a' ) {}", + options: ["never", { exceptRange: true }], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (MIN < x && x < 'a' ) {}", + options: ["never"], + parserOptions: { ecmaVersion: 2015 } + }, + { code: "if (`blue` < x.y && x.y < `green`) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { + }, + { code: "if (0 <= x[`y`] && x[`y`] <= 100) {}", options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } - }, { - code: "if (0 <= x[`y`] && x[\"y\"] <= 100) {}", + }, + { + code: 'if (0 <= x[`y`] && x["y"] <= 100) {}', options: ["never", { exceptRange: true }], parserOptions: { ecmaVersion: 2015 } }, + { + code: "if ('a' <= x && x < 'b') {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if (x < -1n || 1n <= x) {}", + options: ["never", { exceptRange: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: "if (x < -1n || 1n <= x) {}", + options: ["always", { exceptRange: true }], + parserOptions: { ecmaVersion: 2020 } + }, + { + code: "if (1 < a && a <= 2) {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if (x < -1 || 1 < x) {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if (x <= 'bar' || 'foo' < x) {}", + options: ["always", { exceptRange: true }] + }, + { + code: "if (x < 0 || 1 <= x) {}", + options: ["never", { exceptRange: true }] + }, + { + code: "if('a' <= x && x < MAX) {}", + options: ["never", { exceptRange: true }] + }, // onlyEquality - { code: "if (0 < x && x <= 1) {}", options: ["never", { onlyEquality: true }] }, - { code: "if (x !== 'foo' && 'foo' !== x) {}", options: ["never", { onlyEquality: true }] }, - { code: "if (x < 2 && x !== -3) {}", options: ["always", { onlyEquality: true }] }, - { code: "if (x !== `foo` && `foo` !== x) {}", options: ["never", { onlyEquality: true }], parserOptions: { ecmaVersion: 2015 } }, - { code: "if (x < `2` && x !== `-3`) {}", options: ["always", { onlyEquality: true }], parserOptions: { ecmaVersion: 2015 } } + { + code: "if (0 < x && x <= 1) {}", + options: ["never", { onlyEquality: true }] + }, + { + code: "if (x !== 'foo' && 'foo' !== x) {}", + options: ["never", { onlyEquality: true }] + }, + { + code: "if (x < 2 && x !== -3) {}", + options: ["always", { onlyEquality: true }] + }, + { + code: "if (x !== `foo` && `foo` !== x) {}", + options: ["never", { onlyEquality: true }], + parserOptions: { ecmaVersion: 2015 } + }, + { + code: "if (x < `2` && x !== `-3`) {}", + options: ["always", { onlyEquality: true }], + parserOptions: { ecmaVersion: 2015 } + } ], invalid: [ - { - code: "if (\"red\" == value) {}", - output: "if (value == \"red\") {}", + code: "if (x <= 'foo' || 'bar' < x) {}", + output: "if ('foo' >= x || 'bar' < x) {}", + options: ["always", { exceptRange: true }], + errors: [ + { + messageId: "expected", + data: { expectedSide: "left", operator: "<=" }, + type: "BinaryExpression" + } + ] + }, + { + code: 'if ("red" == value) {}', + output: 'if (value == "red") {}', options: ["never"], errors: [ { @@ -222,8 +388,8 @@ ruleTester.run("yoda", rule, { ] }, { - code: "if (\"red\" <= value) {}", - output: "if (value >= \"red\") {}", + code: 'if ("red" <= value) {}', + output: 'if (value >= "red") {}', options: ["never"], errors: [ { @@ -260,8 +426,8 @@ ruleTester.run("yoda", rule, { ] }, { - code: "if (`red` <= `${\"red\"}`) {}", - output: "if (`${\"red\"}` >= `red`) {}", + code: 'if (`red` <= `${"red"}`) {}', + output: 'if (`${"red"}` >= `red`) {}', options: ["never"], parserOptions: { ecmaVersion: 2015 }, errors: [ @@ -321,8 +487,8 @@ ruleTester.run("yoda", rule, { ] }, { - code: "if (value == \"red\") {}", - output: "if (\"red\" == value) {}", + code: 'if (value == "red") {}', + output: 'if ("red" == value) {}', options: ["always"], errors: [ { @@ -371,8 +537,8 @@ ruleTester.run("yoda", rule, { ] }, { - code: "if (`${\"red\"}` <= `red`) {}", - output: "if (`red` >= `${\"red\"}`) {}", + code: 'if (`${"red"}` <= `red`) {}', + output: 'if (`red` >= `${"red"}`) {}', options: ["always"], parserOptions: { ecmaVersion: 2015 }, errors: [ @@ -480,6 +646,19 @@ ruleTester.run("yoda", rule, { } ] }, + { + code: "if (`green` < x.y && x.y < `blue`) {}", + output: "if (x.y > `green` && x.y < `blue`) {}", + options: ["never", { exceptRange: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [ + { + messageId: "expected", + data: { expectedSide: "right", operator: "<" }, + type: "BinaryExpression" + } + ] + }, { code: "if (0 <= a[b] && a['b'] < 1) {}", output: "if (a[b] >= 0 && a['b'] < 1) {}", @@ -641,19 +820,6 @@ ruleTester.run("yoda", rule, { } ] }, - { - code: "if (`green` < x.y && x.y < `blue`) {}", - output: "if (x.y > `green` && x.y < `blue`) {}", - options: ["never", { exceptRange: true }], - parserOptions: { ecmaVersion: 2015 }, - errors: [ - { - messageId: "expected", - data: { expectedSide: "right", operator: "<" }, - type: "BinaryExpression" - } - ] - }, { code: "if (3 == a) {}", output: "if (a == 3) {}", @@ -992,6 +1158,67 @@ ruleTester.run("yoda", rule, { type: "BinaryExpression" } ] + }, + { + code: "if (`green` < x.y && x.y < `blue`) {}", + output: "if (`green` < x.y && `blue` > x.y) {}", + options: ["always", { exceptRange: true }], + parserOptions: { ecmaVersion: 2015 }, + errors: [ + { + messageId: "expected", + data: { expectedSide: "left", operator: "<" }, + type: "BinaryExpression" + } + ] + }, + { + code: "if('a' <= x && x < 'b') {}", + output: "if('a' <= x && 'b' > x) {}", + options: ["always"], + errors: [ + { + messageId: "expected", + data: { expectedSide: "left", operator: "<" }, + type: "BinaryExpression" + } + ] + }, + { + code: "if ('b' <= x && x < 'a') {}", + output: "if (x >= 'b' && x < 'a') {}", + options: ["never", { exceptRange: true }], + errors: [ + { + messageId: "expected", + data: { expectedSide: "right", operator: "<=" }, + type: "BinaryExpression" + } + ] + }, + { + code: "if('a' <= x && x < 1) {}", + output: "if(x >= 'a' && x < 1) {}", + options: ["never", { exceptRange: true }], + errors: [ + { + messageId: "expected", + data: { expectedSide: "right", operator: "<=" }, + type: "BinaryExpression" + } + ] + }, + { + code: "if (0 < a && b < max) {}", + output: "if (a > 0 && b < max) {}", + options: ["never", { exceptRange: true }], + errors: [ + { + messageId: "expected", + data: { expectedSide: "right", operator: "<" }, + type: "BinaryExpression" + } + ] } ] });