#![allow(clippy::missing_docs_in_private_items)]
mod enter_jsx_element;
mod exit_jsx_attribute;
mod exit_jsx_child;
mod exit_jsx_element;
mod exit_jsx_spread_attribute;
mod oxc_impl;
use std::cell::Cell;
use oxc::{
allocator::{Allocator, CloneIn, Vec},
ast::ast::{
Argument, ArrowFunctionExpression, CallExpression, Expression, ExpressionStatement,
FormalParameterKind, FormalParameters, FunctionBody, IdentifierName, IdentifierReference,
JSXIdentifier, JSXMemberExpressionObject, Statement, StaticMemberExpression,
},
diagnostics::OxcDiagnostic,
semantic::ReferenceId,
span::Span,
};
use oxc_traverse::TraverseCtx;
use crate::{constants::S, element::SurplusElement};
pub struct SurplusTraverser<'a> {
pub s_ref: ReferenceId,
pub performed_transformation: bool,
pub element_stack: Vec<'a, SurplusElement<'a>>,
pub allocator: &'a Allocator,
pub errors: std::vec::Vec<OxcDiagnostic>,
}
impl<'a> SurplusTraverser<'a> {
pub fn new_in(s_ref: ReferenceId, allocator: &'a Allocator) -> Self {
Self {
s_ref,
performed_transformation: false,
element_stack: Vec::new_in(allocator),
allocator,
errors: std::vec::Vec::new(),
}
}
#[expect(dead_code)]
pub fn s_computation<const N: usize>(
&self,
ctx: &mut TraverseCtx<'a>,
span: Span,
stmts: [Statement<'a>; N],
) -> Expression<'a> {
Expression::CallExpression(ctx.alloc(CallExpression {
span,
callee: Expression::Identifier(ctx.alloc(IdentifierReference {
span: Span::default(),
name: S,
reference_id: Cell::new(Some(self.s_ref)),
})),
type_arguments: None,
arguments: Vec::from_array_in(
[Argument::ArrowFunctionExpression(ctx.alloc(
ArrowFunctionExpression {
span,
expression: false,
r#async: false,
type_parameters: None,
params: ctx.alloc(FormalParameters {
span,
kind: FormalParameterKind::ArrowFormalParameters,
items: Vec::new_in(self.allocator),
rest: None,
}),
return_type: None,
body: ctx.alloc(FunctionBody {
span,
directives: Vec::new_in(self.allocator),
statements: Vec::from_array_in(stmts, self.allocator),
}),
scope_id: Cell::new(None),
pure: false,
},
))],
self.allocator,
),
optional: false,
pure: false,
}))
}
pub fn s_expression(
&self,
ctx: &mut TraverseCtx<'a>,
span: Span,
expr: Expression<'a>,
) -> Expression<'a> {
Expression::CallExpression(ctx.alloc(CallExpression {
span,
callee: Expression::Identifier(ctx.alloc(IdentifierReference {
span: Span::default(),
name: S,
reference_id: Cell::new(Some(self.s_ref)),
})),
type_arguments: None,
arguments: Vec::from_array_in(
[Argument::ArrowFunctionExpression(ctx.alloc(
ArrowFunctionExpression {
span,
expression: true,
r#async: false,
type_parameters: None,
params: ctx.alloc(FormalParameters {
span,
kind: FormalParameterKind::ArrowFormalParameters,
items: Vec::new_in(self.allocator),
rest: None,
}),
return_type: None,
body: ctx.alloc(FunctionBody {
span,
directives: Vec::new_in(self.allocator),
statements: Vec::from_array_in(
[Statement::ExpressionStatement(ctx.alloc(
ExpressionStatement {
span,
expression: expr,
},
))],
self.allocator,
),
}),
scope_id: Cell::new(None),
pure: false,
},
))],
self.allocator,
),
optional: false,
pure: false,
}))
}
pub fn member_to_expression(
&self,
ctx: &mut TraverseCtx<'a>,
object: &JSXMemberExpressionObject<'a>,
property: &JSXIdentifier<'a>,
) -> Expression<'a> {
match object {
JSXMemberExpressionObject::ThisExpression(expr) => {
Expression::ThisExpression(expr.clone_in(self.allocator))
}
JSXMemberExpressionObject::IdentifierReference(expr) => {
Expression::Identifier(expr.clone_in(self.allocator))
}
JSXMemberExpressionObject::MemberExpression(member) => {
let member_expr = self.member_to_expression(ctx, &member.object, &member.property);
Expression::StaticMemberExpression(ctx.alloc(StaticMemberExpression {
span: member.span,
object: member_expr,
property: IdentifierName {
span: property.span,
name: property.name,
},
optional: false,
}))
}
}
}
}