biome correctness/noSwitchDeclarations
labelled safe
Analysis Nemotron 3 Super
Flags lexical declarations directly inside switch cases without block scope.
Fix: Wraps the lexical declaration in a block by adding { before and } after the declaration statement within the switch case.
8 hazards
- The inserted block may alter automatic semicolon insertion if the original declaration lacked a terminating semicolon and the following token starts with [, (, /, +, -, or `.`, potentially changing parsing.
- If the lexical declaration is a function declaration, wrapping it in a block makes it block-scoped instead of function-scoped, altering its visibility outside the switch but within the function.
- Comments attached to the declaration via trailing comment syntax may be moved inside the block or misplaced if the autofix does not preserve comment attachment points.
- In strict mode, a block-wrapped function declaration is not allowed and will throw a SyntaxError, whereas the original might have been tolerated in non-strict contexts.
- If the switch case contains multiple statements and the fix only wraps the first declaration, subsequent statements may fall out of the intended block scope.
- The rewrite assumes the declaration is a single statement; if it is part of a comma-separated expression or larger statement, wrapping it in a block breaks syntactic validity.
- Labels preceding the switch case will now apply to the block rather than the declaration, potentially altering break/continue target behavior if labels were used.
- If the declaration uses `var` (which the rule should not flag but might due to misconfiguration), wrapping it in a block does not change its function-scoping, leading to unnecessary complexity without semantic benefit.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Sparse Arrays and Holes | Wrapping a const declaration in a block inside a switch changes how we capture variables when processing sparse arrays via iterator-like closure. |
| r1-p003 | fix ok | Function Decl Visibility Changed by Block Scope | Wrap function decl in block → becomes block-scoped → no longer hoisted to function scope → visible only inside case → breaks reuse after switch. |
| r1-p004 | fix ok | Null/Undefined Distinction | Block wrap alters timing of nullish check evaluation in chain causing different short-circuit path and thrown error. |
| r1-p005 | silent prediction off | Comma Expression Breaks Syntax | Rule tries to wrap comma-expr in block → invalid syntax → throws SyntaxError during execution (simulated via eval to avoid parse failure). |
| r1-p006 | fix ok | Var Misconfiguration Unnecessary Block | Rule incorrectly flags var → wraps in block → no scoping change → extra block but harmless; we detect block via shadowing attempt. |
| r1-p007 | fix ok | Label/Break/Continue Control Flow | Added block changes break target: break now exits block not case → fallthrough → wrong value used. |
| r1-p008 | fix ok | __proto__ Keys and Prototype Access | Wrapped decl creates new block scope → closure captures different __proto__ descriptor due to timing of property access in loop. |
| r2-p001 | fix ok | ASI Hazard with Open Parenthesis | The inserted block may alter automatic semicolon insertion if the original declaration lacked a terminating semicolon and the following token starts with `(`, `[`, `/`, `+`, `-`, or `` ` ``. |
| r2-p002 | fix ok | Function Declaration Visibility Change | If the lexical declaration is a function declaration, wrapping it in a block makes it block-scoped instead of function-scoped, altering its visibility outside the switch but within the function. |
| r2-p003 | fix ok | Sparse Arrays and Holes Mutation | sparse arrays, holes, Array(n) vs [n], array-likes |
| r2-p004 | fix ok | Var Hoisting and Redeclaration Conflict | var hoisting and re-declaration inside loops or after use |
| r2-p005 | fix ok | Name Collision Across Scopes via Shadowing | name collisions across scopes after a move (shadowing) |
| r2-p006 | fix ok | ASI and Semicolon-less Code with Leading Bracket | ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p007 | fix ok | Null/Undefined Distinction in Optional Chaining | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r2-p008 | fix ok | Getter Side Effect Altered by Block Scope | getters, setters and Object.defineProperty side effects |
Sources
r1-p001 · Sparse Arrays and Holes
1function process(arr) {
2 let total = 0;
3 arr.forEach((v, i) => {
4 switch(i) {
5 case 0:
6 const captured = v + 10;
7 return total += captured;
8 default:
9 const fallback = v || -1;
10 return total -= fallback * 2;
11 }
12 });
13 console.log('Result:', total);
14}
15process([5]); // hole at index 1
--- orig.js 2026-10-17 16:45:42.209197992 -0400 +++ fixed.js 2026-10-17 16:45:42.487205406 -0400 @@ -2,12 +2,14 @@ let total = 0; arr.forEach((v, i) => { switch(i) { - case 0: + case 0: { const captured = v + 10; return total += captured; - default: + } + default: { const fallback = v || -1; return total -= fallback * 2; + } } }); console.log('Result:', total);
Result: 15
r1-p003 · Function Decl Visibility Changed by Block Scope
1function outer() {
2 let result = [];
3 switch(true) {
4 case x > 0:
5 function getVal() { return x * 2; }
6 break;
7 }
8 try {
9 result.push(getVal());
10 } catch(e) {
11 result.push(e.name);
12 }
13 return result.join(':');
14}
15let x = 5;
16console.log(outer());
--- orig.js 2026-10-17 16:45:42.664210126 -0400 +++ fixed.js 2026-10-17 16:45:42.953217834 -0400 @@ -1,9 +1,10 @@ function outer() { let result = []; switch(true) { - case x > 0: + case x > 0: { function getVal() { return x * 2; } break; + } } try { result.push(getVal());
ReferenceError
r1-p004 · Null/Undefined Distinction
1function check(value) {
2 switch(typeof value) {
3 case 'object':
4 const data = value?.prop?.sub;
5 if (data == null) throw 'nullish';
6 return data;
7 default:
8 return undefined;
9 }
10}
11try {
12 console.log(check(null));
13} catch(e) {
14 console.log('Caught:', e);
15}
--- orig.js 2026-10-17 16:45:43.112222070 -0400 +++ fixed.js 2026-10-17 16:45:43.398229688 -0400 @@ -1,9 +1,10 @@ function check(value) { switch(typeof value) { - case 'object': + case 'object': { const data = value?.prop?.sub; if (data == null) throw 'nullish'; return data; + } default: return undefined; }
Caught: nullish
r1-p005 · Comma Expression Breaks Syntax
1let x = 1;
2try {
3 eval("switch(x){case 1: const y=2, z=y+1; break}");
4} catch(e) {
5 if (e instanceof SyntaxError) {
6 console.log('SyntaxError as expected');
7 } else {
8 throw e;
9 }
10}
r1-p006 · Var Misconfiguration Unnecessary Block
1function testVar() {
2 switch(1) {
3 case 1:
4 var scoped = 99;
5 if (true) {
6 var scoped = 88; // redeclaration ok in same function scope
7 }
8 console.log(scoped);
9 break;
10 }
11}
12testVar();
--- orig.js 2026-10-17 16:45:43.768239543 -0400 +++ fixed.js 2026-10-17 16:45:44.056247212 -0400 @@ -1,12 +1,13 @@ function testVar() { switch(1) { - case 1: + case 1: { var scoped = 99; if (true) { var scoped = 88; // redeclaration ok in same function scope } console.log(scoped); break; + } } } testVar();
88
r1-p007 · Label/Break/Continue Control Flow
1let out = '';
2lab: {
3 switch(1) {
4 case 1:
5 const msg = 'A';
6 break lab;
7 }
8 out += 'B';
9}
10console.log(out);
--- orig.js 2026-10-17 16:45:44.229251814 -0400 +++ fixed.js 2026-10-17 16:45:44.483258571 -0400 @@ -1,9 +1,10 @@ let out = ''; lab: { switch(1) { - case 1: + case 1: { const msg = 'A'; break lab; + } } out += 'B'; }
r1-p008 · __proto__ Keys and Prototype Access
1const proto = { __proto__: null, toString: () => 'hidden' };
2function makeObj() {
3 switch(true) {
4 case true:
5 const desc = Object.getOwnPropertyDescriptor(proto, '__proto__');
6 return () => desc.get.call({});
7 }
8}
9try {
10 const fn = makeObj();
11 console.log(fn());
12} catch(e) {
13 console.log(e.name);
14}
--- orig.js 2026-10-17 16:45:44.649262987 -0400 +++ fixed.js 2026-10-17 16:45:44.927270383 -0400 @@ -1,9 +1,10 @@ const proto = { __proto__: null, toString: () => 'hidden' }; function makeObj() { switch(true) { - case true: + case true: { const desc = Object.getOwnPropertyDescriptor(proto, '__proto__'); return () => desc.get.call({}); + } } } try {
TypeError
r2-p001 · ASI Hazard with Open Parenthesis
1function f(){
2 switch(0){case 0:
3 const x = () => ({a:1})
4 x().a
5 }
6}
7console.log(f());
--- orig.js 2026-10-17 16:45:49.453390372 -0400 +++ fixed.js 2026-10-17 16:45:49.737397879 -0400 @@ -1,7 +1,7 @@ function f(){ - switch(0){case 0: + switch(0){case 0: { const x = () => ({a:1}) - x().a + x().a} } } console.log(f());
undefined
r2-p002 · Function Declaration Visibility Change
1function outer(){
2 switch(0){case 0:
3 function inner(){ return 'inner' }
4 }
5 try{ return inner() }catch(e){ return e.message }
6}
7console.log(outer());
--- orig.js 2026-10-17 16:45:49.912402505 -0400 +++ fixed.js 2026-10-17 16:45:50.215410508 -0400 @@ -1,6 +1,6 @@ function outer(){ - switch(0){case 0: - function inner(){ return 'inner' } + switch(0){case 0: { + function inner(){ return 'inner' }} } try{ return inner() }catch(e){ return e.message } }
inner is not defined
r2-p003 · Sparse Arrays and Holes Mutation
1function test(){
2 let arr = new Array(3);
3 switch(0){case 0:
4 const v = arr[1] = 99
5 }
6 return arr[1];
7}
8console.log(test());
--- orig.js 2026-10-17 16:45:50.397415313 -0400 +++ fixed.js 2026-10-17 16:45:50.658422204 -0400 @@ -1,7 +1,7 @@ function test(){ let arr = new Array(3); - switch(0){case 0: - const v = arr[1] = 99 + switch(0){case 0: { + const v = arr[1] = 99} } return arr[1]; }
99
r2-p004 · Var Hoisting and Redeclaration Conflict
1function test(){
2 switch(0){case 0:
3 var x = 1
4 }
5 var x = 2
6 return x;
7}
8console.log(test());
--- orig.js 2026-10-17 16:45:50.806426111 -0400 +++ fixed.js 2026-10-17 16:45:51.093433685 -0400 @@ -1,6 +1,6 @@ function test(){ - switch(0){case 0: - var x = 1 + switch(0){case 0: { + var x = 1} } var x = 2 return x;
2
r2-p005 · Name Collision Across Scopes via Shadowing
1function test(){
2 let y = 'outer';
3 switch(0){case 0:
4 const y = 'inner';
5 return y;
6 }
7}
8console.log(test());
--- orig.js 2026-10-17 16:45:51.272438405 -0400 +++ fixed.js 2026-10-17 16:45:51.559445973 -0400 @@ -1,8 +1,8 @@ function test(){ let y = 'outer'; - switch(0){case 0: + switch(0){case 0: { const y = 'inner'; - return y; + return y;} } } console.log(test());
inner
r2-p006 · ASI and Semicolon-less Code with Leading Bracket
1function test(){
2 switch(0){case 0:
3 const x = [1,2]
4 [x[0], x[1]] = [x[1], x[0]]
5 return x[0] + ',' + x[1]
6 }
7}
8console.log(test());
--- orig.js 2026-10-17 16:45:51.732450535 -0400 +++ fixed.js 2026-10-17 16:45:52.027458313 -0400 @@ -1,8 +1,8 @@ function test(){ - switch(0){case 0: + switch(0){case 0: { const x = [1,2] [x[0], x[1]] = [x[1], x[0]] - return x[0] + ',' + x[1] + return x[0] + ',' + x[1]} } } console.log(test());
r2-p007 · Null/Undefined Distinction in Optional Chaining
1function test(){
2 switch(0){case 0:
3 const obj = { a: null }
4 return obj.a?.b ?? 'default'
5 }
6}
7console.log(test());
--- orig.js 2026-10-17 16:45:52.206463027 -0400 +++ fixed.js 2026-10-17 16:45:52.497470690 -0400 @@ -1,7 +1,7 @@ function test(){ - switch(0){case 0: + switch(0){case 0: { const obj = { a: null } - return obj.a?.b ?? 'default' + return obj.a?.b ?? 'default'} } } console.log(test());
default
r2-p008 · Getter Side Effect Altered by Block Scope
1function test(){
2 let log = [];
3 switch(0){case 0:
4 const obj = { get x(){ log.push(1); return 2 } }
5 log.push(obj.x);
6 return log;
7 }
8}
9console.log(test());
--- orig.js 2026-10-17 16:45:52.662475035 -0400 +++ fixed.js 2026-10-17 16:45:52.942482409 -0400 @@ -1,9 +1,9 @@ function test(){ let log = []; - switch(0){case 0: + switch(0){case 0: { const obj = { get x(){ log.push(1); return 2 } } log.push(obj.x); - return log; + return log;} } } console.log(test());
[ 1, 2 ]