fixhunt

biome complexity/useRegexLiterals

labelled safe
Runs / 2026-10-17T20-13-15-620Z-xspf-biome-complexity_useRegexLiteralsbiome 2.5.152026-10-17 20:13 UTC8 programs × 2 round(s)16 programs, 6 fired, 6 fixed, 1 findings, 0 rejectedmodel cost $0.03

Analysis Nemotron 3 Super

Flags uses of the RegExp constructor where both arguments are static strings, recommending replacement with a regex literal.

Fix: Replaces `new RegExp(pattern, flags)` with `/pattern/flags` when both `pattern` and `flags` are string literals, preserving the exact literal values including escape sequences.

10 hazards
  • If the pattern contains a forward slash (`/`), the regex literal may terminate early, causing a syntax error or incorrect pattern (e.g., `new RegExp("/abc/", "")` becomes `///abc///`, which is invalid).
  • If the pattern contains unescaped regex metacharacters that were intended to be literal (e.g., `new RegExp("[abc]", "")`), the literal behaves the same, but future maintainers might misinterpret intent—though behavior is preserved, this is noted as a readability hazard in some contexts.
  • If the flags string contains characters not valid in regex literals (e.g., `new RegExp("a", "xy")`), the literal `/a/xy` is invalid and throws a SyntaxError, whereas the constructor would have thrown a runtime TypeError—changing error timing and type.
  • If the pattern is an empty string (`new RegExp("", "g")`), the literal `//g` is invalid due to ambiguous comment start, causing a parse failure where the constructor succeeded.
  • If the flags string is empty (`new RegExp("abc", "")`), the literal `/abc/` is valid and equivalent, so no hazard here—but included for completeness in edge-case analysis.
  • If the RegExp call is inside a larger expression (e.g., `x = new RegExp("a", "b") + 1`), the rewrite changes the expression structure and may affect operator precedence or parsing if not properly parenthesized (though Biome’s fix assumes standalone or safe contexts).
  • If the code relies on the RegExp constructor creating a distinct object each time (e.g., for testing `instanceof`), the literal also creates a new object per evaluation, so behavior is preserved—no hazard in this case.
  • If the pattern or flags string literals contain line terminators (e.g., via template literals misidentified as literals—though rule only fires on string literals), the rewrite would fail, but the rule only triggers on actual string literals, so this is excluded by precondition.
  • If a comment is between `new` and `RegExp` (e.g., `new /* hint */ RegExp("a", "b")`), Biome’s fixer may not trigger or may mishandle spacing, but the rule as documented flags the call shape regardless of whitespace—so assuming the fixer handles whitespace, no semantic hazard, but potential formatting loss.
  • If the code is in a context where `RegExp` has been shadowed (e.g., `let RegExp = String;`), the rule should not fire because it’s not the built-in, but if it does due to flawed detection, rewriting to a literal would break behavior by bypassing the shadow.

Findings

programoraclelabeljudgestatussummary
r2-p001fix-breaks-syntaxlabelled safereal · highrelatedThe fix rewrites `new RegExp('a', 'xy')` to the invalid regex literal `/a/xy`, which contains illegal flags 'x' and 'y'. The RegExp constructor accepts arbitra…

Programs

