Skip to content

Commit d85e291

Browse files
authoredApr 24, 2020
Fix: yoda left string fix for exceptRange (fixes #12883) (#13052)
* Fix: yoda left string fix for exceptRange * Chore: aded string check for isOutsideTest yoda * Fix: removed inconsistency btn never and always * Chore: fixed false negatives * Chore: fixed false negative string <= number * Chore: simplify range checks (yoda) * Chore: fixed false negative and added test * Chore: removed un-neccesary comment for defaultValue * Chore: removed un-neccesary checks * Chore: added removed tests * Chore: linting fixes
1 parent 2ce6bed commit d85e291

File tree

2 files changed

+415
-138
lines changed

2 files changed

+415
-138
lines changed
 

‎lib/rules/yoda.js

+101-51
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const astUtils = require("./utils/ast-utils");
2020
* @returns {boolean} Whether or not it is a comparison operator.
2121
*/
2222
function isComparisonOperator(operator) {
23-
return (/^(==|===|!=|!==|<|>|<=|>=)$/u).test(operator);
23+
return /^(==|===|!=|!==|<|>|<=|>=)$/u.test(operator);
2424
}
2525

2626
/**
@@ -29,7 +29,7 @@ function isComparisonOperator(operator) {
2929
* @returns {boolean} Whether or not it is an equality operator.
3030
*/
3131
function isEqualityOperator(operator) {
32-
return (/^(==|===)$/u).test(operator);
32+
return /^(==|===)$/u.test(operator);
3333
}
3434

3535
/**
@@ -50,10 +50,12 @@ function isRangeTestOperator(operator) {
5050
* real literal and should be treated as such.
5151
*/
5252
function isNegativeNumericLiteral(node) {
53-
return (node.type === "UnaryExpression" &&
53+
return (
54+
node.type === "UnaryExpression" &&
5455
node.operator === "-" &&
5556
node.prefix &&
56-
astUtils.isNumericLiteral(node.argument));
57+
astUtils.isNumericLiteral(node.argument)
58+
);
5759
}
5860

5961
/**
@@ -71,25 +73,21 @@ function isStaticTemplateLiteral(node) {
7173
* @returns {boolean} True if the node should be treated as a single Literal node.
7274
*/
7375
function looksLikeLiteral(node) {
74-
return isNegativeNumericLiteral(node) ||
75-
isStaticTemplateLiteral(node);
76+
return isNegativeNumericLiteral(node) || isStaticTemplateLiteral(node);
7677
}
7778

7879
/**
7980
* Attempts to derive a Literal node from nodes that are treated like literals.
8081
* @param {ASTNode} node Node to normalize.
81-
* @param {number} [defaultValue] The default value to be returned if the node
82-
* is not a Literal.
8382
* @returns {ASTNode} One of the following options.
8483
* 1. The original node if the node is already a Literal
8584
* 2. A normalized Literal node with the negative number as the value if the
8685
* node represents a negative number literal.
8786
* 3. A normalized Literal node with the string as the value if the node is
8887
* a Template Literal without expression.
89-
* 4. The Literal node which has the `defaultValue` argument if it exists.
90-
* 5. Otherwise `null`.
88+
* 4. Otherwise `null`.
9189
*/
92-
function getNormalizedLiteral(node, defaultValue) {
90+
function getNormalizedLiteral(node) {
9391
if (node.type === "Literal") {
9492
return node;
9593
}
@@ -110,14 +108,6 @@ function getNormalizedLiteral(node, defaultValue) {
110108
};
111109
}
112110

113-
if (defaultValue) {
114-
return {
115-
type: "Literal",
116-
value: defaultValue,
117-
raw: String(defaultValue)
118-
};
119-
}
120-
121111
return null;
122112
}
123113

@@ -183,7 +173,7 @@ module.exports = {
183173
type: "suggestion",
184174

185175
docs: {
186-
description: "require or disallow \"Yoda\" conditions",
176+
description: 'require or disallow "Yoda" conditions',
187177
category: "Best Practices",
188178
recommended: false,
189179
url: "https://eslint.org/docs/rules/yoda"
@@ -211,16 +201,19 @@ module.exports = {
211201

212202
fixable: "code",
213203
messages: {
214-
expected: "Expected literal to be on the {{expectedSide}} side of {{operator}}."
204+
expected:
205+
"Expected literal to be on the {{expectedSide}} side of {{operator}}."
215206
}
216207
},
217208

218209
create(context) {
219210

220211
// Default to "never" (!always) if no option
221-
const always = (context.options[0] === "always");
222-
const exceptRange = (context.options[1] && context.options[1].exceptRange);
223-
const onlyEquality = (context.options[1] && context.options[1].onlyEquality);
212+
const always = context.options[0] === "always";
213+
const exceptRange =
214+
context.options[1] && context.options[1].exceptRange;
215+
const onlyEquality =
216+
context.options[1] && context.options[1].onlyEquality;
224217

225218
const sourceCode = context.getSourceCode();
226219

@@ -243,27 +236,48 @@ module.exports = {
243236
* @returns {boolean} Whether node is a "between" range test.
244237
*/
245238
function isBetweenTest() {
246-
let leftLiteral, rightLiteral;
239+
if (node.operator === "&&" && same(left.right, right.left)) {
240+
const leftLiteral = getNormalizedLiteral(left.left);
241+
const rightLiteral = getNormalizedLiteral(right.right);
242+
243+
if (leftLiteral === null && rightLiteral === null) {
244+
return false;
245+
}
247246

248-
return (node.operator === "&&" &&
249-
(leftLiteral = getNormalizedLiteral(left.left)) &&
250-
(rightLiteral = getNormalizedLiteral(right.right, Number.POSITIVE_INFINITY)) &&
251-
leftLiteral.value <= rightLiteral.value &&
252-
same(left.right, right.left));
247+
if (rightLiteral === null || leftLiteral === null) {
248+
return true;
249+
}
250+
251+
if (leftLiteral.value <= rightLiteral.value) {
252+
return true;
253+
}
254+
}
255+
return false;
253256
}
254257

255258
/**
256259
* Determines whether node is of the form `x < 0 || 1 <= x`.
257260
* @returns {boolean} Whether node is an "outside" range test.
258261
*/
259262
function isOutsideTest() {
260-
let leftLiteral, rightLiteral;
263+
if (node.operator === "||" && same(left.left, right.right)) {
264+
const leftLiteral = getNormalizedLiteral(left.right);
265+
const rightLiteral = getNormalizedLiteral(right.left);
266+
267+
if (leftLiteral === null && rightLiteral === null) {
268+
return false;
269+
}
270+
271+
if (rightLiteral === null || leftLiteral === null) {
272+
return true;
273+
}
274+
275+
if (leftLiteral.value <= rightLiteral.value) {
276+
return true;
277+
}
278+
}
261279

262-
return (node.operator === "||" &&
263-
(leftLiteral = getNormalizedLiteral(left.right, Number.NEGATIVE_INFINITY)) &&
264-
(rightLiteral = getNormalizedLiteral(right.left)) &&
265-
leftLiteral.value <= rightLiteral.value &&
266-
same(left.left, right.right));
280+
return false;
267281
}
268282

269283
/**
@@ -276,13 +290,15 @@ module.exports = {
276290
return astUtils.isParenthesised(sourceCode, node);
277291
}
278292

279-
return (node.type === "LogicalExpression" &&
293+
return (
294+
node.type === "LogicalExpression" &&
280295
left.type === "BinaryExpression" &&
281296
right.type === "BinaryExpression" &&
282297
isRangeTestOperator(left.operator) &&
283298
isRangeTestOperator(right.operator) &&
284299
(isBetweenTest() || isOutsideTest()) &&
285-
isParenWrapped());
300+
isParenWrapped()
301+
);
286302
}
287303

288304
const OPERATOR_FLIP_MAP = {
@@ -303,21 +319,52 @@ module.exports = {
303319
*/
304320
function getFlippedString(node) {
305321
const tokenBefore = sourceCode.getTokenBefore(node);
306-
const operatorToken = sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
307-
const textBeforeOperator = sourceCode.getText().slice(sourceCode.getTokenBefore(operatorToken).range[1], operatorToken.range[0]);
308-
const textAfterOperator = sourceCode.getText().slice(operatorToken.range[1], sourceCode.getTokenAfter(operatorToken).range[0]);
309-
const leftText = sourceCode.getText().slice(node.range[0], sourceCode.getTokenBefore(operatorToken).range[1]);
322+
const operatorToken = sourceCode.getFirstTokenBetween(
323+
node.left,
324+
node.right,
325+
token => token.value === node.operator
326+
);
327+
const textBeforeOperator = sourceCode
328+
.getText()
329+
.slice(
330+
sourceCode.getTokenBefore(operatorToken).range[1],
331+
operatorToken.range[0]
332+
);
333+
const textAfterOperator = sourceCode
334+
.getText()
335+
.slice(
336+
operatorToken.range[1],
337+
sourceCode.getTokenAfter(operatorToken).range[0]
338+
);
339+
const leftText = sourceCode
340+
.getText()
341+
.slice(
342+
node.range[0],
343+
sourceCode.getTokenBefore(operatorToken).range[1]
344+
);
310345
const firstRightToken = sourceCode.getTokenAfter(operatorToken);
311-
const rightText = sourceCode.getText().slice(firstRightToken.range[0], node.range[1]);
346+
const rightText = sourceCode
347+
.getText()
348+
.slice(firstRightToken.range[0], node.range[1]);
312349

313350
let prefix = "";
314351

315-
if (tokenBefore && tokenBefore.range[1] === node.range[0] &&
316-
!astUtils.canTokensBeAdjacent(tokenBefore, firstRightToken)) {
352+
if (
353+
tokenBefore &&
354+
tokenBefore.range[1] === node.range[0] &&
355+
!astUtils.canTokensBeAdjacent(tokenBefore, firstRightToken)
356+
) {
317357
prefix = " ";
318358
}
319359

320-
return prefix + rightText + textBeforeOperator + OPERATOR_FLIP_MAP[operatorToken.value] + textAfterOperator + leftText;
360+
return (
361+
prefix +
362+
rightText +
363+
textBeforeOperator +
364+
OPERATOR_FLIP_MAP[operatorToken.value] +
365+
textAfterOperator +
366+
leftText
367+
);
321368
}
322369

323370
//--------------------------------------------------------------------------
@@ -331,8 +378,12 @@ module.exports = {
331378

332379
// If `expectedLiteral` is not a literal, and `expectedNonLiteral` is a literal, raise an error.
333380
if (
334-
(expectedNonLiteral.type === "Literal" || looksLikeLiteral(expectedNonLiteral)) &&
335-
!(expectedLiteral.type === "Literal" || looksLikeLiteral(expectedLiteral)) &&
381+
(expectedNonLiteral.type === "Literal" ||
382+
looksLikeLiteral(expectedNonLiteral)) &&
383+
!(
384+
expectedLiteral.type === "Literal" ||
385+
looksLikeLiteral(expectedLiteral)
386+
) &&
336387
!(!isEqualityOperator(node.operator) && onlyEquality) &&
337388
isComparisonOperator(node.operator) &&
338389
!(exceptRange && isRangeTest(context.getAncestors().pop()))
@@ -344,12 +395,11 @@ module.exports = {
344395
operator: node.operator,
345396
expectedSide: always ? "left" : "right"
346397
},
347-
fix: fixer => fixer.replaceText(node, getFlippedString(node))
398+
fix: fixer =>
399+
fixer.replaceText(node, getFlippedString(node))
348400
});
349401
}
350-
351402
}
352403
};
353-
354404
}
355405
};

‎tests/lib/rules/yoda.js

+314-87
Original file line numberDiff line numberDiff line change
@@ -21,148 +21,314 @@ ruleTester.run("yoda", rule, {
2121
valid: [
2222

2323
// "never" mode
24-
{ code: "if (value === \"red\") {}", options: ["never"] },
24+
{ code: 'if (value === "red") {}', options: ["never"] },
2525
{ code: "if (value === value) {}", options: ["never"] },
2626
{ code: "if (value != 5) {}", options: ["never"] },
2727
{ code: "if (5 & foo) {}", options: ["never"] },
2828
{ code: "if (5 === 4) {}", options: ["never"] },
29-
{ code: "if (value === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
30-
{ code: "if (`red` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
31-
{ code: "if (`${foo}` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
32-
{ code: "if (`${\"\"}` === `red`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
33-
{ code: "if (`${\"red\"}` === foo) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
34-
{ code: "if (b > `a` && b > `a`) {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
35-
{ code: "if (`b` > `a` && \"b\" > \"a\") {}", options: ["never"], parserOptions: { ecmaVersion: 2015 } },
29+
{
30+
code: "if (value === `red`) {}",
31+
options: ["never"],
32+
parserOptions: { ecmaVersion: 2015 }
33+
},
34+
{
35+
code: "if (`red` === `red`) {}",
36+
options: ["never"],
37+
parserOptions: { ecmaVersion: 2015 }
38+
},
39+
{
40+
code: "if (`${foo}` === `red`) {}",
41+
options: ["never"],
42+
parserOptions: { ecmaVersion: 2015 }
43+
},
44+
{
45+
code: 'if (`${""}` === `red`) {}',
46+
options: ["never"],
47+
parserOptions: { ecmaVersion: 2015 }
48+
},
49+
{
50+
code: 'if (`${"red"}` === foo) {}',
51+
options: ["never"],
52+
parserOptions: { ecmaVersion: 2015 }
53+
},
54+
{
55+
code: "if (b > `a` && b > `a`) {}",
56+
options: ["never"],
57+
parserOptions: { ecmaVersion: 2015 }
58+
},
59+
{
60+
code: 'if (`b` > `a` && "b" > "a") {}',
61+
options: ["never"],
62+
parserOptions: { ecmaVersion: 2015 }
63+
},
3664

3765
// "always" mode
38-
{ code: "if (\"blue\" === value) {}", options: ["always"] },
66+
{ code: 'if ("blue" === value) {}', options: ["always"] },
3967
{ code: "if (value === value) {}", options: ["always"] },
4068
{ code: "if (4 != value) {}", options: ["always"] },
4169
{ code: "if (foo & 4) {}", options: ["always"] },
4270
{ code: "if (5 === 4) {}", options: ["always"] },
43-
{ code: "if (`red` === value) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
44-
{ code: "if (`red` === `red`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
45-
{ code: "if (`red` === `${foo}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
46-
{ code: "if (`red` === `${\"\"}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
47-
{ code: "if (foo === `${\"red\"}`) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
48-
{ code: "if (`a` > b && `a` > b) {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
49-
{ code: "if (`b` > `a` && \"b\" > \"a\") {}", options: ["always"], parserOptions: { ecmaVersion: 2015 } },
71+
{
72+
code: "if (`red` === value) {}",
73+
options: ["always"],
74+
parserOptions: { ecmaVersion: 2015 }
75+
},
76+
{
77+
code: "if (`red` === `red`) {}",
78+
options: ["always"],
79+
parserOptions: { ecmaVersion: 2015 }
80+
},
81+
{
82+
code: "if (`red` === `${foo}`) {}",
83+
options: ["always"],
84+
parserOptions: { ecmaVersion: 2015 }
85+
},
86+
{
87+
code: 'if (`red` === `${""}`) {}',
88+
options: ["always"],
89+
parserOptions: { ecmaVersion: 2015 }
90+
},
91+
{
92+
code: 'if (foo === `${"red"}`) {}',
93+
options: ["always"],
94+
parserOptions: { ecmaVersion: 2015 }
95+
},
96+
{
97+
code: "if (`a` > b && `a` > b) {}",
98+
options: ["always"],
99+
parserOptions: { ecmaVersion: 2015 }
100+
},
101+
{
102+
code: 'if (`b` > `a` && "b" > "a") {}',
103+
options: ["always"],
104+
parserOptions: { ecmaVersion: 2015 }
105+
},
50106

51107
// Range exception
52108
{
53-
code: "if (0 < x && x <= 1) {}",
109+
code: 'if ("a" < x && x < MAX ) {}',
54110
options: ["never", { exceptRange: true }]
55-
}, {
56-
code: "if (x < 0 || 1 <= x) {}",
111+
},
112+
{
113+
code: "if (1 < x && x < MAX ) {}",
114+
options: ["never", { exceptRange: true }]
115+
},
116+
{
117+
code: "if ('a' < x && x < MAX ) {}",
118+
options: ["never", { exceptRange: true }]
119+
},
120+
{
121+
code: "if (x < `x` || `x` <= x) {}",
122+
options: ["never", { exceptRange: true }],
123+
parserOptions: { ecmaVersion: 2015 }
124+
},
125+
{
126+
code: "if (0 < x && x <= 1) {}",
57127
options: ["never", { exceptRange: true }]
58-
}, {
128+
},
129+
{
59130
code: "if (0 <= x && x < 1) {}",
60131
options: ["always", { exceptRange: true }]
61-
}, {
62-
code: "if (x <= 'bar' || 'foo' < x) {}",
63-
options: ["always", { exceptRange: true }]
64-
}, {
132+
},
133+
{
65134
code: "if ('blue' < x.y && x.y < 'green') {}",
66135
options: ["never", { exceptRange: true }]
67-
}, {
136+
},
137+
{
68138
code: "if (0 < x[``] && x[``] < 100) {}",
69139
options: ["never", { exceptRange: true }],
70140
parserOptions: { ecmaVersion: 2015 }
71-
}, {
141+
},
142+
{
72143
code: "if (0 < x[''] && x[``] < 100) {}",
73144
options: ["never", { exceptRange: true }],
74145
parserOptions: { ecmaVersion: 2015 }
75-
}, {
146+
},
147+
{
148+
code:
149+
"if (a < 4 || (b[c[0]].d['e'] < 0 || 1 <= b[c[0]].d['e'])) {}",
150+
options: ["never", { exceptRange: true }]
151+
},
152+
{
76153
code: "if (0 <= x['y'] && x['y'] <= 100) {}",
77154
options: ["never", { exceptRange: true }]
78-
}, {
155+
},
156+
{
79157
code: "if (a < 0 && (0 < b && b < 1)) {}",
80158
options: ["never", { exceptRange: true }]
81-
}, {
159+
},
160+
{
82161
code: "if ((0 < a && a < 1) && b < 0) {}",
83162
options: ["never", { exceptRange: true }]
84-
}, {
85-
code: "if (a < 4 || (b[c[0]].d['e'] < 0 || 1 <= b[c[0]].d['e'])) {}",
86-
options: ["never", { exceptRange: true }]
87-
}, {
163+
},
164+
{
88165
code: "if (-1 < x && x < 0) {}",
89166
options: ["never", { exceptRange: true }]
90-
}, {
167+
},
168+
{
91169
code: "if (0 <= this.prop && this.prop <= 1) {}",
92170
options: ["never", { exceptRange: true }]
93-
}, {
171+
},
172+
{
94173
code: "if (0 <= index && index < list.length) {}",
95174
options: ["never", { exceptRange: true }]
96-
}, {
175+
},
176+
{
97177
code: "if (ZERO <= index && index < 100) {}",
98178
options: ["never", { exceptRange: true }]
99-
}, {
179+
},
180+
{
100181
code: "if (value <= MIN || 10 < value) {}",
101182
options: ["never", { exceptRange: true }]
102-
}, {
183+
},
184+
{
103185
code: "if (value <= 0 || MAX < value) {}",
104186
options: ["never", { exceptRange: true }]
105-
}, {
106-
code: "if (0 <= a.b && a[\"b\"] <= 100) {}",
187+
},
188+
{
189+
code: 'if (0 <= a.b && a["b"] <= 100) {}',
107190
options: ["never", { exceptRange: true }]
108-
}, {
191+
},
192+
{
109193
code: "if (0 <= a.b && a[`b`] <= 100) {}",
110194
options: ["never", { exceptRange: true }],
111195
parserOptions: { ecmaVersion: 2015 }
112-
}, {
196+
},
197+
{
113198
code: "if (-1n < x && x <= 1n) {}",
114199
options: ["never", { exceptRange: true }],
115200
parserOptions: { ecmaVersion: 2020 }
116-
}, {
117-
code: "if (x < -1n || 1n <= x) {}",
118-
options: ["never", { exceptRange: true }],
119-
parserOptions: { ecmaVersion: 2020 }
120-
}, {
201+
},
202+
{
121203
code: "if (-1n <= x && x < 1n) {}",
122204
options: ["always", { exceptRange: true }],
123205
parserOptions: { ecmaVersion: 2020 }
124-
}, {
125-
code: "if (x < -1n || 1n <= x) {}",
126-
options: ["always", { exceptRange: true }],
127-
parserOptions: { ecmaVersion: 2020 }
128-
}, {
206+
},
207+
{
129208
code: "if (x < `1` || `1` < x) {}",
130209
options: ["always", { exceptRange: true }],
131210
parserOptions: { ecmaVersion: 2020 }
132-
}, {
211+
},
212+
{
133213
code: "if (1 <= a['/(?<zero>0)/'] && a[/(?<zero>0)/] <= 100) {}",
134214
options: ["never", { exceptRange: true }],
135215
parserOptions: { ecmaVersion: 2018 }
136-
}, {
216+
},
217+
{
137218
code: "if (x <= `bar` || `foo` < x) {}",
138219
options: ["always", { exceptRange: true }],
139220
parserOptions: { ecmaVersion: 2015 }
140-
}, {
221+
},
222+
{
223+
code: "if ('a' < x && x < MAX ) {}",
224+
options: ["always", { exceptRange: true }],
225+
parserOptions: { ecmaVersion: 2015 }
226+
},
227+
{
228+
code: "if ('a' < x && x < MAX ) {}",
229+
options: ["always"],
230+
parserOptions: { ecmaVersion: 2015 }
231+
},
232+
{
233+
code: "if (MIN < x && x < 'a' ) {}",
234+
options: ["never", { exceptRange: true }],
235+
parserOptions: { ecmaVersion: 2015 }
236+
},
237+
{
238+
code: "if (MIN < x && x < 'a' ) {}",
239+
options: ["never"],
240+
parserOptions: { ecmaVersion: 2015 }
241+
},
242+
{
141243
code: "if (`blue` < x.y && x.y < `green`) {}",
142244
options: ["never", { exceptRange: true }],
143245
parserOptions: { ecmaVersion: 2015 }
144-
}, {
246+
},
247+
{
145248
code: "if (0 <= x[`y`] && x[`y`] <= 100) {}",
146249
options: ["never", { exceptRange: true }],
147250
parserOptions: { ecmaVersion: 2015 }
148-
}, {
149-
code: "if (0 <= x[`y`] && x[\"y\"] <= 100) {}",
251+
},
252+
{
253+
code: 'if (0 <= x[`y`] && x["y"] <= 100) {}',
150254
options: ["never", { exceptRange: true }],
151255
parserOptions: { ecmaVersion: 2015 }
152256
},
257+
{
258+
code: "if ('a' <= x && x < 'b') {}",
259+
options: ["never", { exceptRange: true }]
260+
},
261+
{
262+
code: "if (x < -1n || 1n <= x) {}",
263+
options: ["never", { exceptRange: true }],
264+
parserOptions: { ecmaVersion: 2020 }
265+
},
266+
{
267+
code: "if (x < -1n || 1n <= x) {}",
268+
options: ["always", { exceptRange: true }],
269+
parserOptions: { ecmaVersion: 2020 }
270+
},
271+
{
272+
code: "if (1 < a && a <= 2) {}",
273+
options: ["never", { exceptRange: true }]
274+
},
275+
{
276+
code: "if (x < -1 || 1 < x) {}",
277+
options: ["never", { exceptRange: true }]
278+
},
279+
{
280+
code: "if (x <= 'bar' || 'foo' < x) {}",
281+
options: ["always", { exceptRange: true }]
282+
},
283+
{
284+
code: "if (x < 0 || 1 <= x) {}",
285+
options: ["never", { exceptRange: true }]
286+
},
287+
{
288+
code: "if('a' <= x && x < MAX) {}",
289+
options: ["never", { exceptRange: true }]
290+
},
153291

154292
// onlyEquality
155-
{ code: "if (0 < x && x <= 1) {}", options: ["never", { onlyEquality: true }] },
156-
{ code: "if (x !== 'foo' && 'foo' !== x) {}", options: ["never", { onlyEquality: true }] },
157-
{ code: "if (x < 2 && x !== -3) {}", options: ["always", { onlyEquality: true }] },
158-
{ code: "if (x !== `foo` && `foo` !== x) {}", options: ["never", { onlyEquality: true }], parserOptions: { ecmaVersion: 2015 } },
159-
{ code: "if (x < `2` && x !== `-3`) {}", options: ["always", { onlyEquality: true }], parserOptions: { ecmaVersion: 2015 } }
293+
{
294+
code: "if (0 < x && x <= 1) {}",
295+
options: ["never", { onlyEquality: true }]
296+
},
297+
{
298+
code: "if (x !== 'foo' && 'foo' !== x) {}",
299+
options: ["never", { onlyEquality: true }]
300+
},
301+
{
302+
code: "if (x < 2 && x !== -3) {}",
303+
options: ["always", { onlyEquality: true }]
304+
},
305+
{
306+
code: "if (x !== `foo` && `foo` !== x) {}",
307+
options: ["never", { onlyEquality: true }],
308+
parserOptions: { ecmaVersion: 2015 }
309+
},
310+
{
311+
code: "if (x < `2` && x !== `-3`) {}",
312+
options: ["always", { onlyEquality: true }],
313+
parserOptions: { ecmaVersion: 2015 }
314+
}
160315
],
161316
invalid: [
162-
163317
{
164-
code: "if (\"red\" == value) {}",
165-
output: "if (value == \"red\") {}",
318+
code: "if (x <= 'foo' || 'bar' < x) {}",
319+
output: "if ('foo' >= x || 'bar' < x) {}",
320+
options: ["always", { exceptRange: true }],
321+
errors: [
322+
{
323+
messageId: "expected",
324+
data: { expectedSide: "left", operator: "<=" },
325+
type: "BinaryExpression"
326+
}
327+
]
328+
},
329+
{
330+
code: 'if ("red" == value) {}',
331+
output: 'if (value == "red") {}',
166332
options: ["never"],
167333
errors: [
168334
{
@@ -222,8 +388,8 @@ ruleTester.run("yoda", rule, {
222388
]
223389
},
224390
{
225-
code: "if (\"red\" <= value) {}",
226-
output: "if (value >= \"red\") {}",
391+
code: 'if ("red" <= value) {}',
392+
output: 'if (value >= "red") {}',
227393
options: ["never"],
228394
errors: [
229395
{
@@ -260,8 +426,8 @@ ruleTester.run("yoda", rule, {
260426
]
261427
},
262428
{
263-
code: "if (`red` <= `${\"red\"}`) {}",
264-
output: "if (`${\"red\"}` >= `red`) {}",
429+
code: 'if (`red` <= `${"red"}`) {}',
430+
output: 'if (`${"red"}` >= `red`) {}',
265431
options: ["never"],
266432
parserOptions: { ecmaVersion: 2015 },
267433
errors: [
@@ -321,8 +487,8 @@ ruleTester.run("yoda", rule, {
321487
]
322488
},
323489
{
324-
code: "if (value == \"red\") {}",
325-
output: "if (\"red\" == value) {}",
490+
code: 'if (value == "red") {}',
491+
output: 'if ("red" == value) {}',
326492
options: ["always"],
327493
errors: [
328494
{
@@ -371,8 +537,8 @@ ruleTester.run("yoda", rule, {
371537
]
372538
},
373539
{
374-
code: "if (`${\"red\"}` <= `red`) {}",
375-
output: "if (`red` >= `${\"red\"}`) {}",
540+
code: 'if (`${"red"}` <= `red`) {}',
541+
output: 'if (`red` >= `${"red"}`) {}',
376542
options: ["always"],
377543
parserOptions: { ecmaVersion: 2015 },
378544
errors: [
@@ -480,6 +646,19 @@ ruleTester.run("yoda", rule, {
480646
}
481647
]
482648
},
649+
{
650+
code: "if (`green` < x.y && x.y < `blue`) {}",
651+
output: "if (x.y > `green` && x.y < `blue`) {}",
652+
options: ["never", { exceptRange: true }],
653+
parserOptions: { ecmaVersion: 2015 },
654+
errors: [
655+
{
656+
messageId: "expected",
657+
data: { expectedSide: "right", operator: "<" },
658+
type: "BinaryExpression"
659+
}
660+
]
661+
},
483662
{
484663
code: "if (0 <= a[b] && a['b'] < 1) {}",
485664
output: "if (a[b] >= 0 && a['b'] < 1) {}",
@@ -641,19 +820,6 @@ ruleTester.run("yoda", rule, {
641820
}
642821
]
643822
},
644-
{
645-
code: "if (`green` < x.y && x.y < `blue`) {}",
646-
output: "if (x.y > `green` && x.y < `blue`) {}",
647-
options: ["never", { exceptRange: true }],
648-
parserOptions: { ecmaVersion: 2015 },
649-
errors: [
650-
{
651-
messageId: "expected",
652-
data: { expectedSide: "right", operator: "<" },
653-
type: "BinaryExpression"
654-
}
655-
]
656-
},
657823
{
658824
code: "if (3 == a) {}",
659825
output: "if (a == 3) {}",
@@ -992,6 +1158,67 @@ ruleTester.run("yoda", rule, {
9921158
type: "BinaryExpression"
9931159
}
9941160
]
1161+
},
1162+
{
1163+
code: "if (`green` < x.y && x.y < `blue`) {}",
1164+
output: "if (`green` < x.y && `blue` > x.y) {}",
1165+
options: ["always", { exceptRange: true }],
1166+
parserOptions: { ecmaVersion: 2015 },
1167+
errors: [
1168+
{
1169+
messageId: "expected",
1170+
data: { expectedSide: "left", operator: "<" },
1171+
type: "BinaryExpression"
1172+
}
1173+
]
1174+
},
1175+
{
1176+
code: "if('a' <= x && x < 'b') {}",
1177+
output: "if('a' <= x && 'b' > x) {}",
1178+
options: ["always"],
1179+
errors: [
1180+
{
1181+
messageId: "expected",
1182+
data: { expectedSide: "left", operator: "<" },
1183+
type: "BinaryExpression"
1184+
}
1185+
]
1186+
},
1187+
{
1188+
code: "if ('b' <= x && x < 'a') {}",
1189+
output: "if (x >= 'b' && x < 'a') {}",
1190+
options: ["never", { exceptRange: true }],
1191+
errors: [
1192+
{
1193+
messageId: "expected",
1194+
data: { expectedSide: "right", operator: "<=" },
1195+
type: "BinaryExpression"
1196+
}
1197+
]
1198+
},
1199+
{
1200+
code: "if('a' <= x && x < 1) {}",
1201+
output: "if(x >= 'a' && x < 1) {}",
1202+
options: ["never", { exceptRange: true }],
1203+
errors: [
1204+
{
1205+
messageId: "expected",
1206+
data: { expectedSide: "right", operator: "<=" },
1207+
type: "BinaryExpression"
1208+
}
1209+
]
1210+
},
1211+
{
1212+
code: "if (0 < a && b < max) {}",
1213+
output: "if (a > 0 && b < max) {}",
1214+
options: ["never", { exceptRange: true }],
1215+
errors: [
1216+
{
1217+
messageId: "expected",
1218+
data: { expectedSide: "right", operator: "<" },
1219+
type: "BinaryExpression"
1220+
}
1221+
]
9951222
}
9961223
]
9971224
});

0 commit comments

Comments
 (0)
Please sign in to comment.