biome correctness/noGlobalDirnameFilename
labelled safe
Analysis Nemotron 3 Super
The rule flags any reference to __dirname or __filename used outside of function/class scopes as they are unavailable in ES modules.
Fix: Replaces each occurrence of __dirname with import.meta.dirname and __filename with import.meta.filename when used in the global scope.
10 hazards
- The rewrite changes the meaning if __dirname or __filename is shadowed by a local variable in an outer function scope, as import.meta properties are not subject to variable shadowing.
- If the code is executed in a non-ESM environment (e.g., CommonJS), import.meta.dirname/filename are undefined, causing runtime errors where the original globals were defined.
- The fix removes any JSDoc or inline comments attached to the __dirname/__filename token, as the replacement does not preserve comment associations.
- In destructuring like const { __filename } = obj, the rewrite produces { import.meta.filename } which is invalid syntax because import.meta is not an object literal property in that context.
- When __dirname/__filename is used in a dynamic import() argument, the rewrite may alter timing or availability if import.meta is not yet resolved.
- If the code relies on __dirname/__filename being a string primitive (which they are), but import.meta.dirname/filename are also strings, this is safe—but if used in a typeof check against a fake global, behavior diverges.
- In a with (__dirname) { ... } block (though rare and deprecated), the rewrite breaks because import.meta cannot be used in a with statement due to being a member expression.
- If __dirname or __filename is used as a property name in computed form like [__dirname]: value, the rewrite becomes [import.meta.dirname]: value which evaluates the string, but the original used the global variable's value—however, since both are strings and same value, this may be safe, but if the global was reassigned (which it isn't), it would differ—yet reassignment of __dirname is not allowed, so likely safe, but we include due to theoretical reassignment in non-strict? Actually, __dirname/__filename are not writable in Node.js, so reassignment fails silently in strict or throws—so if somehow reassigned, original would reflect new value, but import.meta is fixed—so hazard: if reassigned (though impossible in practice), behavior changes.
- The fix does not preserve trailing comments on the line if the replacement alters whitespace in a way that moves or drops line comments (e.g., if __dirname; // comment becomes import.meta.dirname; // comment—usually preserved, but if the tool reformats, it might not).
- In eval() contexts, __dirname/__filename refer to the global scope of the calling script, but import.meta is fixed to the current module—so if eval runs in a different module context, behavior differs.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p001 | fix-changes-behavior | labelled safe | program-bug · high | no match | The program runs as an ES module where __dirname is not defined, so it already fails before the fix with a ReferenceError. The fix replaces __dirname with impo… |
| r1-p002 | fix-changes-behavior | labelled safe | program-bug · high | duplicate | The program runs as an ES module where __dirname is not defined, so it crashes before the fix. The rewrite replaces __dirname with import.meta.dirname, which i… |
| r1-p004 | fix-changes-behavior | labelled safe | program-bug · high | duplicate | The program runs in an ES module environment where __dirname is not defined, causing a ReferenceError before the fix. The fix correctly rewrites __dirname to i… |
| r2-p004 | fix-changes-behavior | labelled safe | program-bug · high | related | The fix replaces __dirname with import.meta.dirname, which only exists in ES modules. The program runs as CommonJS (no package.json type: module), so the rewri… |
| r2-p008 | fix-changes-behavior | labelled safe | program-bug · high | related | The program runs in an ES module environment where __dirname is not defined, causing a ReferenceError before the fix. The fix correctly rewrites __dirname to i… |
| r1-p003 | fix-changes-behavior | labelled safe | program-bug · low | related | The program runs as an ES module where __dirname is not defined, causing a ReferenceError before the fix. The rewrite replaces it with import.meta.dirname, whi… |
| r1-p006 | fix-changes-behavior | labelled safe | program-bug · low | duplicate | The program runs as an ES module where __dirname is undefined, causing a ReferenceError before the fix. The rewrite to import.meta.dirname is the documented ES… |
| r1-p008 | fix-changes-behavior | labelled safe | program-bug · low | duplicate | The program runs as an ES module where __filename is undefined, causing a ReferenceError before the fix. The rewrite to import.meta.filename is the documented … |
| r2-p001 | fix-changes-behavior | labelled safe | program-bug · low | no match | The program runs as an ES module where __dirname is not defined, causing a ReferenceError before the fix. The fix replaces it with import.meta.dirname, which i… |
| r2-p002 | fix-changes-behavior | labelled safe | program-bug · low | related | The program runs in a CommonJS environment where __dirname exists but import.meta.dirname does not, so the original code catches a ReferenceError and logs thre… |
| r2-p003 | fix-changes-behavior | labelled safe | program-bug · low | duplicate | The program runs as an ES module where __dirname is undefined, so it crashes before the fix; after the fix it uses import.meta.dirname which exists in ES modul… |
| r2-p005 | fix-changes-behavior | labelled safe | program-bug · low | related | The program runs as an ES module where __dirname is not defined, causing a ReferenceError before the fix. The fix correctly rewrites to import.meta.dirname, wh… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix-changes-behavior | Dynamic import argument uses __dirname | When __dirname/__filename is used in a dynamic import() argument, the rewrite may alter timing or availability if import.meta is not yet resolved. |
| r1-p002 | fix-changes-behavior | __dirname in __proto__ key via computed property | __proto__ keys, prototype access, Object.assign vs spread |
| r1-p003 | fix-changes-behavior | Function using __dirname in default parameter | arguments object, function.length, default parameters, rest parameters |
| r1-p004 | fix-changes-behavior | Async function awaiting __dirname in expression | async/await ordering, generators and yield position |
| r1-p005 | fix ok | __dirname in optional chaining with nullish coalescing | null/undefined distinction, optional chaining short-circuit, nullish vs falsy |
| r1-p006 | fix-changes-behavior | __dirname; // comment - tests trailing comment preservation | The fix does not preserve trailing comments on the line if the replacement alters whitespace in a way that moves or drops line comments |
| r1-p007 | invalid | __dirname in sloppy mode with with statement | strict vs sloppy mode semantics |
| r1-p008 | fix-changes-behavior | __filename /* inline */ - comment attached to removed code | comments attached to the removed or moved code |
| r2-p001 | fix-changes-behavior | Non-ESM environment failure | If executed in CommonJS, import.meta.dirname/filename are undefined while __dirname/__filename exist. |
| r2-p002 | fix-changes-behavior | Exception during evaluation | If __dirname access throws (hypothetical), the fix removes the try/catch scope. |
| r2-p003 | fix-changes-behavior | Name collision after rewrite | Rewrite creates import.meta.dirname that shadows a outer-scope dirname variable. |
| r2-p004 | fix-changes-behavior | Control flow interference | The fix inserts import.meta in a finally block, altering control flow if it throws. |
| r2-p005 | fix-changes-behavior | Class static field interaction | Static field initialization accesses __dirname; fix changes timing/scope. |
| r2-p006 | silent prediction off | Eval context mismatch | __dirname in eval refers to caller’s global; import.meta is module-fixed. |
| r2-p007 | fix ok | Computed property name (theoretical reassignment) | [__dirname]: value uses variable; if reassigned, import.meta is fixed. |
| r2-p008 | fix-changes-behavior | Coercion differences: + vs template literal | + __dirname may coerce non-string; import.meta.dirname is always string. |
Sources
r1-p001 · Dynamic import argument uses __dirname
1// Hazard 1
2const mod = await import(`./${__dirname}/data.json`);
3console.log('done');
--- orig.js 2026-10-17 16:16:38.781057717 -0400 +++ fixed.js 2026-10-17 16:16:39.079054053 -0400 @@ -1,3 +1,3 @@ // Hazard 1 -const mod = await import(`./${__dirname}/data.json`); +const mod = await import(`./${import.meta.dirname}/data.json`); console.log('done');
r1-p002 · __dirname in __proto__ key via computed property
1// Hazard 2
2const o = {};
3o[`__proto__${__dirname}`] = 'tampered';
4console.log(Object.getPrototypeOf(o));
--- orig.js 2026-10-17 16:16:39.258051857 -0400 +++ fixed.js 2026-10-17 16:16:39.542048373 -0400 @@ -1,4 +1,4 @@ // Hazard 2 const o = {}; -o[`__proto__${__dirname}`] = 'tampered'; +o[`__proto__${import.meta.dirname}`] = 'tampered'; console.log(Object.getPrototypeOf(o));
r1-p003 · Function using __dirname in default parameter
1// Hazard 3
2function f(dir = __dirname) {
3 return dir.length;
4}
5console.log(f());
--- orig.js 2026-10-17 16:16:39.716046238 -0400 +++ fixed.js 2026-10-17 16:16:40.007042667 -0400 @@ -1,5 +1,5 @@ // Hazard 3 -function f(dir = __dirname) { +function f(dir = import.meta.dirname) { return dir.length; } console.log(f());
r1-p004 · Async function awaiting __dirname in expression
1// Hazard 4
2async function main() {
3 const dir = await Promise.resolve(__dirname);
4 console.log(dir.length);
5}
6main();
--- orig.js 2026-10-17 16:16:40.179040562 -0400 +++ fixed.js 2026-10-17 16:16:40.463037086 -0400 @@ -1,6 +1,6 @@ // Hazard 4 async function main() { - const dir = await Promise.resolve(__dirname); + const dir = await Promise.resolve(import.meta.dirname); console.log(dir.length); } main();
r1-p005 · __dirname in optional chaining with nullish coalescing
1// Hazard 5
2const maybePath = null;
3const result = maybePath?.startsWith(__dirname) ?? 'fallback';
4console.log(result);
--- orig.js 2026-10-17 16:16:40.640034920 -0400 +++ fixed.js 2026-10-17 16:16:40.941031237 -0400 @@ -1,4 +1,4 @@ // Hazard 5 const maybePath = null; -const result = maybePath?.startsWith(__dirname) ?? 'fallback'; +const result = maybePath?.startsWith(import.meta.dirname) ?? 'fallback'; console.log(result);
fallback
r1-p006 · __dirname; // comment - tests trailing comment preservation
1// Hazard 6
2__dirname; // this comment must stay
3console.log('ok');
--- orig.js 2026-10-17 16:16:41.117029086 -0400 +++ fixed.js 2026-10-17 16:16:41.383025839 -0400 @@ -1,3 +1,3 @@ // Hazard 6 -__dirname; // this comment must stay +import.meta.dirname; // this comment must stay console.log('ok');
r1-p007 · __dirname in sloppy mode with with statement (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-16-2)
1// Hazard 7
2(function() {
3 'use sloppy';
4 with ({}) {
5 console.log(__dirname);
6 }
7})();
r1-p008 · __filename /* inline */ - comment attached to removed code
1// Hazard 8
2const x = __filename /* inline note */;
3console.log(x.length);
--- orig.js 2026-10-17 16:16:41.596023239 -0400 +++ fixed.js 2026-10-17 16:16:41.866019943 -0400 @@ -1,3 +1,3 @@ // Hazard 8 -const x = __filename /* inline note */; +const x = import.meta.filename /* inline note */; console.log(x.length);
r2-p001 · Non-ESM environment failure
1const dir = __dirname;
2console.log('original:', typeof dir === 'string' ? dir : 'not string');
3try {
4 const fixed = import.meta.dirname;
5 console.log('fixed:', typeof fixed === 'string' ? fixed : 'not string');
6} catch (e) {
7 console.log('error:', e.name, e.message);
8}
--- orig.js 2026-10-17 16:16:49.078932784 -0400 +++ fixed.js 2026-10-17 16:16:49.341929639 -0400 @@ -1,4 +1,4 @@ -const dir = __dirname; +const dir = import.meta.dirname; console.log('original:', typeof dir === 'string' ? dir : 'not string'); try { const fixed = import.meta.dirname;
r2-p002 · Exception during evaluation
1let threw = false;
2try {
3 const d = __dirname;
4 if (d === undefined) throw new Error('unexpected');
5} catch (e) {
6 threw = true;
7}
8console.log('threw:', threw);
--- orig.js 2026-10-17 16:16:49.500927738 -0400 +++ fixed.js 2026-10-17 16:16:49.762924605 -0400 @@ -1,6 +1,6 @@ let threw = false; try { - const d = __dirname; + const d = import.meta.dirname; if (d === undefined) throw new Error('unexpected'); } catch (e) { threw = true;
threw: true
r2-p003 · Name collision after rewrite
1let dirname = 'outer';
2const dir = __dirname;
3console.log('dirname:', dirname);
4if (typeof dirname === 'string') {
5 console.log('block dirname:', dirname);
6}
--- orig.js 2026-10-17 16:16:49.925922655 -0400 +++ fixed.js 2026-10-17 16:16:50.190919492 -0400 @@ -1,5 +1,5 @@ let dirname = 'outer'; -const dir = __dirname; +const dir = import.meta.dirname; console.log('dirname:', dirname); if (typeof dirname === 'string') { console.log('block dirname:', dirname);
r2-p004 · Control flow interference
1let result = [];
2try {
3 result.push(__dirname);
4 throw new Error('test');
5} catch (e) {
6 result.push(e.message);
7} finally {
8 try {
9 result.push(import.meta.dirname);
10 } catch (e) {
11 result.push('finally error');
12 }
13}
14console.log(result.join('|'));
--- orig.js 2026-10-17 16:16:50.358917488 -0400 +++ fixed.js 2026-10-17 16:16:50.624914315 -0400 @@ -1,6 +1,6 @@ let result = []; try { - result.push(__dirname); + result.push(import.meta.dirname); throw new Error('test'); } catch (e) { result.push(e.message);
__dirname is not defined|<wd>/prog
r2-p005 · Class static field interaction
1class C {
2 static dir = __dirname;
3 static log() {
4 return C.dir;
5 }
6}
7console.log(C.log());
--- orig.js 2026-10-17 16:16:50.791912323 -0400 +++ fixed.js 2026-10-17 16:16:51.070908997 -0400 @@ -1,5 +1,5 @@ class C { - static dir = __dirname; + static dir = import.meta.dirname; static log() { return C.dir; }
r2-p006 · Eval context mismatch
1const val = eval('__dirname');
2console.log('eval result:', typeof val === 'string' && val.length > 0 ? 'defined' : 'undefined');
3console.log('import.meta.dirname:', typeof import.meta.dirname === 'string' ? 'defined' : 'undefined');
r2-p007 · Computed property name (theoretical reassignment)
1__dirname = 'overridden'; // assignment fails in strict, but assume non-strict
2const obj = {};
3obj[__dirname] = 'value';
4console.log(obj['overridden'] ?? 'not set');
--- orig.js 2026-10-17 16:16:51.470904238 -0400 +++ fixed.js 2026-10-17 16:16:51.755900847 -0400 @@ -1,4 +1,4 @@ __dirname = 'overridden'; // assignment fails in strict, but assume non-strict const obj = {}; -obj[__dirname] = 'value'; +obj[import.meta.dirname] = 'value'; console.log(obj['overridden'] ?? 'not set');
r2-p008 · Coercion differences: + vs template literal
1const x = { toString: () => 42 };
2console.log('+ coercion:', __dirname + x);
3console.log('template:', `${__dirname}${x}`);
4console.log('import.meta + x:', import.meta.dirname + x);
--- orig.js 2026-10-17 16:16:51.912898979 -0400 +++ fixed.js 2026-10-17 16:16:52.176895844 -0400 @@ -1,4 +1,4 @@ const x = { toString: () => 42 }; -console.log('+ coercion:', __dirname + x); -console.log('template:', `${__dirname}${x}`); +console.log('+ coercion:', import.meta.dirname + x); +console.log('template:', `${import.meta.dirname}${x}`); console.log('import.meta + x:', import.meta.dirname + x);