fixhunt

biome style/useTrimStartEnd

labelled safe
Runs / 2026-10-17T21-07-19-761Z-tpod-biome-style_useTrimStartEndbiome 2.5.152026-10-17 21:07 UTC8 programs × 2 round(s)15 programs, 12 fired, 12 fixed, 2 findings, 1 rejectedmodel cost $0.03

Analysis Nemotron 3 Super

Flags calls to String.trimLeft() and trimRight() and suggests replacing them with the semantically identical but preferred String.trimStart() and trimEnd().

Fix: Replaces .trimLeft() with .trimStart() and .trimRight() with .trimEnd(), preserving all surrounding syntax including method call parentheses and any chained expressions.

11 hazards
  • The rewrite assumes the base expression is a string; if it is not, both the original and rewritten code will throw a TypeError at runtime, so behavior is preserved but errors may occur where none were expected.
  • If the method is accessed via a property name that is dynamically computed (e.g., obj[method]()), changing the hardcoded name from 'trimLeft' to 'trimStart' alters which property is looked up, potentially causing a different function to be called or undefined to be invoked.
  • If the code relies on the method being non-enumerable or having specific descriptors (unlikely for built-ins), the rewrite does not affect descriptors since it only changes the identifier used in property access.
  • In rare cases where trimLeft or trimRight has been overridden on String.prototype or an instance, the rewrite bypasses the override by calling the standard trimStart/trimEnd methods, altering behavior.
  • If the call is part of a larger expression with side effects (e.g., in a logical chain like foo && bar.trimLeft()), the rewrite does not change evaluation order or side-effect timing.
  • Comments attached directly to the method name (e.g., trimLeft/*comment*/()) would be lost because the autofix replaces the entire identifier, stripping any inline comments.
  • If the code uses a with statement that binds a variable named trimLeft or trimStart, the lookup semantics could differ, though with is deprecated and rarely used.
  • In strict mode, if trimLeft or trimStart is mistakenly referenced as a variable due to a typo, the rewrite could turn a ReferenceError into a valid method call (or vice versa), but this is outside the rule's scope as it only applies to property accesses.
  • If the base expression evaluates to an object with a custom trimLeft property that is not a function (e.g., a getter with side effects), replacing the property name changes which getter is invoked.
  • The autofix does not preserve trailing whitespace or formatting inside the method call parentheses (which are empty anyway), so no behavioral impact there.
  • If the method is called via optional chaining (e.g., foo?.trimLeft()), the rewrite correctly preserves the optional chaining operator, so no hazard arises from that form.

Findings

