eslint no-extra-label
labelled safe
Analysis Nemotron 3 Super
The rule flags labeled statements where the associated break or continue targets only the immediate enclosing statement.
Fix: Remove the label prefix from the labeled statement and replace any labeled break or continue targeting that label with its unlabeled equivalent.
8 hazards
- Rewriting a labeled block statement (`L: { ... }`) changes scoping: variables declared with `var` inside the block become function-scoped instead of block-scoped after label removal.
- If the labeled statement is a function declaration, removing the label alters hoisting behavior—function declarations are hoisted regardless, but labeled function expressions are not, and the fix incorrectly assumes it's a statement.
- Labels can serve as documentation or markers for debugging tools; removing them may strip meaningful intent even when the label appears 'extra'.
- When a labeled statement contains a `with` block, removing the label does not affect semantics, but linters may misinterpret the shape due to `with` altering scope resolution.
- If the labeled statement is empty (`L: ;`), removing the label yields an empty statement, which is semantically identical, but some minifiers or tools may treat labeled empty statements differently in edge cases.
- In rare cases, labels are used with `eval` or `Function` constructor via string concatenation (e.g., `eval('L: break L;')`), where removing the label changes the evaluated code’s meaning—though this is outside static analysis scope, it represents a semantic dependency.
- If a label is referenced by a `break` or `continue` in a dynamically constructed string passed to `eval`, the autofix cannot detect this usage, so removing the label may break eval’d code that relies on the label existing.
- When a labeled loop contains a `continue` with a label, replacing it with an unlabeled `continue` is only valid if the loop is the immediate enclosing iteration statement—if misidentified, it could target the wrong loop or cause a syntax error.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Empty labeled statement | If the labeled statement is empty (`L: ;`), removing the label yields an empty statement, which is semantically identical, but some minifiers or tools may treat labeled empty statements differently in |
| r1-p002 | invalid | Function declaration labeling | If the labeled statement is a function declaration, removing the label alters hoisting behavior—function declarations are hoisted regardless, but labeled function expressions are not, and the fix inco |
| r1-p003 | fix ok | Strict vs sloppy mode | strict vs sloppy mode semantics |
| r1-p004 | fix ok | Comments attached to label | comments attached to the removed or moved code |
| r1-p005 | invalid | Arguments object capture | arguments object, function.length, default parameters, rest parameters |
| r1-p006 | silent prediction off | Eval with dynamic label reference | If a label is referenced by a `break` or `continue` in a dynamically constructed string passed to `eval`, the autofix cannot detect this usage, so removing the label may break eval’d code that relies |
| r1-p007 | invalid | Function declaration in block | function declarations inside blocks, switch cases, labeled statements |
| r1-p008 | invalid | Class field with label | class fields, static blocks, private names, super calls |
| r2-p001 | fix ok | Regular expression with global flag and lastIndex mutation | regular expressions: escapes, unicode flag, lastIndex with the g flag |
| r2-p002 | fix ok | Object.defineProperty with getter side effect | getters, setters and Object.defineProperty side effects |
| r2-p003 | fix ok | Label removal causes variable shadowing in inner scope | name collisions across scopes after a move (shadowing) |
| r2-p004 | fix ok | Temporal dead zone after label removal affects let access | temporal dead zone after code is hoisted or reordered |
| r2-p005 | invalid | With block inside labeled statement - label removal safe but shape altered | When a labeled statement contains a `with` block, removing the label does not affect semantics, but linters may misinterpret the shape due to `with` altering scope resolution. |
| r2-p006 | silent prediction off | Mislabeled continue in nested loop - fix creates syntax error | When a labeled loop contains a `continue` with a label, replacing it with an unlabeled `continue` is only valid if the loop is the immediate enclosing iteration statement—if misidentified, it could ta |
| r2-p007 | invalid | Class field initialization with label - removal does not alter semantics | class fields, static blocks, private names, super calls |
| r2-p008 | silent prediction off | Function declaration in labeled block - label removal changes nothing but interacts with scope | function declarations inside blocks, switch cases, labeled statements |
Sources
r1-p001 · Empty labeled statement
1L: ;
2console.log('empty');
empty
r1-p002 · Function declaration labeling (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1function f() {
2 console.log(typeof g);
3}
4F: function g() { return 42; }
5console.log(g());
r1-p003 · Strict vs sloppy mode
1'use strict';
2X: while (false) { break X; }
3console.log('strict ok');
--- orig.js 2026-10-22 14:17:20.855602769 -0400 +++ fixed.js 2026-10-22 14:17:23.685699547 -0400 @@ -1,3 +1,3 @@ 'use strict'; -X: while (false) { break X; } +X: while (false) { break; } console.log('strict ok');
strict ok
r1-p004 · Comments attached to label
1Y: /* important */ while (false) { break Y; }
2console.log('comment preserved?');
--- orig.js 2026-10-22 14:17:20.855602769 -0400 +++ fixed.js 2026-10-22 14:17:24.405724230 -0400 @@ -1,2 +1,2 @@ -Y: /* important */ while (false) { break Y; } +Y: /* important */ while (false) { break; } console.log('comment preserved?');
comment preserved?
r1-p005 · Arguments object capture (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1Z: function(a, b = 1, ...rest) {
2 console.log(arguments.length, b, rest.length);
3 break Z;
4}(5)
5console.log('done');
r1-p006 · Eval with dynamic label reference
1label: {
2 const code = 'break label;';
3 try { eval(code); } catch (e) {
4 console.log(e.name + ': ' + e.message);
5 }
6}
SyntaxError: Undefined label 'label'
r1-p007 · Function declaration in block (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1{ A: function f() { return 1; } }
2console.log(f());
r1-p008 · Class field with label (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1B: class C { x = 1; }
2console.log(new C().x);
r2-p001 · Regular expression with global flag and lastIndex mutation
1let count = 0;
2X: while (count < 3) {
3 const re = /a/g;
4 re.lastIndex = 0;
5 const m = re.exec('baaab');
6 if (!m) break X;
7 count += m[0].length;
8}
9console.log(count);
--- orig.js 2026-10-22 14:17:31.318962446 -0400 +++ fixed.js 2026-10-22 14:17:36.745150964 -0400 @@ -3,7 +3,7 @@ const re = /a/g; re.lastIndex = 0; const m = re.exec('baaab'); - if (!m) break X; + if (!m) break; count += m[0].length; } console.log(count);
3
r2-p002 · Object.defineProperty with getter side effect
1const obj = {};
2let log = '';
3Y: while (!obj.prop) {
4 Object.defineProperty(obj, 'prop', {
5 get() { log += 'get'; return 1; }
6 });
7 if (obj.prop) break Y;
8}
9console.log(log);
--- orig.js 2026-10-22 14:17:31.319962481 -0400 +++ fixed.js 2026-10-22 14:17:36.659147966 -0400 @@ -4,6 +4,6 @@ Object.defineProperty(obj, 'prop', { get() { log += 'get'; return 1; } }); - if (obj.prop) break Y; + if (obj.prop) break; } console.log(log);
get
r2-p003 · Label removal causes variable shadowing in inner scope
1let x = 1;
2A: for (; ;) {
3 let x = 2;
4 if (x === 2) break A;
5}
6console.log(x);
--- orig.js 2026-10-22 14:17:31.320962516 -0400 +++ fixed.js 2026-10-22 14:17:36.708149674 -0400 @@ -1,6 +1,6 @@ let x = 1; A: for (; ;) { let x = 2; - if (x === 2) break A; + if (x === 2) break; } console.log(x);
1
r2-p004 · Temporal dead zone after label removal affects let access
1B: while (false) {
2 console.log(typeof tmp);
3 let tmp = 1;
4 break B;
5}
6console.log('done');
--- orig.js 2026-10-22 14:17:31.321962550 -0400 +++ fixed.js 2026-10-22 14:17:34.403069432 -0400 @@ -1,6 +1,6 @@ B: while (false) { console.log(typeof tmp); let tmp = 1; - break B; + break; } console.log('done');
done
r2-p005 · With block inside labeled statement - label removal safe but shape altered (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1let v = 5;
2C: { with ({v: 10}) { break C; } }
3console.log(v);
r2-p006 · Mislabeled continue in nested loop - fix creates syntax error
1let out = 0;
2D: for (let i=0; i<2; i++) {
3 E: for (let j=0; j<2; j++) {
4 if (j === 0) continue D;
5 out += i + j;
6 }
7}
8console.log(out);
0
r2-p007 · Class field initialization with label - removal does not alter semantics (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-17-1)
1class C {
2 F: {
3 instanceField = 1;
4 break F;
5 }
6 static getValue() { return new C().instanceField; }
7}
8console.log(C.getValue());
r2-p008 · Function declaration in labeled block - label removal changes nothing but interacts with scope
1G: {
2 function f() { return 1; }
3 if (f() === 1) break G;
4}
5console.log(typeof f);
function