biome style/useNumericSeparators
labelled safe
Analysis Nemotron 3 Super
The rule flags integer and floating-point literals lacking digit group separators according to configurable minimum length and group size.
Fix: Inserts underscores as digit separators starting from the least significant digits, grouping according to the rule's groupLength option for the literal's base, only when the total digit count meets or exceeds minimumDigits.
11 hazards
- In template literals like `${12345}`, inserting separators changes the evaluated string value because digits are altered.
- In tagged template literals such as `str`12345`ess`, the raw string received by the tag function differs, potentially changing the tag's output.
- When a numeric literal is part of a larger identifier via concatenation like `"num" + 12345`, the fix changes the resulting string from "num12345" to "num12_345".
- If the literal appears in a comment-assisting context such as `// value: 12345 → process()`, moving or altering the literal breaks the comment's accuracy.
- In regex literals containing digit patterns like `/12345/`, the rule does not apply, but if misapplied would break the pattern; however, the fix only targets standalone literals, so this is not a direct hazard—yet adjacent slashes could be confused during tokenization if whitespace is mishandled.
- In legacy octal literals like `0644` (invalid in strict mode), the rule does not fire, but if mistakenly processed, inserting separators would yield `0_6_4_4`, which is not a valid octal literal and causes a syntax error.
- When the literal is inside a JSX text node such as `<Text>12345</Text>`, the rule does not apply because it's not a JS expression, but if incorrectly targeted, the UI would render "12_345" instead of "12345".
- If the literal is a boundary case like `12345` and groupLength is 2, producing `1_23_45`, a subsequent dot access like `(1_23_45).toString()` remains valid, but if the literal were mistakenly applied to a property access chain such as `obj.12345` (invalid syntax), no fix occurs because it's not a literal.
- In eval contexts like `eval("12345")`, the fix does not apply because the literal is inside a string, but if the string were rewritten, the evaluated result changes from 12345 to 12_345 (invalid syntax) or, if parsed as separate tokens, may throw.
- When the literal has leading zeros such as `0012345` (treated as decimal 12345), inserting separators yields `00_12_345`, which is still a valid decimal literal but may be unexpected if the leading zeros were semantically meaningful (e.g., for padding).
- In automatic semicolon insertion scenarios, if the fix introduces a line break due to formatting changes (though it doesn't), it could affect ASI—but the fix only inserts underscores, so line structure is preserved.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Tagged Template Literal Raw String Change | In tagged template literals such as `str`12345`ess`, the raw string received by the tag function differs, potentially changing the tag's output. |
| r1-p002 | fix ok | Function Declaration in Block Scope Capture | function declarations inside blocks, switch cases, labeled statements |
| r1-p003 | fix ok | __proto__ Key vs Property Access Interaction | __proto__ keys, prototype access, Object.assign vs spread |
| r1-p004 | fix ok | ASI with Leading Parenthesis After Underscored Literal | ASI and semicolon-less code, leading ( or [ on the next line |
| r1-p005 | fix ok prediction off | Property Access Chain Invalid Syntax Near-Miss | If the literal is a boundary case like `12345` and groupLength is 2, producing `1_23_45`, a subsequent dot access like `(1_23_45).toString()` remains valid, but if the literal were mistakenly applied |
| r1-p006 | fix ok | Class Field Initialization with Underscored Literal | class fields, static blocks, private names, super calls |
| r1-p007 | fix ok | Arguments Object and Default Parameter Interaction | arguments object, function.length, default parameters, rest parameters |
| r1-p008 | fix ok | Async Await Ordering with Underscored Literal in Yield Context | async/await ordering, generators and yield position |
| r2-p001 | fix ok | Function declaration inside block scope with numeric separator insertion | function declarations inside blocks, switch cases, labeled statements |
| r2-p002 | silent | Regex literal adjacency confusion due to missing whitespace handling | adjacent slashes confused during tokenization if whitespace is mishandled |
| r2-p003 | fix ok | __proto__ key interaction with numeric separator insertion | __proto__ keys, prototype access, Object.assign vs spread |
| r2-p004 | fix ok | Temporal Dead Zone after hoisting/reordering with numeric literal rewrite | temporal dead zone after code is hoisted or reordered |
| r2-p005 | invalid | Leading zeros in decimal literal preserved but separator inserted | When the literal has leading zeros such as `0012345` |
| r2-p006 | fix ok | Exception thrown inside code that gets rewritten by fix | exceptions thrown inside the code the fix removes or rewrites |
| r2-p007 | fix ok | Template literal interpolation changed by numeric separator insertion | In template literals like `${12345}`, inserting separators changes the evaluated string value |
| r2-p008 | fix ok | Getter/setter interaction with numeric separator in property initialization | getters, setters and Object.defineProperty side effects |
Sources
r1-p001 · Tagged Template Literal Raw String Change
1function str(parts) {
2 return parts.raw[0] + '|' + parts.raw[1];
3}
4console.log(str`a${12345}b`);
--- orig.js 2026-10-17 17:06:31.197025464 -0400 +++ fixed.js 2026-10-17 17:06:31.479028544 -0400 @@ -1,4 +1,4 @@ function str(parts) { return parts.raw[0] + '|' + parts.raw[1]; } -console.log(str`a${12345}b`); +console.log(str`a${12_345}b`);
a|b
r1-p002 · Function Declaration in Block Scope Capture
1{ function f() { return 12345; }
2 console.log(f()); }
3{ function f() { return 67890; }
4 console.log(f()); }
--- orig.js 2026-10-17 17:06:31.652030434 -0400 +++ fixed.js 2026-10-17 17:06:31.923033395 -0400 @@ -1,4 +1,4 @@ -{ function f() { return 12345; } +{ function f() { return 12_345; } console.log(f()); } -{ function f() { return 67890; } +{ function f() { return 67_890; } console.log(f()); }
12345 67890
r1-p003 · __proto__ Key vs Property Access Interaction
1const obj = { __proto__: { toString: () => 'proto' }, 12345: 'value' };
2console.log(obj.__proto__.toString(), obj[12345]);
--- orig.js 2026-10-17 17:06:32.088035197 -0400 +++ fixed.js 2026-10-17 17:06:32.373038309 -0400 @@ -1,2 +1,2 @@ const obj = { __proto__: { toString: () => 'proto' }, 12345: 'value' }; -console.log(obj.__proto__.toString(), obj[12345]); +console.log(obj.__proto__.toString(), obj[12_345]);
proto value
r1-p004 · ASI with Leading Parenthesis After Underscored Literal
1let x = 12345
2(function(){ return x * 2; })()
3console.log(x)
--- orig.js 2026-10-17 17:06:32.542040155 -0400 +++ fixed.js 2026-10-17 17:06:32.815043136 -0400 @@ -1,3 +1,3 @@ -let x = 12345 +let x = 12_345 (function(){ return x * 2; })() console.log(x)
r1-p005 · Property Access Chain Invalid Syntax Near-Miss
1try {
2 eval('obj.12345');
3} catch(e) {
4 console.log(e.name + ': ' + e.message);
5}
6console.log((12345).toString());
--- orig.js 2026-10-17 17:06:32.983044971 -0400 +++ fixed.js 2026-10-17 17:06:33.247047853 -0400 @@ -3,4 +3,4 @@ } catch(e) { console.log(e.name + ': ' + e.message); } -console.log((12345).toString()); +console.log((12_345).toString());
SyntaxError: Unexpected number 12345
r1-p006 · Class Field Initialization with Underscored Literal
1class C {
2 instance = 12345;
3 static staticVal = 67890;
4 #private = 11111;
5 constructor() { console.log(this.instance, C.staticVal, this.#private); }
6}
7new C();
--- orig.js 2026-10-17 17:06:33.411049644 -0400 +++ fixed.js 2026-10-17 17:06:33.677052548 -0400 @@ -1,7 +1,7 @@ class C { - instance = 12345; - static staticVal = 67890; - #private = 11111; + instance = 12_345; + static staticVal = 67_890; + #private = 11_111; constructor() { console.log(this.instance, C.staticVal, this.#private); } } new C();
12345 67890 11111
r1-p007 · Arguments Object and Default Parameter Interaction
1function f(a = 12345, b, ...rest) {
2 console.log(arguments[0], a, b, rest.length);
3}
4f(undefined, 67890);
--- orig.js 2026-10-17 17:06:33.845054382 -0400 +++ fixed.js 2026-10-17 17:06:34.116057340 -0400 @@ -1,4 +1,4 @@ -function f(a = 12345, b, ...rest) { +function f(a = 12_345, b, ...rest) { console.log(arguments[0], a, b, rest.length); } -f(undefined, 67890); +f(undefined, 67_890);
undefined 12345 67890 0
r1-p008 · Async Await Ordering with Underscored Literal in Yield Context
1async function* gen() {
2 yield 12345;
3 yield await 67890;
4}
5(async() => {
6 for await (const v of gen()) console.log(v);
7})();
--- orig.js 2026-10-17 17:06:34.275059076 -0400 +++ fixed.js 2026-10-17 17:06:34.534061902 -0400 @@ -1,6 +1,6 @@ async function* gen() { - yield 12345; - yield await 67890; + yield 12_345; + yield await 67_890; } (async() => { for await (const v of gen()) console.log(v);
12345 67890
r2-p001 · Function declaration inside block scope with numeric separator insertion
1{
2 function foo() {
3 return 12345;
4 }
5 console.log(foo());
6}
--- orig.js 2026-10-17 17:06:37.955099225 -0400 +++ fixed.js 2026-10-17 17:06:38.220102115 -0400 @@ -1,6 +1,6 @@ { function foo() { - return 12345; + return 12_345; } console.log(foo()); }
12345
r2-p002 · Regex literal adjacency confusion due to missing whitespace handling
1/12345//test/
2console.log('pattern matched');
r2-p003 · __proto__ key interaction with numeric separator insertion
1const obj = {
2 __proto__: null,
3 x: 12345
4};
5console.log(obj.x);
--- orig.js 2026-10-17 17:06:38.621106487 -0400 +++ fixed.js 2026-10-17 17:06:38.901109539 -0400 @@ -1,5 +1,5 @@ const obj = { __proto__: null, - x: 12345 + x: 12_345 }; console.log(obj.x);
12345
r2-p004 · Temporal Dead Zone after hoisting/reordering with numeric literal rewrite
1console.log(typeof y);
2let y = 12345;
3console.log(y);
--- orig.js 2026-10-17 17:06:39.081111502 -0400 +++ fixed.js 2026-10-17 17:06:39.348114412 -0400 @@ -1,3 +1,3 @@ console.log(typeof y); -let y = 12345; +let y = 12_345; console.log(y);
r2-p005 · Leading zeros in decimal literal preserved but separator inserted (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-06-2)
1let code = 0012345;
2console.log(code.toString());
r2-p006 · Exception thrown inside code that gets rewritten by fix
1try {
2 throw new Error('value: ' + 12345);
3} catch (e) {
4 console.log(e.message);
5}
--- orig.js 2026-10-17 17:06:39.557116690 -0400 +++ fixed.js 2026-10-17 17:06:39.819119546 -0400 @@ -1,5 +1,5 @@ try { - throw new Error('value: ' + 12345); + throw new Error('value: ' + 12_345); } catch (e) { console.log(e.message); }
value: 12345
r2-p007 · Template literal interpolation changed by numeric separator insertion
1let id = 12345;
2console.log(`ID: ${id}`);
--- orig.js 2026-10-17 17:06:39.988121388 -0400 +++ fixed.js 2026-10-17 17:06:40.271124472 -0400 @@ -1,2 +1,2 @@ -let id = 12345; +let id = 12_345; console.log(`ID: ${id}`);
ID: 12345
r2-p008 · Getter/setter interaction with numeric separator in property initialization
1const obj = {
2 get num() {
3 return 12345;
4 }
5};
6console.log(obj.num);
--- orig.js 2026-10-17 17:06:40.437126281 -0400 +++ fixed.js 2026-10-17 17:06:40.722129387 -0400 @@ -1,6 +1,6 @@ const obj = { get num() { - return 12345; + return 12_345; } }; console.log(obj.num);
12345