use super::expressions::{ChainState, ExprFlags, write_expression, write_expressions};
use super::statements::write_block_statement;
use super::{
Ctx, JsonWriter, close_node, node_header, write_function_flags_fields,
write_identifier_with_optional, write_or_null, write_return_type_field,
write_type_arguments_field, write_type_parameters_field,
};
use crate::ast;
use tsv_lang::Span;
pub(super) fn write_arrow_function_expression(
w: &mut JsonWriter,
arrow: &ast::ArrowFunctionExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
) {
node_header(w, "ArrowFunctionExpression", span, ctx);
let generic_async = arrow.r#async
&& arrow
.type_parameters
.as_ref()
.is_some_and(|tp| tp.span.start > span.start);
if generic_async {
write_type_parameters_field(w, arrow.type_parameters.as_ref(), ctx);
w.raw(",\"params\":");
write_expressions(w, arrow.params, ctx);
write_return_type_field(w, arrow.return_type.as_ref(), ctx);
w.raw_pick(
arrow.body.is_expression(),
b",\"id\":null,\"expression\":true,\"generator\":false,\"async\":true,\"body\":",
b",\"id\":null,\"expression\":false,\"generator\":false,\"async\":true,\"body\":",
);
write_arrow_body(w, &arrow.body, ctx);
} else {
write_return_type_field(w, arrow.return_type.as_ref(), ctx);
w.raw_pick(
arrow.body.is_expression(),
b",\"id\":null,\"expression\":true,\"generator\":false,\"async\":",
b",\"id\":null,\"expression\":false,\"generator\":false,\"async\":",
);
w.raw_pick(arrow.r#async, b"true,\"params\":", b"false,\"params\":");
write_expressions(w, arrow.params, ctx);
w.raw(",\"body\":");
write_arrow_body(w, &arrow.body, ctx);
write_type_parameters_field(w, arrow.type_parameters.as_ref(), ctx);
}
close_node(w, "ArrowFunctionExpression", span, ctx);
}
fn write_arrow_body(w: &mut JsonWriter, body: &ast::ArrowFunctionBody<'_>, ctx: &Ctx<'_>) {
match body {
ast::ArrowFunctionBody::Expression(expr) => write_expression(w, expr, ctx),
ast::ArrowFunctionBody::BlockStatement(block) => write_block_statement(w, block, ctx),
}
}
pub(super) fn write_function_expression(
w: &mut JsonWriter,
func: &ast::FunctionExpression<'_>,
ctx: &Ctx<'_>,
type_params_last: bool,
) {
node_header(w, "FunctionExpression", func.span, ctx);
w.raw(",\"id\":");
write_or_null(w, func.id.as_ref(), |w, id| {
write_identifier_with_optional(w, id, ctx);
});
write_function_flags_fields(w, func.generator, func.r#async);
if !type_params_last {
write_type_parameters_field(w, func.type_parameters.as_ref(), ctx);
}
w.raw(",\"params\":");
write_expressions(w, func.params, ctx);
write_return_type_field(w, func.return_type.as_ref(), ctx);
w.raw(",\"body\":");
write_block_statement(w, &func.body, ctx);
if type_params_last {
write_type_parameters_field(w, func.type_parameters.as_ref(), ctx);
}
close_node(w, "FunctionExpression", func.span, ctx);
}
pub(super) fn write_new_expression(
w: &mut JsonWriter,
new_expr: &ast::NewExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
) {
node_header(w, "NewExpression", span, ctx);
w.raw(",\"callee\":");
write_expression(w, new_expr.callee, ctx);
write_type_arguments_field(w, new_expr.type_arguments.as_ref(), ctx);
w.raw(",\"arguments\":");
write_expressions(w, new_expr.arguments.iter().copied(), ctx);
close_node(w, "NewExpression", span, ctx);
}
pub(super) fn call_callee_flags(
call: &ast::CallExpression<'_>,
callee_chain: ChainState,
strip_optional: bool,
) -> ExprFlags {
ExprFlags {
chain: callee_chain,
force_optional: call.optional && call.type_arguments.is_some(),
strip_optional,
}
}
pub(super) fn write_call_expression_tail(
w: &mut JsonWriter,
call: &ast::CallExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
callee_chain: ChainState,
force_optional: bool,
strip_optional: bool,
) {
w.raw(",\"arguments\":");
write_expressions(w, call.arguments.iter().copied(), ctx);
write_type_arguments_field(w, call.type_arguments.as_ref(), ctx);
if strip_optional {
} else if force_optional {
w.raw(",\"optional\":true");
} else {
if call.type_arguments.is_none()
|| call.optional
|| (callee_chain != ChainState::KnownFree
&& span.start >= call.callee.span().start
&& call.callee.has_optional_in_chain())
{
w.raw_pick(call.optional, b",\"optional\":true", b",\"optional\":false");
}
}
close_node(w, "CallExpression", span, ctx);
}
pub(super) fn write_member_expression_tail(
w: &mut JsonWriter,
member: &ast::MemberExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
force_optional: bool,
strip_optional: bool,
) {
w.raw(",\"property\":");
write_expression(w, member.property, ctx);
if strip_optional {
w.raw_pick(
member.computed,
b",\"computed\":true",
b",\"computed\":false",
);
} else if force_optional || member.optional {
w.raw_pick(
member.computed,
b",\"computed\":true,\"optional\":true",
b",\"computed\":false,\"optional\":true",
);
} else {
w.raw_pick(
member.computed,
b",\"computed\":true,\"optional\":false",
b",\"computed\":false,\"optional\":false",
);
}
close_node(w, "MemberExpression", span, ctx);
}
pub(super) fn write_conditional_expression(
w: &mut JsonWriter,
cond: &ast::ConditionalExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
) {
node_header(w, "ConditionalExpression", span, ctx);
w.raw(",\"test\":");
write_expression(w, cond.test, ctx);
w.raw(",\"consequent\":");
write_expression(w, cond.consequent, ctx);
w.raw(",\"alternate\":");
write_expression(w, cond.alternate, ctx);
close_node(w, "ConditionalExpression", span, ctx);
}
pub(super) fn write_await_expression(
w: &mut JsonWriter,
await_expr: &ast::AwaitExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
) {
node_header(w, "AwaitExpression", span, ctx);
w.raw(",\"argument\":");
write_expression(w, await_expr.argument, ctx);
close_node(w, "AwaitExpression", span, ctx);
}
pub(super) fn write_yield_expression(
w: &mut JsonWriter,
yield_expr: &ast::YieldExpression<'_>,
span: Span,
ctx: &Ctx<'_>,
) {
node_header(w, "YieldExpression", span, ctx);
w.raw(",\"delegate\":");
w.bool(yield_expr.delegate);
w.raw(",\"argument\":");
write_or_null(w, yield_expr.argument.as_ref(), |w, e| {
write_expression(w, e, ctx);
});
close_node(w, "YieldExpression", span, ctx);
}