diff --git a/oxc-rsc/src/hoist.rs b/oxc-rsc/src/hoist.rs index 710f1958..20667f56 100644 --- a/oxc-rsc/src/hoist.rs +++ b/oxc-rsc/src/hoist.rs @@ -29,6 +29,68 @@ impl<'a> HoistTransformer<'a> { } impl<'a> Traverse<'a> for HoistTransformer<'a> { + // TODO: this misses + fn exit_statement( + &mut self, + stmt: &mut Statement<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) { + match stmt { + Statement::FunctionDeclaration(node) => { + if let (Some(body), Some(name)) = (&node.body, &node.id) { + // check "use server" + if body + .directives + .iter() + .any(|e| e.expression.value == self.directive) + { + let new_name = format!("$$hoist_{}", self.hoisted_functions.len()); + + // $$register(...) + let register_call = ctx.ast.call_expression( + SPAN, + ctx.ast.identifier_reference_expression( + ctx.ast.identifier_reference(SPAN, &self.runtime), + ), + ctx.ast.new_vec_from_iter([ + Argument::from(ctx.ast.identifier_reference_expression( + ctx.ast.identifier_reference(SPAN, &new_name.clone()), + )), + Argument::from(ctx.ast.literal_string_expression( + ctx.ast.string_literal(SPAN, &self.id), + )), + Argument::from(ctx.ast.literal_string_expression( + ctx.ast.string_literal(SPAN, &new_name), + )), + ]), + false, + None, + ); + + // const = $$register(...) + *stmt = Statement::VariableDeclaration(ctx.ast.variable_declaration( + SPAN, + oxc::ast::ast::VariableDeclarationKind::Const, + ctx.ast.new_vec_single(ctx.ast.variable_declarator( + SPAN, + oxc::ast::ast::VariableDeclarationKind::Const, + ctx.ast.binding_pattern( + ctx.ast.binding_pattern_identifier(name.clone()), + None, + false, + ), + Some(register_call), + true, + )), + Modifiers::empty(), + )); + } + } + } + _ => {} + } + } + fn exit_expression( &mut self, expr: &mut Expression<'a>, diff --git a/oxc-rsc/tests/hoist/top.js b/oxc-rsc/tests/hoist/top.js index 8644bf89..e271b785 100644 --- a/oxc-rsc/tests/hoist/top.js +++ b/oxc-rsc/tests/hoist/top.js @@ -1,26 +1,25 @@ const x = "x"; -export const f = async () => { +const f = async () => { "use server"; return x; }; -// export async function f() { -// "use server"; -// return x; -// } -export const g = async () => {}; -// export async function g() {} +async function f2() { + "use server"; + return x; +} -export const h = async (formData) => { +const g = async () => {}; + +async function g2() {} + +const h = async (formData) => { "use server"; return formData.get(x); }; -// export async function h(formData) { -// "use server"; -// return formData.get(x); -// } -// export default function w() { -// "use server"; -// } +async function h2(formData) { + "use server"; + return formData.get(x); +} diff --git a/oxc-rsc/tests/hoist/top.snap b/oxc-rsc/tests/hoist/top.snap index ca32268d..a65d6339 100644 --- a/oxc-rsc/tests/hoist/top.snap +++ b/oxc-rsc/tests/hoist/top.snap @@ -3,9 +3,12 @@ source: src/hoist.rs input_file: tests/hoist/top.js --- const x = 'x'; -export const f = $$register($$hoist_0, '', '$$hoist_0'); -export const g = async () => {}; -export const h = $$register($$hoist_1, '', '$$hoist_1'); +const f = $$register($$hoist_0, '', '$$hoist_0'); +const f2 = $$register($$hoist_1, '', '$$hoist_1'); +const g = async () => {}; +async function g2() {} +const h = $$register($$hoist_1, '', '$$hoist_1'); +const h2 = $$register($$hoist_2, '', '$$hoist_2'); export async function $$hoist_0() { return x; }