Repository: biomejs/biome (language: rust)

Issue:
📎 Implement noGlobalDirnameFilename rule
### Description

`__dirname` doesn't work in ESM context, but is not easily caught by tests, as e. g. vitest injects `__dirname`, so it works correctly there, but then fails in production. __filename is also in a similar situation. 

Prior art: https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md

Also see https://github.com/biomejs/biome/discussions/4245


Discussion / hints:
@ematipico I don't know Rust, so unfortunately can't implement it myself.
Then why was this task open? Usually, these issues are open after a previous discussion, or by maintainers.

If there wasn't prior discussion, could you please open a discussion instead?
@ematipico I've linked previous discussion, see https://github.com/biomejs/biome/discussions/4245. I believe you thumbs uped it as well :D

There was an ask to open a task for it from one of the collaborators.
We have the [noCommonJs](https://biomejs.dev/linter/rules/no-common-js/) rule, but it only applies to imports and exports.

If we want to add the [prefer-modules](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md) rule, I think we should break it down into a few specific rules.

- Disallows 'use strict' directive.
	- [x] `noRedundantUseStrict` done this
- Disallows “Global Return”.
	- [ ] `noGlobalReturn`? 
- Disallows the global variables `__dirname and __filename.
	- [ ] `noGlobalDirnameFilename` this issue
- Disallows `require(…)`.
	- [x] `noCommonJs` done this
- Disallows `exports` and `module.exports`. 
	- [x] `noCommonJs` done this

`noGlobalLegacyPath` might be better, because we have already noGlobalXXX rules.

IMO from a user's perspective "noGlobalLegacyPath" reads like it's banning something related to paths, not global variables 
`noGlobalDirnameAndFilename`? It's not cool but expressing itself directly and easy to search.
> Disallows 'use strict' directive.

Is this not covered by [noRedundantUseStrict](https://biomejs.dev/linter/rules/no-redundant-use-strict/)?

> Disallows “Global Return”. 

It is already a syntax error in module. Do I miss something?

> Disallows the global variables `__dirname and __filename. 

I wonder, is there reason to create a dedicated rule or should we ad this to `noCommonJs`?

> noGlobalDirnameAndFilename?

noGlobalDirnameFilename should be fine.
> should we add this to `noCommonJs`

From a quick search, it looks like these globals _are_ only valid in commonjs environments. So I think yeah, it would make sense to put it in the same rule. However, things against this that I can think of is:
- that we could be taking some granularity away from users.
- vitest injects these variables when it runs, so these can be available in esm looking environments, IIRC.

For those reasons I think it would make sense to keep this as a separate rule, or have options for the `noCommonJs` rule to enable/disable these different aspects of the rule. Adding rule options would be weird IMO, we generally tend to add rules and minimize the scope of those rules as much as possible.
> Is this not covered by [noRedundantUseStrict](https://biomejs.dev/linter/rules/no-redundant-use-strict/)?

It's covered! I missed it.


> For those reasons I think it would make sense to keep this as a separate rule, or have options for the `noCommonJs` rule to enable/disable these different aspects of the rule. Adding rule options would be weird IMO, we generally tend to add rules and minimize the scope of those rules as much as possible.

You made a good point. Let's keep the rule separated. We should certainly add a pointer to the new rule in `noCommonJs`.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14ae79fc7566..b39ea2c2b003 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -129,6 +129,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b
   Also, this will bring the Biome rule closer to the [no-undef ESLint rule](https://eslint.org/docs/latest/rules/no-undef).
 
   Contributed by @Conaclos
+  
+- Add [noGlobalDirnameFilename](https://biomejs.dev/linter/rules/no-global-dirname-filename/). Contributed by @unvalley
 
 #### Enhancements
 
diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
index 5b26123d9de5..fcf1a4cabd0a 100644
--- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
+++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs
@@ -1637,6 +1637,20 @@ pub(crate) fn migrate_eslint_any_rule(
             let rule = group.use_date_now.get_or_insert(Default::default());
             rule.set_level(rule_severity.into());
         }
+        "unicorn/prefer-module" => {
+            if !options.include_inspired {
+                results.has_inspired_rules = true;
+                return false;
+            }
+            if !options.include_nursery {
+                return false;
+            }
+            let group = rules.nursery.get_or_insert_with(Default::default);
+            let rule = group
+                .no_global_dirname_filename
+                .get_or_insert(Default::default());
+            rule.set_level(rule_severity.into());
+        }
         "unicorn/prefer-node-protocol" => {
             let group = rules.style.get_or_insert_with(Default::default);
             let rule = group
diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs
index db931a9c76c8..c6800dbba27f 100644
--- a/crates/biome_configuration/src/analyzer/linter/rules.rs
+++ b/crates/biome_configuration/src/analyzer/linter/rules.rs
@@ -3312,6 +3312,10 @@ pub struct Nursery {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_exported_imports:
         Option<RuleConfiguration<biome_js_analyze::options::NoExportedImports>>,
+    #[doc = "Disallow the use of __dirname and __filename in the global scope."]
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub no_global_dirname_filename:
+        Option<RuleFixConfiguration<biome_js_analyze::options::NoGlobalDirnameFilename>>,
     #[doc = "Prevent usage of \\<head> element in a Next.js project."]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub no_head_element: Option<RuleConfiguration<biome_js_analyze::options::NoHeadElement>>,
@@ -3484,6 +3488,7 @@ impl Nursery {
         "noDynamicNamespaceImportAccess",
         "noEnum",
         "noExportedImports",
+        "noGlobalDirnameFilename",
         "noHeadElement",
         "noHeadImportInDocument",
         "noImgElement",
@@ -3547,16 +3552,16 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[5]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[6]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[7]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]),
-        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]),
     ];
     const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
@@ -3609,6 +3614,7 @@ impl Nursery {
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]),
         RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]),
+        RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]),
     ];
     #[doc = r" Retrieves the recommended rules"]
     pub(crate) fn is_recommended_true(&self) -> bool {
@@ -3680,201 +3686,206 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[10]));
             }
         }
-        if let Some(rule) = self.no_head_element.as_ref() {
+        if let Some(rule) = self.no_global_dirname_filename.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[11]));
             }
         }
-        if let Some(rule) = self.no_head_import_in_document.as_ref() {
+        if let Some(rule) = self.no_head_element.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]));
             }
         }
-        if let Some(rule) = self.no_img_element.as_ref() {
+        if let Some(rule) = self.no_head_import_in_document.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]));
             }
         }
-        if let Some(rule) = self.no_irregular_whitespace.as_ref() {
+        if let Some(rule) = self.no_img_element.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14]));
             }
         }
-        if let Some(rule) = self.no_missing_var_function.as_ref() {
+        if let Some(rule) = self.no_irregular_whitespace.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]));
             }
         }
-        if let Some(rule) = self.no_nested_ternary.as_ref() {
+        if let Some(rule) = self.no_missing_var_function.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]));
             }
         }
-        if let Some(rule) = self.no_octal_escape.as_ref() {
+        if let Some(rule) = self.no_nested_ternary.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
             }
         }
-        if let Some(rule) = self.no_process_env.as_ref() {
+        if let Some(rule) = self.no_octal_escape.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
             }
         }
-        if let Some(rule) = self.no_restricted_imports.as_ref() {
+        if let Some(rule) = self.no_process_env.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
             }
         }
-        if let Some(rule) = self.no_restricted_types.as_ref() {
+        if let Some(rule) = self.no_restricted_imports.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
             }
         }
-        if let Some(rule) = self.no_secrets.as_ref() {
+        if let Some(rule) = self.no_restricted_types.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
             }
         }
-        if let Some(rule) = self.no_static_element_interactions.as_ref() {
+        if let Some(rule) = self.no_secrets.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
             }
         }
