eslint no-regex-spaces
labelled safe
Analysis Nemotron 3 Super
Flags regex patterns containing two or more consecutive literal spaces.
Fix: Replaces every maximal sequence of N ≥ 2 literal spaces inside a regex pattern with '{N}' (e.g., ' ' → '{3}'), preserving quotes and flags.
1 hazards
- The fix assumes the pattern is a literal string; if the regex is built via concatenation or variables, the autofix may corrupt non-literal parts.], [
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p004 | fix-changes-behavior | labelled safe | program-bug · low | related | The program attempts to call a regular expression literal as a function, which throws a TypeError both before and after the fix. The behavioral difference is c… |
| r2-p005 | fix-changes-behavior | labelled safe | program-bug · low | related | The program fails before the fix with a TypeError because the regex literal is immediately followed by `.test` without a semicolon, causing the parser to treat… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | invalid | Function declaration nested in block with repeated call | function declarations inside blocks, switch cases, labeled statements |
| r1-p002 | fix ok | Arguments object accessing parameter after regex-dependent shift | arguments object, function.length, default parameters, rest parameters |
| r1-p003 | fix ok | __proto__ key mutation affecting regex lookup via prototype chain | __proto__ keys, prototype access, Object.assign vs spread |
| r1-p004 | fix-changes-behavior | ASI hazard: leading paren misparsed as function call after regex | ASI and semicolon-less code, leading ( or [ on the next line |
| r1-p005 | silent | Regex built via concatenation: fix corrupts variable part | The fix assumes the pattern is a literal string; if the regex is built via concatenation or variables, the autofix may corrupt non-literal parts. |
| r1-p006 | fix ok | Var hoisting and redeclaration inside loop after regex use | var hoisting and re-declaration inside loops or after use |
| r1-p007 | fix ok | Unicode flag and lastIndex interaction with g flag after fix | regular expressions: escapes, unicode flag, lastIndex with the g flag |
| r1-p008 | silent prediction off | Exception thrown in closure capturing rewritten regex | exceptions thrown inside the code the fix removes or rewrites |
| r2-p001 | fix ok | Sparse Arrays Holes Interaction | sparse arrays, holes, Array(n) vs [n], array-likes |
| r2-p002 | fix ok | __proto__ Key Mutation Prototype Lookup | __proto__ keys, prototype access, Object.assign vs spread |
| r2-p003 | fix ok | Var Hoisting Redefinition Loop After Use | var hoisting and re-declaration inside loops or after use |
| r2-p004 | fix ok | Order of Evaluation Merged Duplicated Deleted Side Effects | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
| r2-p005 | fix-changes-behavior | ASI Semicolon-less Leading Paren Bracket Next Line | ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p006 | fix ok | Comments Attached to Removed Moved Code | comments attached to the removed or moved code |
| r2-p007 | fix ok | Getters Setters DefineProperty Side Effects | getters, setters and Object.defineProperty side effects |
| r2-p008 | fix ok | Null Undefined Distinction Optional Chaining Nullish | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
Sources
r1-p001 · Function declaration nested in block with repeated call (generated program does not terminate within the time limit)
1if (true) {
2 let count = 0;
3 function f() { return /a b/.test('a b'); }
4 do {
5 if (f()) count++;
6 } while (count < 2);
7}
8console.log(count);
r1-p002 · Arguments object accessing parameter after regex-dependent shift
1function g(x, y = /x y\s+/.test('x y')) {
2 if (arguments.length === 2 && arguments[1]) return arguments[0] + 1;
3 return 0;
4}
5console.log(g(5));
--- orig.js 2026-10-22 14:18:52.486908933 -0400 +++ fixed.js 2026-10-22 14:18:55.757032769 -0400 @@ -1,4 +1,4 @@ -function g(x, y = /x y\s+/.test('x y')) { +function g(x, y = /x {4}y\s+/.test('x y')) { if (arguments.length === 2 && arguments[1]) return arguments[0] + 1; return 0; }
0
r1-p003 · __proto__ key mutation affecting regex lookup via prototype chain
1const base = { getPat: () => /test{2,} end/ };
2const obj = { __proto__: base };
3obj.getPat = () => /test{2,} end/;
4let hits = 0;
5for (let i = 0; i < 2; i++) {
6 if (obj.getPat().test('testxx end')) hits++;
7}
8console.log(hits);
--- orig.js 2026-10-22 14:18:52.486908933 -0400 +++ fixed.js 2026-10-22 14:18:56.372056100 -0400 @@ -1,6 +1,6 @@ -const base = { getPat: () => /test{2,} end/ }; +const base = { getPat: () => /test{2,} {2}end/ }; const obj = { __proto__: base }; -obj.getPat = () => /test{2,} end/; +obj.getPat = () => /test{2,} {2}end/; let hits = 0; for (let i = 0; i < 2; i++) { if (obj.getPat().test('testxx end')) hits++;
0
r1-p004 · ASI hazard: leading paren misparsed as function call after regex
1let x = /'hello world'/
2(['a','b']).forEach(c => { if (/^h/.test(c)) x = null })
3console.log(x === null ? 'failed' : x.source)
--- orig.js 2026-10-22 14:18:52.487908971 -0400 +++ fixed.js 2026-10-22 14:18:56.208049877 -0400 @@ -1,3 +1,3 @@ -let x = /'hello world'/ +let x = /'hello {3}world'/ (['a','b']).forEach(c => { if (/^h/.test(c)) x = null }) console.log(x === null ? 'failed' : x.source)
r1-p005 · Regex built via concatenation: fix corrupts variable part
1const spacer = ' ';
2const pat = new RegExp('foo' + spacer + 'bar');
3console.log(pat.test('foo bar') ? 'ok' : 'bad');
ok
r1-p006 · Var hoisting and redeclaration inside loop after regex use
1function scopeTest() {
2 if (true) {
3 var v = 1;
4 if (/pattern{1,3} tail/.test('patternxx tail')) v = 2;
5 {
6 var v = 3;
7 console.log(v);
8 }
9 }
10}
11scopeTest();
--- orig.js 2026-10-22 14:18:52.489909047 -0400 +++ fixed.js 2026-10-22 14:18:54.628990012 -0400 @@ -1,7 +1,7 @@ function scopeTest() { if (true) { var v = 1; - if (/pattern{1,3} tail/.test('patternxx tail')) v = 2; + if (/pattern{1,3} {3}tail/.test('patternxx tail')) v = 2; { var v = 3; console.log(v);
3
r1-p007 · Unicode flag and lastIndex interaction with g flag after fix
1let re = /\s+ \d+/gu;
2re.lastIndex = 0;
3let m1 = re.exec('a 5');
4let m2 = re.exec('a 5');
5console.log(m1 ? m1.index : -1, m2 ? m2.index : -1);
--- orig.js 2026-10-22 14:18:55.680029850 -0400 +++ fixed.js 2026-10-22 14:18:58.910152509 -0400 @@ -1,4 +1,4 @@ -let re = /\s+ \d+/gu; +let re = /\s+ {2}\d+/gu; re.lastIndex = 0; let m1 = re.exec('a 5'); let m2 = re.exec('a 5');
-1 -1
r1-p008 · Exception thrown in closure capturing rewritten regex
1let fails = 0;
2try {
3 [/start \t middle/].forEach(r => {
4 if (!r.test('start\t\tmiddle')) throw new Error('no match');
5 });
6} catch (e) {
7 fails++;
8 console.log(e.name, e.message);
9}
10console.log(fails);
Error no match 1
r2-p001 · Sparse Arrays Holes Interaction
1const arr = [];
2arr[0] = /a b/.test('a b');
3arr[2] = /x y/.test('x y');
4console.log(arr.length, arr[0], arr[1], arr[2]);
--- orig.js 2026-10-22 14:19:13.256701362 -0400 +++ fixed.js 2026-10-22 14:19:15.872802139 -0400 @@ -1,4 +1,4 @@ const arr = []; -arr[0] = /a b/.test('a b'); -arr[2] = /x y/.test('x y'); +arr[0] = /a {2}b/.test('a b'); +arr[2] = /x {4}y/.test('x y'); console.log(arr.length, arr[0], arr[1], arr[2]);
3 true undefined true
r2-p002 · __proto__ Key Mutation Prototype Lookup
1let obj = { __proto__: null };
2obj.__proto__ = { test: /hello world/.test('hello world') };
3const copy = Object.assign({}, obj);
4console.log(copy.test);
--- orig.js 2026-10-22 14:19:13.256701362 -0400 +++ fixed.js 2026-10-22 14:19:17.029846777 -0400 @@ -1,4 +1,4 @@ let obj = { __proto__: null }; -obj.__proto__ = { test: /hello world/.test('hello world') }; +obj.__proto__ = { test: /hello {2}world/.test('hello world') }; const copy = Object.assign({}, obj); console.log(copy.test);
true
r2-p003 · Var Hoisting Redefinition Loop After Use
1for (var i = 0; i < 2; i++) {
2 if (i === 0) var pattern = /test case/;
3 console.log(pattern.test('test case'));
4}
5console.log(typeof pattern);
--- orig.js 2026-10-22 14:19:13.257701401 -0400 +++ fixed.js 2026-10-22 14:19:17.069848322 -0400 @@ -1,5 +1,5 @@ for (var i = 0; i < 2; i++) { - if (i === 0) var pattern = /test case/; + if (i === 0) var pattern = /test {2}case/; console.log(pattern.test('test case')); } console.log(typeof pattern);
true true object
r2-p004 · Order of Evaluation Merged Duplicated Deleted Side Effects
1let count = 0;
2function side() { return ++count; }
3console.log((/a b/.test('a b'), side()) + (side(), /x y/.test('x y')));
--- orig.js 2026-10-22 14:19:13.257701401 -0400 +++ fixed.js 2026-10-22 14:19:17.025846623 -0400 @@ -1,3 +1,3 @@ let count = 0; function side() { return ++count; } -console.log((/a b/.test('a b'), side()) + (side(), /x y/.test('x y'))); +console.log((/a {2}b/.test('a b'), side()) + (side(), /x {4}y/.test('x y')));
2
r2-p005 · ASI Semicolon-less Leading Paren Bracket Next Line
1let x = /hello world/.test('hello world')
2
3(() => { console.log('IIFE ran'); })()
4console.log(x);
--- orig.js 2026-10-22 14:19:13.258701439 -0400 +++ fixed.js 2026-10-22 14:19:17.125850484 -0400 @@ -1,4 +1,4 @@ -let x = /hello world/.test('hello world') +let x = /hello {2}world/.test('hello world') (() => { console.log('IIFE ran'); })() console.log(x);
r2-p006 · Comments Attached to Removed Moved Code
1// Keep this
2/pattern match/
3// Important comment
4console.log(/pattern match/.test('pattern match'));
--- orig.js 2026-10-22 14:19:13.258701439 -0400 +++ fixed.js 2026-10-22 14:19:17.022846507 -0400 @@ -1,4 +1,4 @@ // Keep this -/pattern match/ +/pattern {2}match/ // Important comment -console.log(/pattern match/.test('pattern match')); +console.log(/pattern {2}match/.test('pattern match'));
true
r2-p007 · Getters Setters DefineProperty Side Effects
1let obj = {};
2Object.defineProperty(obj, 'prop', {
3 get: () => /test value/.test('test value'),
4 enumerable: true
5});
6console.log(obj.prop);
--- orig.js 2026-10-22 14:19:17.472863883 -0400 +++ fixed.js 2026-10-22 14:19:21.205008194 -0400 @@ -1,6 +1,6 @@ let obj = {}; Object.defineProperty(obj, 'prop', { - get: () => /test value/.test('test value'), + get: () => /test {2}value/.test('test value'), enumerable: true }); console.log(obj.prop);
true
r2-p008 · Null Undefined Distinction Optional Chaining Nullish
1let value = null;
2console.log(value?.match(/a b/));
3value = undefined;
4console.log(value?.match(/a b/) ?? 'nullish');
--- orig.js 2026-10-22 14:19:18.656909621 -0400 +++ fixed.js 2026-10-22 14:19:21.288011409 -0400 @@ -1,4 +1,4 @@ let value = null; -console.log(value?.match(/a b/)); +console.log(value?.match(/a {2}b/)); value = undefined; -console.log(value?.match(/a b/) ?? 'nullish'); +console.log(value?.match(/a {2}b/) ?? 'nullish');
undefined nullish