Skip to content

Commit ec765fe

Browse files
committed
add support for decorators
1 parent d0baa48 commit ec765fe

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

turbopack/crates/turbopack-ecmascript/src/analyzer/side_effects.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,11 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10491049
return;
10501050
}
10511051

1052+
// Check decorators - they execute at definition time
1053+
for decorator in &class.decorators {
1054+
decorator.visit_with(self);
1055+
}
1056+
10521057
// Check the extends clause - this is evaluated at definition time
10531058
if let Some(super_class) = &class.super_class {
10541059
super_class.visit_with(self);
@@ -1073,6 +1078,10 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10731078
}
10741079
// Check static properties - they execute at definition time
10751080
ClassMember::ClassProp(class_prop) if class_prop.is_static => {
1081+
// Check decorators - they execute at definition time
1082+
for decorator in &class_prop.decorators {
1083+
decorator.visit_with(self);
1084+
}
10761085
// Check the property key (for computed properties)
10771086
class_prop.key.visit_with(self);
10781087
// Check the initializer - static property initializers execute at definition time
@@ -1082,6 +1091,10 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10821091
}
10831092
// Check computed property keys for all members
10841093
ClassMember::Method(method) => {
1094+
// Check decorators - they execute at definition time
1095+
for decorator in &method.function.decorators {
1096+
decorator.visit_with(self);
1097+
}
10851098
method.key.visit_with(self);
10861099
// Method bodies don't execute at definition time
10871100
}
@@ -1090,26 +1103,46 @@ impl<'a> Visit for SideEffectVisitor<'a> {
10901103
// Constructor body doesn't execute at definition time
10911104
}
10921105
ClassMember::PrivateMethod(private_method) => {
1106+
// Check decorators - they execute at definition time
1107+
for decorator in &private_method.function.decorators {
1108+
decorator.visit_with(self);
1109+
}
10931110
private_method.key.visit_with(self);
10941111
// Method bodies don't execute at definition time
10951112
}
10961113
ClassMember::ClassProp(class_prop) => {
1114+
// Check decorators - they execute at definition time
1115+
for decorator in &class_prop.decorators {
1116+
decorator.visit_with(self);
1117+
}
10971118
// For non-static properties, only check the key
10981119
class_prop.key.visit_with(self);
10991120
// Instance property initializers don't execute at definition time
11001121
}
11011122
ClassMember::PrivateProp(private_prop) => {
1123+
// Check decorators - they execute at definition time
1124+
for decorator in &private_prop.decorators {
1125+
decorator.visit_with(self);
1126+
}
11021127
private_prop.key.visit_with(self);
11031128
// Instance property initializers don't execute at definition time
11041129
}
11051130
ClassMember::AutoAccessor(auto_accessor) if auto_accessor.is_static => {
1131+
// Check decorators - they execute at definition time
1132+
for decorator in &auto_accessor.decorators {
1133+
decorator.visit_with(self);
1134+
}
11061135
// Static auto accessors execute at definition time
11071136
auto_accessor.key.visit_with(self);
11081137
if let Some(value) = &auto_accessor.value {
11091138
value.visit_with(self);
11101139
}
11111140
}
11121141
ClassMember::AutoAccessor(auto_accessor) => {
1142+
// Check decorators - they execute at definition time
1143+
for decorator in &auto_accessor.decorators {
1144+
decorator.visit_with(self);
1145+
}
11131146
// Non-static auto accessors only check the key
11141147
auto_accessor.key.visit_with(self);
11151148
}
@@ -1122,6 +1155,17 @@ impl<'a> Visit for SideEffectVisitor<'a> {
11221155
}
11231156
}
11241157

1158+
fn visit_decorator(&mut self, _decorator: &Decorator) {
1159+
if self.has_side_effects {
1160+
return;
1161+
}
1162+
1163+
// Decorators always have side effects because they are function calls
1164+
// that execute at class/member definition time, even if they're just
1165+
// identifier references (e.g., @decorator is equivalent to calling decorator())
1166+
self.mark_side_effect();
1167+
}
1168+
11251169
fn visit_pat(&mut self, pat: &Pat) {
11261170
if self.has_side_effects {
11271171
return;
@@ -1197,6 +1241,7 @@ mod tests {
11971241
&fm,
11981242
Syntax::Es(EsSyntax {
11991243
jsx: true,
1244+
decorators: true,
12001245
..Default::default()
12011246
}),
12021247
EsVersion::latest(),
@@ -2193,4 +2238,62 @@ mod tests {
21932238
test_destructure_default_pure_annotation,
21942239
"const { foo = /*#__PURE__*/ compute() } = obj;"
21952240
);
2241+
2242+
// ==================== Phase 14: Decorator Side Effects ====================
2243+
2244+
// Class decorator has side effects (executes at definition time)
2245+
side_effects!(
2246+
test_class_decorator,
2247+
r#"
2248+
@decorator
2249+
class Foo {}
2250+
"#
2251+
);
2252+
2253+
// Method decorator has side effects
2254+
side_effects!(
2255+
test_method_decorator,
2256+
r#"
2257+
class Foo {
2258+
@decorator
2259+
method() {}
2260+
}
2261+
"#
2262+
);
2263+
2264+
// Property decorator has side effects
2265+
side_effects!(
2266+
test_property_decorator,
2267+
r#"
2268+
class Foo {
2269+
@decorator
2270+
prop = 1;
2271+
}
2272+
"#
2273+
);
2274+
2275+
// Multiple decorators
2276+
side_effects!(
2277+
test_multiple_decorators,
2278+
r#"
2279+
@decorator1
2280+
@decorator2
2281+
class Foo {
2282+
@propDecorator
2283+
prop = 1;
2284+
2285+
@methodDecorator
2286+
method() {}
2287+
}
2288+
"#
2289+
);
2290+
2291+
// Decorator with arguments
2292+
side_effects!(
2293+
test_decorator_with_args,
2294+
r#"
2295+
@decorator(config())
2296+
class Foo {}
2297+
"#
2298+
);
21962299
}

0 commit comments

Comments
 (0)