Skip to content

Commit b138019

Browse files
authored
Support transforming getInitialProps (#20)
* Add test cases * Add a tool function for getInitialProps * Add ident keywords for getInitialProps * Add wrapper util for getInitialProps * Add flags whether using getInitialProps * Add import statement by flag * Add class visitor * Modify test cases * Add visiting flag * Skip transforming props by flag * Reverse order * Visit children in class member visitor * Add visitors * Visit children while finding ssg prop * Format codes * Add app.js test case * Ignore app.js * Revert "Ignore app.js" This reverts commit a9ee545. * Ignore prop transforming by finding page first * Add test case * Keep page and push later * Fix export as
1 parent 0745893 commit b138019

File tree

11 files changed

+402
-54
lines changed

11 files changed

+402
-54
lines changed

src/lib.rs

Lines changed: 186 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ use utils::*;
1717
mod utils;
1818

1919
static SSG_EXPORTS: &[&str; 2] = &["getStaticProps", "getServerSideProps"];
20+
static INITIAL_PROPS: &str = "getInitialProps";
2021

2122
// import { withSuperJSONProps as _withSuperJSONProps } from "next-superjson-plugin/tools";
2223
static SUPERJSON_PROPS_IMPORTED: &str = "withSuperJSONProps";
2324
static SUPERJSON_PROPS_LOCAL: &str = "_withSuperJSONProps";
2425

26+
// import { withSuperJSONInitProps as _withSuperJSONInitProps } from "next-superjson-plugin/tools";
27+
static SUPERJSON_INIT_PROPS_IMPORTED: &str = "withSuperJSONInitProps";
28+
static SUPERJSON_INIT_PROPS_LOCAL: &str = "_withSuperJSONInitProps";
29+
2530
// import { withSuperJSONPage as _withSuperJSONPage } from "next-superjson-plugin/tools";
2631
static SUPERJSON_PAGE_IMPORTED: &str = "withSuperJSONPage";
2732
static SUPERJSON_PAGE_LOCAL: &str = "_withSuperJSONPage";
@@ -55,6 +60,9 @@ struct NextSuperJsonTransformer {
5560

5661
props: TransformTarget,
5762
page: TransformTarget,
63+
64+
has_init_props: bool,
65+
use_init_props: bool,
5866
}
5967

6068
#[derive(Debug, Default, Clone, Deserialize)]
@@ -74,27 +82,36 @@ pub fn transform(config: Config) -> impl VisitMut {
7482

7583
props: Default::default(),
7684
page: Default::default(),
85+
86+
has_init_props: false,
87+
use_init_props: false,
7788
}
7889
}
7990

8091
impl Fold for NextSuperJsonTransformer {}
8192