idresulttitlehazard
r1-p001fix okVar hoisting and redeclarationvar hoisting and re-declaration inside loops or after use
r1-p002silent prediction offName collision across scopesname collisions across scopes after a move (shadowing)
r1-p003fix okDistinct object creationIf the code relies on the RegExp constructor creating a distinct object each time (e.g., for testing `instanceof`), the literal also creates a new object per evaluation, so behavior is preserved—no ha
r1-p004silent prediction offRegExp shadowingIf the code is in a context where `RegExp` has been shadowed (e.g., `let RegExp = String;`), the rule should not fire because it’s not the built-in, but if it does due to flawed detection, rewriting t
r1-p005silent prediction offNull/undefined distinctionnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r1-p006silent prediction offThis bindingthis binding: arrow vs function, methods extracted from objects, call/apply/bind
r1-p007fix okPattern contains forward slashIf the pattern contains a forward slash (`/`), the regex literal may terminate early, causing a syntax error or incorrect pattern (e.g., `new RegExp("/abc/", "")` becomes `///abc///`, which is invalid
r1-p008silent prediction offNumeric/string coercionnumeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt
r2-p001fix-breaks-syntaxInvalid flags in regex literal cause SyntaxError instead of TypeErrorIf the flags string contains characters not valid in regex literals (e.g., `new RegExp("a", "xy")`), the literal `/a/xy` is invalid and throws a SyntaxError, whereas the constructor would have thrown
r2-p002silent prediction offName collision across scopes after a move (shadowing)name collisions across scopes after a move (shadowing)
r2-p003silent prediction offNull/undefined distinction with optional chainingnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r2-p004fix okSparse arrays and holes interactionsparse arrays, holes, Array(n) vs [n], array-likes
r2-p005silent prediction offOrder of evaluation with side effects duplicatedorder of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never)
r2-p006silent prediction offTemporal dead zone after hoisting/reorderingtemporal dead zone after code is hoisted or reordered
r2-p007silent prediction offFunction declaration inside block interacts with rewritefunction declarations inside blocks, switch cases, labeled statements
r2-p008fix ok prediction offVar hoisting and redeclaration inside loopVar hoisting and redeclaration (var hoisting and re-declaration inside loops or after use)

Sources

r1-p001 · Var hoisting and redeclaration
1for (var i = 0; i < 2; i++) {
2 var re = new RegExp('a', '');
3 console.log(re.test('a'));
4}
5console.log(typeof re);
--- orig.js	2026-10-17 16:13:28.891035700 -0400
+++ fixed.js	2026-10-17 16:13:29.198029711 -0400
@@ -1,5 +1,5 @@
 for (var i = 0; i < 2; i++) {
-  var re = new RegExp('a', '');
+  var re = /a/;
   console.log(re.test('a'));
 }
 console.log(typeof re);
true
true
object
r1-p002 · Name collision across scopes
1function outer() {
2 var RegExp = Array;
3 function inner() {
4 var re = new RegExp('x', '');
5 console.log(re instanceof RegExp);
6 }
7 inner();
8}
9outer();
true
r1-p003 · Distinct object creation
1function test() {
2 var a = new RegExp('a', '');
3 var b = new RegExp('a', '');
4 console.log(a !== b);
5}
6test();
--- orig.js	2026-10-17 16:13:29.583022207 -0400
+++ fixed.js	2026-10-17 16:13:29.864016730 -0400
@@ -1,6 +1,6 @@
 function test() {
-  var a = new RegExp('a', '');
-  var b = new RegExp('a', '');
+  var a = /a/;
+  var b = /a/;
   console.log(a !== b);
 }
 test();
