Skip to content

Commit c12e9a0

Browse files
authored
fix: inner graph class static block usage (#12114)
1 parent a2ba295 commit c12e9a0

File tree

10 files changed

+107
-14
lines changed

10 files changed

+107
-14
lines changed

crates/rspack_plugin_javascript/src/parser_plugin/common_js_exports_parse_plugin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
402402
&self,
403403
parser: &mut JavascriptParser,
404404
expr: &swc_core::ecma::ast::ThisExpr,
405+
_for_name: &str,
405406
) -> Option<bool> {
406407
if self.should_skip_handler(parser) {
407408
return None;

crates/rspack_plugin_javascript/src/parser_plugin/drive.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,10 @@ impl JavascriptParserPlugin for JavaScriptParserPluginDrive {
454454
&self,
455455
parser: &mut JavascriptParser,
456456
expr: &swc_core::ecma::ast::ThisExpr,
457+
for_name: &str,
457458
) -> Option<bool> {
458459
for plugin in &self.plugins {
459-
let res = plugin.this(parser, expr);
460+
let res = plugin.this(parser, expr, for_name);
460461
// `SyncBailHook`
461462
if res.is_some() {
462463
return res;

crates/rspack_plugin_javascript/src/parser_plugin/esm_top_level_this_plugin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ impl JavascriptParserPlugin for ESMTopLevelThisParserPlugin {
1010
&self,
1111
parser: &mut JavascriptParser,
1212
expr: &swc_core::ecma::ast::ThisExpr,
13+
_for_name: &str,
1314
) -> Option<bool> {
1415
(parser.is_esm && parser.is_top_level_this()).then(|| {
1516
parser.add_presentational_dependency(Box::new(ConstDependency::new(

crates/rspack_plugin_javascript/src/parser_plugin/inner_graph/plugin.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use crate::{
2020
is_pure_class, is_pure_class_member, is_pure_expression, is_pure_function,
2121
},
2222
visitors::{
23-
JavascriptParser, Statement, TagInfoData, VariableDeclaration, scope_info::VariableInfoFlags,
23+
ExportedVariableInfo, JavascriptParser, Statement, TagInfoData, VariableDeclaration,
24+
scope_info::VariableInfoFlags,
2425
},
2526
};
2627

@@ -639,19 +640,42 @@ impl JavascriptParserPlugin for InnerGraphPlugin {
639640
fn class_body_element(
640641
&self,
641642
parser: &mut JavascriptParser,
642-
_element: &swc_core::ecma::ast::ClassMember,
643+
element: &ClassMember,
643644
class_decl_or_expr: crate::visitors::ClassDeclOrExpr,
644645
) -> Option<bool> {
645646
if !parser.inner_graph.is_enabled() || !parser.is_top_level_scope() {
646647
return None;
647648
}
648-
649-
if parser
649+
if let Some(top_level_symbol) = parser
650650
.inner_graph
651651
.class_with_top_level_symbol
652-
.contains_key(&class_decl_or_expr.span())
652+
.get(&class_decl_or_expr.span())
653653
{
654+
let top_level_symbol_variable_name = top_level_symbol.name.clone();
654655
parser.inner_graph.set_top_level_symbol(None);
656+
/*
657+
* ```js
658+
* var A = class B {
659+
* static {
660+
* this;
661+
* B;
662+
* }
663+
* }
664+
* ```
665+
* Alias `this` and `B` (class ident) to top level symbol `A` here, so `A` is used if `this` or `B`
666+
* is used in static block (`add_usage` in identifier hook and this hook), even `A` is not used in
667+
* any other place.
668+
*/
669+
if let ClassMember::StaticBlock(_) = element {
670+
let class_var = parser
671+
.get_variable_info(&top_level_symbol_variable_name)
672+
.map(|info| ExportedVariableInfo::VariableInfo(info.id()))
673+
.unwrap_or(ExportedVariableInfo::Name(top_level_symbol_variable_name));
674+
if let Some(class_ident) = class_decl_or_expr.ident() {
675+
parser.set_variable(class_ident.sym.clone(), class_var.clone());
676+
}
677+
parser.set_variable("this".into(), class_var);
678+
}
655679
}
656680

657681
None
@@ -804,4 +828,14 @@ impl JavascriptParserPlugin for InnerGraphPlugin {
804828
Self::for_each_expression(parser, for_name);
805829
None
806830
}
831+
832+
fn this(
833+
&self,
834+
parser: &mut JavascriptParser,
835+
_expr: &swc_core::ecma::ast::ThisExpr,
836+
for_name: &str,
837+
) -> Option<bool> {
838+
Self::for_each_expression(parser, for_name);
839+
None
840+
}
807841
}

crates/rspack_plugin_javascript/src/parser_plugin/side_effects_parser_plugin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,8 @@ pub fn is_pure_class(
454454
}
455455
ClassMember::TsIndexSignature(_) => unreachable!(),
456456
ClassMember::Empty(_) => true,
457-
ClassMember::StaticBlock(_) => true,
458-
ClassMember::AutoAccessor(_) => true,
457+
ClassMember::StaticBlock(_) => false, // TODO: support is pure analyze for statements
458+
ClassMember::AutoAccessor(_) => false,
459459
}
460460
})
461461
}

crates/rspack_plugin_javascript/src/parser_plugin/trait.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,12 @@ pub trait JavascriptParserPlugin {
302302
None
303303
}
304304

305-
fn this(&self, _parser: &mut JavascriptParser, _expr: &ThisExpr) -> Option<bool> {
305+
fn this(
306+
&self,
307+
_parser: &mut JavascriptParser,
308+
_expr: &ThisExpr,
309+
_for_name: &str,
310+
) -> Option<bool> {
306311
None
307312
}
308313

crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,9 @@ impl JavascriptParser<'_> {
488488
}
489489

490490
fn walk_this_expression(&mut self, expr: &ThisExpr) {
491-
// TODO: `this.hooks.call_hooks_for_names`
492-
self.plugin_drive.clone().this(self, expr);
491+
"this".call_hooks_name(self, |this, for_name| {
492+
this.plugin_drive.clone().this(this, expr, for_name)
493+
});
493494
}
494495

495496
pub(crate) fn walk_template_expression(&mut self, expr: &Tpl) {
@@ -1533,9 +1534,12 @@ impl JavascriptParser<'_> {
15331534
self.walk_expression(super_class);
15341535
}
15351536

1536-
let scope_params = if let Some(pat) = class_decl_or_expr
1537-
.ident()
1538-
.map(|ident| warp_ident_to_pat(ident.clone()))
1537+
// TODO: define variable for class expression in block pre walk
1538+
let scope_params = if let ClassDeclOrExpr::Expr(class_expr) = class_decl_or_expr
1539+
&& let Some(pat) = class_expr
1540+
.ident
1541+
.as_ref()
1542+
.map(|ident| warp_ident_to_pat(ident.clone()))
15391543
{
15401544
vec![Cow::Owned(pat)]
15411545
} else {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { a, b, c, d } from "./module"
2+
3+
let _A;
4+
class A {
5+
static {
6+
_A = A;
7+
}
8+
prop = a();
9+
}
10+
11+
let _B;
12+
class B {
13+
static {
14+
_B = this;
15+
}
16+
prop = b();
17+
}
18+
19+
let _C;
20+
let __C = class C {
21+
static {
22+
_C = this;
23+
}
24+
prop = c();
25+
}
26+
27+
let _D;
28+
let __D = class D {
29+
static {
30+
_D = D;
31+
}
32+
prop = d();
33+
}
34+
35+
export { _A, _B, _C, _D };
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { _A, _B, _C, _D } from "./class";
2+
3+
it("should handle class static block correctly", () => {
4+
expect((new _A()).prop).toBe("a");
5+
expect((new _B()).prop).toBe("b");
6+
expect((new _C()).prop).toBe("c");
7+
expect((new _D()).prop).toBe("d");
8+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const a = () => "a";
2+
export const b = () => "b";
3+
export const c = () => "c";
4+
export const d = () => "d";

0 commit comments

Comments
 (0)