-        if let Some(rule) = self.no_substr.as_ref() {
+        if let Some(rule) = self.no_static_element_interactions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
             }
         }
-        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
+        if let Some(rule) = self.no_substr.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
+        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
             }
         }
-        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]));
             }
         }
-        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
+        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]));
             }
         }
-        if let Some(rule) = self.no_useless_string_raw.as_ref() {
+        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_useless_undefined.as_ref() {
+        if let Some(rule) = self.no_useless_string_raw.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_named_operation.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_named_operation.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_enabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_enabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]));
+            }
+        }
         index_set
     }
     pub(crate) fn get_disabled_rules(&self) -> FxHashSet<RuleFilter<'static>> {
@@ -3934,201 +3945,206 @@ impl Nursery {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[10]));
             }
         }
-        if let Some(rule) = self.no_head_element.as_ref() {
+        if let Some(rule) = self.no_global_dirname_filename.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[11]));
             }
         }
-        if let Some(rule) = self.no_head_import_in_document.as_ref() {
+        if let Some(rule) = self.no_head_element.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[12]));
             }
         }
-        if let Some(rule) = self.no_img_element.as_ref() {
+        if let Some(rule) = self.no_head_import_in_document.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[13]));
             }
         }
-        if let Some(rule) = self.no_irregular_whitespace.as_ref() {
+        if let Some(rule) = self.no_img_element.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[14]));
             }
         }
-        if let Some(rule) = self.no_missing_var_function.as_ref() {
+        if let Some(rule) = self.no_irregular_whitespace.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[15]));
             }
         }
-        if let Some(rule) = self.no_nested_ternary.as_ref() {
+        if let Some(rule) = self.no_missing_var_function.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[16]));
             }
         }
-        if let Some(rule) = self.no_octal_escape.as_ref() {
+        if let Some(rule) = self.no_nested_ternary.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[17]));
             }
         }
-        if let Some(rule) = self.no_process_env.as_ref() {
+        if let Some(rule) = self.no_octal_escape.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]));
             }
         }
-        if let Some(rule) = self.no_restricted_imports.as_ref() {
+        if let Some(rule) = self.no_process_env.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19]));
             }
         }
-        if let Some(rule) = self.no_restricted_types.as_ref() {
+        if let Some(rule) = self.no_restricted_imports.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]));
             }
         }
-        if let Some(rule) = self.no_secrets.as_ref() {
+        if let Some(rule) = self.no_restricted_types.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]));
             }
         }
-        if let Some(rule) = self.no_static_element_interactions.as_ref() {
+        if let Some(rule) = self.no_secrets.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22]));
             }
         }
-        if let Some(rule) = self.no_substr.as_ref() {
+        if let Some(rule) = self.no_static_element_interactions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23]));
             }
         }
-        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
+        if let Some(rule) = self.no_substr.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
+        if let Some(rule) = self.no_template_curly_in_string.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25]));
             }
         }
-        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_class.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26]));
             }
         }
-        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
+        if let Some(rule) = self.no_unknown_pseudo_element.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27]));
             }
         }
-        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
+        if let Some(rule) = self.no_unknown_type_selector.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28]));
             }
         }
-        if let Some(rule) = self.no_useless_string_raw.as_ref() {
+        if let Some(rule) = self.no_useless_escape_in_regex.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29]));
             }
         }
-        if let Some(rule) = self.no_useless_undefined.as_ref() {
+        if let Some(rule) = self.no_useless_string_raw.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30]));
             }
         }
-        if let Some(rule) = self.no_value_at_rule.as_ref() {
+        if let Some(rule) = self.no_useless_undefined.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31]));
             }
         }
-        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
+        if let Some(rule) = self.no_value_at_rule.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32]));
             }
         }
-        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
+        if let Some(rule) = self.use_adjacent_overload_signatures.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33]));
             }
         }
-        if let Some(rule) = self.use_at_index.as_ref() {
+        if let Some(rule) = self.use_aria_props_supported_by_role.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34]));
             }
         }
-        if let Some(rule) = self.use_collapsed_if.as_ref() {
+        if let Some(rule) = self.use_at_index.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35]));
             }
         }
-        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
+        if let Some(rule) = self.use_collapsed_if.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36]));
             }
         }
-        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
+        if let Some(rule) = self.use_component_export_only_modules.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37]));
             }
         }
-        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
+        if let Some(rule) = self.use_consistent_curly_braces.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38]));
             }
         }
-        if let Some(rule) = self.use_deprecated_reason.as_ref() {
+        if let Some(rule) = self.use_consistent_member_accessibility.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39]));
             }
         }
-        if let Some(rule) = self.use_explicit_type.as_ref() {
+        if let Some(rule) = self.use_deprecated_reason.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40]));
             }
         }
-        if let Some(rule) = self.use_google_font_display.as_ref() {
+        if let Some(rule) = self.use_explicit_type.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41]));
             }
         }
-        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
+        if let Some(rule) = self.use_google_font_display.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42]));
             }
         }
-        if let Some(rule) = self.use_guard_for_in.as_ref() {
+        if let Some(rule) = self.use_google_font_preconnect.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43]));
             }
         }
-        if let Some(rule) = self.use_import_restrictions.as_ref() {
+        if let Some(rule) = self.use_guard_for_in.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44]));
             }
         }
-        if let Some(rule) = self.use_named_operation.as_ref() {
+        if let Some(rule) = self.use_import_restrictions.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45]));
             }
         }
-        if let Some(rule) = self.use_sorted_classes.as_ref() {
+        if let Some(rule) = self.use_named_operation.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46]));
             }
         }
-        if let Some(rule) = self.use_strict_mode.as_ref() {
+        if let Some(rule) = self.use_sorted_classes.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47]));
             }
         }
-        if let Some(rule) = self.use_trim_start_end.as_ref() {
+        if let Some(rule) = self.use_strict_mode.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48]));
             }
         }
-        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+        if let Some(rule) = self.use_trim_start_end.as_ref() {
             if rule.is_disabled() {
                 index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49]));
             }
         }
+        if let Some(rule) = self.use_valid_autocomplete.as_ref() {
+            if rule.is_disabled() {
+                index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50]));
+            }
+        }
         index_set
     }
     #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"]
