use oxc_allocator::TakeIn;
use oxc_ast::ast::*;
use oxc_ast_visit::{VisitMut, walk_mut};
use oxc_semantic::ScopeFlags;
use oxc_span::SPAN;
use crate::{Helper, common::helper_loader::helper_call_expr, context::TraverseCtx};
use super::{
ClassProperties,
super_converter::{ClassPropertiesSuperConverter, ClassPropertiesSuperConverterMode},
};
impl<'a> ClassProperties<'a> {
pub(super) fn convert_private_method(
&mut self,
method: &mut MethodDefinition<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Statement<'a>> {
let MethodDefinition { key, value, span, kind, r#static, .. } = method;
let PropertyKey::PrivateIdentifier(ident) = &key else {
return None;
};
let mut function = value.take_in_box(ctx.ast);
let resolved_private_prop = if *kind == MethodDefinitionKind::Set {
self.classes_stack.find_writable_private_prop(ident)
} else {
self.classes_stack.find_readable_private_prop(ident)
};
let temp_binding = resolved_private_prop.unwrap().prop_binding;
function.span = *span;
function.id = Some(temp_binding.create_binding_identifier(ctx));
function.r#type = FunctionType::FunctionDeclaration;
let scope_id = function.scope_id();
let new_parent_id = ctx.current_scope_id();
ctx.scoping_mut().change_scope_parent_id(scope_id, Some(new_parent_id));
let is_strict_mode = ctx.current_scope_flags().is_strict_mode();
let flags = ctx.scoping_mut().scope_flags_mut(scope_id);
*flags -= ScopeFlags::GetAccessor | ScopeFlags::SetAccessor;
if !is_strict_mode {
*flags -= ScopeFlags::StrictMode;
}
PrivateMethodVisitor::new(*r#static, self, ctx)
.visit_function(&mut function, ScopeFlags::Function);
Some(Statement::FunctionDeclaration(function))
}
pub(super) fn create_class_private_method_init_spec(
&self,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let brand = self.classes_stack.last().bindings.brand.as_ref().unwrap();
let arguments = ctx.ast.vec_from_array([
Argument::from(ctx.ast.expression_this(SPAN)),
Argument::from(brand.create_read_expression(ctx)),
]);
helper_call_expr(Helper::ClassPrivateMethodInitSpec, arguments, ctx)
}
}
struct PrivateMethodVisitor<'a, 'v> {
super_converter: ClassPropertiesSuperConverter<'a, 'v>,
ctx: &'v mut TraverseCtx<'a>,
}
impl<'a, 'v> PrivateMethodVisitor<'a, 'v> {
fn new(
is_static: bool,
class_properties: &'v mut ClassProperties<'a>,
ctx: &'v mut TraverseCtx<'a>,
) -> Self {
let mode = if is_static {
ClassPropertiesSuperConverterMode::StaticPrivateMethod
} else {
ClassPropertiesSuperConverterMode::PrivateMethod
};
Self { super_converter: ClassPropertiesSuperConverter::new(mode, class_properties), ctx }
}
}
impl<'a> VisitMut<'a> for PrivateMethodVisitor<'a, '_> {
#[inline]
fn visit_expression(&mut self, expr: &mut Expression<'a>) {
match expr {
Expression::StaticMemberExpression(_) => {
self.super_converter.transform_static_member_expression(expr, self.ctx);
}
Expression::ComputedMemberExpression(_) => {
self.super_converter.transform_computed_member_expression(expr, self.ctx);
}
Expression::CallExpression(call_expr) => {
self.super_converter
.transform_call_expression_for_super_member_expr(call_expr, self.ctx);
}
Expression::AssignmentExpression(_) => {
self.super_converter
.transform_assignment_expression_for_super_assignment_target(expr, self.ctx);
}
Expression::UpdateExpression(_) => {
self.super_converter
.transform_update_expression_for_super_assignment_target(expr, self.ctx);
}
_ => {}
}
walk_mut::walk_expression(self, expr);
}
fn visit_identifier_reference(&mut self, ident: &mut IdentifierReference<'a>) {
self.super_converter.class_properties.replace_class_name_with_temp_var(ident, self.ctx);
}
#[inline]
fn visit_class(&mut self, _class: &mut Class<'a>) {
}
}