use oxc_ast::ast::*;
use oxc_traverse::TraverseCtx;
use super::{CoverageState, CoverageTransform};
impl<'arena> CoverageTransform<'_, 'arena> {
pub(super) fn resolve_function_name(
&mut self,
func: &Function,
ctx: &TraverseCtx<'arena, CoverageState>,
) -> String {
if let Some(name) = self.pending_name.take() {
return name;
}
if let Some(id) = &func.id {
return id.name.to_string();
}
if self.name_callback_arguments
&& let Some(name) = callback_argument_name(ctx)
{
return name;
}
format!("(anonymous_{})", self.fn_map.len())
}
}
pub(super) fn callback_argument_name(ctx: &TraverseCtx<'_, CoverageState>) -> Option<String> {
use oxc_traverse::Ancestor;
let mut ancestors = ctx.ancestors();
let callee = loop {
match ancestors.next()? {
Ancestor::ParenthesizedExpressionExpression(_) => {}
Ancestor::CallExpressionArguments(call) => break call.callee(),
Ancestor::NewExpressionArguments(new_expr) => break new_expr.callee(),
_ => return None,
}
};
callee_name(callee)
}
fn callee_name(callee: &Expression<'_>) -> Option<String> {
match callee {
Expression::Identifier(ident) => Some(ident.name.to_string()),
Expression::StaticMemberExpression(member) => Some(member.property.name.to_string()),
Expression::ComputedMemberExpression(member) => match &member.expression {
Expression::StringLiteral(lit) => Some(lit.value.to_string()),
_ => None,
},
Expression::ParenthesizedExpression(paren) => callee_name(&paren.expression),
_ => None,
}
}
pub(super) fn property_key_to_name(key: &PropertyKey<'_>) -> Option<String> {
match key {
PropertyKey::StaticIdentifier(id) => Some(id.name.to_string()),
PropertyKey::PrivateIdentifier(id) => Some(format!("#{}", id.name)),
PropertyKey::StringLiteral(s) => Some(s.value.to_string()),
PropertyKey::NumericLiteral(n) => {
Some(n.raw.map_or_else(|| n.value.to_string(), |raw| raw.to_string()))
}
PropertyKey::TemplateLiteral(t) if t.expressions.is_empty() => {
t.quasis.first().and_then(|quasi| quasi.value.cooked.as_ref()).map(ToString::to_string)
}
_ => None,
}
}
pub(super) fn declarator_function_name(decl: &VariableDeclarator<'_>) -> Option<String> {
let id = decl.id.get_binding_identifier()?;
let init = decl.init.as_ref()?;
if matches!(init, Expression::ArrowFunctionExpression(_) | Expression::FunctionExpression(_)) {
return Some(id.name.to_string());
}
None
}
pub(super) enum AssignmentTargetName {
Unchanged,
Update(Option<String>),
}
pub(super) fn assignment_target_name(expr: &AssignmentExpression<'_>) -> AssignmentTargetName {
use oxc_syntax::operator::AssignmentOperator;
if !matches!(expr.operator, AssignmentOperator::Assign)
|| !matches!(
expr.right,
Expression::FunctionExpression(_)
| Expression::ArrowFunctionExpression(_)
| Expression::ClassExpression(_)
)
{
return AssignmentTargetName::Unchanged;
}
AssignmentTargetName::Update(match &expr.left {
AssignmentTarget::StaticMemberExpression(member) => Some(member.property.name.to_string()),
AssignmentTarget::ComputedMemberExpression(member) => match &member.expression {
Expression::StringLiteral(lit) => Some(lit.value.to_string()),
_ => None,
},
_ => None,
})
}
pub(super) fn method_label(kind: MethodDefinitionKind, name: String) -> String {
match kind {
MethodDefinitionKind::Get => format!("get {name}"),
MethodDefinitionKind::Set => format!("set {name}"),
MethodDefinitionKind::Method | MethodDefinitionKind::Constructor => name,
}
}