Skip to content

Commit 9d568eb

Browse files
Copilotsapphi-red
andauthored
feat(transformer_plugins): support import.meta injection in inject_global_variables (#15125)
Signed-off-by: 翠 <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: sapphi-red <[email protected]> Co-authored-by: 翠 <[email protected]>
1 parent 205aab6 commit 9d568eb

File tree

3 files changed

+139
-19
lines changed

3 files changed

+139
-19
lines changed

crates/oxc_transformer_plugins/src/inject_global_variables.rs

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -261,27 +261,55 @@ impl<'a> InjectGlobalVariables<'a> {
261261
}
262262

263263
fn replace_dot_defines(&mut self, expr: &mut Expression<'a>, ctx: &TraverseCtx<'a>) {
264-
if let Expression::StaticMemberExpression(member) = expr {
265-
for DotDefineState { dot_define, value_atom } in &mut self.dot_defines {
266-
if ReplaceGlobalDefines::is_dot_define(
267-
ctx,
268-
dot_define,
269-
DotDefineMemberExpression::StaticMemberExpression(member),
270-
) {
271-
// If this is first replacement made for this dot define,
272-
// create `Atom` for replacement, and record in `replaced_dot_defines`
273-
let value_atom = *value_atom.get_or_insert_with(|| {
274-
self.replaced_dot_defines
275-
.push((dot_define.parts[0].clone(), dot_define.value.clone()));
276-
self.ast.atom(dot_define.value.as_str())
277-
});
278-
279-
let value = self.ast.expression_identifier(SPAN, value_atom);
280-
*expr = value;
281-
self.mark_as_changed();
282-
break;
264+
match expr {
265+
Expression::StaticMemberExpression(member) => {
266+
for DotDefineState { dot_define, value_atom } in &mut self.dot_defines {
267+
if ReplaceGlobalDefines::is_dot_define(
268+
ctx,
269+
dot_define,
270+
DotDefineMemberExpression::StaticMemberExpression(member),
271+
) {
272+
// If this is first replacement made for this dot define,
273+
// create `Atom` for replacement, and record in `replaced_dot_defines`
274+
let value_atom = *value_atom.get_or_insert_with(|| {
275+
self.replaced_dot_defines
276+
.push((dot_define.parts[0].clone(), dot_define.value.clone()));
277+
self.ast.atom(dot_define.value.as_str())
278+
});
279+
280+
let value = self.ast.expression_identifier(SPAN, value_atom);
281+
*expr = value;
282+
self.mark_as_changed();
283+
break;
284+
}
285+
}
286+
}
287+
Expression::MetaProperty(meta_property) => {
288+
// Check if this is import.meta and if it should be replaced
289+
if meta_property.meta.name == "import" && meta_property.property.name == "meta" {
290+
for DotDefineState { dot_define, value_atom } in &mut self.dot_defines {
291+
// Check if dot_define is exactly ["import", "meta"]
292+
if dot_define.parts.len() == 2
293+
&& dot_define.parts[0].as_str() == "import"
294+
&& dot_define.parts[1].as_str() == "meta"
295+
{
296+
// If this is first replacement made for this dot define,
297+
// create `Atom` for replacement, and record in `replaced_dot_defines`
298+
let value_atom = *value_atom.get_or_insert_with(|| {
299+
self.replaced_dot_defines
300+
.push((dot_define.parts[0].clone(), dot_define.value.clone()));
301+
self.ast.atom(dot_define.value.as_str())
302+
});
303+
304+
let value = self.ast.expression_identifier(SPAN, value_atom);
305+
*expr = value;
306+
self.mark_as_changed();
307+
break;
308+
}
309+
}
283310
}
284311
}
312+
_ => {}
285313
}
286314
}
287315
}

crates/oxc_transformer_plugins/src/replace_global_defines.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,25 @@ impl<'a> ReplaceGlobalDefines<'a> {
616616
cur_part_name = &THIS_ATOM;
617617
None
618618
}
619+
Expression::MetaProperty(meta) => {
620+
// Handle import.meta
621+
// When we encounter a MetaProperty, we need to verify that the remaining
622+
// parts match ["import", "meta"]
623+
if meta.meta.name == "import" && meta.property.name == "meta" {
624+
// At this point, i is the current position we're checking
625+
// We need the next two parts (going backwards) to be "meta" then "import"
626+
// i.e., parts[i-1] == "meta" and parts[i-2] == "import"
627+
if i >= 2
628+
&& dot_define.parts[i - 1].as_str() == "meta"
629+
&& dot_define.parts[i - 2].as_str() == "import"
630+
{
631+
// Successfully matched import.meta at the expected position
632+
// Return true if we've consumed all parts (i == 2)
633+
return i == 2;
634+
}
635+
}
636+
None
637+
}
619638
_ => None,
620639
}
621640
} else {

crates/oxc_transformer_plugins/tests/integrations/inject_global_variables.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,76 @@ fn escape_source_with_newline() {
424424
config,
425425
);
426426
}
427+
428+
#[test]
429+
fn import_meta() {
430+
// handles import.meta
431+
let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier(
432+
"foo",
433+
None,
434+
"import.meta",
435+
)]);
436+
test(
437+
"console.log(import.meta)",
438+
"
439+
import { default as $inject_import_meta } from 'foo';
440+
console.log($inject_import_meta);
441+
",
442+
config,
443+
);
444+
}
445+
446+
#[test]
447+
fn import_meta_property() {
448+
// handles import.meta.foo
449+
let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier(
450+
"bar",
451+
None,
452+
"import.meta.foo",
453+
)]);
454+
test(
455+
"console.log(import.meta.foo)",
456+
"
457+
import { default as $inject_import_meta_foo } from 'bar';
458+
console.log($inject_import_meta_foo);
459+
",
460+
config,
461+
);
462+
}
463+
464+
#[test]
465+
fn import_meta_nested_property() {
466+
// handles import.meta.env.MODE
467+
let config = InjectGlobalVariablesConfig::new(vec![InjectImport::named_specifier(
468+
"baz",
469+
None,
470+
"import.meta.env.MODE",
471+
)]);
472+
test(
473+
"console.log(import.meta.env.MODE)",
474+
"
475+
import { default as $inject_import_meta_env_MODE } from 'baz';
476+
console.log($inject_import_meta_env_MODE);
477+
",
478+
config,
479+
);
480+
}
481+
482+
#[test]
483+
fn import_meta_combined() {
484+
// handles both import.meta and import.meta.foo together
485+
let config = InjectGlobalVariablesConfig::new(vec![
486+
InjectImport::named_specifier("foo", None, "import.meta"),
487+
InjectImport::named_specifier("bar", None, "import.meta.foo"),
488+
]);
489+
test(
490+
"console.log(import.meta); console.log(import.meta.foo)",
491+
"
492+
import { default as $inject_import_meta } from 'foo';
493+
import { default as $inject_import_meta_foo } from 'bar';
494+
console.log($inject_import_meta);
495+
console.log($inject_import_meta_foo);
496+
",
497+
config,
498+
);
499+
}

0 commit comments

Comments
 (0)