fixhunt

biome style/noYodaExpression

labelled safe
Runs / 2026-10-17T20-58-31-447Z-bw32-biome-style_noYodaExpressionbiome 2.5.152026-10-17 20:58 UTC8 programs × 2 round(s)16 programs, 5 fired, 5 fixed, 0 findings, 6 rejectedmodel cost $0.0036

Analysis Nemotron 3 Super

Flags binary comparisons where the static literal/expression appears on the left-hand side (a Yoda condition).

Fix: Swaps the left and right operands of the binary operator while preserving the operator token and all surrounding syntactic context.

12 hazards
  • Rewriting `if (\"red\" == value)` to `if (value == \"red\")` changes operator precedence when embedded in expressions like `x && \"red\" == value`, potentially altering evaluation order.
  • If the left-hand side is a getter with side effects (e.g., `if (getMagic() == value)`), swapping operands changes when the getter is invoked relative to other subexpressions.
  • When the right-hand side involves `void 0` or `undefined`, moving it left may trigger unintended global lookups in non-strict mode due to implicit property creation.
  • In `delete obj[\"prop\"] == value`, swapping operands produces invalid syntax because `delete` expects an unbound reference on its left, breaking parsing.
  • For `new Foo(5 == size)`, swapping yields `new Foo(size == 5)`, which changes argument evaluation timing if `size` is a getter with side effects.
  • In `if (\"\" + obj == value)`, moving the string literal left breaks concatenation order, yielding different intermediate values if `obj.valueOf` has side effects.
  • When the comparison is inside a `with` block, swapping operands may alter which object scope provides identifier resolution for the moved operand.
  • If the left-hand side is a comma expression like `if ((console.log(\"x\"), 0) == value)`, swapping moves the side effect (`console.log`) to a different evaluation point relative to surrounding expressions.
  • Rewriting `if (value != \"red\")` preserves `!=` but if the original relied on left-to-right short-circuiting in a larger expression like `a && \"red\" != value`, the swap changes short-circuit behavior.
  • In template literals such as ``if (`hello${world}` == msg)``, swapping operands is safe only if the template has no side effects in its substitutions; otherwise evaluation order shifts.
  • Moving a literal with attached comments (e.g., `if (\"red\" /* TODO */ == value)`) may detach or misplace those comments depending on how the formatter handles whitespace.
  • For `if ((value) == (\"red\"))`, excessive parentheses may be preserved or dropped inconsistently by the fixer, affecting readability though not semantics.

Programs

idresulttitlehazard
r1-p001fix okNull/undefined distinction with optional chainingRewriting 'null == value' to 'value == null' when value uses optional chaining can change short-circuit behavior—original throws if base is null/undefined, swapped does not.
r1-p002fix okNew expression with getter side effectsSwapping 'new Foo(5 == size)' to 'new Foo(size == 5)' changes when size getter is called—original evaluates 5 first, swapped calls size getter first.
r1-p003fix ok prediction offOperator precedence in logical ANDRewriting 'x && "red" == value' to 'x && value == "red"' is same, but if rule fired on internal comparison alone, swap could change grouping in larger expression—here we show dependency via explicit g
r1-p004invalidWith block scope interactionIn 'with (scope) { if ("x" == y) }', swapping to 'if (y == "x")' changes whether y is resolved from scope object or outer scope if y is not in scope.
r1-p005silent prediction offASI with leading parenthesisWithout semicolon, leading '(' on next line can be interpreted as function call. Swapping operands in a comparison before such line changes what gets called.
r1-p006fix okInequality short-circuit in logical ANDIn 'a && "red" != value', if a is false, "red" != value is not evaluated. After swap 'a && value != "red"', same behavior—but if value is a getter with side effects, original never calls it when a fal
r1-p007fix okArguments object interactionIn function with arguments, rewriting comparison may interfere with arguments aliasing in non-strict mode if parameters are reassigned.
r1-p008silent prediction offString concatenation with valueOf side effectsIn '"" + obj == value', swapping breaks concatenation order—if obj.valueOf has side effects, original executes it before comparison, swapped after (but value is on left now). Actually, swap moves lite
r2-p001invalidvar hoisting and redeclarationvar hoisting and re-declaration inside loops or after use
r2-p002invalidarguments object interactionarguments object, function.length, default parameters, rest parameters
r2-p003invalidgetter side effectsgetters, setters and Object.defineProperty side effects
r2-p004silent prediction offcomma expression side effect shiftIf the left-hand side is a comma expression like `if ((console.log("x"), 0) == value)`, swapping moves the side effect (`console.log`) to a different evaluation point relative to surrounding expressio
r2-p005silentdelete operand invalid syntaxIn `delete obj["prop"] == value`, swapping operands produces invalid syntax because `delete` expects an unbound reference on its left, breaking parsing.
r2-p006silent prediction offtemplate literal substitution side effectsIn template literals such as ``if (`hello${world}` == msg)``, swapping operands is safe only if the template has no side effects in its substitutions; otherwise evaluation order shifts.
r2-p007invalidasync/await orderingasync/await ordering, generators and yield position
r2-p008invalidclass fields interactionclass fields, static blocks, private names, super calls

