diff --git a/crates/oxc_transformer_plugins/src/inject_global_variables.rs b/crates/oxc_transformer_plugins/src/inject_global_variables.rs index fada088867696..8458a3dc37913 100644 --- a/crates/oxc_transformer_plugins/src/inject_global_variables.rs +++ b/crates/oxc_transformer_plugins/src/inject_global_variables.rs @@ -261,27 +261,55 @@ impl<'a> InjectGlobalVariables<'a> { } fn replace_dot_defines(&mut self, expr: &mut Expression<'a>, ctx: &TraverseCtx<'a>) { - if let Expression::StaticMemberExpression(member) = expr { - for DotDefineState { dot_define, value_atom } in &mut self.dot_defines { - if ReplaceGlobalDefines::is_dot_define( - ctx, - dot_define, - DotDefineMemberExpression::StaticMemberExpression(member), - ) { - // If this is first replacement made for this dot define, - // create `Atom` for replacement, and record in `replaced_dot_defines` - let value_atom = *value_atom.get_or_insert_with(|| { - self.replaced_dot_defines - .push((dot_define.parts[0].clone(), dot_define.value.clone())); - self.ast.atom(dot_define.value.as_str()) - }); - - let value = self.ast.expression_identifier(SPAN, value_atom); - *expr = value; - self.mark_as_changed(); - break; + match expr { + Expression::StaticMemberExpression(member) => { + for DotDefineState { dot_define, value_atom } in &mut self.dot_defines { + if ReplaceGlobalDefines::is_dot_define( + ctx, + dot_define, + DotDefineMemberExpression::StaticMemberExpression(member), + ) { + // If this is first replacement made for this dot define, + // create `Atom` for replacement, and record in `replaced_dot_defines` + let value_atom = *value_atom.get_or_insert_with(|| { + self.replaced_dot_defines + .push((dot_define.parts[0].clone(), dot_define.value.clone())); + self.ast.atom(dot_define.value.as_str()) + }); + + let value = self.ast.expression_identifier(SPAN, value_atom); + *expr = value; + self.mark_as_changed(); + break; + } + } + } + Expression::MetaProperty(meta_property) => { + // Check if this is import.meta and if it should be replaced + if meta_property.meta.name == "import" && meta_property.property.name == "meta" { + for DotDefineState { dot_define, value_atom } in &mut self.dot_defines { + // Check if dot_define is exactly ["import", "meta"] + if dot_define.parts.len() == 2 + && dot_define.parts[0].as_str() == "import" + && dot_define.parts[1].as_str() == "meta" + { + // If this is first replacement made for this dot define, + // create `Atom` for replacement, and record in `replaced_dot_defines` + let value_atom = *value_atom.get_or_insert_with(|| { + self.replaced_dot_defines + .push((dot_define.parts[0].clone(), dot_define.value.clone())); + self.ast.atom(dot_define.value.as_str()) + }); + + let value = self.ast.expression_identifier(SPAN, value_atom); + *expr = value; + self.mark_as_changed(); + break; + } + } } } + _ => {} } } } diff --git a/crates/oxc_transformer_plugins/src/replace_global_defines.rs b/crates/oxc_transformer_plugins/src/replace_global_defines.rs index 73df7ddfd4ae3..17396adf38dc4 100644 --- a/crates/oxc_transformer_plugins/src/replace_global_defines.rs +++ b/crates/oxc_transformer_plugins/src/replace_global_defines.rs @@ -616,6 +616,25 @@ impl<'a> ReplaceGlobalDefines<'a> { cur_part_name = &THIS_ATOM; None } + Expression::MetaProperty(meta) => { + // Handle import.meta + // When we encounter a MetaProperty, we need to verify that the remaining + // parts match ["import", "meta"] + if meta.meta.name == "import" && meta.property.name == "meta" { + // At this point, i is the current position we're checking + // We need the next two parts (going backwards) to be "meta" then "import" + // i.e., parts[i-1] == "meta" and parts[i-2] == "import" + if i >= 2 + && dot_define.parts[i - 1].as_str() == "meta" + && dot_define.parts[i - 2].as_str() == "import" + { + // Successfully matched import.meta at the expected position + // Return true if we've consumed all parts (i == 2) + return i == 2; + } + } + None + } _ => None, } } else { diff --git a/crates/oxc_transformer_plugins/tests/integrations/inject_global_variables.rs b/crates/oxc_transformer_plugins/tests/integrations/inject_global_variables.rs index 3a3492b7433ed..bec9f975ac4ba 100644 --- a/crates/oxc_transformer_plugins/tests/integrations/inject_global_variables.rs +++ b/crates/oxc_transformer_plugins/tests/integrations/inject_global_variables.rs @@ -424,3 +424,76 @@ fn escape_source_with_newline() { config, ); } + +#[test] +fn import_meta() { + // handles import.meta + let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier( + "foo", + None, + "import.meta", + )]); + test( + "console.log(import.meta)", + " + import { default as $inject_import_meta } from 'foo'; + console.log($inject_import_meta); + ", + config, + ); +} + +#[test] +fn import_meta_property() { + // handles import.meta.foo + let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier( + "bar", + None, + "import.meta.foo", + )]); + test( + "console.log(import.meta.foo)", + " + import { default as $inject_import_meta_foo } from 'bar'; + console.log($inject_import_meta_foo); + ", + config, + ); +} + +#[test] +fn import_meta_nested_property() { + // handles import.meta.env.MODE + let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier( + "baz", + None, + "import.meta.env.MODE", + )]); + test( + "console.log(import.meta.env.MODE)", + " + import { default as $inject_import_meta_env_MODE } from 'baz'; + console.log($inject_import_meta_env_MODE); + ", + config, + ); +} + +#[test] +fn import_meta_combined() { + // handles both import.meta and import.meta.foo together + let config = InjectGlobalVariablesConfig::new(vec![ + InjectImport::named_specifier("foo", None, "import.meta"), + InjectImport::named_specifier("bar", None, "import.meta.foo"), + ]); + test( + "console.log(import.meta); console.log(import.meta.foo)", + " + import { default as $inject_import_meta } from 'foo'; + import { default as $inject_import_meta_foo } from 'bar'; + console.log($inject_import_meta); + console.log($inject_import_meta_foo); + ", + config, + ); +}