Skip to content

Commit aa95558

Browse files
authored
Fix bugs (#1132)
swc_ecma_transforms: - Handle typescript class properties correctly. (#1122) - Handle optional chaining properly. (#1130) - Inject variables for nullisn coalescing in correct scope. (#1123)
1 parent 81490de commit aa95558

File tree

7 files changed

+240
-15
lines changed

7 files changed

+240
-15
lines changed

ecmascript/transforms/src/compat/es2020/class_properties.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ impl ClassProperties {
443443
MemberExpr {
444444
span: DUMMY_SP,
445445
obj: ident.clone().as_obj(),
446-
computed: false,
446+
computed: prop.computed,
447447
prop: key,
448448
}
449449
.into(),
@@ -460,7 +460,7 @@ impl ClassProperties {
460460
MemberExpr {
461461
span: DUMMY_SP,
462462
obj: ThisExpr { span: DUMMY_SP }.as_obj(),
463-
computed: false,
463+
computed: prop.computed,
464464
prop: key,
465465
}
466466
.into(),

ecmascript/transforms/src/compat/es2020/nullish_coalescing/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ impl NullishCoalescing {
5050
impl Fold for NullishCoalescing {
5151
noop_fold_type!();
5252

53+
/// Prevents #1123
54+
fn fold_block_stmt(&mut self, s: BlockStmt) -> BlockStmt {
55+
s.fold_children_with(&mut NullishCoalescing::default())
56+
}
57+
58+
/// Prevents #1123
59+
fn fold_switch_case(&mut self, s: SwitchCase) -> SwitchCase {
60+
s.fold_children_with(&mut NullishCoalescing::default())
61+
}
62+
5363
fn fold_module_items(&mut self, n: Vec<ModuleItem>) -> Vec<ModuleItem> {
5464
self.fold_stmt_like(n)
5565
}

ecmascript/transforms/src/compat/es2020/nullish_coalescing/tests.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::*;
2-
use swc_ecma_parser::{EsConfig, Syntax};
2+
use crate::typescript::strip;
3+
use swc_common::chain;
4+
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
35

46
fn tr(_: ()) -> impl Fold {
57
nullish_coalescing()
@@ -106,3 +108,54 @@ function foo() {
106108
107109
"#
108110
);
111+
112+
test!(
113+
Syntax::Typescript(TsConfig {
114+
..Default::default()
115+
}),
116+
|_| chain!(strip(), tr(())),
117+
issue_1123_1,
118+
r#"
119+
interface SuperSubmission {
120+
[key: string]: any;
121+
}
122+
123+
const normalizedQuestionSet: any = {};
124+
125+
const submissions: SuperSubmission[] = (
126+
normalizedQuestionSet.submissionIds ?? []
127+
).map(
128+
(id, index): SuperSubmission => {
129+
const submission = normalizedQuestionSet.submissions?.[id];
130+
131+
const submissionAnswers = (submission.answers ?? []).map(
132+
(answerId) => normalizedQuestionSet.answers?.[answerId]
133+
);
134+
135+
console.log(id, index);
136+
137+
return {
138+
type: "super-submission",
139+
};
140+
}
141+
);
142+
143+
console.log(submissions);
144+
"#,
145+
r#"
146+
const normalizedQuestionSet = {
147+
};
148+
var _submissionIds;
149+
const submissions = ((_submissionIds = normalizedQuestionSet.submissionIds) !== null && _submissionIds !== void 0 ? _submissionIds : []).map((id, index)=>{
150+
const submission = normalizedQuestionSet.submissions?.[id];
151+
var _answers;
152+
const submissionAnswers = ((_answers = submission.answers) !== null && _answers !== void 0 ? _answers : []).map((answerId)=>normalizedQuestionSet.answers?.[answerId]
153+
);
154+
console.log(id, index);
155+
return {
156+
type: "super-submission"
157+
};
158+
});
159+
console.log(submissions);
160+
"#
161+
);

ecmascript/transforms/src/compat/es2020/opt_chaining.rs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ impl Fold for OptChaining {
3030
Ok(v) => v,
3131
Err(v) => v,
3232
},
33-
Expr::Call(e) => validate!(self.handle_call(e)),
33+
Expr::Call(e) => match self.handle_call(e).map(Expr::Cond) {
34+
Ok(v) => v,
35+
Err(v) => v,
36+
},
3437
_ => e,
3538
};
3639

@@ -129,28 +132,28 @@ impl OptChaining {
129132
}
130133

131134
/// Only called from [Fold].
132-
fn handle_call(&mut self, e: CallExpr) -> Expr {
135+
fn handle_call(&mut self, e: CallExpr) -> Result<CondExpr, Expr> {
133136
match e.callee {
134137
ExprOrSuper::Expr(callee) if callee.is_opt_chain() => {
135138
let callee = callee.opt_chain().unwrap();
136139
let expr = self.unwrap(callee);
137140

138-
return CondExpr {
141+
return Ok(CondExpr {
139142
span: DUMMY_SP,
140143
alt: Box::new(Expr::Call(CallExpr {
141144
callee: ExprOrSuper::Expr(expr.alt),
142145
..e
143146
})),
144147
..expr
145-
}
146-
.into();
148+
});
147149
}
148150
ExprOrSuper::Expr(callee) if callee.is_member() => {
149151
let callee = callee.member().unwrap();
150152
let callee = self.handle_member(callee);
151153

152154
return match callee {
153-
Ok(expr) => Expr::Cond(CondExpr {
155+
Ok(expr) => Ok(CondExpr {
156+
span: e.span,
154157
alt: Box::new(Expr::Call(CallExpr {
155158
span: DUMMY_SP,
156159
callee: expr.alt.as_callee(),
@@ -159,16 +162,16 @@ impl OptChaining {
159162
})),
160163
..expr
161164
}),
162-
Err(callee) => Expr::Call(CallExpr {
165+
Err(callee) => Err(Expr::Call(CallExpr {
163166
callee: callee.as_callee(),
164167
..e
165-
}),
168+
})),
166169
};
167170
}
168171
_ => {}
169172
}
170173

171-
Expr::Call(e)
174+
Err(Expr::Call(e))
172175
}
173176

174177
/// Returns `Ok` if it handled optional chaining.
@@ -202,6 +205,35 @@ impl OptChaining {
202205
_ => ExprOrSuper::Expr(Box::new(obj)),
203206
}
204207
}
208+
209+
ExprOrSuper::Expr(obj) if obj.is_call() => {
210+
let obj = obj.call().unwrap();
211+
let obj = self.handle_call(obj).map(Expr::Cond);
212+
let (obj, handled) = match obj {
213+
Ok(v) => (v, true),
214+
Err(v) => (v, false),
215+
};
216+
217+
match obj {
218+
Expr::Cond(obj) => {
219+
let cond_expr = CondExpr {
220+
span: DUMMY_SP,
221+
alt: Box::new(Expr::Member(MemberExpr {
222+
obj: ExprOrSuper::Expr(obj.alt),
223+
..e
224+
})),
225+
..obj
226+
};
227+
//
228+
return if handled {
229+
Ok(cond_expr)
230+
} else {
231+
Err(Expr::Cond(cond_expr))
232+
};
233+
}
234+
_ => ExprOrSuper::Expr(Box::new(obj)),
235+
}
236+
}
205237
_ => e.obj,
206238
};
207239

ecmascript/transforms/tests/es2020_class_properties.rs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use swc_ecma_transforms::{
66
es2015::{arrow, block_scoping, classes, function_name},
77
es2016::exponentation,
88
es2017::async_to_generator,
9-
es2020::class_properties,
9+
es2020::{class_properties, typescript_class_properties},
1010
es3::reserved_words,
1111
},
1212
proposals::decorators,
@@ -4858,3 +4858,107 @@ expect(foo.y).toBe('bar');
48584858
48594859
"#
48604860
);
4861+
4862+
test!(
4863+
syntax(),
4864+
|_| typescript_class_properties(),
4865+
issue_1122_1,
4866+
"
4867+
const identifier = 'bar';
4868+
4869+
class Foo {
4870+
[identifier] = 5;
4871+
}
4872+
4873+
4874+
",
4875+
"
4876+
const identifier = \"bar\";
4877+
class Foo {
4878+
constructor(){
4879+
this[identifier] = 5;
4880+
}
4881+
}
4882+
"
4883+
);
4884+
4885+
test!(
4886+
syntax(),
4887+
|_| typescript_class_properties(),
4888+
issue_1122_2,
4889+
"
4890+
const identifier = 'bar';
4891+
4892+
class Foo {
4893+
identifier = 5;
4894+
}
4895+
",
4896+
"
4897+
const identifier = \"bar\";
4898+
class Foo {
4899+
constructor(){
4900+
this.identifier = 5;
4901+
}
4902+
}
4903+
"
4904+
);
4905+
4906+
test!(
4907+
syntax(),
4908+
|_| typescript_class_properties(),
4909+
issue_1122_3,
4910+
"
4911+
const identifier = 'bar';
4912+
4913+
class Foo {
4914+
['identifier'] = 5;
4915+
}
4916+
",
4917+
"
4918+
const identifier = \"bar\";
4919+
class Foo {
4920+
constructor(){
4921+
this[\"identifier\"] = 5;
4922+
}
4923+
}
4924+
"
4925+
);
4926+
4927+
test!(
4928+
syntax(),
4929+
|_| typescript_class_properties(),
4930+
issue_1122_4,
4931+
"
4932+
const identifier = 'bar';
4933+
4934+
class Foo {
4935+
static [identifier] = 5;
4936+
}
4937+
",
4938+
"
4939+
const identifier = \"bar\";
4940+
class Foo {
4941+
}
4942+
Foo[identifier] = 5;
4943+
4944+
"
4945+
);
4946+
4947+
test!(
4948+
syntax(),
4949+
|_| typescript_class_properties(),
4950+
issue_1122_5,
4951+
"
4952+
const identifier = 'bar';
4953+
4954+
class Foo {
4955+
static identifier = 5;
4956+
}
4957+
",
4958+
"
4959+
const identifier = \"bar\";
4960+
class Foo {
4961+
}
4962+
Foo.identifier = 5;
4963+
"
4964+
);

ecmascript/transforms/tests/es2020_optional_chaining.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,34 @@ test!(
636636
expect(obj?.a?.b?.c()).toBe(2)
637637
",
638638
"
639-
var ref, ref1;
639+
var ref, ref1;
640640
expect(obj === null || obj === void 0 ? void 0 : (ref = obj.a) === null || ref === void 0 ? void 0 \
641641
: (ref1 = ref.b) === null || ref1 === void 0 ? void 0 : ref1.c()).toBe(2);
642642
"
643643
);
644+
645+
test!(
646+
syntax(),
647+
|_| tr(()),
648+
issue_1130_1,
649+
"
650+
const result = data?.filter(item => Math.random() > 0.5).map(item => JSON.stringify(item));
651+
",
652+
"
653+
const result = data === null || data === void 0 ? void 0 : data.filter(item => Math.random() > \
654+
0.5).map(item => JSON.stringify(item));
655+
"
656+
);
657+
658+
test!(
659+
syntax(),
660+
|_| tr(()),
661+
issue_1130_2,
662+
"
663+
const r = d?.filter(i => Math.random() > 0.5).map(i => JSON.stringify(i));
664+
",
665+
"
666+
const r = d === null || d === void 0 ? void 0 : d.filter(i => Math.random() > 0.5).map(i => \
667+
JSON.stringify(i));
668+
"
669+
);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@swc/core",
3-
"version": "1.2.34",
3+
"version": "1.2.35",
44
"description": "Super-fast alternative for babel",
55
"homepage": "https://swc.rs",
66
"main": "./index.js",

0 commit comments

Comments
 (0)