fixhunt

biome complexity/useWhile

labelled safe
Runs / 2026-10-17T20-16-00-929Z-j9nr-biome-complexity_useWhilebiome 2.5.152026-10-17 20:16 UTC8 programs × 2 round(s)15 programs, 15 fired, 15 fixed, 0 findings, 0 rejectedmodel cost $0.0026

Analysis Nemotron 3 Super

Flags for-loops without initialization or increment parts where only a condition remains, suggesting replacement with while loops.

Fix: Replace the for-loop with a while-loop using the condition as the test, keeping the loop body unchanged.

12 hazards
  • Moving variable declarations from the init part to before the loop may cause hoisting issues if the variable is used prior to the loop.
  • If the init part contains side-effecting expressions (e.g., function calls), removing them alters execution order and may omit required initialization.
  • The fix assumes no update part exists; if present but ignored by the rule due to being empty, the rewrite incorrectly drops it.
  • Labels or break/continue statements targeting the for-loop by label may become invalid if the loop structure changes.
  • Comments attached to the for or semicolons may be lost during rewrite if not preserved by the tool.
  • In strict mode, deleting a variable via the init part (if present) would behave differently if the init is removed.
  • If the condition uses `with` or indirect eval, scope resolution could differ between for and while constructs.
  • The rewrite may interfere with automatic semicolon insertion if the loop header is malformed or adjacent to problematic tokens.
  • If the loop is part of a larger expression (e.g., return for (;cond;) expr;), the statement conversion breaks grammar.
  • Using `this` in the condition may capture a different object if the loop rewrite changes execution context indirectly.
  • If the init part declares a variable with `var` that is later accessed outside the loop, moving it outside may not preserve temporal dead zone behavior (though var has none, confusion with let/const could arise).
  • If the condition is a complex expression involving commas, the rewrite may misinterpret precedence or evaluation order.

Programs

