biome complexity/noUselessEmptyExport
labelled safe
Analysis Nemotron 3 Super
The rule flags unnecessary 'export {}' statements when another top-level import or export already exists in the same module.
Fix: The autofix removes the 'export {}' statement entirely, leaving the rest of the file unchanged.
8 hazards
- Removing 'export {}' in a file with only that export turns the module into a script, potentially breaking top-level 'this' semantics and strict mode enforcement.
- If the file relies on being a module for proper lexical scoping of top-level 'var' (which is not added to global in modules), removing the export could inadvertently expose 'var'-declared variables globally.
- In environments sensitive to module vs script distinction (e.g., Chrome extensions, Web Workers), removing the export may alter loading behavior or security policies.
- If the 'export {}' is followed by a comment that has semantic meaning (e.g., licensing, dependency metadata), its removal could strip important information even if the fix aims to preserve comments.
- When using bundlers that treat empty exports as entry points or side-effect markers, removing it might affect tree-shaking or bundle inclusion logic.
- If the file is intended to be imported solely for its side effects and the 'export {}' ensures module status, removing it could cause the file to be treated as a script, altering execution context.
- In TypeScript, removing the empty export may affect how the file is interpreted in ambient contexts or declaration merging, though less likely at term level.
- If the 'export {}' appears after a top-level await, removing it does not change module status (since await already makes it a module), but the fix still applies and is safe—however, this is not a hazard; instead, note that the fix remains safe even then.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Comment stripping hazard | If the 'export {}' is followed by a comment that has semantic meaning (e.g., licensing, dependency metadata), its removal could strip important information even if the fix aims to preserve comments. |
| r1-p002 | invalid | Exception during rewrite hazard | Exceptions thrown inside the code the fix removes or rewrites |
| r1-p003 | silent prediction off | Top-level var scoping hazard | If the file relies on being a module for proper lexical scoping of top-level 'var' (which is not added to global in modules), removing the export could inadvertently expose 'var'-declared variables gl |
| r1-p004 | silent prediction off | Null/undefined distinction hazard | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r1-p005 | silent prediction off | ASI and semicolon-less code hazard | ASI and semicolon-less code, leading ( or [ on the next line |
| r1-p006 | silent prediction off | Comments attached to removed code hazard | comments attached to the removed or moved code |
| r1-p007 | invalid | Top-level await safety note | If the 'export {}' appears after a top-level await, removing it does not change module status (since await already makes it a module), but the fix still applies and is safe—however, this is not a haza |
| r1-p008 | silent prediction off | __proto__ and prototype access hazard | __proto__ keys, prototype access, Object.assign vs spread |
| r2-p001 | fix ok | Bundler entry point / side-effect marker | When using bundlers that treat empty exports as entry points or side-effect markers, removing it might affect tree-shaking or bundle inclusion logic. |
| r2-p002 | silent prediction off | Sparse arrays and holes | sparse arrays, holes, Array(n) vs [n], array-likes |
| r2-p003 | silent prediction off | Arguments object and function length | arguments object, function.length, default parameters, rest parameters |
| r2-p004 | invalid | ASI and semicolon-less code with leading paren/bracket | ASI and semicolon-less code, leading ( or [ on the next line |
| r2-p005 | silent | Module-to-script conversion and top-level this | Removing 'export {}' in a file with only that export turns the module into a script, potentially breaking top-level 'this' semantics and strict mode enforcement. |
| r2-p006 | silent prediction off | This binding: arrow vs function, methods extracted | this binding: arrow vs function, methods extracted from objects, call/apply/bind |
| r2-p007 | silent prediction off | TypeScript ambient contexts and declaration merging | In TypeScript, removing the empty export may affect how the file is interpreted in ambient contexts or declaration merging, though less likely at term level. |
| r2-p008 | silent prediction off | Temporal Dead Zone after hoisting/reordering | temporal dead zone after code is hoisted or reordered |
Sources
r1-p001 · Comment stripping hazard
1// SPDX-License-Identifier: MIT
2import { x } from 'fs'; var v = 1;
3export {}; // Copyright 2024 Example Corp
4console.log(v);
--- orig.js 2026-10-17 16:06:08.344652809 -0400 +++ fixed.js 2026-10-17 16:06:08.643637460 -0400 @@ -1,4 +1,3 @@ // SPDX-License-Identifier: MIT import { x } from 'fs'; var v = 1; -export {}; // Copyright 2024 Example Corp console.log(v);
r1-p002 · Exception during rewrite hazard (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-0)
1const obj = {};
2try {
3 delete obj.x;
4export {}; // This line triggers the rule
5} catch (e) {
6 console.log(e.constructor.name + ': ' + e.message);
7}
r1-p003 · Top-level var scoping hazard
1var scoped = 'module-only';
2export {};
3function check() {
4 return typeof scoped !== 'undefined' && !globalThis.hasOwnProperty('scoped');
5}
6console.log(check());
true
r1-p004 · Null/undefined distinction hazard
1let value = null;
2export {};
3console.log(value == undefined ? 'nullish' : 'truthy');
4console.log(value ?? 'default');
nullish default
r1-p005 · ASI and semicolon-less code hazard
1const x = 1
2export {}
3;(function(){ console.log('IIFE ran') })()
4console.log('x:', x)
IIFE ran x: 1
r1-p006 · Comments attached to removed code hazard
1const data = 42;
2// This export is useless but has a comment
3export {}; // Keep license info here
4console.log(data);
42
r1-p007 · Top-level await safety note (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-0)
1(async () => {
2 await Promise.resolve();
3 var local = 'safe';
4 export {};
5 console.log(typeof local === 'string' && !globalThis.local);
6})();
r1-p008 · __proto__ and prototype access hazard
1const obj = { __proto__: null }; export {};
2obj.toString = () => 'custom';
3console.log(obj.toString());
custom
r2-p001 · Bundler entry point / side-effect marker
1import { x } from './mod.js'; export {};
2console.log('entry:', typeof x !== 'undefined');
3export const y = 42;
--- orig.js 2026-10-17 16:06:14.281349820 -0400 +++ fixed.js 2026-10-17 16:06:14.557335829 -0400 @@ -1,3 +1,3 @@ -import { x } from './mod.js'; export {}; +import { x } from './mod.js'; console.log('entry:', typeof x !== 'undefined'); export const y = 42;
r2-p002 · Sparse arrays and holes
1const arr = new Array(3);
2arr[1] = 'hole';
3export {};
4console.log(arr.length, arr[0] === undefined, arr[1] === 'hole', arr[2] === undefined);
3 true true true
r2-p003 · Arguments object and function length
1function f(a, b = 1, ...rest) {
2 return { args: arguments.length, len: f.length, rest };
3}
4export {};
5console.log(JSON.stringify(f(5)));
{"args":1,"len":1,"rest":[]}r2-p004 · ASI and semicolon-less code with leading paren/bracket (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-06-0)
1import { x } from './mod.js'
2export {}
3;(function(){ console.log('IIFE ran:', x) })()
4[].push.call({length:0}, 99)
5export const y = 1;
r2-p005 · Module-to-script conversion and top-level this
1'use strict';
2console.log(this === undefined ? 'module' : 'script', typeof this);
module undefined
r2-p006 · This binding: arrow vs function, methods extracted
1const obj = { value: 42, get: function() { return this.value } };
2export {};
3const fn = obj.get;
4console.log('direct:', obj.get(), 'via var:', fn(), 'bound:', fn.call(obj));
r2-p007 · TypeScript ambient contexts and declaration merging
1// @ts-nocheck
2export {};
3let x = 1;
4if (typeof x === 'number') console.log('TS-like number check passed');
TS-like number check passed
r2-p008 · Temporal Dead Zone after hoisting/reordering
1try { console.log(z); } catch(e) { console.log('TDZ:', e.name); }
2let z = 1;
3export {};
4try { console.log(z); } catch(e) { console.log('After init:', z); }
TDZ: ReferenceError 1