@@ -4209,6 +4225,10 @@ impl Nursery {
                 .no_exported_imports
                 .as_ref()
                 .map(|conf| (conf.level(), conf.get_options())),
+            "noGlobalDirnameFilename" => self
+                .no_global_dirname_filename
+                .as_ref()
+                .map(|conf| (conf.level(), conf.get_options())),
             "noHeadElement" => self
                 .no_head_element
                 .as_ref()
diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs
index 9db3d75cf0f1..60b4beea4c04 100644
--- a/crates/biome_diagnostics_categories/src/categories.rs
+++ b/crates/biome_diagnostics_categories/src/categories.rs
@@ -148,6 +148,7 @@ define_categories! {
     "lint/nursery/noDynamicNamespaceImportAccess": "https://biomejs.dev/linter/rules/no-dynamic-namespace-import-access",
     "lint/nursery/noEnum": "https://biomejs.dev/linter/rules/no-enum",
     "lint/nursery/noExportedImports": "https://biomejs.dev/linter/rules/no-exported-imports",
+    "lint/nursery/noGlobalDirnameFilename": "https://biomejs.dev/linter/rules/no-global-dirname-filename",
     "lint/nursery/noHeadElement": "https://biomejs.dev/linter/rules/no-head-element",
     "lint/nursery/noHeadImportInDocument": "https://biomejs.dev/linter/rules/no-head-import-in-document",
     "lint/nursery/noImgElement": "https://biomejs.dev/linter/rules/no-img-element",
diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs
index 75ad6d83466d..16986ac68a18 100644
--- a/crates/biome_js_analyze/src/lint/nursery.rs
+++ b/crates/biome_js_analyze/src/lint/nursery.rs
@@ -9,6 +9,7 @@ pub mod no_duplicate_else_if;
 pub mod no_dynamic_namespace_import_access;
 pub mod no_enum;
 pub mod no_exported_imports;
+pub mod no_global_dirname_filename;
 pub mod no_head_element;
 pub mod no_head_import_in_document;
 pub mod no_img_element;
@@ -53,6 +54,7 @@ declare_lint_group! {
             self :: no_dynamic_namespace_import_access :: NoDynamicNamespaceImportAccess ,
             self :: no_enum :: NoEnum ,
             self :: no_exported_imports :: NoExportedImports ,
+            self :: no_global_dirname_filename :: NoGlobalDirnameFilename ,
             self :: no_head_element :: NoHeadElement ,
             self :: no_head_import_in_document :: NoHeadImportInDocument ,
             self :: no_img_element :: NoImgElement ,
diff --git a/crates/biome_js_analyze/src/lint/nursery/no_global_dirname_filename.rs b/crates/biome_js_analyze/src/lint/nursery/no_global_dirname_filename.rs
new file mode 100644
index 000000000000..7f617da339c8
--- /dev/null
+++ b/crates/biome_js_analyze/src/lint/nursery/no_global_dirname_filename.rs
@@ -0,0 +1,248 @@
+use crate::{services::semantic::Semantic, JsRuleAction};
+use biome_analyze::{
+    context::RuleContext, declare_lint_rule, FixKind, Rule, RuleDiagnostic, RuleSource,
+    RuleSourceKind,
+};
+use biome_console::markup;
+use biome_js_factory::make;
+use biome_js_semantic::SemanticModel;
+use biome_js_syntax::{
+    global_identifier, AnyJsExpression, AnyJsName, AnyJsObjectMember, JsFileSource,
+    JsObjectExpression, JsPropertyObjectMember, JsStaticMemberExpression, JsSyntaxKind,
+    JsSyntaxToken, JsVariableDeclarator,
+};
+use biome_rowan::{declare_node_union, AstSeparatedList, BatchMutationExt, TriviaPieceKind};
+
+declare_lint_rule! {
+    /// Disallow the use of `__dirname` and `__filename` in the global scope.
+    ///
+    /// They are [not available in ES modules](https://nodejs.org/api/esm.html#esm_no_filename_or_dirname).
+    /// Starting with Node.js 20.11, `import.meta.dirname` and `import.meta.filename` have been introduced in ES modules, providing identical functionality to `__dirname` and `__filename` in CommonJS (CJS).
+    ///
+    /// ## Examples
+    ///
+    /// ### Invalid
+    ///
+    /// ```js,expect_diagnostic
+    /// const dirname = __dirname;
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// const filename = __filename;
+    /// ```
+    ///
+    /// ``` js,expect_diagnostic
+    /// const foo = { __filename }
+    /// ```
+    ///
+    /// ```js,expect_diagnostic
+    /// if (__dirname.startsWith("/project/src/")) {}
+    /// ```
+    ///
+    /// ### Valid
+    ///
+    /// ```js
+    /// const dirname = import.meta.dirname
+    /// const filename = import.meta.filename
+    /// const foo = {__filename: import.meta.filename };
+    /// if (import.meta.dirname.startsWith("/project/src/")) {}
+    /// ```
+    ///
+    pub NoGlobalDirnameFilename {
+        version: "next",
+        name: "noGlobalDirnameFilename",
+        language: "js",
+        recommended: false,
+        sources: &[RuleSource::EslintUnicorn("prefer-module")],
+        source_kind: RuleSourceKind::Inspired,
+        fix_kind: FixKind::Safe,
+    }
+}
+
+declare_node_union! {
+    pub AnyGlobalDirnameFileName =
+        JsVariableDeclarator
+        | JsObjectExpression
+        | JsStaticMemberExpression
+}
+
+impl Rule for NoGlobalDirnameFilename {
+    type Query = Semantic<AnyGlobalDirnameFileName>;
+    type State = (JsSyntaxToken, String);
+    type Signals = Option<Self::State>;
+    type Options = ();
+
+    fn run(ctx: &RuleContext<Self>) -> Self::Signals {
+        let node = ctx.query();
+        let model = ctx.model();
+        let file_source = ctx.source_type::<JsFileSource>();
+        if file_source.is_script() {
+            return None;
+        };
+
+        match node {
+            // const dirname = __dirname;
+            AnyGlobalDirnameFileName::JsVariableDeclarator(declarator) => {
+                let init = declarator.initializer()?;
+                let expr = init.expression().ok()?;
+                validate_dirname_filename(&expr, model)
+            }
+            // `if (__dirname.startsWith("/project/src"))`
+            AnyGlobalDirnameFileName::JsStaticMemberExpression(member_expr) => {
+                let expr = member_expr.object().ok()?;
+                let expr = expr.as_js_identifier_expression()?;
+                let expr = AnyJsExpression::JsIdentifierExpression(expr.clone());
+                validate_dirname_filename(&expr, model)
+            }
+            // const dirname = { __dirname };
+            AnyGlobalDirnameFileName::JsObjectExpression(object_expr) => {
+                for member in object_expr.members().iter().flatten() {
+                    match member {
+                        AnyJsObjectMember::JsPropertyObjectMember(member) => {
+                            let expr = member.value().ok()?;
+                            return validate_dirname_filename(&expr, model);
+                        }
+                        AnyJsObjectMember::JsShorthandPropertyObjectMember(member) => {
+                            let token = member.name().and_then(|name| name.value_token()).ok()?;
+                            let text = maybe_text(&token)?;
+                            return Some((token, text));
+                        }
+                        _ => continue,
+                    }
+                }
+                None
+            }
+        }
+    }
+
+    fn diagnostic(_ctx: &RuleContext<Self>, state: &Self::State) -> Option<RuleDiagnostic> {
+        let syntax_token = &state.0;
+        Some(
+            RuleDiagnostic::new(
+                rule_category!(),
+                syntax_token.text_range(),
+                markup! {
+                    "Don't use "<Emphasis>""{syntax_token.text_trimmed()}""</Emphasis>"."
+                },
+            )
+            .note(markup! {
+                {syntax_token.text_trimmed()}" is not available in ES modules."
+            }),
+        )
+    }
+
+    fn action(ctx: &RuleContext<Self>, state: &Self::State) -> Option<JsRuleAction> {
+        let mut mutation = ctx.root().begin();
+        let node = ctx.query();
+        let syntax_token = &state.0;
+        let dirname_or_filename = state.1.as_str();
+
+        match node {
+            AnyGlobalDirnameFileName::JsVariableDeclarator(declarator) => {
+                mutation.replace_node(
+                    declarator.initializer()?.expression().ok()?,
+                    AnyJsExpression::JsStaticMemberExpression(make_import_meta(
+                        dirname_or_filename,
+                    )),
+                );
+            }
+            AnyGlobalDirnameFileName::JsObjectExpression(object_expr) => {
+                for member in object_expr.members().iter().flatten() {
+                    match member {
+                        AnyJsObjectMember::JsPropertyObjectMember(member) => {
+                            let expr = member.value().ok()?;
+                            let expr = expr.as_js_identifier_expression()?;
+                            let id = expr.name().ok()?.value_token().ok()?;
+                            if &id == syntax_token {
+                                let key = member.name().ok()?;
+                                let key = key.as_js_literal_member_name()?;
+                                let property_member = make_property_object_member(
+                                    &key.value().ok()?,
+                                    dirname_or_filename,
+                                );
+                                mutation.replace_node(member.clone(), property_member);
+                                break;
+                            };
+                        }
+                        AnyJsObjectMember::JsShorthandPropertyObjectMember(member) => {
+                            let key = member.name().ok()?.value_token().ok()?;
+                            if &key == syntax_token {
+                                let property_member =
+                                    make_property_object_member(&key, dirname_or_filename);
+                                mutation.replace_node(
+                                    AnyJsObjectMember::JsShorthandPropertyObjectMember(
+                                        member.clone(),
+                                    ),
+                                    AnyJsObjectMember::JsPropertyObjectMember(property_member),
+                                );
+                                break;
+                            };
+                        }
+                        _ => continue,
+                    }
+                }
+            }
+            AnyGlobalDirnameFileName::JsStaticMemberExpression(member_expr) => {
+                mutation.replace_node(
+                    member_expr.object().ok()?,
+                    AnyJsExpression::JsStaticMemberExpression(make_import_meta(
+                        dirname_or_filename,
+                    )),
+                );
+            }
+        }
+
+        Some(JsRuleAction::new(
+            ctx.metadata().action_category(ctx.category(), ctx.group()),
+            ctx.metadata().applicability(),
+            markup! {
+                "Replace "{syntax_token.text_trimmed()}" with "<Emphasis>{format!("import.meta.{}", dirname_or_filename)}</Emphasis>"."
+            },
+            mutation,
+        ))
+    }
+}
+
+fn validate_dirname_filename(
+    expr: &AnyJsExpression,
+    model: &SemanticModel,
+) -> Option<(JsSyntaxToken, String)> {
+    let (reference, _name) = global_identifier(expr)?;
+    let token = reference.value_token().ok()?;
+    maybe_text(&token)
+        .filter(|_| model.binding(&reference).is_none())
+        .map(|name| (token, name))
+}
+
+fn maybe_text(token: &JsSyntaxToken) -> Option<String> {
+    match token.text_trimmed() {
+        "__dirname" => Some("dirname".to_string()),
+        "__filename" => Some("filename".to_string()),
+        _ => None,
+    }
+}
+
+fn make_import_meta(dirname_or_filename: &str) -> JsStaticMemberExpression {
+    make::js_static_member_expression(
+        AnyJsExpression::from(make::js_import_meta_expression(
+            make::token(JsSyntaxKind::IMPORT_KW),
+            make::token(JsSyntaxKind::DOT),
+            make::token(JsSyntaxKind::META_KW),
+        )),
+        make::token(JsSyntaxKind::DOT),
+        AnyJsName::JsName(make::js_name(make::ident(dirname_or_filename))),
+    )
+}
+
+fn make_property_object_member(
+    key: &JsSyntaxToken,
+    import_meta_property: &str,
+) -> JsPropertyObjectMember {
+    make::js_property_object_member(
+        biome_js_syntax::AnyJsObjectMemberName::JsLiteralMemberName(make::js_literal_member_name(
+            make::ident(key.text_trimmed()),
+        )),
+        make::token(JsSyntaxKind::COLON).with_trailing_trivia([(TriviaPieceKind::Whitespace, " ")]),
+        AnyJsExpression::JsStaticMemberExpression(make_import_meta(import_meta_property)),
+    )
+}
diff --git a/crates/biome_js_analyze/src/options.rs b/crates/biome_js_analyze/src/options.rs
index 77013c5f1616..99c40bcc5b05 100644
--- a/crates/biome_js_analyze/src/options.rs
+++ b/crates/biome_js_analyze/src/options.rs
@@ -107,6 +107,7 @@ pub type NoFunctionAssign =
     <lint::suspicious::no_function_assign::NoFunctionAssign as biome_analyze::Rule>::Options;
 pub type NoGlobalAssign =
     <lint::suspicious::no_global_assign::NoGlobalAssign as biome_analyze::Rule>::Options;
+pub type NoGlobalDirnameFilename = < lint :: nursery :: no_global_dirname_filename :: NoGlobalDirnameFilename as biome_analyze :: Rule > :: Options ;
 pub type NoGlobalEval =
     <lint::security::no_global_eval::NoGlobalEval as biome_analyze::Rule>::Options;
 pub type NoGlobalIsFinite =
diff --git a/crates/biome_js_syntax/src/generated/kind.rs b/crates/biome_js_syntax/src/generated/kind.rs
index febf32803792..2ba713dafffe 100644
--- a/crates/biome_js_syntax/src/generated/kind.rs
+++ b/crates/biome_js_syntax/src/generated/kind.rs
@@ -154,6 +154,7 @@ pub enum JsSyntaxKind {
     OF_KW,
     OUT_KW,
     USING_KW,
+    META_KW,
     JS_NUMBER_LITERAL,
     JS_BIGINT_LITERAL,
     JS_STRING_LITERAL,
@@ -665,6 +666,7 @@ impl JsSyntaxKind {
             "of" => OF_KW,
             "out" => OUT_KW,
             "using" => USING_KW,
+            "meta" => META_KW,
             _ => return None,
         };
         Some(kw)
@@ -812,6 +814,7 @@ impl JsSyntaxKind {
             OF_KW => "of",
             OUT_KW => "out",
             USING_KW => "using",
+            META_KW => "meta",
             JS_STRING_LITERAL => "string literal",
             _ => return None,
         };
@@ -820,4 +823,4 @@ impl JsSyntaxKind {
 }
 #[doc = r" Utility macro for creating a SyntaxKind through simple macro syntax"]
 #[macro_export]
-macro_rules ! T { [;] => { $ crate :: JsSyntaxKind :: SEMICOLON } ; [,] => { $ crate :: JsSyntaxKind :: COMMA } ; ['('] => { $ crate :: JsSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: JsSyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: JsSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: JsSyntaxKind :: R_CURLY } ; ['['] => { $ crate :: JsSyntaxKind :: L_BRACK } ; [']'] => { $ crate :: JsSyntaxKind :: R_BRACK } ; [<] => { $ crate :: JsSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: JsSyntaxKind :: R_ANGLE } ; [~] => { $ crate :: JsSyntaxKind :: TILDE } ; [?] => { $ crate :: JsSyntaxKind :: QUESTION } ; [??] => { $ crate :: JsSyntaxKind :: QUESTION2 } ; [?.] => { $ crate :: JsSyntaxKind :: QUESTIONDOT } ; [&] => { $ crate :: JsSyntaxKind :: AMP } ; [|] => { $ crate :: JsSyntaxKind :: PIPE } ; [+] => { $ crate :: JsSyntaxKind :: PLUS } ; [++] => { $ crate :: JsSyntaxKind :: PLUS2 } ; [*] => { $ crate :: JsSyntaxKind :: STAR } ; [**] => { $ crate :: JsSyntaxKind :: STAR2 } ; [/] => { $ crate :: JsSyntaxKind :: SLASH } ; [^] => { $ crate :: JsSyntaxKind :: CARET } ; [%] => { $ crate :: JsSyntaxKind :: PERCENT } ; [.] => { $ crate :: JsSyntaxKind :: DOT } ; [...] => { $ crate :: JsSyntaxKind :: DOT3 } ; [:] => { $ crate :: JsSyntaxKind :: COLON } ; [=] => { $ crate :: JsSyntaxKind :: EQ } ; [==] => { $ crate :: JsSyntaxKind :: EQ2 } ; [===] => { $ crate :: JsSyntaxKind :: EQ3 } ; [=>] => { $ crate :: JsSyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: JsSyntaxKind :: BANG } ; [!=] => { $ crate :: JsSyntaxKind :: NEQ } ; [!==] => { $ crate :: JsSyntaxKind :: NEQ2 } ; [-] => { $ crate :: JsSyntaxKind :: MINUS } ; [--] => { $ crate :: JsSyntaxKind :: MINUS2 } ; [<=] => { $ crate :: JsSyntaxKind :: LTEQ } ; [>=] => { $ crate :: JsSyntaxKind :: GTEQ } ; [+=] => { $ crate :: JsSyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: JsSyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: JsSyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: JsSyntaxKind :: AMPEQ } ; [^=] => { $ crate :: JsSyntaxKind :: CARETEQ } ; [/=] => { $ crate :: JsSyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: JsSyntaxKind :: STAREQ } ; [%=] => { $ crate :: JsSyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: JsSyntaxKind :: AMP2 } ; [||] => { $ crate :: JsSyntaxKind :: PIPE2 } ; [<<] => { $ crate :: JsSyntaxKind :: SHL } ; [>>] => { $ crate :: JsSyntaxKind :: SHR } ; [>>>] => { $ crate :: JsSyntaxKind :: USHR } ; [<<=] => { $ crate :: JsSyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: JsSyntaxKind :: SHREQ } ; [>>>=] => { $ crate :: JsSyntaxKind :: USHREQ } ; [&&=] => { $ crate :: JsSyntaxKind :: AMP2EQ } ; [||=] => { $ crate :: JsSyntaxKind :: PIPE2EQ } ; [**=] => { $ crate :: JsSyntaxKind :: STAR2EQ } ; [??=] => { $ crate :: JsSyntaxKind :: QUESTION2EQ } ; [@] => { $ crate :: JsSyntaxKind :: AT } ; ['`'] => { $ crate :: JsSyntaxKind :: BACKTICK } ; [break] => { $ crate :: JsSyntaxKind :: BREAK_KW } ; [case] => { $ crate :: JsSyntaxKind :: CASE_KW } ; [catch] => { $ crate :: JsSyntaxKind :: CATCH_KW } ; [class] => { $ crate :: JsSyntaxKind :: CLASS_KW } ; [const] => { $ crate :: JsSyntaxKind :: CONST_KW } ; [continue] => { $ crate :: JsSyntaxKind :: CONTINUE_KW } ; [debugger] => { $ crate :: JsSyntaxKind :: DEBUGGER_KW } ; [default] => { $ crate :: JsSyntaxKind :: DEFAULT_KW } ; [delete] => { $ crate :: JsSyntaxKind :: DELETE_KW } ; [do] => { $ crate :: JsSyntaxKind :: DO_KW } ; [else] => { $ crate :: JsSyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: JsSyntaxKind :: ENUM_KW } ; [export] => { $ crate :: JsSyntaxKind :: EXPORT_KW } ; [extends] => { $ crate :: JsSyntaxKind :: EXTENDS_KW } ; [false] => { $ crate :: JsSyntaxKind :: FALSE_KW } ; [finally] => { $ crate :: JsSyntaxKind :: FINALLY_KW } ; [for] => { $ crate :: JsSyntaxKind :: FOR_KW } ; [function] => { $ crate :: JsSyntaxKind :: FUNCTION_KW } ; [if] => { $ crate :: JsSyntaxKind :: IF_KW } ; [in] => { $ crate :: JsSyntaxKind :: IN_KW } ; [instanceof] => { $ crate :: JsSyntaxKind :: INSTANCEOF_KW } ; [import] => { $ crate :: JsSyntaxKind :: IMPORT_KW } ; [new] => { $ crate :: JsSyntaxKind :: NEW_KW } ; [null] => { $ crate :: JsSyntaxKind :: NULL_KW } ; [return] => { $ crate :: JsSyntaxKind :: RETURN_KW } ; [super] => { $ crate :: JsSyntaxKind :: SUPER_KW } ; [switch] => { $ crate :: JsSyntaxKind :: SWITCH_KW } ; [this] => { $ crate :: JsSyntaxKind :: THIS_KW } ; [throw] => { $ crate :: JsSyntaxKind :: THROW_KW } ; [try] => { $ crate :: JsSyntaxKind :: TRY_KW } ; [true] => { $ crate :: JsSyntaxKind :: TRUE_KW } ; [typeof] => { $ crate :: JsSyntaxKind :: TYPEOF_KW } ; [var] => { $ crate :: JsSyntaxKind :: VAR_KW } ; [void] => { $ crate :: JsSyntaxKind :: VOID_KW } ; [while] => { $ crate :: JsSyntaxKind :: WHILE_KW } ; [with] => { $ crate :: JsSyntaxKind :: WITH_KW } ; [implements] => { $ crate :: JsSyntaxKind :: IMPLEMENTS_KW } ; [interface] => { $ crate :: JsSyntaxKind :: INTERFACE_KW } ; [let] => { $ crate :: JsSyntaxKind :: LET_KW } ; [package] => { $ crate :: JsSyntaxKind :: PACKAGE_KW } ; [private] => { $ crate :: JsSyntaxKind :: PRIVATE_KW } ; [protected] => { $ crate :: JsSyntaxKind :: PROTECTED_KW } ; [public] => { $ crate :: JsSyntaxKind :: PUBLIC_KW } ; [static] => { $ crate :: JsSyntaxKind :: STATIC_KW } ; [yield] => { $ crate :: JsSyntaxKind :: YIELD_KW } ; [abstract] => { $ crate :: JsSyntaxKind :: ABSTRACT_KW } ; [accessor] => { $ crate :: JsSyntaxKind :: ACCESSOR_KW } ; [as] => { $ crate :: JsSyntaxKind :: AS_KW } ; [satisfies] => { $ crate :: JsSyntaxKind :: SATISFIES_KW } ; [asserts] => { $ crate :: JsSyntaxKind :: ASSERTS_KW } ; [assert] => { $ crate :: JsSyntaxKind :: ASSERT_KW } ; [any] => { $ crate :: JsSyntaxKind :: ANY_KW } ; [async] => { $ crate :: JsSyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: JsSyntaxKind :: AWAIT_KW } ; [boolean] => { $ crate :: JsSyntaxKind :: BOOLEAN_KW } ; [constructor] => { $ crate :: JsSyntaxKind :: CONSTRUCTOR_KW } ; [declare] => { $ crate :: JsSyntaxKind :: DECLARE_KW } ; [get] => { $ crate :: JsSyntaxKind :: GET_KW } ; [infer] => { $ crate :: JsSyntaxKind :: INFER_KW } ; [is] => { $ crate :: JsSyntaxKind :: IS_KW } ; [keyof] => { $ crate :: JsSyntaxKind :: KEYOF_KW } ; [module] => { $ crate :: JsSyntaxKind :: MODULE_KW } ; [namespace] => { $ crate :: JsSyntaxKind :: NAMESPACE_KW } ; [never] => { $ crate :: JsSyntaxKind :: NEVER_KW } ; [readonly] => { $ crate :: JsSyntaxKind :: READONLY_KW } ; [require] => { $ crate :: JsSyntaxKind :: REQUIRE_KW } ; [number] => { $ crate :: JsSyntaxKind :: NUMBER_KW } ; [object] => { $ crate :: JsSyntaxKind :: OBJECT_KW } ; [set] => { $ crate :: JsSyntaxKind :: SET_KW } ; [string] => { $ crate :: JsSyntaxKind :: STRING_KW } ; [symbol] => { $ crate :: JsSyntaxKind :: SYMBOL_KW } ; [type] => { $ crate :: JsSyntaxKind :: TYPE_KW } ; [undefined] => { $ crate :: JsSyntaxKind :: UNDEFINED_KW } ; [unique] => { $ crate :: JsSyntaxKind :: UNIQUE_KW } ; [unknown] => { $ crate :: JsSyntaxKind :: UNKNOWN_KW } ; [from] => { $ crate :: JsSyntaxKind :: FROM_KW } ; [global] => { $ crate :: JsSyntaxKind :: GLOBAL_KW } ; [bigint] => { $ crate :: JsSyntaxKind :: BIGINT_KW } ; [override] => { $ crate :: JsSyntaxKind :: OVERRIDE_KW } ; [of] => { $ crate :: JsSyntaxKind :: OF_KW } ; [out] => { $ crate :: JsSyntaxKind :: OUT_KW } ; [using] => { $ crate :: JsSyntaxKind :: USING_KW } ; [ident] => { $ crate :: JsSyntaxKind :: IDENT } ; [EOF] => { $ crate :: JsSyntaxKind :: EOF } ; [UNICODE_BOM] => { $ crate :: JsSyntaxKind :: UNICODE_BOM } ; [#] => { $ crate :: JsSyntaxKind :: HASH } ; }
+macro_rules ! T { [;] => { $ crate :: JsSyntaxKind :: SEMICOLON } ; [,] => { $ crate :: JsSyntaxKind :: COMMA } ; ['('] => { $ crate :: JsSyntaxKind :: L_PAREN } ; [')'] => { $ crate :: JsSyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: JsSyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: JsSyntaxKind :: R_CURLY } ; ['['] => { $ crate :: JsSyntaxKind :: L_BRACK } ; [']'] => { $ crate :: JsSyntaxKind :: R_BRACK } ; [<] => { $ crate :: JsSyntaxKind :: L_ANGLE } ; [>] => { $ crate :: JsSyntaxKind :: R_ANGLE } ; [~] => { $ crate :: JsSyntaxKind :: TILDE } ; [?] => { $ crate :: JsSyntaxKind :: QUESTION } ; [??] => { $ crate :: JsSyntaxKind :: QUESTION2 } ; [?.] => { $ crate :: JsSyntaxKind :: QUESTIONDOT } ; [&] => { $ crate :: JsSyntaxKind :: AMP } ; [|] => { $ crate :: JsSyntaxKind :: PIPE } ; [+] => { $ crate :: JsSyntaxKind :: PLUS } ; [++] => { $ crate :: JsSyntaxKind :: PLUS2 } ; [*] => { $ crate :: JsSyntaxKind :: STAR } ; [**] => { $ crate :: JsSyntaxKind :: STAR2 } ; [/] => { $ crate :: JsSyntaxKind :: SLASH } ; [^] => { $ crate :: JsSyntaxKind :: CARET } ; [%] => { $ crate :: JsSyntaxKind :: PERCENT } ; [.] => { $ crate :: JsSyntaxKind :: DOT } ; [...] => { $ crate :: JsSyntaxKind :: DOT3 } ; [:] => { $ crate :: JsSyntaxKind :: COLON } ; [=] => { $ crate :: JsSyntaxKind :: EQ } ; [==] => { $ crate :: JsSyntaxKind :: EQ2 } ; [===] => { $ crate :: JsSyntaxKind :: EQ3 } ; [=>] => { $ crate :: JsSyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: JsSyntaxKind :: BANG } ; [!=] => { $ crate :: JsSyntaxKind :: NEQ } ; [!==] => { $ crate :: JsSyntaxKind :: NEQ2 } ; [-] => { $ crate :: JsSyntaxKind :: MINUS } ; [--] => { $ crate :: JsSyntaxKind :: MINUS2 } ; [<=] => { $ crate :: JsSyntaxKind :: LTEQ } ; [>=] => { $ crate :: JsSyntaxKind :: GTEQ } ; [+=] => { $ crate :: JsSyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: JsSyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: JsSyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: JsSyntaxKind :: AMPEQ } ; [^=] => { $ crate :: JsSyntaxKind :: CARETEQ } ; [/=] => { $ crate :: JsSyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: JsSyntaxKind :: STAREQ } ; [%=] => { $ crate :: JsSyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: JsSyntaxKind :: AMP2 } ; [||] => { $ crate :: JsSyntaxKind :: PIPE2 } ; [<<] => { $ crate :: JsSyntaxKind :: SHL } ; [>>] => { $ crate :: JsSyntaxKind :: SHR } ; [>>>] => { $ crate :: JsSyntaxKind :: USHR } ; [<<=] => { $ crate :: JsSyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: JsSyntaxKind :: SHREQ } ; [>>>=] => { $ crate :: JsSyntaxKind :: USHREQ } ; [&&=] => { $ crate :: JsSyntaxKind :: AMP2EQ } ; [||=] => { $ crate :: JsSyntaxKind :: PIPE2EQ } ; [**=] => { $ crate :: JsSyntaxKind :: STAR2EQ } ; [??=] => { $ crate :: JsSyntaxKind :: QUESTION2EQ } ; [@] => { $ crate :: JsSyntaxKind :: AT } ; ['`'] => { $ crate :: JsSyntaxKind :: BACKTICK } ; [break] => { $ crate :: JsSyntaxKind :: BREAK_KW } ; [case] => { $ crate :: JsSyntaxKind :: CASE_KW } ; [catch] => { $ crate :: JsSyntaxKind :: CATCH_KW } ; [class] => { $ crate :: JsSyntaxKind :: CLASS_KW } ; [const] => { $ crate :: JsSyntaxKind :: CONST_KW } ; [continue] => { $ crate :: JsSyntaxKind :: CONTINUE_KW } ; [debugger] => { $ crate :: JsSyntaxKind :: DEBUGGER_KW } ; [default] => { $ crate :: JsSyntaxKind :: DEFAULT_KW } ; [delete] => { $ crate :: JsSyntaxKind :: DELETE_KW } ; [do] => { $ crate :: JsSyntaxKind :: DO_KW } ; [else] => { $ crate :: JsSyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: JsSyntaxKind :: ENUM_KW } ; [export] => { $ crate :: JsSyntaxKind :: EXPORT_KW } ; [extends] => { $ crate :: JsSyntaxKind :: EXTENDS_KW } ; [false] => { $ crate :: JsSyntaxKind :: FALSE_KW } ; [finally] => { $ crate :: JsSyntaxKind :: FINALLY_KW } ; [for] => { $ crate :: JsSyntaxKind :: FOR_KW } ; [function] => { $ crate :: JsSyntaxKind :: FUNCTION_KW } ; [if] => { $ crate :: JsSyntaxKind :: IF_KW } ; [in] => { $ crate :: JsSyntaxKind :: IN_KW } ; [instanceof] => { $ crate :: JsSyntaxKind :: INSTANCEOF_KW } ; [import] => { $ crate :: JsSyntaxKind :: IMPORT_KW } ; [new] => { $ crate :: JsSyntaxKind :: NEW_KW } ; [null] => { $ crate :: JsSyntaxKind :: NULL_KW } ; [return] => { $ crate :: JsSyntaxKind :: RETURN_KW } ; [super] => { $ crate :: JsSyntaxKind :: SUPER_KW } ; [switch] => { $ crate :: JsSyntaxKind :: SWITCH_KW } ; [this] => { $ crate :: JsSyntaxKind :: THIS_KW } ; [throw] => { $ crate :: JsSyntaxKind :: THROW_KW } ; [try] => { $ crate :: JsSyntaxKind :: TRY_KW } ; [true] => { $ crate :: JsSyntaxKind :: TRUE_KW } ; [typeof] => { $ crate :: JsSyntaxKind :: TYPEOF_KW } ; [var] => { $ crate :: JsSyntaxKind :: VAR_KW } ; [void] => { $ crate :: JsSyntaxKind :: VOID_KW } ; [while] => { $ crate :: JsSyntaxKind :: WHILE_KW } ; [with] => { $ crate :: JsSyntaxKind :: WITH_KW } ; [implements] => { $ crate :: JsSyntaxKind :: IMPLEMENTS_KW } ; [interface] => { $ crate :: JsSyntaxKind :: INTERFACE_KW } ; [let] => { $ crate :: JsSyntaxKind :: LET_KW } ; [package] => { $ crate :: JsSyntaxKind :: PACKAGE_KW } ; [private] => { $ crate :: JsSyntaxKind :: PRIVATE_KW } ; [protected] => { $ crate :: JsSyntaxKind :: PROTECTED_KW } ; [public] => { $ crate :: JsSyntaxKind :: PUBLIC_KW } ; [static] => { $ crate :: JsSyntaxKind :: STATIC_KW } ; [yield] => { $ crate :: JsSyntaxKind :: YIELD_KW } ; [abstract] => { $ crate :: JsSyntaxKind :: ABSTRACT_KW } ; [accessor] => { $ crate :: JsSyntaxKind :: ACCESSOR_KW } ; [as] => { $ crate :: JsSyntaxKind :: AS_KW } ; [satisfies] => { $ crate :: JsSyntaxKind :: SATISFIES_KW } ; [asserts] => { $ crate :: JsSyntaxKind :: ASSERTS_KW } ; [assert] => { $ crate :: JsSyntaxKind :: ASSERT_KW } ; [any] => { $ crate :: JsSyntaxKind :: ANY_KW } ; [async] => { $ crate :: JsSyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: JsSyntaxKind :: AWAIT_KW } ; [boolean] => { $ crate :: JsSyntaxKind :: BOOLEAN_KW } ; [constructor] => { $ crate :: JsSyntaxKind :: CONSTRUCTOR_KW } ; [declare] => { $ crate :: JsSyntaxKind :: DECLARE_KW } ; [get] => { $ crate :: JsSyntaxKind :: GET_KW } ; [infer] => { $ crate :: JsSyntaxKind :: INFER_KW } ; [is] => { $ crate :: JsSyntaxKind :: IS_KW } ; [keyof] => { $ crate :: JsSyntaxKind :: KEYOF_KW } ; [module] => { $ crate :: JsSyntaxKind :: MODULE_KW } ; [namespace] => { $ crate :: JsSyntaxKind :: NAMESPACE_KW } ; [never] => { $ crate :: JsSyntaxKind :: NEVER_KW } ; [readonly] => { $ crate :: JsSyntaxKind :: READONLY_KW } ; [require] => { $ crate :: JsSyntaxKind :: REQUIRE_KW } ; [number] => { $ crate :: JsSyntaxKind :: NUMBER_KW } ; [object] => { $ crate :: JsSyntaxKind :: OBJECT_KW } ; [set] => { $ crate :: JsSyntaxKind :: SET_KW } ; [string] => { $ crate :: JsSyntaxKind :: STRING_KW } ; [symbol] => { $ crate :: JsSyntaxKind :: SYMBOL_KW } ; [type] => { $ crate :: JsSyntaxKind :: TYPE_KW } ; [undefined] => { $ crate :: JsSyntaxKind :: UNDEFINED_KW } ; [unique] => { $ crate :: JsSyntaxKind :: UNIQUE_KW } ; [unknown] => { $ crate :: JsSyntaxKind :: UNKNOWN_KW } ; [from] => { $ crate :: JsSyntaxKind :: FROM_KW } ; [global] => { $ crate :: JsSyntaxKind :: GLOBAL_KW } ; [bigint] => { $ crate :: JsSyntaxKind :: BIGINT_KW } ; [override] => { $ crate :: JsSyntaxKind :: OVERRIDE_KW } ; [of] => { $ crate :: JsSyntaxKind :: OF_KW } ; [out] => { $ crate :: JsSyntaxKind :: OUT_KW } ; [using] => { $ crate :: JsSyntaxKind :: USING_KW } ; [meta] => { $ crate :: JsSyntaxKind :: META_KW } ; [ident] => { $ crate :: JsSyntaxKind :: IDENT } ; [EOF] => { $ crate :: JsSyntaxKind :: EOF } ; [UNICODE_BOM] => { $ crate :: JsSyntaxKind :: UNICODE_BOM } ; [#] => { $ crate :: JsSyntaxKind :: HASH } ; }
diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
index a1d5046ac99f..c25fc70014d4 100644
--- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts
+++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts
@@ -1270,6 +1270,10 @@ export interface Nursery {
 	 * Disallow exporting an imported variable.
 	 */
 	noExportedImports?: RuleConfiguration_for_Null;
+	/**
+	 * Disallow the use of __dirname and __filename in the global scope.
+	 */
+	noGlobalDirnameFilename?: RuleFixConfiguration_for_Null;
 	/**
 	 * Prevent usage of \<head> element in a Next.js project.
 	 */
@@ -3057,6 +3061,7 @@ export type Category =
 	| "lint/nursery/noDynamicNamespaceImportAccess"
 	| "lint/nursery/noEnum"
 	| "lint/nursery/noExportedImports"
+	| "lint/nursery/noGlobalDirnameFilename"
 	| "lint/nursery/noHeadElement"
 	| "lint/nursery/noHeadImportInDocument"
 	| "lint/nursery/noImgElement"
diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json
index a5c12e949462..fcf9f1c1f679 100644
--- a/packages/@biomejs/biome/configuration_schema.json
+++ b/packages/@biomejs/biome/configuration_schema.json
@@ -2218,6 +2218,13 @@
 						{ "type": "null" }
 					]
 				},
+				"noGlobalDirnameFilename": {
+					"description": "Disallow the use of __dirname and __filename in the global scope.",
+					"anyOf": [
+						{ "$ref": "#/definitions/RuleFixConfiguration" },
+						{ "type": "null" }
+					]
+				},
 				"noHeadElement": {
 					"description": "Prevent usage of \\<head> element in a Next.js project.",
 					"anyOf": [
diff --git a/xtask/codegen/src/js_kinds_src.rs b/xtask/codegen/src/js_kinds_src.rs
index 09f05a304392..af32c8b89a97 100644
--- a/xtask/codegen/src/js_kinds_src.rs
+++ b/xtask/codegen/src/js_kinds_src.rs
@@ -155,6 +155,7 @@ pub const JS_KINDS_SRC: KindsSrc = KindsSrc {
         "of",
         "out",
         "using",
+        "meta",
     ],
     literals: &[
         "JS_NUMBER_LITERAL",


Test patch:
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js
new file mode 100644
index 000000000000..05dca9a8250d
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js
@@ -0,0 +1,9 @@
+const dirname = __dirname;
+const filename = __filename;
+const dirname_ = { __dirname };
+const filename_ = { __filename };
+const dirname__ = { dirname: __dirname, foo: "foo" };
+const filename__ = { filename: __filename, foo: "foo" };
+
+if (__dirname.startsWith("/project/src/")) {}
+if (__filename.endsWith(".js")) {}
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js.snap
new file mode 100644
index 000000000000..7bc6e6463354
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/invalid.js.snap
@@ -0,0 +1,207 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: invalid.js
+---
+# Input
+```jsx
+const dirname = __dirname;
+const filename = __filename;
+const dirname_ = { __dirname };
+const filename_ = { __filename };
+const dirname__ = { dirname: __dirname, foo: "foo" };
+const filename__ = { filename: __filename, foo: "foo" };
+
+if (__dirname.startsWith("/project/src/")) {}
+if (__filename.endsWith(".js")) {}
+
+```
+
+# Diagnostics
+```
+invalid.js:1:17 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __dirname.
+  
+  > 1 │ const dirname = __dirname;
+      │                 ^^^^^^^^^
+    2 │ const filename = __filename;
+    3 │ const dirname_ = { __dirname };
+  
+  i __dirname is not available in ES modules.
+  
+  i Safe fix: Replace __dirname with import.meta.dirname.
+  
+     1    │ - const·dirname·=·__dirname;
+        1 │ + const·dirname·=·import.meta.dirname;
+     2  2 │   const filename = __filename;
+     3  3 │   const dirname_ = { __dirname };
+  
+
+```
+
+```
+invalid.js:2:18 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __filename.
+  
+    1 │ const dirname = __dirname;
+  > 2 │ const filename = __filename;
+      │                  ^^^^^^^^^^
+    3 │ const dirname_ = { __dirname };
+    4 │ const filename_ = { __filename };
+  
+  i __filename is not available in ES modules.
+  
+  i Safe fix: Replace __filename with import.meta.filename.
+  
+     1  1 │   const dirname = __dirname;
+     2    │ - const·filename·=·__filename;
+        2 │ + const·filename·=·import.meta.filename;
+     3  3 │   const dirname_ = { __dirname };
+     4  4 │   const filename_ = { __filename };
+  
+
+```
+
+```
+invalid.js:3:20 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __dirname.
+  
+    1 │ const dirname = __dirname;
+    2 │ const filename = __filename;
+  > 3 │ const dirname_ = { __dirname };
+      │                    ^^^^^^^^^^
+    4 │ const filename_ = { __filename };
+    5 │ const dirname__ = { dirname: __dirname, foo: "foo" };
+  
+  i __dirname is not available in ES modules.
+  
+  i Safe fix: Replace __dirname with import.meta.dirname.
+  
+    3 │ const·dirname_·=·{·__dirname:·import.meta.dirname·};
+      │                             +++++++++++++++++++++   
+
+```
+
+```
+invalid.js:4:21 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __filename.
+  
+    2 │ const filename = __filename;
+    3 │ const dirname_ = { __dirname };
+  > 4 │ const filename_ = { __filename };
+      │                     ^^^^^^^^^^^
+    5 │ const dirname__ = { dirname: __dirname, foo: "foo" };
+    6 │ const filename__ = { filename: __filename, foo: "foo" };
+  
+  i __filename is not available in ES modules.
+  
+  i Safe fix: Replace __filename with import.meta.filename.
+  
+    4 │ const·filename_·=·{·__filename:·import.meta.filename·};
+      │                               ++++++++++++++++++++++   
+
+```
+
+```
+invalid.js:5:30 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __dirname.
+  
+    3 │ const dirname_ = { __dirname };
+    4 │ const filename_ = { __filename };
+  > 5 │ const dirname__ = { dirname: __dirname, foo: "foo" };
+      │                              ^^^^^^^^^
+    6 │ const filename__ = { filename: __filename, foo: "foo" };
+    7 │ 
+  
+  i __dirname is not available in ES modules.
+  
+  i Safe fix: Replace __dirname with import.meta.dirname.
+  
+     3  3 │   const dirname_ = { __dirname };
+     4  4 │   const filename_ = { __filename };
+     5    │ - const·dirname__·=·{·dirname:·__dirname,·foo:·"foo"·};
+        5 │ + const·dirname__·=·{·dirname:·import.meta.dirname,·foo:·"foo"·};
+     6  6 │   const filename__ = { filename: __filename, foo: "foo" };
+     7  7 │   
+  
+
+```
+
+```
+invalid.js:6:32 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __filename.
+  
+    4 │ const filename_ = { __filename };
+    5 │ const dirname__ = { dirname: __dirname, foo: "foo" };
+  > 6 │ const filename__ = { filename: __filename, foo: "foo" };
+      │                                ^^^^^^^^^^
+    7 │ 
+    8 │ if (__dirname.startsWith("/project/src/")) {}
+  
+  i __filename is not available in ES modules.
+  
+  i Safe fix: Replace __filename with import.meta.filename.
+  
+     4  4 │   const filename_ = { __filename };
+     5  5 │   const dirname__ = { dirname: __dirname, foo: "foo" };
+     6    │ - const·filename__·=·{·filename:·__filename,·foo:·"foo"·};
+        6 │ + const·filename__·=·{·filename:·import.meta.filename,·foo:·"foo"·};
+     7  7 │   
+     8  8 │   if (__dirname.startsWith("/project/src/")) {}
+  
+
+```
+
+```
+invalid.js:8:5 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __dirname.
+  
+     6 │ const filename__ = { filename: __filename, foo: "foo" };
+     7 │ 
+   > 8 │ if (__dirname.startsWith("/project/src/")) {}
+       │     ^^^^^^^^^
+     9 │ if (__filename.endsWith(".js")) {}
+    10 │ 
+  
+  i __dirname is not available in ES modules.
+  
+  i Safe fix: Replace __dirname with import.meta.dirname.
+  
+     6  6 │   const filename__ = { filename: __filename, foo: "foo" };
+     7  7 │   
+     8    │ - if·(__dirname.startsWith("/project/src/"))·{}
+        8 │ + if·(import.meta.dirname.startsWith("/project/src/"))·{}
+     9  9 │   if (__filename.endsWith(".js")) {}
+    10 10 │   
+  
+
+```
+
+```
+invalid.js:9:5 lint/nursery/noGlobalDirnameFilename  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+  ! Don't use __filename.
+  
+     8 │ if (__dirname.startsWith("/project/src/")) {}
+   > 9 │ if (__filename.endsWith(".js")) {}
+       │     ^^^^^^^^^^
+    10 │ 
+  
+  i __filename is not available in ES modules.
+  
+  i Safe fix: Replace __filename with import.meta.filename.
+  
+     7  7 │   
+     8  8 │   if (__dirname.startsWith("/project/src/")) {}
+     9    │ - if·(__filename.endsWith(".js"))·{}
+        9 │ + if·(import.meta.filename.endsWith(".js"))·{}
+    10 10 │   
+  
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs
new file mode 100644
index 000000000000..31e931b63072
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs
@@ -0,0 +1,10 @@
+/* should not generate diagnostics */
+const __filename = 1;
+const foo = __filename;
+
+const __dirname = 1;
+const bar = __dirname;
+
+import {__filename as filename} from "foo.mjs"
+const baz = 1;
+export {foo as __dirname}
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs.snap b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs.snap
new file mode 100644
index 000000000000..edd09c526b0a
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.cjs.snap
@@ -0,0 +1,18 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: valid.cjs
+---
+# Input
+```cjs
+/* should not generate diagnostics */
+const __filename = 1;
+const foo = __filename;
+
+const __dirname = 1;
+const bar = __dirname;
+
+import {__filename as filename} from "foo.mjs"
+const baz = 1;
+export {foo as __dirname}
+
+```
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js
new file mode 100644
index 000000000000..a6334323ae1e
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js
@@ -0,0 +1,9 @@
+const dirname = import.meta.dirname;
+const filename = import.meta.filename;
+const dirname_ = { __dirname: import.meta.dirname };
+const filename_ = { __filename: import.meta.filename };
+const dirname__ = { dirname: import.meta.dirname, foo: "foo" };
+const filename__ = { filename: import.meta.filename, foo: "foo" };
+
+if (import.meta.dirname.startsWith("/project/src/")) {}
+if (import.meta.filename.endsWith(".js")) {}
diff --git a/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js.snap
new file mode 100644
index 000000000000..e38546cb8d2a
--- /dev/null
+++ b/crates/biome_js_analyze/tests/specs/nursery/noGlobalDirnameFilename/valid.js.snap
@@ -0,0 +1,17 @@
+---
+source: crates/biome_js_analyze/tests/spec_tests.rs
+expression: valid.js
+---
+# Input
+```jsx
+const dirname = import.meta.dirname;
+const filename = import.meta.filename;
+const dirname_ = { __dirname: import.meta.dirname };
+const filename_ = { __filename: import.meta.filename };
+const dirname__ = { dirname: import.meta.dirname, foo: "foo" };
+const filename__ = { filename: import.meta.filename, foo: "foo" };
+
+if (import.meta.dirname.startsWith("/project/src/")) {}
+if (import.meta.filename.endsWith(".js")) {}
+
+```