perf(transformer, minifier): use static_ident! macro to create static Idents (#23727)

Optimize the use of `Ident`s in transformer (and a couple in minifier).

2 separate optimizations:

### 1. Reduce allocations

There's no need to allocate strings into arena for static identifiers - can just refer to the `&'static str` without allocating it.

i.e. `ctx.ast.ident("require")` -> `static_ident!("require")`.

### 2. Hash idents at compile time not run time

Where an `Ident` is created directly from a static string, calculating the hash can be const-folded and performed at compile time. But for dynamic strings, the hash is calculated at runtime.

```rust
// Before - runtime hash calculation (performed in `identifier_name` via `Into<Ident>`)
let name = if needs_await { "a" } else { "u" };
let id = ctx.ast.identifier_name(SPAN, name);

// After - compile time hash calc (pass `identifier_name` a precalculated `Ident`)
let name = if needs_await { static_ident!("a") } else { static_ident!("u") };
let id = ctx.ast.identifier_name(SPAN, name);
```

Similarly, passing strings into a shared function and converting to `Ident` in the function will perform runtime hashing. Instead, make the function take an `Ident`, and create the `Ident`s in the callers with `static_ident!(...)` (compile time calc). `&str` and `Ident` are both 16 bytes, so it makes no difference to the cost of calling the function, only removes work within the function.

Alter `create_member_callee` (class properties transform) and `create_global_identifier` (decorators transform) to take an `Ident`, to avoid the runtime hash calculations.
This commit is contained in:
overlookmotel committed 2026-06-24 01:29:50 +00:00
1 parent e0c652bf89
commit e1886a0c76
21 files changed
+79 -58

No files matched your search

@@ -13,6 +13,7 @@ use oxc_ecmascript::{
use oxc_semantic::ReferenceFlags;
use oxc_span::GetSpan;
use oxc_span::SPAN;
use oxc_str::static_ident;
use oxc_syntax::precedence::GetPrecedence;
use oxc_syntax::{
identifier::is_identifier_name_patched,
@@ -1336,11 +1337,11 @@ impl<'a> PeepholeOptimizations {
.as_member_expression()
.is_some_and(|mem_expr| mem_expr.is_specific_member_access("window", "Object"))
{
let object = ctx.ast.ident("Object");
let object = static_ident!("Object");
let reference_id = ctx.create_unbound_reference(object, ReferenceFlags::Read);
let new_callee = ctx.ast.expression_identifier_with_reference_id(
call_expr.callee.span(),
"Object",
object,
reference_id,
);
ctx.replace_expression(&mut call_expr.callee, new_callee);
@@ -97,7 +97,7 @@ use oxc_ast_visit::{VisitMut, walk_mut::walk_expression};
use oxc_data_structures::stack::{NonEmptyStack, SparseStack};
use oxc_semantic::{ReferenceFlags, SymbolId};
use oxc_span::{GetSpan, SPAN};
use oxc_str::Ident;
use oxc_str::{Ident, static_ident};
use oxc_syntax::{
scope::{ScopeFlags, ScopeId},
symbol::SymbolFlags,
@@ -1111,14 +1111,14 @@ impl<'a> ArrowFunctionConverter<'a> {
Self::adjust_binding_scope(target_scope_id, &arguments_var, ctx);
let mut init =
ctx.create_unbound_ident_expr(SPAN, ctx.ast.ident("arguments"), ReferenceFlags::Read);
ctx.create_unbound_ident_expr(SPAN, static_ident!("arguments"), ReferenceFlags::Read);
// Top level may not have `arguments`, so we need to check it.
// `typeof arguments === "undefined" ? void 0 : arguments;`
if ctx.scoping().root_scope_id() == target_scope_id {
let argument = ctx.create_unbound_ident_expr(
SPAN,
ctx.ast.ident("arguments"),
static_ident!("arguments"),
ReferenceFlags::Read,
);
let typeof_arguments = ctx.ast.expression_unary(SPAN, UnaryOperator::Typeof, argument);
@@ -77,7 +77,7 @@ use oxc_ast::{
};
use oxc_semantic::{ReferenceFlags, SymbolFlags};
use oxc_span::SPAN;
use oxc_str::Str;
use oxc_str::{Str, static_ident};
use oxc_traverse::BoundIdentifier;
use crate::context::TraverseCtx;
@@ -334,9 +334,7 @@ impl<'a> HelperLoaderStore<'a> {
}
fn transform_for_external_helper(helper: Helper, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
static HELPER_VAR: &str = "babelHelpers";
let helper_var = ctx.ast.ident(HELPER_VAR);
let helper_var = static_ident!("babelHelpers");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), helper_var);
let object = ctx.create_ident_expr(SPAN, helper_var, symbol_id, ReferenceFlags::Read);
let property = ctx.ast.identifier_name(SPAN, helper.name());
+2 -1
View File
@@ -3,6 +3,7 @@
use arrow_function_converter::ArrowFunctionConverter;
use oxc_allocator::ArenaVec;
use oxc_ast::ast::*;
use oxc_str::static_ident;
use oxc_traverse::{Ancestor, Traverse};
use crate::{EnvOptions, context::TraverseCtx, state::TransformState};
@@ -42,7 +43,7 @@ impl<'a> Traverse<'a, TransformState<'a>> for Common<'a> {
.collect();
ctx.state.top_level_statements.insert_statements(stmts);
} else {
let require_symbol_id = ctx.scoping().get_root_binding(ctx.ast.ident("require"));
let require_symbol_id = ctx.scoping().get_root_binding(static_ident!("require"));
let stmts: Vec<_> = imports
.into_iter()
.map(|(source, names)| {
@@ -35,7 +35,7 @@ use indexmap::{IndexMap, map::Entry as IndexMapEntry};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::ReferenceFlags;
use oxc_span::SPAN;
use oxc_str::Str;
use oxc_str::{Str, static_ident};
use oxc_syntax::symbol::SymbolId;
use oxc_traverse::BoundIdentifier;
@@ -174,7 +174,7 @@ impl<'a> ModuleImportsStore<'a> {
) -> Statement<'a> {
let callee = ctx.create_ident_expr(
SPAN,
ctx.ast.ident("require"),
static_ident!("require"),
require_symbol_id,
ReferenceFlags::read(),
);
@@ -82,6 +82,7 @@ use oxc_ast::ast::*;
use oxc_data_structures::stack::SparseStack;
use oxc_semantic::{Reference, ReferenceFlags, SymbolId};
use oxc_span::{ContentEq, SPAN};
use oxc_str::{Ident, static_ident};
use oxc_traverse::{MaybeBoundIdentifier, Traverse};
use rustc_hash::FxHashMap;
@@ -708,53 +709,53 @@ impl<'a> LegacyDecoratorMetadata<'a> {
}
#[inline]
fn create_global_identifier(ident: &'static str, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
ctx.create_unbound_ident_expr(SPAN, ctx.ast.ident(ident), ReferenceFlags::Read)
fn create_global_identifier(ident: Ident<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
ctx.create_unbound_ident_expr(SPAN, ident, ReferenceFlags::Read)
}
#[inline]
fn global_object(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Object", ctx)
Self::create_global_identifier(static_ident!("Object"), ctx)
}
#[inline]
fn global_function(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Function", ctx)
Self::create_global_identifier(static_ident!("Function"), ctx)
}
#[inline]
fn global_array(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Array", ctx)
Self::create_global_identifier(static_ident!("Array"), ctx)
}
#[inline]
fn global_boolean(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Boolean", ctx)
Self::create_global_identifier(static_ident!("Boolean"), ctx)
}
#[inline]
fn global_string(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("String", ctx)
Self::create_global_identifier(static_ident!("String"), ctx)
}
#[inline]
fn global_number(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Number", ctx)
Self::create_global_identifier(static_ident!("Number"), ctx)
}
#[inline]
fn global_bigint(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("BigInt", ctx)
Self::create_global_identifier(static_ident!("BigInt"), ctx)
}
#[inline]
fn global_symbol(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Symbol", ctx)
Self::create_global_identifier(static_ident!("Symbol"), ctx)
}
#[inline]
fn global_promise(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
Self::create_global_identifier("Promise", ctx)
Self::create_global_identifier(static_ident!("Promise"), ctx)
}
// `_metadata(key, value)
@@ -54,6 +54,7 @@ use oxc_ast_visit::{Visit, VisitMut};
use oxc_data_structures::stack::NonEmptyStack;
use oxc_semantic::{ScopeFlags, ScopeId, SymbolFlags};
use oxc_span::SPAN;
use oxc_str::static_ident;
use oxc_syntax::operator::AssignmentOperator;
use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, ast_operations::get_var_name_from_node};
use rustc_hash::FxHashMap;
@@ -509,7 +510,7 @@ impl<'a> LegacyDecorator<'a> {
(params, stmt)
} else {
let value_binding = ctx.generate_binding(
Str::from("value").into(),
static_ident!("value"),
scope_id,
SymbolFlags::FunctionScopedVariable,
);
@@ -36,6 +36,7 @@ use oxc_allocator::{ArenaVec, CloneIn, TakeIn};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::ReferenceFlags;
use oxc_span::{SPAN, Span};
use oxc_str::static_ident;
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
use oxc_traverse::{BoundIdentifier, Traverse};
@@ -542,7 +543,7 @@ impl<'a> ExponentiationOperator<'a> {
right: Expression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let math = ctx.ast.ident("Math");
let math = static_ident!("Math");
let math_symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), math);
let object = ctx.create_ident_expr(SPAN, math, math_symbol_id, ReferenceFlags::Read);
let property = ctx.ast.identifier_name(SPAN, "pow");
@@ -58,7 +58,7 @@ use oxc_ast::{NONE, ast::*};
use oxc_ast_visit::Visit;
use oxc_semantic::{ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags};
use oxc_span::{GetSpan, SPAN};
use oxc_str::Ident;
use oxc_str::{Ident, static_ident};
use oxc_syntax::{
identifier::{is_identifier_name, is_identifier_part, is_identifier_start},
keyword::is_reserved_keyword,
@@ -278,7 +278,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
let this_argument = Argument::from(ctx.ast.expression_this(SPAN));
let arguments_argument = Argument::from(ctx.create_unbound_ident_expr(
SPAN,
ctx.ast.ident("arguments"),
static_ident!("arguments"),
ReferenceFlags::Read,
));
(callee, ctx.ast.vec_from_array([this_argument, arguments_argument]))
@@ -639,7 +639,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
}
if name.is_empty() {
return ctx.ast.ident("_");
return static_ident!("_");
}
if is_reserved_keyword(name.as_str()) {
@@ -687,7 +687,7 @@ impl<'a> AsyncGeneratorExecutor<'a> {
bound_ident: &BoundIdentifier<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Statement<'a> {
let arguments = ctx.ast.ident("arguments");
let arguments = static_ident!("arguments");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), arguments);
let arguments_ident =
Argument::from(ctx.create_ident_expr(SPAN, arguments, symbol_id, ReferenceFlags::Read));
@@ -4,6 +4,7 @@ use oxc_allocator::{ArenaVec, TakeIn};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::{ScopeFlags, ScopeId, SymbolFlags};
use oxc_span::{SPAN, Span};
use oxc_str::static_ident;
use oxc_traverse::{Ancestor, BoundIdentifier};
use crate::{
@@ -357,7 +358,7 @@ impl<'a> AsyncGeneratorFunctions<'a> {
let catch_scope_id = ctx.create_child_scope(parent_scope_id, ScopeFlags::CatchClause);
let block_scope_id = ctx.create_child_scope(catch_scope_id, ScopeFlags::empty());
let err_ident = ctx.generate_binding(
ctx.ast.ident("err"),
static_ident!("err"),
block_scope_id,
SymbolFlags::CatchVariable | SymbolFlags::FunctionScopedVariable,
);
@@ -4,7 +4,7 @@
use oxc_allocator::{Address, GetAddress, TakeIn, UnstableAddress};
use oxc_ast::{NONE, ast::*};
use oxc_span::SPAN;
use oxc_str::Ident;
use oxc_str::{Ident, static_ident};
use oxc_syntax::{
node::NodeId,
reference::ReferenceFlags,
@@ -884,7 +884,7 @@ fn create_new_weakmap<'a>(
symbol_id: &mut Option<Option<SymbolId>>,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let weak_map = ctx.ast.ident("WeakMap");
let weak_map = static_ident!("WeakMap");
let symbol_id = *symbol_id
.get_or_insert_with(|| ctx.scoping().find_binding(ctx.current_scope_id(), weak_map));
let ident = ctx.create_ident_expr(SPAN, weak_map, symbol_id, ReferenceFlags::Read);
@@ -893,7 +893,7 @@ fn create_new_weakmap<'a>(
/// Create `new WeakSet()` expression.
fn create_new_weakset<'a>(ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
let weak_set = ctx.ast.ident("WeakSet");
let weak_set = static_ident!("WeakSet");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), weak_set);
let ident = ctx.create_ident_expr(SPAN, weak_set, symbol_id, ReferenceFlags::Read);
ctx.ast.expression_new_with_pure(SPAN, ident, NONE, ctx.ast.vec(), true)
@@ -6,6 +6,7 @@ use std::mem;
use oxc_allocator::{ArenaBox, TakeIn};
use oxc_ast::{NONE, ast::*};
use oxc_span::SPAN;
use oxc_str::static_ident;
use oxc_syntax::{reference::ReferenceId, symbol::SymbolId};
use oxc_traverse::{Ancestor, BoundIdentifier, ast_operations::get_var_name_from_node};
@@ -1870,7 +1871,7 @@ impl<'a> ClassProperties<'a> {
} else {
prop_binding.create_read_expression(ctx)
};
let callee = create_member_callee(callee, "has", span, ctx);
let callee = create_member_callee(callee, static_ident!("has"), span, ctx);
let argument = self.create_check_in_rhs(right, ctx);
ctx.ast.expression_call(span, callee, NONE, ctx.ast.vec1(Argument::from(argument)), false)
}
@@ -2145,7 +2146,7 @@ impl<'a> ClassProperties<'a> {
let class_ident = class_binding.create_read_expression(ctx);
let object = self.create_assert_class_brand_without_value(class_ident, object, ctx);
let arguments = ctx.ast.vec_from_array([Argument::from(object), Argument::from(value)]);
let callee = create_member_callee(prop_ident, "call", span, ctx);
let callee = create_member_callee(prop_ident, static_ident!("call"), span, ctx);
// `_prop.call(_assertClassBrand(Class, object), value)`
ctx.ast.expression_call(span, callee, NONE, arguments, false)
} else {
@@ -3,6 +3,7 @@
use oxc_ast::{NONE, ast::*};
use oxc_span::{SPAN, Span};
use oxc_str::static_ident;
use oxc_syntax::reference::ReferenceFlags;
use crate::{
@@ -347,7 +348,7 @@ impl<'a> ClassProperties<'a> {
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
// `Object.defineProperty`
let object_name = ctx.ast.ident("Object");
let object_name = static_ident!("Object");
let object_symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), object_name);
let object =
ctx.create_ident_expr(SPAN, object_name, object_symbol_id, ReferenceFlags::Read);
@@ -42,6 +42,7 @@ use oxc_ast::{NONE, ast::*};
use oxc_ecmascript::BoundNames;
use oxc_semantic::{NodeId, ScopeFlags, ScopeId, SymbolFlags, SymbolId};
use oxc_span::{SPAN, Span};
use oxc_str::static_ident;
use oxc_traverse::{BoundIdentifier, Traverse};
use crate::{
@@ -392,7 +393,7 @@ impl<'a> Traverse<'a, TransformState<'a>> for ExplicitResourceManagement<'a> {
}
_ => (
ctx.generate_binding_in_current_scope(
ctx.ast.ident("_default"),
static_ident!("_default"),
SymbolFlags::FunctionScopedVariable,
),
SPAN,
@@ -686,7 +687,11 @@ impl<'a> ExplicitResourceManagement<'a> {
.create_read_expression(ctx),
ctx.ast.identifier_name(
SPAN,
if needs_await { "a" } else { "u" },
if needs_await {
static_ident!("a")
} else {
static_ident!("u")
},
),
false,
),
@@ -806,7 +811,14 @@ impl<'a> ExplicitResourceManagement<'a> {
Expression::from(ctx.ast.member_expression_static(
SPAN,
using_ctx.as_ref().unwrap().create_read_expression(ctx),
ctx.ast.identifier_name(SPAN, if is_await_using { "a" } else { "u" }),
ctx.ast.identifier_name(
SPAN,
if is_await_using {
static_ident!("a")
} else {
static_ident!("u")
},
),
false,
)),
NONE,
@@ -869,7 +881,7 @@ impl<'a> ExplicitResourceManagement<'a> {
// We can skip using `generate_uid` here as no code within the `catch` block which can use a
// binding called `_`. `using_ctx` is a UID with prefix `_usingCtx`.
let ident = ctx.generate_binding(
ctx.ast.ident("_"),
static_ident!("_"),
block_scope_id,
SymbolFlags::CatchVariable | SymbolFlags::FunctionScopedVariable,
);
@@ -47,7 +47,7 @@
use oxc_ast::ast::*;
use oxc_span::SPAN;
use oxc_str::Str;
use oxc_str::{Ident, Str, static_ident};
use oxc_traverse::{Ancestor, Traverse};
use crate::{context::TraverseCtx, state::TransformState};
@@ -154,7 +154,8 @@ impl<'a> ReactDisplayName {
/// Add key value `displayName: name` to the `React.createClass` object.
fn add_display_name(obj_expr: &mut ObjectExpression<'a>, name: Str<'a>, ctx: &TraverseCtx<'a>) {
const DISPLAY_NAME: &str = "displayName";
const DISPLAY_NAME: Ident<'static> = static_ident!("displayName");
// Not safe with existing display name.
let not_safe = obj_expr.properties.iter().any(|prop| {
matches!(prop, ObjectPropertyKind::ObjectProperty(p) if p.key.static_name().is_some_and(|name| name == DISPLAY_NAME))
+2 -1
View File
@@ -30,11 +30,12 @@
use oxc_ast::ast::*;
use oxc_span::SPAN;
use oxc_str::{Ident, static_ident};
use oxc_traverse::{Ancestor, Traverse};
use crate::{context::TraverseCtx, state::TransformState};
const SELF: &str = "__self";
const SELF: Ident<'static> = static_ident!("__self");
pub struct JsxSelf;
+2 -1
View File
@@ -50,6 +50,7 @@ use oxc_regular_expression::{
};
use oxc_semantic::ReferenceFlags;
use oxc_span::SPAN;
use oxc_str::static_ident;
use oxc_traverse::Traverse;
use crate::{context::TraverseCtx, state::TransformState};
@@ -158,7 +159,7 @@ impl<'a> RegExp {
}
let callee = {
let regexp = ctx.ast.ident("RegExp");
let regexp = static_ident!("RegExp");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), regexp);
ctx.create_ident_expr(SPAN, regexp, symbol_id, ReferenceFlags::read())
};
@@ -6,7 +6,7 @@ use oxc_ast_visit::{VisitMut, walk_mut};
use oxc_data_structures::stack::NonEmptyStack;
use oxc_semantic::{ScopeFlags, ScopeId};
use oxc_span::{SPAN, Span};
use oxc_str::Ident;
use oxc_str::{Ident, static_ident};
use oxc_syntax::{
constant_value::ConstantValue,
number::NumberBase,
@@ -481,7 +481,7 @@ impl<'a> TypeScriptEnum {
// Infinity
let expr = if value.is_infinite() {
let infinity = ctx.ast.ident("Infinity");
let infinity = static_ident!("Infinity");
let infinity_symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), infinity);
ctx.create_ident_expr(SPAN, infinity, infinity_symbol_id, ReferenceFlags::Read)
} else {
@@ -70,10 +70,10 @@ impl<'a> TypeScriptModule {
// module.exports
let module_exports = {
let reference_id = ctx
.create_reference_in_current_scope(ctx.ast.ident("module"), ReferenceFlags::Read);
let module = static_ident!("module");
let reference_id = ctx.create_reference_in_current_scope(module, ReferenceFlags::Read);
let reference =
ctx.ast.alloc_identifier_reference_with_reference_id(SPAN, "module", reference_id);
ctx.ast.alloc_identifier_reference_with_reference_id(SPAN, module, reference_id);
let object = Expression::Identifier(reference);
let property = ctx.ast.identifier_name(SPAN, "exports");
ctx.ast.member_expression_static(SPAN, object, property, false)
@@ -4,7 +4,7 @@ use oxc_allocator::{ArenaBox, ArenaVec};
use oxc_ast::{NONE, ast::*};
use oxc_semantic::{ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags};
use oxc_span::{GetSpan, SPAN};
use oxc_str::Ident;
use oxc_str::{Ident, static_ident};
use oxc_traverse::BoundIdentifier;
use crate::context::TraverseCtx;
@@ -12,11 +12,11 @@ use crate::context::TraverseCtx;
/// `object` -> `object.call`.
pub fn create_member_callee<'a>(
object: Expression<'a>,
property: &'static str,
property: Ident<'a>,
span: Span,
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
let property = ctx.ast.identifier_name(SPAN, Str::from(property));
let property = ctx.ast.identifier_name(SPAN, property);
Expression::from(ctx.ast.member_expression_static(span, object, property, false))
}
@@ -27,7 +27,7 @@ pub fn create_bind_call<'a>(
span: Span,
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
let callee = create_member_callee(callee, "bind", span, ctx);
let callee = create_member_callee(callee, static_ident!("bind"), span, ctx);
let arguments = ctx.ast.vec1(Argument::from(this));
ctx.ast.expression_call(span, callee, NONE, arguments, false)
}
@@ -39,7 +39,7 @@ pub fn create_call_call<'a>(
span: Span,
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
let callee = create_member_callee(callee, "call", span, ctx);
let callee = create_member_callee(callee, static_ident!("call"), span, ctx);
let arguments = ctx.ast.vec1(Argument::from(this));
ctx.ast.expression_call(span, callee, NONE, arguments, false)
}
@@ -725,8 +725,8 @@ impl<'a> ModuleRunnerTransform<'a> {
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let object =
ctx.create_unbound_ident_expr(SPAN, ctx.ast.ident("Object"), ReferenceFlags::Read);
let member = create_member_callee(object, "defineProperty", ctx);
ctx.create_unbound_ident_expr(SPAN, static_ident!("Object"), ReferenceFlags::Read);
let member = create_member_callee(object, static_ident!("defineProperty"), ctx);
ctx.ast.expression_call(SPAN, member, NONE, arguments, false)
}
@@ -852,10 +852,10 @@ fn create_compute_property_access<'a>(
/// `object` -> `object.call`.
pub fn create_member_callee<'a>(
object: Expression<'a>,
property: &'static str,
property: Ident<'a>,
ctx: &TraverseCtx<'a>,
) -> Expression<'a> {
let property = ctx.ast.identifier_name(SPAN, Str::from(property));
let property = ctx.ast.identifier_name(SPAN, property);
Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false))
}