programoraclelabeljudgestatussummary
r1-p004fix-changes-behaviorlabelled safeintended-change · lowno matchThe rule intentionally replaces the deprecated aliases trimLeft/trimRight with the standard trimStart/trimEnd methods. The program calls trimLeft on a plain ob…
r1-p005fix-changes-behaviorlabelled safeintrospection-only · lowno matchThe program throws a TypeError because `s` is null, and the error message includes the method name that was called. The fix changes `trimLeft` to its alias `tr…

Programs

idresulttitlehazard
r1-p001fix okControl Flow Interferencelabel/break/continue control flow, finally blocks, early returns in nested blocks
r1-p002invalidWith Statement Lookup HazardIf the code uses a with statement that binds a variable named trimLeft or trimStart, the lookup semantics could differ, though with is deprecated and rarely used.
r1-p003fix okTrailing Whitespace PreservationThe autofix does not preserve trailing whitespace or formatting inside the method call parentheses (which are empty anyway), so no behavioral impact there.
r1-p004fix-changes-behaviorCoercion Interactionsnumeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt
r1-p005fix-changes-behaviorException Safetyexceptions thrown inside the code the fix removes or rewrites
r1-p006silent prediction offPrototype and Property Access__proto__ keys, prototype access, Object.assign vs spread
r1-p007fix okProperty Descriptor SensitivityIf the code relies on the method being non-enumerable or having specific descriptors (unlikely for built-ins), the rewrite does not affect descriptors since it only changes the identifier used in prop
r1-p008fix okOptional Chaining PreservationIf the method is called via optional chaining (e.g., foo?.trimLeft()), the rewrite correctly preserves the optional chaining operator, so no hazard arises from that form.
r2-p002fix okSide effects in logical chainEvaluation order and side-effect timing must be preserved in logical expressions.
r2-p003fix okAsync/await orderingRewriting must not alter await timing or promise resolution order.
r2-p004fix okInline comment on method nameAutofix strips inline comments attached to the method identifier.
r2-p005fix okComment on removed code lineComments on the line containing the trimmed method may be lost after rewrite.
r2-p006silent prediction offFunction declaration in blockBlock-scoped function declarations must not be disturbed by rewrites in their scope.
r2-p007fix okTrailing whitespace in parenthesesAutofix does not change whitespace inside method call parentheses (irrelevant here).
r2-p008fix okOrder of evaluation with side effectsSide effects in surrounding expressions must not run twice or be skipped.

Sources

r1-p001 · Control Flow Interference
1outer: {
2 let s = ' hello ';
3 inner: {
4 if (true) break outer;
5 console.log(s.trimLeft());
6 }
7}
8console.log('done');
--- orig.js	2026-10-17 17:07:29.974662689 -0400
+++ fixed.js	2026-10-17 17:07:30.251665670 -0400
@@ -2,7 +2,7 @@
   let s = '   hello   ';
   inner: {
     if (true) break outer;
-    console.log(s.trimLeft());
+    console.log(s.trimStart());
   }
 }
 console.log('done');
done
r1-p002 · With Statement Lookup Hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-07-1)
1(function() {
2 var trimLeft = function() { return 'BAD'; };
3 with ({ s: ' x ' }) {
4 console.log(s.trimLeft());
5 }
6})();
r1-p003 · Trailing Whitespace Preservation
1let s = ' test ';
2console.log(s.trimLeft().length);
--- orig.js	2026-10-17 17:07:30.464667962 -0400
+++ fixed.js	2026-10-17 17:07:30.747671006 -0400
@@ -1,2 +1,2 @@
 let s = '  test  ';
-console.log(s.trimLeft().length);
+console.log(s.trimStart().length);
6
r1-p004 · Coercion Interactions
1let obj = {
2 toString: () => ' abc '
3};
4console.log((obj).trimLeft() + 'def');
--- orig.js	2026-10-17 17:07:30.919672857 -0400
+++ fixed.js	2026-10-17 17:07:31.183675697 -0400
@@ -1,4 +1,4 @@
 let obj = {
   toString: () => '   abc   '
 };
-console.log((obj).trimLeft() + 'def');
+console.log((obj).trimStart() + 'def');
r1-p005 · Exception Safety
1let s = null;
2try {
3 console.log(s.trimLeft());
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
--- orig.js	2026-10-17 17:07:31.355677548 -0400
+++ fixed.js	2026-10-17 17:07:31.629680495 -0400
@@ -1,6 +1,6 @@
 let s = null;
 try {
-  console.log(s.trimLeft());
+  console.log(s.trimStart());
 } catch (e) {
   console.log(e.name + ': ' + e.message);
 }
TypeError: Cannot read properties of null (reading 'trimLeft')
r1-p006 · Prototype and Property Access
1let s = ' hi ';
2let o = { __proto__: String.prototype };
3console.log(o.trimLeft.call(s));
hi
r1-p007 · Property Descriptor Sensitivity
1let s = ' x ';
2let desc = Object.getOwnPropertyDescriptor(String.prototype, 'trimLeft');
3console.log(desc.enumerable);
4console.log(s.trimLeft());
--- orig.js	2026-10-17 17:07:32.022684723 -0400
+++ fixed.js	2026-10-17 17:07:32.287687573 -0400
@@ -1,4 +1,4 @@
 let s = '  x  ';
 let desc = Object.getOwnPropertyDescriptor(String.prototype, 'trimLeft');
 console.log(desc.enumerable);
-console.log(s.trimLeft());
+console.log(s.trimStart());
false
x
r1-p008 · Optional Chaining Preservation
1let s = null;
2console.log(s?.trimLeft() ?? 'null');
3s = ' ok ';
4console.log(s?.trimLeft());
--- orig.js	2026-10-17 17:07:32.450689326 -0400
+++ fixed.js	2026-10-17 17:07:32.720692230 -0400
@@ -1,4 +1,4 @@
 let s = null;
-console.log(s?.trimLeft() ?? 'null');
+console.log(s?.trimStart() ?? 'null');
 s = '  ok  ';
-console.log(s?.trimLeft());
+console.log(s?.trimStart());
null
ok
r2-p002 · Side effects in logical chain
1let side = 0;
2function log() { return ++side; }
3const result = log() && ' hello'.trimLeft();
4console.log(`side=${side}, result='${result}'`);
--- orig.js	2026-10-17 17:07:37.141739749 -0400
+++ fixed.js	2026-10-17 17:07:37.431742865 -0400
@@ -1,4 +1,4 @@
 let side = 0;
 function log() { return ++side; }
-const result = log() && '  hello'.trimLeft();
+const result = log() && '  hello'.trimStart();
 console.log(`side=${side}, result='${result}'`);
side=1, result='hello'
r2-p003 · Async/await ordering
1async function test() {
2 const p = Promise.resolve(' world');
3 const a = await p;
4 const b = a.trimRight();
5 console.log(`'${b}'`);
6}
7test().catch(e => console.error(e));
--- orig.js	2026-10-17 17:07:37.593744604 -0400
+++ fixed.js	2026-10-17 17:07:37.859747462 -0400
@@ -1,7 +1,7 @@
 async function test() {
   const p = Promise.resolve('  world');
   const a = await p;
-  const b = a.trimRight();
+  const b = a.trimEnd();
   console.log(`'${b}'`);
 }
 test().catch(e => console.error(e));
'  world'
r2-p004 · Inline comment on method name
1const s = ' hello';
2console.log(s.trimLeft/* keep this */());
--- orig.js	2026-10-17 17:07:38.048749492 -0400
+++ fixed.js	2026-10-17 17:07:38.329752510 -0400
@@ -1,2 +1,2 @@
 const s = '  hello';
-console.log(s.trimLeft/* keep this */());
+console.log(s.trimStart/* keep this */());
hello
r2-p005 · Comment on removed code line
1// trim whitespace from input
2const input = ' test ';
3const out = input.trimLeft(); // keep this comment
4console.log(`'${out}'`);
--- orig.js	2026-10-17 17:07:38.503754378 -0400
+++ fixed.js	2026-10-17 17:07:38.775757300 -0400
@@ -1,4 +1,4 @@
 // trim whitespace from input
 const input = '  test  ';
-const out = input.trimLeft(); // keep this comment
+const out = input.trimStart(); // keep this comment
 console.log(`'${out}'`);
'test  '
r2-p006 · Function declaration in block
1{
2 function f() { return ' ok '; }
3 const result = f().trimEnd();
4 console.log(`'${result}'`);
5}
'  ok'
r2-p007 · Trailing whitespace in parentheses
1const s = ' foo';
2console.log(s.trimLeft( /* no args */ ));
--- orig.js	2026-10-17 17:07:39.156761391 -0400
+++ fixed.js	2026-10-17 17:07:39.414764161 -0400
@@ -1,2 +1,2 @@
 const s = '  foo';
-console.log(s.trimLeft( /* no args */ ));
+console.log(s.trimStart( /* no args */ ));
foo
r2-p008 · Order of evaluation with side effects
1let count = 0;
2function inc() { return ++count; }
3const vals = [inc(), inc()].map(v => `${v}`.trimLeft());
4console.log(`count=${count}, vals=${vals}`);
--- orig.js	2026-10-17 17:07:39.578765922 -0400
+++ fixed.js	2026-10-17 17:07:39.851768853 -0400
@@ -1,4 +1,4 @@
 let count = 0;
 function inc() { return ++count; }
-const vals = [inc(), inc()].map(v => `${v}`.trimLeft());
+const vals = [inc(), inc()].map(v => `${v}`.trimStart());
 console.log(`count=${count}, vals=${vals}`);
count=2, vals=1,2