true
r1-p004 · RegExp shadowing
1let RegExp = String;
2try {
3 var re = new RegExp('a', '');
4 console.log(re);
5} catch (e) {
6 console.log(e.name + ': ' + e.message);
7}
[String: 'a']
r1-p005 · Null/undefined distinction
1function getPattern() { return null; }
2var re = new RegExp(getPattern(), '');
3console.log(re === null ? 'null' : typeof re);
object
r1-p006 · This binding
1var obj = {
2 getPattern: function() { return 'a'; },
3 makeRE: function() { return new RegExp(this.getPattern(), ''); }
4};
5var fn = obj.makeRE;
6console.log(fn().test('a')); // Should be false due to lost this
r1-p007 · Pattern contains forward slash
1try {
2 var re = new RegExp('/abc/', '');
3 console.log(re.test('/abc/'));
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
--- orig.js	2026-10-17 16:13:30.706000351 -0400
+++ fixed.js	2026-10-17 16:13:30.959995412 -0400
@@ -1,5 +1,5 @@
 try {
-  var re = new RegExp('/abc/', '');
+  var re = /\/abc\//;
   console.log(re.test('/abc/'));
 } catch (e) {
   console.log(e.name + ': ' + e.message);
true
r1-p008 · Numeric/string coercion
1var obj = {
2 toString: function() { return '\\d+'; }
3};
4var re = new RegExp(obj, 'g');
5console.log(re.test('123'));
true
r2-p001 · Invalid flags in regex literal cause SyntaxError instead of TypeError
1try {
2 console.log(new RegExp('a', 'xy').test(''));
3} catch (e) {
4 console.log(e.constructor.name + ': ' + e.message);
5}
--- orig.js	2026-10-17 16:13:37.696865576 -0400
+++ fixed.js	2026-10-17 16:13:37.977860201 -0400
@@ -1,5 +1,5 @@
 try {
-  console.log(new RegExp('a', 'xy').test(''));
+  console.log(/a/xy.test(''));
 } catch (e) {
   console.log(e.constructor.name + ': ' + e.message);
 }
SyntaxError: Invalid flags supplied to RegExp constructor 'xy'
r2-p002 · Name collision across scopes after a move (shadowing)
1function outer() {
2 let RegExp = class {};
3 try {
4 console.log(new RegExp('a', 'g').test('a'));
5 } catch (e) {
6 console.log(e.constructor.name + ': ' + e.message);
7 }
8}
9outer();
TypeError: (intermediate value).test is not a function
r2-p003 · Null/undefined distinction with optional chaining
1const maybePattern = null;
2console.log((maybePattern ?? '\\d+').length);
3try {
4 console.log(new RegExp(maybePattern ?? '\\d+', 'g').test('1'));
5} catch (e) {
6 console.log(e.constructor.name + ': ' + e.message);
7}
3
true
r2-p004 · Sparse arrays and holes interaction
1const arr = Array(2);
2arr[0] = new RegExp('a', 'g');
3console.log(arr[0].test('a'));
4console.log(arr[1] === undefined ? 'hole' : arr[1]);
--- orig.js	2026-10-17 16:13:38.464850905 -0400
+++ fixed.js	2026-10-17 16:13:38.734845752 -0400
@@ -1,4 +1,4 @@
 const arr = Array(2);
-arr[0] = new RegExp('a', 'g');
+arr[0] = /a/g;
 console.log(arr[0].test('a'));
 console.log(arr[1] === undefined ? 'hole' : arr[1]);
true
hole
r2-p005 · Order of evaluation with side effects duplicated
1let count = 0;
2function getPattern() {
3 count++;
4 return 'a';
5}
6function getFlags() {
7 count++;
8 return 'g';
9}
10try {
11 console.log(new RegExp(getPattern(), getFlags()).test('a'));
12} catch (e) {
13 console.log(e.constructor.name + ': ' + e.message);
14}
15console.log('count: ' + count);
true
count: 2
r2-p006 · Temporal dead zone after hoisting/reordering
1function test() {
2 console.log(typeof pattern);
3 const pattern = '\\d+';
4 try {
5 console.log(new RegExp(pattern, 'g').test('1'));
6 } catch (e) {
7 console.log(e.constructor.name + ': ' + e.message);
8 }
9}
10test();
r2-p007 · Function declaration inside block interacts with rewrite
1{
2 function getFlags() { return 'g'; }
3 try {
4 console.log(new RegExp('a', getFlags()).test('a'));
5 } catch (e) {
6 console.log(e.constructor.name + ': ' + e.message);
7 }
8}
true
r2-p008 · Var hoisting and redeclaration inside loop
1for (var i = 0; i < 2; i++) {
2 var re = new RegExp('a', 'g');
3 console.log(re.test('a'));
4}
5console.log(typeof re);
--- orig.js	2026-10-17 16:13:39.594829366 -0400
+++ fixed.js	2026-10-17 16:13:39.853824434 -0400
@@ -1,5 +1,5 @@
 for (var i = 0; i < 2; i++) {
-  var re = new RegExp('a', 'g');
+  var re = /a/g;
   console.log(re.test('a'));
 }
 console.log(typeof re);
true
true
object