idresulttitlehazard
r1-p002fix ok__proto__ keys prototype accessRewriting a for-loop accessing obj.__proto__ in condition may alter prototype chain mutation visibility if loop re-runs after mutation.
r1-p003fix okcomplex expression with commasThe comma operator in for-condition has left-to-right evaluation; rewriting to while may break if condition relies on comma sequencing.
r1-p004fix oksparse arrays holesLoop condition checks array length; rewriting doesn't change behavior but must show interaction with sparse elements.
r1-p005fix ok prediction offtemporal dead zone after hoistingLoop condition accesses a let variable before its declaration (TDZ); rewriting doesn't move the condition, so TDZ still throws.
r1-p006fix okfunction declarations inside blocks switch labeledFunction declaration in loop body; rewriting loop shouldn't affect hoisting, but must show function is redefined each iteration if re-entered.
r1-p007fix ok prediction offstrict mode deleting variable via init partNot applicable: rule only triggers when init part is absent; no init to remove, so strict mode delete behavior unchanged.
r1-p008fix okregular expressions escapes unicode lastIndex g flagLoop condition uses regex.test() which advances lastIndex with g flag; rewriting doesn't change evaluation, so behavior preserved.
r2-p001fix okHoisting issue due to moving const/init variableMoving variable declarations from the init part to before the loop may cause hoisting issues if the variable is used prior to the loop.
r2-p002fix okVar redeclaration shadowing outer scopeIf the init part declares a variable with `var` that is later accessed outside the loop, moving it outside may not preserve temporal dead zone behavior (though var has none, confusion with let/const c
r2-p003fix okFunction declaration inside loop body affected by scopingfunction declarations inside blocks, switch cases, labeled statements
r2-p004fix okComment loss during rewrite affecting readabilityComments attached to the for or semicolons may be lost during rewrite if not preserved by the tool.
r2-p005fix okClass field initialization order dependencyclass fields, static blocks, private names, super calls
r2-p006fix okASI hazard with leading parenthesis after loopASI and semicolon-less code, leading ( or [ on the next line
r2-p007fix okSparse array length check in conditionsparse arrays, holes, Array(n) vs [n], array-likes
r2-p008fix okLabel break target invalidated by loop rewriteLabels or break/continue statements targeting the for-loop by label may become invalid if the loop structure changes.

Sources

r1-p002 · __proto__ keys prototype access
1let obj = { a: 1 };
2let proto = { b: 2 };
3obj.__proto__ = proto;
4let seen = [];
5for (; obj.__proto__;) {
6 seen.push(obj.__proto__.b);
7 obj.__proto__ = null;
8 break;
9}
10console.log(seen.length ? seen[0] : 'null');
--- orig.js	2026-10-17 16:16:14.821361406 -0400
+++ fixed.js	2026-10-17 16:16:15.112357606 -0400
@@ -2,7 +2,7 @@
 let proto = { b: 2 };
 obj.__proto__ = proto;
 let seen = [];
-for (; obj.__proto__;) {
+while (obj.__proto__) {
   seen.push(obj.__proto__.b);
   obj.__proto__ = null;
   break;
2
r1-p003 · complex expression with commas
1let x = 0, y = 0;
2for (; (x++, y++, x < 3);) {
3 console.log(`x:${x},y:${y}`);
4}
--- orig.js	2026-10-17 16:16:15.270355545 -0400
+++ fixed.js	2026-10-17 16:16:15.532352128 -0400
@@ -1,4 +1,4 @@
 let x = 0, y = 0;
-for (; (x++, y++, x < 3);) {
+while ((x++, y++, x < 3)) {
   console.log(`x:${x},y:${y}`);
 }
x:1,y:1
x:2,y:2
r1-p004 · sparse arrays holes
1let arr = [, , 3];
2let sum = 0;
3for (; arr.length > 0;) {
4 const v = arr.pop();
5 if (v !== undefined) sum += v;
6}
7console.log(sum);
--- orig.js	2026-10-17 16:16:15.715349742 -0400
+++ fixed.js	2026-10-17 16:16:15.986346208 -0400
@@ -1,6 +1,6 @@
 let arr = [, , 3];
 let sum = 0;
-for (; arr.length > 0;) {
+while (arr.length > 0) {
   const v = arr.pop();
   if (v !== undefined) sum += v;
 }
3
r1-p005 · temporal dead zone after hoisting
1try {
2 for (; typeof x === 'undefined';) {
3 console.log('unreachable');
4 }
5} catch (e) {
6 console.log(e.name + ': ' + e.message);
7}
8let x = 1;
--- orig.js	2026-10-17 16:16:16.161343931 -0400
+++ fixed.js	2026-10-17 16:16:16.452340146 -0400
@@ -1,5 +1,5 @@
 try {
-  for (; typeof x === 'undefined';) {
+  while (typeof x === 'undefined') {
     console.log('unreachable');
   }
 } catch (e) {
ReferenceError: Cannot access 'x' before initialization
r1-p006 · function declarations inside blocks switch labeled
1let fns = [];
2for (; fns.length < 2;) {
3 function f() { return fns.length; }
4 fns.push(f);
5}
6console.log(fns[0](), fns[1]());
--- orig.js	2026-10-17 16:16:16.623337921 -0400
+++ fixed.js	2026-10-17 16:16:16.892334422 -0400
@@ -1,5 +1,5 @@
 let fns = [];
-for (; fns.length < 2;) {
+while (fns.length < 2) {
   function f() { return fns.length; }
   fns.push(f);
 }
2 2
r1-p007 · strict mode deleting variable via init part
1'use strict';
2let v = 1;
3for (; v;) {
4 console.log(v);
5 v = 0;
6}
--- orig.js	2026-10-17 16:16:17.059332252 -0400
+++ fixed.js	2026-10-17 16:16:17.337328644 -0400
@@ -1,6 +1,6 @@
 'use strict';
 let v = 1;
-for (; v;) {
+while (v) {
   console.log(v);
   v = 0;
 }
1
r1-p008 · regular expressions escapes unicode lastIndex g flag
1let str = 'abab';
2let re = /ab/g;
3let matches = 0;
4for (; re.test(str);) {
5 matches++;
6}
7console.log(matches);
--- orig.js	2026-10-17 16:16:17.515326335 -0400
+++ fixed.js	2026-10-17 16:16:17.794322715 -0400
@@ -1,7 +1,7 @@
 let str = 'abab';
 let re = /ab/g;
 let matches = 0;
-for (; re.test(str);) {
+while (re.test(str)) {
   matches++;
 }
 console.log(matches);
2
r2-p001 · Hoisting issue due to moving const/init variable
1console.log(typeof x); // ReferenceError expected
2for (; false;) {}
3let x = 1;
4console.log('done');
--- orig.js	2026-10-17 16:16:23.064254837 -0400
+++ fixed.js	2026-10-17 16:16:23.348251208 -0400
@@ -1,4 +1,4 @@
 console.log(typeof x); // ReferenceError expected
-for (; false;) {}
+while (false) {}
 let x = 1;
 console.log('done');
r2-p002 · Var redeclaration shadowing outer scope
1var x = 1;
2for (; x < 2;) {
3 var x = 3;
4 console.log(x);
5 x++;
6}
7console.log(x);
--- orig.js	2026-10-17 16:16:23.516249060 -0400
+++ fixed.js	2026-10-17 16:16:23.780245687 -0400
@@ -1,5 +1,5 @@
 var x = 1;
-for (; x < 2;) {
+while (x < 2) {
   var x = 3;
   console.log(x);
   x++;
3
4
r2-p003 · Function declaration inside loop body affected by scoping
1for (; false;) {
2 function f() { return 1; }
3 break;
4}
5try { console.log(f()); } catch (e) { console.log(e.name + ': ' + e.message); }
--- orig.js	2026-10-17 16:16:23.942243616 -0400
+++ fixed.js	2026-10-17 16:16:24.213240160 -0400
@@ -1,4 +1,4 @@
-for (; false;) {
+while (false) {
   function f() { return 1; }
   break;
 }
ReferenceError: f is not defined
r2-p004 · Comment loss during rewrite affecting readability
1// precondition
2for (; /* stop */false;) {/* body */}
3console.log('executed');
--- orig.js	2026-10-17 16:16:24.386237955 -0400
+++ fixed.js	2026-10-17 16:16:24.661234449 -0400
@@ -1,3 +1,3 @@
 // precondition
-for (; /* stop */false;) {/* body */}
+while (/* stop */false) {/* body */}
 console.log('executed');
executed
r2-p005 · Class field initialization order dependency
1class C { static y = console.log('static') || 1; }
2for (; C.y;) {
3 console.log('loop');
4 break;
5}
--- orig.js	2026-10-17 16:16:24.832232269 -0400
+++ fixed.js	2026-10-17 16:16:25.115228666 -0400
@@ -1,5 +1,5 @@
 class C { static y = console.log('static') || 1; }
-for (; C.y;) {
+while (C.y) {
   console.log('loop');
   break;
 }
static
loop
r2-p006 · ASI hazard with leading parenthesis after loop
1for (; false;)
2(function(){ return console.log('IIFE') })()
3console.log('done')
--- orig.js	2026-10-17 16:16:25.278226593 -0400
+++ fixed.js	2026-10-17 16:16:25.555223071 -0400
@@ -1,3 +1,3 @@
-for (; false;)
+while (false)
 (function(){ return console.log('IIFE') })()
 console.log('done')
done
r2-p007 · Sparse array length check in condition
1const arr = Array(3); arr[1] = 'a';
2for (; arr.length > 1;) {
3 console.log(arr.length);
4 arr.pop();
5}
6console.log('end')
--- orig.js	2026-10-17 16:16:25.729220858 -0400
+++ fixed.js	2026-10-17 16:16:26.016217210 -0400
@@ -1,5 +1,5 @@
 const arr = Array(3); arr[1] = 'a';
-for (; arr.length > 1;) {
+while (arr.length > 1) {
   console.log(arr.length);
   arr.pop();
 }
3
2
end
r2-p008 · Label break target invalidated by loop rewrite
1outer:
2for (; false;) {
3 break outer;
4}
5console.log('after loop')
--- orig.js	2026-10-17 16:16:26.187215041 -0400
+++ fixed.js	2026-10-17 16:16:26.465211515 -0400
@@ -1,5 +1,5 @@
 outer:
-for (; false;) {
+while (false) {
   break outer;
 }
 console.log('after loop')
after loop