Skip to content

Commit

Permalink
Fix shorthand prop wrongly handled in the Server Actions compiler (#5…
Browse files Browse the repository at this point in the history
…0937)

This PR fixes the case of having a shorthand prop `{ id }` referenced from a non-top level closure in the Server Actions compiler. The main problem is that an `Ident` in `PropOrSpread` is not considered as an `Expr`.

See corresponding issue report and test case for more details.
fix #50445
fix NEXT-1254
  • Loading branch information
shuding committed Jun 8, 2023
1 parent e562ddf commit 18d2f7d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
41 changes: 40 additions & 1 deletion packages/next-swc/crates/core/src/server_actions.rs
Expand Up @@ -357,7 +357,7 @@ impl<C: Comments> ServerActions<C> {
// export async function $ACTION_myAction () {}
let mut new_params: Vec<Param> = vec![];

// $$ACTION_ARG_{index}
// add params from closure collected ids
for i in 0..ids_from_closure.len() {
new_params.push(Param {
span: DUMMY_SP,
Expand Down Expand Up @@ -618,6 +618,20 @@ impl<C: Comments> VisitMut for ServerActions<C> {
}
}

fn visit_mut_prop_or_spread(&mut self, n: &mut PropOrSpread) {
if self.in_action_fn && self.in_action_closure {
if let PropOrSpread::Prop(box Prop::Shorthand(i)) = n {
self.in_action_closure = false;
self.action_closure_idents.push(Name::from(&*i));
n.visit_mut_children_with(self);
self.in_action_closure = true;
return;
}
}

n.visit_mut_children_with(self);
}

fn visit_mut_expr(&mut self, n: &mut Expr) {
if self.in_action_fn && self.in_action_closure {
if let Ok(name) = Name::try_from(&*n) {
Expand Down Expand Up @@ -1474,12 +1488,37 @@ impl VisitMut for ClosureReplacer<'_> {
));
}
}

fn visit_mut_prop_or_spread(&mut self, n: &mut PropOrSpread) {
n.visit_mut_children_with(self);

if let PropOrSpread::Prop(box Prop::Shorthand(i)) = n {
let name = Name::from(&*i);
if let Some(index) = self.used_ids.iter().position(|used_id| *used_id == name) {
*n = PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(i.clone()),
value: Box::new(Expr::Ident(Ident::new(
// $$ACTION_ARG_0
format!("$$ACTION_ARG_{}", index).into(),
DUMMY_SP,
))),
})));
}
}
}

noop_visit_mut_type!();
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Name(Id, Vec<(JsWord, bool)>);

impl From<&'_ Ident> for Name {
fn from(value: &Ident) -> Self {
Name(value.to_id(), vec![])
}
}

impl TryFrom<&'_ Expr> for Name {
type Error = ();

Expand Down
Expand Up @@ -2,13 +2,15 @@ import deleteFromDb from 'db'

const v1 = 'v1'

export function Item({ id1, id2 }) {
export function Item({ id1, id2, id3, id4 }) {
const v2 = id2
async function deleteItem() {
'use server'
await deleteFromDb(id1)
await deleteFromDb(v1)
await deleteFromDb(v2)
await deleteFromDb({ id3 })
await deleteFromDb(id4.x)
}
return <Button action={deleteItem}>Delete</Button>
}
@@ -1,19 +1,25 @@
/* __next_internal_action_entry_do_not_use__ $$ACTION_0 */ import __create_action_proxy__ from "private-next-rsc-action-proxy";
import deleteFromDb from 'db';
const v1 = 'v1';
export function Item({ id1 , id2 }) {
export function Item({ id1 , id2 , id3 , id4 }) {
const v2 = id2;
async function deleteItem(...args) {
return $$ACTION_0.apply(null, (deleteItem.$$bound || []).concat(args));
}
__create_action_proxy__("6d53ce510b2e36499b8f56038817b9bad86cabb4", [
id1,
v2
v2,
id3,
id4.x
], deleteItem, $$ACTION_0);
return <Button action={deleteItem}>Delete</Button>;
}
export async function $$ACTION_0($$ACTION_ARG_0, $$ACTION_ARG_1) {
export async function $$ACTION_0($$ACTION_ARG_0, $$ACTION_ARG_1, $$ACTION_ARG_2, $$ACTION_ARG_3) {
await deleteFromDb($$ACTION_ARG_0);
await deleteFromDb(v1);
await deleteFromDb($$ACTION_ARG_1);
await deleteFromDb({
id3: $$ACTION_ARG_2
});
await deleteFromDb($$ACTION_ARG_3);
}

0 comments on commit 18d2f7d

Please sign in to comment.