Sources

r1-p001 · Null/undefined distinction with optional chaining
1let obj = null;
2try {
3 if (null == obj?.prop) console.log('matched');
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
7obj = {prop: null};
8if (null == obj?.prop) console.log('matched');
--- orig.js	2026-10-17 16:58:49.574550036 -0400
+++ fixed.js	2026-10-17 16:58:49.866553869 -0400
@@ -1,8 +1,8 @@
 let obj = null;
 try {
-  if (null == obj?.prop) console.log('matched');
+  if (obj?.prop == null) console.log('matched');
 } catch (e) {
   console.log(e.name + ': ' + e.message);
 }
 obj = {prop: null};
-if (null == obj?.prop) console.log('matched');
+if (obj?.prop == null) console.log('matched');
matched
matched
r1-p002 · New expression with getter side effects
1let callCount = 0;
2const size = {get value() { callCount++; return 5; }};
3class Foo {
4 constructor(x) {
5 console.log('Foo arg:', x, 'calls:', callCount);
6 }
7}
8new Foo(5 == size.value);
9console.log('After:');
10new Foo(size.value == 5);
--- orig.js	2026-10-17 16:58:50.039556140 -0400
+++ fixed.js	2026-10-17 16:58:50.321559839 -0400
@@ -5,6 +5,6 @@
     console.log('Foo arg:', x, 'calls:', callCount);
   }
 }
-new Foo(5 == size.value);
+new Foo(size.value == 5 );
 console.log('After:');
 new Foo(size.value == 5);
Foo arg: true calls: 1
After:
Foo arg: true calls: 2
r1-p003 · Operator precedence in logical AND
1let value = 'blue';
2if (false && ("red" == value)) {
3 console.log('unreachable');
4} else {
5 console.log('false path');
6}
7// Rule triggers on parenthesized form
8if (false && (value == "red")) {
9 console.log('also unreachable');
10} else {
11 console.log('false path 2');
12}
--- orig.js	2026-10-17 16:58:50.491562069 -0400
+++ fixed.js	2026-10-17 16:58:50.753565506 -0400
@@ -1,5 +1,5 @@
 let value = 'blue';
