mirror of
https://github.com/swc-project/swc.git
synced 2024-10-05 12:49:21 +03:00
Fix bugs (#949)
swc_ecma_parser: - Allow `in` in class properties (#944) - Make `delete` with optional chaining valid (#947) swc_ecma_transforms: - Add a `typescript_class_properties` pass (#930)
This commit is contained in:
parent
26f49099aa
commit
1315d58059
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "swc_ecma_parser"
|
name = "swc_ecma_parser"
|
||||||
version = "0.33.1"
|
version = "0.33.2"
|
||||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
|
@ -364,6 +364,7 @@ impl Error {
|
|||||||
|
|
||||||
Eof => "Unexpected eof".into(),
|
Eof => "Unexpected eof".into(),
|
||||||
|
|
||||||
|
TS2703 => "The operand of a delete operator must be a property reference.".into(),
|
||||||
// TODO:
|
// TODO:
|
||||||
_ => format!("{:?}", kind).into(),
|
_ => format!("{:?}", kind).into(),
|
||||||
};
|
};
|
||||||
|
@ -750,6 +750,7 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
let ctx = Context {
|
let ctx = Context {
|
||||||
in_class_prop: true,
|
in_class_prop: true,
|
||||||
in_method: false,
|
in_method: false,
|
||||||
|
include_in_expr: true,
|
||||||
..self.ctx()
|
..self.ctx()
|
||||||
};
|
};
|
||||||
self.with_ctx(ctx).parse_with(|p| {
|
self.with_ctx(ctx).parse_with(|p| {
|
||||||
|
@ -284,8 +284,13 @@ impl<'a, I: Tokens> Parser<I> {
|
|||||||
_ => e,
|
_ => e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match *arg {
|
match &*arg {
|
||||||
Expr::Member(..) => {}
|
Expr::Member(..) => {}
|
||||||
|
Expr::OptChain(e)
|
||||||
|
if match &*e.expr {
|
||||||
|
Expr::Member(..) => true,
|
||||||
|
_ => false,
|
||||||
|
} => {}
|
||||||
_ => self.emit_err(unwrap_paren(&arg).span(), SyntaxError::TS2703),
|
_ => self.emit_err(unwrap_paren(&arg).span(), SyntaxError::TS2703),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
ecmascript/parser/tests/typescript/issue-944/input.ts
Normal file
3
ecmascript/parser/tests/typescript/issue-944/input.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class CTest {
|
||||||
|
myFunc = () => "key" in {};
|
||||||
|
}
|
109
ecmascript/parser/tests/typescript/issue-944/input.ts.json
Normal file
109
ecmascript/parser/tests/typescript/issue-944/input.ts.json
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{
|
||||||
|
"type": "Module",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 47,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ClassDeclaration",
|
||||||
|
"identifier": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 6,
|
||||||
|
"end": 11,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "CTest",
|
||||||
|
"typeAnnotation": null,
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"declare": false,
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 47,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"decorators": [],
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ClassProperty",
|
||||||
|
"span": {
|
||||||
|
"start": 18,
|
||||||
|
"end": 45,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 18,
|
||||||
|
"end": 24,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "myFunc",
|
||||||
|
"typeAnnotation": null,
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "ArrowFunctionExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 27,
|
||||||
|
"end": 44,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"params": [],
|
||||||
|
"body": {
|
||||||
|
"type": "BinaryExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 33,
|
||||||
|
"end": 44,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"operator": "in",
|
||||||
|
"left": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"span": {
|
||||||
|
"start": 33,
|
||||||
|
"end": 38,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "key",
|
||||||
|
"hasEscape": false
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"type": "ObjectExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 42,
|
||||||
|
"end": 44,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"properties": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"async": false,
|
||||||
|
"generator": false,
|
||||||
|
"typeParameters": null,
|
||||||
|
"returnType": null
|
||||||
|
},
|
||||||
|
"typeAnnotation": null,
|
||||||
|
"isStatic": false,
|
||||||
|
"decorators": [],
|
||||||
|
"computed": false,
|
||||||
|
"accessibility": null,
|
||||||
|
"isAbstract": false,
|
||||||
|
"isOptional": false,
|
||||||
|
"readonly": false,
|
||||||
|
"declare": false,
|
||||||
|
"definite": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"superClass": null,
|
||||||
|
"isAbstract": false,
|
||||||
|
"typeParams": null,
|
||||||
|
"superTypeParams": null,
|
||||||
|
"implements": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpreter": null
|
||||||
|
}
|
1
ecmascript/parser/tests/typescript/issue-947/input.ts
Normal file
1
ecmascript/parser/tests/typescript/issue-947/input.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
delete obj?.myProp;
|
72
ecmascript/parser/tests/typescript/issue-947/input.ts.json
Normal file
72
ecmascript/parser/tests/typescript/issue-947/input.ts.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"type": "Module",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 19,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 19,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "UnaryExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 18,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"operator": "delete",
|
||||||
|
"argument": {
|
||||||
|
"type": "OptionalChainingExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 7,
|
||||||
|
"end": 18,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"questionDotToken": {
|
||||||
|
"start": 10,
|
||||||
|
"end": 11,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"expr": {
|
||||||
|
"type": "MemberExpression",
|
||||||
|
"span": {
|
||||||
|
"start": 7,
|
||||||
|
"end": 18,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"object": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 7,
|
||||||
|
"end": 10,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "obj",
|
||||||
|
"typeAnnotation": null,
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 12,
|
||||||
|
"end": 18,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "myProp",
|
||||||
|
"typeAnnotation": null,
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"computed": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpreter": null
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"type": "Module",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 30,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "TryStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 30,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"type": "BlockStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 4,
|
||||||
|
"end": 7,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"stmts": []
|
||||||
|
},
|
||||||
|
"handler": {
|
||||||
|
"type": "CatchClause",
|
||||||
|
"span": {
|
||||||
|
"start": 8,
|
||||||
|
"end": 30,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"param": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 15,
|
||||||
|
"end": 16,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "e",
|
||||||
|
"typeAnnotation": {
|
||||||
|
"type": "TsTypeAnnotation",
|
||||||
|
"span": {
|
||||||
|
"start": 16,
|
||||||
|
"end": 25,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"typeAnnotation": {
|
||||||
|
"type": "TsKeywordType",
|
||||||
|
"span": {
|
||||||
|
"start": 18,
|
||||||
|
"end": 25,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"kind": "unknown"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"type": "BlockStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 27,
|
||||||
|
"end": 30,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"stmts": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"finalizer": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpreter": null
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
class_properties::class_properties, nullish_coalescing::nullish_coalescing,
|
class_properties::{class_properties, typescript_class_properties},
|
||||||
|
nullish_coalescing::nullish_coalescing,
|
||||||
opt_chaining::optional_chaining,
|
opt_chaining::optional_chaining,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,11 +30,23 @@ mod used_name;
|
|||||||
///
|
///
|
||||||
/// We use custom helper to handle export defaul class
|
/// We use custom helper to handle export defaul class
|
||||||
pub fn class_properties() -> impl Fold {
|
pub fn class_properties() -> impl Fold {
|
||||||
ClassProperties { mark: Mark::root() }
|
ClassProperties {
|
||||||
|
typescript: false,
|
||||||
|
mark: Mark::root(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Class properties pass for the typescript.
|
||||||
|
pub fn typescript_class_properties() -> impl Fold {
|
||||||
|
ClassProperties {
|
||||||
|
typescript: true,
|
||||||
|
mark: Mark::root(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ClassProperties {
|
struct ClassProperties {
|
||||||
|
typescript: bool,
|
||||||
mark: Mark,
|
mark: Mark,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,77 +341,135 @@ impl ClassProperties {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = match *prop.key {
|
let key = if self.typescript {
|
||||||
Expr::Ident(ref i) if !prop.computed => Lit::Str(Str {
|
// `b` in
|
||||||
span: i.span,
|
//
|
||||||
value: i.sym.clone(),
|
// class A {
|
||||||
has_escape: false,
|
// b = 'foo';
|
||||||
})
|
// }
|
||||||
.as_arg(),
|
prop.key
|
||||||
Expr::Lit(ref lit) if !prop.computed => lit.clone().as_arg(),
|
} else {
|
||||||
|
match *prop.key {
|
||||||
|
Expr::Ident(ref i) if !prop.computed => {
|
||||||
|
Box::new(Expr::from(Lit::Str(Str {
|
||||||
|
span: i.span,
|
||||||
|
value: i.sym.clone(),
|
||||||
|
has_escape: false,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
Expr::Lit(ref lit) if !prop.computed => {
|
||||||
|
Box::new(Expr::from(lit.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let (ident, aliased) = if let Expr::Ident(ref i) = *prop.key {
|
let (ident, aliased) = if let Expr::Ident(ref i) = *prop.key {
|
||||||
if used_key_names.contains(&i.sym) {
|
if used_key_names.contains(&i.sym) {
|
||||||
(alias_ident_for(&prop.key, "_ref"), true)
|
(alias_ident_for(&prop.key, "_ref"), true)
|
||||||
|
} else {
|
||||||
|
alias_if_required(&prop.key, "_ref")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alias_if_required(&prop.key, "_ref")
|
alias_if_required(&prop.key, "_ref")
|
||||||
|
};
|
||||||
|
// ident.span = ident.span.apply_mark(Mark::fresh(Mark::root()));
|
||||||
|
if aliased {
|
||||||
|
// Handle computed property
|
||||||
|
vars.push(VarDeclarator {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
name: Pat::Ident(ident.clone()),
|
||||||
|
init: Some(prop.key),
|
||||||
|
definite: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
Box::new(Expr::from(ident))
|
||||||
alias_if_required(&prop.key, "_ref")
|
|
||||||
};
|
|
||||||
// ident.span = ident.span.apply_mark(Mark::fresh(Mark::root()));
|
|
||||||
if aliased {
|
|
||||||
// Handle computed property
|
|
||||||
vars.push(VarDeclarator {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
name: Pat::Ident(ident.clone()),
|
|
||||||
init: Some(prop.key),
|
|
||||||
definite: false,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
ident.as_arg()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = prop.value.unwrap_or_else(|| undefined(prop_span)).as_arg();
|
let value = prop.value.unwrap_or_else(|| undefined(prop_span));
|
||||||
|
let value = if prop.is_static {
|
||||||
|
value
|
||||||
|
.fold_with(&mut SuperFieldAccessFolder {
|
||||||
|
class_name: &ident,
|
||||||
|
vars: &mut vars,
|
||||||
|
constructor_this_mark: None,
|
||||||
|
is_static: true,
|
||||||
|
folding_constructor: false,
|
||||||
|
in_injected_define_property_call: false,
|
||||||
|
in_nested_scope: false,
|
||||||
|
this_alias_mark: None,
|
||||||
|
})
|
||||||
|
.fold_with(&mut ThisInStaticFolder {
|
||||||
|
ident: ident.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
let callee = helper!(define_property, "defineProperty");
|
if self.typescript {
|
||||||
|
if prop.is_static {
|
||||||
|
extra_stmts.push(
|
||||||
|
AssignExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
left: PatOrExpr::Expr(Box::new(
|
||||||
|
MemberExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
obj: ident.clone().as_obj(),
|
||||||
|
computed: false,
|
||||||
|
prop: key,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
op: op!("="),
|
||||||
|
right: value,
|
||||||
|
}
|
||||||
|
.into_stmt(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
constructor_exprs.push(Box::new(Expr::Assign(AssignExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
left: (PatOrExpr::Expr(Box::new(
|
||||||
|
MemberExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
obj: ThisExpr { span: DUMMY_SP }.as_obj(),
|
||||||
|
computed: false,
|
||||||
|
prop: key,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
))),
|
||||||
|
op: op!("="),
|
||||||
|
right: value,
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let callee = helper!(define_property, "defineProperty");
|
||||||
|
|
||||||
if prop.is_static {
|
if prop.is_static {
|
||||||
extra_stmts.push(
|
extra_stmts.push(
|
||||||
CallExpr {
|
CallExpr {
|
||||||
|
span: DUMMY_SP,
|
||||||
|
callee,
|
||||||
|
args: vec![
|
||||||
|
ident.clone().as_arg(),
|
||||||
|
key.as_arg(),
|
||||||
|
value.as_arg(),
|
||||||
|
],
|
||||||
|
type_args: Default::default(),
|
||||||
|
}
|
||||||
|
.into_stmt(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
constructor_exprs.push(Box::new(Expr::Call(CallExpr {
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
callee,
|
callee,
|
||||||
args: vec![
|
args: vec![
|
||||||
ident.clone().as_arg(),
|
ThisExpr { span: DUMMY_SP }.as_arg(),
|
||||||
key,
|
key.as_arg(),
|
||||||
value
|
value.as_arg(),
|
||||||
.fold_with(&mut SuperFieldAccessFolder {
|
|
||||||
class_name: &ident,
|
|
||||||
vars: &mut vars,
|
|
||||||
constructor_this_mark: None,
|
|
||||||
is_static: true,
|
|
||||||
folding_constructor: false,
|
|
||||||
in_injected_define_property_call: false,
|
|
||||||
in_nested_scope: false,
|
|
||||||
this_alias_mark: None,
|
|
||||||
})
|
|
||||||
.fold_with(&mut ThisInStaticFolder {
|
|
||||||
ident: ident.clone(),
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
type_args: Default::default(),
|
type_args: Default::default(),
|
||||||
}
|
})));
|
||||||
.into_stmt(),
|
}
|
||||||
)
|
|
||||||
} else {
|
|
||||||
constructor_exprs.push(Box::new(Expr::Call(CallExpr {
|
|
||||||
span: DUMMY_SP,
|
|
||||||
callee,
|
|
||||||
args: vec![ThisExpr { span: DUMMY_SP }.as_arg(), key, value],
|
|
||||||
type_args: Default::default(),
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClassMember::PrivateProp(prop) => {
|
ClassMember::PrivateProp(prop) => {
|
||||||
@ -524,6 +594,35 @@ impl ClassProperties {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Legacy support.
|
||||||
|
///
|
||||||
|
/// ## Why is this required?
|
||||||
|
///
|
||||||
|
/// Hygiene data of
|
||||||
|
///
|
||||||
|
///```ts
|
||||||
|
/// class A {
|
||||||
|
/// b = this.a;
|
||||||
|
/// constructor(a){
|
||||||
|
/// this.a = a;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// is
|
||||||
|
///
|
||||||
|
///```ts
|
||||||
|
/// class A0 {
|
||||||
|
/// constructor(a1){
|
||||||
|
/// this.a0 = a0;
|
||||||
|
/// this.b0 = this.a0;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// which is valid only for es2020 properties.
|
||||||
|
///
|
||||||
|
/// Legacy proposal which is used by typescript requires different hygiene.
|
||||||
#[allow(clippy::vec_box)]
|
#[allow(clippy::vec_box)]
|
||||||
fn process_constructor(
|
fn process_constructor(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -534,28 +633,32 @@ impl ClassProperties {
|
|||||||
) -> Option<Constructor> {
|
) -> Option<Constructor> {
|
||||||
let constructor = constructor
|
let constructor = constructor
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
let mut folder = UsedNameRenamer {
|
if self.typescript {
|
||||||
mark: Mark::fresh(Mark::root()),
|
c
|
||||||
used_names,
|
} else {
|
||||||
};
|
let mut folder = UsedNameRenamer {
|
||||||
|
mark: Mark::fresh(Mark::root()),
|
||||||
|
used_names,
|
||||||
|
};
|
||||||
|
|
||||||
// Handle collisions like
|
// Handle collisions like
|
||||||
//
|
//
|
||||||
// var foo = "bar";
|
// var foo = "bar";
|
||||||
//
|
//
|
||||||
// class Foo {
|
// class Foo {
|
||||||
// bar = foo;
|
// bar = foo;
|
||||||
// static bar = baz;
|
// static bar = baz;
|
||||||
//
|
//
|
||||||
// constructor() {
|
// constructor() {
|
||||||
// var foo = "foo";
|
// var foo = "foo";
|
||||||
// var baz = "baz";
|
// var baz = "baz";
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
let body = c.body.fold_with(&mut folder);
|
let body = c.body.fold_with(&mut folder);
|
||||||
|
|
||||||
let params = c.params.fold_with(&mut folder);
|
let params = c.params.fold_with(&mut folder);
|
||||||
Constructor { body, params, ..c }
|
Constructor { body, params, ..c }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if constructor_exprs.is_empty() {
|
if constructor_exprs.is_empty() {
|
||||||
@ -565,8 +668,19 @@ impl ClassProperties {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(c) = constructor {
|
if let Some(mut c) = constructor {
|
||||||
Some(inject_after_super(c, constructor_exprs))
|
if self.typescript {
|
||||||
|
// Append properties
|
||||||
|
c.body
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.stmts
|
||||||
|
.extend(constructor_exprs.into_iter().map(|v| v.into_stmt()));
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
// Prepend properties
|
||||||
|
Some(inject_after_super(c, constructor_exprs))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
use swc_common::chain;
|
use swc_common::chain;
|
||||||
use swc_ecma_transforms::{resolver, typescript::strip};
|
use swc_ecma_transforms::{
|
||||||
|
compat::es2020::typescript_class_properties, resolver, typescript::strip,
|
||||||
|
};
|
||||||
|
use swc_ecma_visit::Fold;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
fn tr() -> impl Fold {
|
||||||
|
strip()
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! to {
|
macro_rules! to {
|
||||||
($name:ident, $from:expr, $to:expr) => {
|
($name:ident, $from:expr, $to:expr) => {
|
||||||
test!(
|
test!(
|
||||||
::swc_ecma_parser::Syntax::Typescript(Default::default()),
|
::swc_ecma_parser::Syntax::Typescript(Default::default()),
|
||||||
|_| strip(),
|
|_| tr(),
|
||||||
$name,
|
$name,
|
||||||
$from,
|
$from,
|
||||||
$to,
|
$to,
|
||||||
@ -695,3 +702,37 @@ to!(
|
|||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test!(
|
||||||
|
::swc_ecma_parser::Syntax::Typescript(Default::default()),
|
||||||
|
|_| chain!(tr(), typescript_class_properties()),
|
||||||
|
issue_930_instance,
|
||||||
|
"class A {
|
||||||
|
b = this.a;
|
||||||
|
constructor(a){
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"class A {
|
||||||
|
constructor(a) {
|
||||||
|
this.a = a;
|
||||||
|
this.b = this.a;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
);
|
||||||
|
|
||||||
|
test!(
|
||||||
|
::swc_ecma_parser::Syntax::Typescript(Default::default()),
|
||||||
|
|_| chain!(tr(), typescript_class_properties()),
|
||||||
|
issue_930_static,
|
||||||
|
"class A {
|
||||||
|
static b = 'foo';
|
||||||
|
constructor(a){
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"class A {
|
||||||
|
constructor(a) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
A.b = 'foo';"
|
||||||
|
);
|
||||||
|
@ -144,10 +144,17 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
|||||||
compat::es2020::optional_chaining(),
|
compat::es2020::optional_chaining(),
|
||||||
self.target < JscTarget::Es2020
|
self.target < JscTarget::Es2020
|
||||||
),
|
),
|
||||||
Optional::new(
|
if syntax.typescript() {
|
||||||
compat::es2020::class_properties(),
|
Either::Left(Optional::new(
|
||||||
self.target < JscTarget::Es2020
|
compat::es2020::typescript_class_properties(),
|
||||||
),
|
self.target < JscTarget::Es2020,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Either::Right(Optional::new(
|
||||||
|
compat::es2020::class_properties(),
|
||||||
|
self.target < JscTarget::Es2020,
|
||||||
|
))
|
||||||
|
},
|
||||||
Optional::new(compat::es2018(), self.target <= JscTarget::Es2018),
|
Optional::new(compat::es2018(), self.target <= JscTarget::Es2018),
|
||||||
Optional::new(compat::es2017(), self.target <= JscTarget::Es2017),
|
Optional::new(compat::es2017(), self.target <= JscTarget::Es2017),
|
||||||
Optional::new(compat::es2016(), self.target <= JscTarget::Es2016),
|
Optional::new(compat::es2016(), self.target <= JscTarget::Es2016),
|
||||||
|
Loading…
Reference in New Issue
Block a user