8293
impl VisitMut for NextSuperJsonTransformer {
8394
fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
84-
self.find_ssg_prop(items);
95+
self.find_page(items);
8596

86-
if self.props.export.orig.is_none() {
97+
if self.page.export.orig.is_none() {
8798
return;
8899
}
89100

90-
self.find_page(items);
101+
self.find_ssg_prop(items);
91102

92-
if self.page.export.orig.is_none() {
93-
return;
103+
if self.props.export.orig.is_none() {
104+
if !self.use_init_props {
105+
return;
106+
}
107+
108+
self.props.skip = true;
94109
}
95110

96111
let mut new_items = vec![];
97112

113+
let mut temp_page = None;
114+
98115
for (pos, item) in items.iter_mut().enumerate() {
99116
if self.props.ident.orig.is_some()
100117
&& pos == self.props.ident.orig.unwrap()
@@ -194,7 +211,7 @@ impl VisitMut for NextSuperJsonTransformer {
194211
_ => {}
195212
}
196213
} else {
197-
if pos == self.props.export.orig.unwrap() && !self.props.skip {
214+
if !self.props.skip && pos == self.props.export.orig.unwrap() {
198215
match item {
199216
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
200217
decl: export_decl,
@@ -303,16 +320,20 @@ impl VisitMut for NextSuperJsonTransformer {
303320
}
304321
}
305322

323+
let mut keep_page = false;
324+
306325
if pos == self.page.export.orig.unwrap() && !self.page.skip {
307326
match item {
308327
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(
309328
ExportDefaultExpr { expr, .. },
310329
)) => {
330+
keep_page = self.use_init_props;
311331
*expr = expr.take().wrap_page();
312332
}
313333
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(
314334
ExportDefaultDecl { decl, .. },
315335
)) => {
336+
keep_page = self.use_init_props;
316337
// TODO: remove duplicate code
317338
match decl {
318339
DefaultDecl::Class(class_expr) => {
@@ -390,7 +411,7 @@ impl VisitMut for NextSuperJsonTransformer {
390411
src,
391412
));
392413

393-
new_items.push(ModuleItem::ModuleDecl(
414+
let new_page = ModuleItem::ModuleDecl(
394415
ModuleDecl::ExportDefaultExpr(ExportDefaultExpr {
395416
expr: Box::new(Expr::Ident(Ident::new(
396417
NEXT_PAGE_LOCAL.into(),
@@ -399,19 +420,29 @@ impl VisitMut for NextSuperJsonTransformer {
399420
.wrap_page(),
400421
span: DUMMY_SP,
401422
}),
402-
));
423+
);
424+
if !self.use_init_props {
425+
new_items.push(new_page);
426+
} else {
427+
temp_page = Some(new_page);
428+
}
403429

404430
// export { Page as default }
405431
// =>
406432
// export default wrap(Page, excluded)
407433
} else {
408434
if let ModuleExportName::Ident(id) = &s.orig {
409-
new_items.push(ModuleItem::ModuleDecl(
435+
let new_page = ModuleItem::ModuleDecl(
410436
ModuleDecl::ExportDefaultExpr(ExportDefaultExpr {
411437
expr: Box::new(Expr::Ident(id.clone())).wrap_page(),
412438
span: DUMMY_SP,
413439
}),
414-
))
440+
);
441+
if !self.use_init_props {
442+
new_items.push(new_page);
443+
} else {
444+
temp_page = Some(new_page);
445+
}
415446
}
416447
}
417448

@@ -427,23 +458,41 @@ impl VisitMut for NextSuperJsonTransformer {
427458
..
428459
})) => {
429460
if !specifiers.is_empty() {
430-
new_items.push(item.take());
461+
if !keep_page {
462+
new_items.push(item.take());
463+
} else {
464+
temp_page = Some(item.take());
465+
}
431466
}
432467
}
433468
_ => {
434-
new_items.push(item.take());
469+
if !keep_page {
470+
new_items.push(item.take());
471+
} else {
472+
temp_page = Some(item.take());
473+
}
435474
}
436475
}
437476
}
438477
}
439478

479+
if let Some(tmp) = temp_page {
480+
new_items.push(tmp);
481+
}
482+
440483
// TODO: these two stmts can be combined
441484
if !self.props.skip {
442485
prepend_stmt(
443486
&mut new_items,
444487
superjson_import_decl(SUPERJSON_PROPS_IMPORTED),
445488
);
446489
}
490+
if self.use_init_props {
491+
prepend_stmt(
492+
&mut new_items,
493+
superjson_import_decl(SUPERJSON_INIT_PROPS_IMPORTED),
494+
);
495+
}
447496
if !self.page.skip {
448497
prepend_stmt(
449498
&mut new_items,
@@ -453,6 +502,81 @@ impl VisitMut for NextSuperJsonTransformer {
453502

454503
*items = new_items;
455504
}
505+
506+
fn visit_mut_class_member(&mut self, member: &mut ClassMember) {
507+
member.visit_mut_children_with(self);
508+
match member {
509+
ClassMember::ClassProp(p) => {
510+
if let PropName::Ident(id) = &p.key {
511+
if &*id.sym == INITIAL_PROPS {
512+
if let Some(expr) = &mut p.value {
513+
self.use_init_props = true;
514+
p.value = Some(expr.take().wrap_init_props(self.excluded_expr()));
515+
}
516+
}
517+
}
518+
}
519+
ClassMember::Method(m) => {
520+
if let PropName::Ident(id) = &m.key {
521+
if &*id.sym == INITIAL_PROPS {
522+
self.use_init_props = true;
523+
*member = ClassMember::ClassProp(ClassProp {
524+
accessibility: m.accessibility.take(),
525+
declare: false,
526+
decorators: vec![],
527+
definite: false,
528+
is_abstract: m.is_abstract,
529+
is_optional: m.is_optional,
530+
is_override: m.is_override,
531+
is_static: m.is_static,
532+
key: m.key.take(),
533+
readonly: false,
534+
span: DUMMY_SP,
535+
type_ann: None,
536+
value: Some(
537+
Box::new(Expr::Fn(FnExpr {
538+
function: m.function.take(),
539+
ident: None,
540+
}))
541+
.wrap_init_props(self.excluded_expr()),
542+
),
543+
});
544+
}
545+
}
546+
}
547+
_ => {}
548+
}
549+
}
550+
551+
fn visit_mut_assign_expr(&mut self, a: &mut AssignExpr) {
552+
a.visit_mut_children_with(self);
553+
554+
if a.left.is_expr() {
555+
if let Some(mut expr) = a.left.take().expr() {
556+
if let Some(MemberExpr { prop, .. }) = expr.as_mut_member() {
557+
prop.visit_mut_children_with(self);
558+
}
559+
560+
if self.has_init_props {
561+
a.right = a.right.take().wrap_init_props(self.excluded_expr());
562+
self.use_init_props = true;
563+
self.has_init_props = false;
564+
}
565+
566+
a.left = PatOrExpr::Expr(expr);
567+
}
568+
}
569+
}
570+
571+
fn visit_mut_member_prop(&mut self, p: &mut MemberProp) {
572+
p.visit_mut_children_with(self);
573+
574+
if let Some(id) = p.as_ident() {
575+
if &*id.sym == INITIAL_PROPS {
576+
self.has_init_props = true;
577+
}
578+
}
579+
}
456580
}
457581

458582
impl NextSuperJsonTransformer {
@@ -482,52 +606,61 @@ impl NextSuperJsonTransformer {
482606
pub fn find_ssg_prop(&mut self, items: &mut Vec<ModuleItem>) {
483607
let mut ssg_prop_ident = None;
484608

485-
self.props.export.orig = items.iter().position(|item| match item {
486-
// check has ssg props
487-
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { decl, .. })) => match decl {
488-
Decl::Fn(fn_decl) => SSG_EXPORTS.contains(&&*fn_decl.ident.sym),
489-
Decl::Var(var_decl) => {
490-
self.props.export.decl = var_decl.decls.iter().position(|decl| {
491-
SSG_EXPORTS.contains(&&*decl.name.as_ident().unwrap().sym)
492-
});
609+
self.props.export.orig = items.iter_mut().position(|item| {
610+
// check initial props
611+
item.visit_mut_children_with(self);
493612

494-
self.props.export.decl.is_some()
495-
}
496-
_ => false,
497-
},
498-
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
499-
specifiers,
500-
src,
501-
..
502-
})) => {
503-
self.props.export.spec = specifiers.iter().position(|specifier| match specifier {
504-
ExportSpecifier::Named(ExportNamedSpecifier {
505-
orig: ModuleExportName::Ident(orig_id),
506-
exported,
507-
..
508-
}) => {
509-
let exported_as = match exported {
510-
Some(ModuleExportName::Ident(exported_id)) => &exported_id.sym,
511-
_ => &orig_id.sym,
512-
};
513-
514-
if SSG_EXPORTS.contains(&&**exported_as) {
515-
self.props.skip = src.is_some()
516-
&& (exported.is_none() || (&&**exported_as == &&*orig_id.sym));
517-
518-
if !self.props.skip {
519-
ssg_prop_ident = Some((*orig_id.sym).to_string());
520-
}
521-
return true;
613+
match item {
614+
// check has ssg props
615+
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { decl, .. })) => {
616+
match decl {
617+
Decl::Fn(fn_decl) => SSG_EXPORTS.contains(&&*fn_decl.ident.sym),
618+
Decl::Var(var_decl) => {
619+
self.props.export.decl = var_decl.decls.iter().position(|decl| {
620+
SSG_EXPORTS.contains(&&*decl.name.as_ident().unwrap().sym)
621+
});
622+
623+
self.props.export.decl.is_some()
522624
}
523-
false
625+
_ => false,
524626
}
525-
_ => false,
526-
});
627+
}
628+
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
629+
specifiers,
630+
src,
631+
..
632+
})) => {
633+
self.props.export.spec =
634+
specifiers.iter().position(|specifier| match specifier {
635+
ExportSpecifier::Named(ExportNamedSpecifier {
636+
orig: ModuleExportName::Ident(orig_id),
637+
exported,
638+
..
639+
}) => {
640+
let exported_as = match exported {
641+
Some(ModuleExportName::Ident(exported_id)) => &exported_id.sym,
642+
_ => &orig_id.sym,
643+
};
644+
645+
if SSG_EXPORTS.contains(&&**exported_as) {
646+
self.props.skip = src.is_some()
647+
&& (exported.is_none()
648+
|| (&&**exported_as == &&*orig_id.sym));
649+
650+
if !self.props.skip {
651+
ssg_prop_ident = Some((*orig_id.sym).to_string());
652+
}
653+
return true;
654+
}
655+
false
656+
}
657+
_ => false,
658+
});
527659

528-
self.props.export.spec.is_some()
660+
self.props.export.spec.is_some()
661+
}
662+
_ => false,
529663
}
530-
_ => false,
531664
});
532665

533666
if ssg_prop_ident.is_some() && !self.props.skip {

0 commit comments

Comments
 (0)