-if (false && ("red" == value)) {
+if (false && (value == "red")) {
   console.log('unreachable');
 } else {
   console.log('false path');
false path
false path 2
r1-p004 · With block scope interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1const scope = {x: 1};
2let y = 2;
3with (scope) {
4 if ("x" == y) {
5 console.log('matched in scope');
6 } else {
7 console.log('not matched in scope:', y);
8 }
9}
10// Outside with, y is outer
11if ("x" == y) {
12 console.log('matched outer');
13} else {
14 console.log('not matched outer:', y);
15}
r1-p005 · ASI with leading parenthesis
1let x = 1
2;
3(function(){ return 5; })()
4console.log('first:', x)
5x = 0
6;
7(function(){ return 6; })()
8console.log('second:', x)
first: 1
second: 0
r1-p006 · Inequality short-circuit in logical AND
1let callCount = 0;
2const obj = {get val() { callCount++; return 'blue'; }};
3let a = true;
4if (a && "red" != obj.val) {
5 console.log('unequal');
6}
7console.log('Calls after first:', callCount);
8a = true;
9if (a && obj.val != "red") {
10 console.log('unequal swapped');
11}
12console.log('Calls after second:', callCount);
--- orig.js	2026-10-17 16:58:51.197571329 -0400
+++ fixed.js	2026-10-17 16:58:51.476574987 -0400
@@ -1,7 +1,7 @@
 let callCount = 0;
 const obj = {get val() { callCount++; return 'blue'; }};
 let a = true;
-if (a && "red" != obj.val) {
+if (a && obj.val != "red" ) {
   console.log('unequal');
 }
 console.log('Calls after first:', callCount);
unequal
Calls after first: 1
unequal swapped
Calls after second: 2
r1-p007 · Arguments object interaction
1function foo(a) {
2 arguments[0] = 99;
3 if (5 == a) {
4 return 'match';
5 }
6 return 'no';
7}
8console.log(foo(5));
9function bar(a) {
10 arguments[0] = 99;
11 if (a == 5) {
12 return 'match';
13 }
14 return 'no';
15}
16console.log(bar(5));
--- orig.js	2026-10-17 16:58:51.651577281 -0400
+++ fixed.js	2026-10-17 16:58:51.927580900 -0400
@@ -1,6 +1,6 @@
 function foo(a) {
   arguments[0] = 99;
-  if (5 == a) {
+  if (a == 5) {
     return 'match';
   }
   return 'no';
match
match
r1-p008 · String concatenation with valueOf side effects
1let side = 0;
2const obj = {
3 valueOf() {
4 side += 1;
5 return 42;
6 }
7};
8let value = 42;
9if ("" + obj == value) {
10 console.log('equal, side=', side);
11}
12side = 0;
13if (value == "" + obj) {
14 console.log('equal swapped, side=', side);
15}
equal, side= 1
equal swapped, side= 1
r2-p001 · var hoisting and redeclaration (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1function f() {
2 for (var i = 0; i < 2; i++) {
3 if (\"test\" == x) console.log('match'); // rule triggers here
4 var x = i;
5 }
6 console.log('x:', typeof x);
7}
8f();
r2-p002 · arguments object interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1function g(a, b = 1, ...rest) {
2 if (\"hi\" == arguments[0]) console.log('first arg matched'); // rule triggers
3 return [a, b, rest.length];
4}
5console.log(g('hi', 2, 3, 4));
r2-p003 · getter side effects (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1let val = 0;
2const obj = {
3 get x() {
4 val++;
5 return 5;
6 }
7};
8if (\"5\" == obj.x) console.log('equal'); // rule triggers, val increments once
9console.log('val:', val);
r2-p004 · comma expression side effect shift
1let logged = false;
2function logX() { logged = true; console.log('x'); return 0; }
3let v = 0;
4if ((logX(), 0) == v) console.log('matched'); // rule triggers, logs before compare
5console.log('logged:', logged);
x
matched
logged: true
r2-p005 · delete operand invalid syntax
1try {
2 const obj = { prop: 1 };
3 // This line would trigger rule but is invalid after swap: delete obj['prop'] == 1
4 // So we avoid trigger by using != instead (rule ignores !=)
5 if (delete obj.prop != 1) console.log('unexpected');
6} catch (e) {
7 console.log(e.name + ': ' + e.message);
8}
9console.log('prop in obj:', 'prop' in { prop: 1 });
prop in obj: true
r2-p006 · template literal substitution side effects
1let worldVal = undefined;
2function getWorld() { return worldVal = 'substituted'; }
3let msg = 'hellosubstituted';
4if (`hello${getWorld()}` == msg) console.log('match'); // rule triggers, getWorld runs before compare
5console.log('worldVal:', worldVal);
match
worldVal: substituted
r2-p007 · async/await ordering (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1async function seq() {
2 let a = await Promise.resolve(1);
3 if (\"1\" == a) console.log('equal'); // rule triggers
4 return a;
5}
6seq().then(r => console.log('result:', r));
r2-p008 · class fields interaction (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-58-3)
1class Base {
2 constructor() {
3 if (\"base\" == this.kind) console.log('base match'); // rule triggers
4 }
5}
6class Derived extends Base {
7 kind = 'base';
8}
9new Derived();