feat(es/compat): Implement loose mode for class_properties (#3722)

This commit is contained in:
Austaras 2022-02-26 23:09:02 +08:00 committed by GitHub
parent d23e19abe9
commit 14155eb0e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1388 additions and 642 deletions

View File

@ -184,7 +184,14 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
} else {
Either::Right(chain!(
Optional::new(
compat::es2022::es2022(compat::es2022::Config { loose: self.loose }),
compat::es2022::es2022(compat::es2022::Config {
class_properties: compat::es2022::class_properties::Config {
private_as_properties: self.loose,
constant_super: self.loose,
set_public_fields: self.loose,
no_document_all: self.loose
}
}),
should_enable(self.target, EsVersion::Es2022)
),
Optional::new(

View File

@ -1,16 +1,3 @@
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
var ClassA = function ClassA() {
"use strict";
};
@ -24,6 +11,6 @@ module.exports = (function() {
};
return ClassB;
}();
_defineProperty(ClassB, "MyA", ClassA);
ClassB.MyA = ClassA;
return ClassB;
})();

View File

@ -1,16 +1,11 @@
var a = function() {};
module.exports = (function() {
var b, c, d, e = function() {
var b = function() {
"use strict";
function e() {}
return e.prototype.it = function() {
this.bb = new e.MyA();
}, e;
function b() {}
return b.prototype.it = function() {
this.bb = new b.MyA();
}, b;
}();
return b = e, c = "MyA", d = a, c in b ? Object.defineProperty(b, c, {
value: d,
enumerable: !0,
configurable: !0,
writable: !0
}) : b[c] = d, e;
return b.MyA = a, b;
})();

View File

@ -69,26 +69,26 @@ function _createSuper(Derived) {
return _possibleConstructorReturn(this, result);
};
}
var C = /*#__PURE__*/ function(_super) {
var C = /*#__PURE__*/ function(__class) {
"use strict";
_inherits(_class, _super);
var _super1 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
_classCallCheck(this, _class);
var _this;
_this = _super1.apply(this, arguments);
_this = _super.apply(this, arguments);
_this.c = 3;
return _this;
}
return _class;
}(/*#__PURE__*/ function(_super) {
}(/*#__PURE__*/ function(__class) {
"use strict";
_inherits(_class, _super);
var _super2 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
_classCallCheck(this, _class);
var _this;
_this = _super2.apply(this, arguments);
_this = _super.apply(this, arguments);
_this.b = 2;
return _this;
}

View File

@ -44,22 +44,22 @@ function _createSuper(Derived) {
})(self);
};
}
var c = new (function(_super) {
var c = new (function(__class) {
"use strict";
_inherits(_class, _super);
var _super1 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
var _this;
return _classCallCheck(this, _class), _this = _super1.apply(this, arguments), _this.c = 3, _this;
return _classCallCheck(this, _class), _this = _super.apply(this, arguments), _this.c = 3, _this;
}
return _class;
}(function(_super) {
}(function(__class) {
"use strict";
_inherits(_class, _super);
var _super2 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
var _this;
return _classCallCheck(this, _class), _this = _super2.apply(this, arguments), _this.b = 2, _this;
return _classCallCheck(this, _class), _this = _super.apply(this, arguments), _this.b = 2, _this;
}
return _class;
}(function _class() {

View File

@ -70,26 +70,26 @@ function _createSuper(Derived) {
};
}
// @target: es6
var C = /*#__PURE__*/ function(_super) {
var C = /*#__PURE__*/ function(__class) {
"use strict";
_inherits(_class, _super);
var _super1 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
_classCallCheck(this, _class);
var _this;
_this = _super1.apply(this, arguments);
_this = _super.apply(this, arguments);
_this.c = 3;
return _this;
}
return _class;
}(/*#__PURE__*/ function(_super) {
}(/*#__PURE__*/ function(__class) {
"use strict";
_inherits(_class, _super);
var _super2 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
_classCallCheck(this, _class);
var _this;
_this = _super2.apply(this, arguments);
_this = _super.apply(this, arguments);
_this.b = 2;
return _this;
}

View File

@ -44,22 +44,22 @@ function _createSuper(Derived) {
})(self);
};
}
var c = new (function(_super) {
var c = new (function(__class) {
"use strict";
_inherits(_class, _super);
var _super1 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
var _this;
return _classCallCheck(this, _class), _this = _super1.apply(this, arguments), _this.c = 3, _this;
return _classCallCheck(this, _class), _this = _super.apply(this, arguments), _this.c = 3, _this;
}
return _class;
}(function(_super) {
}(function(__class) {
"use strict";
_inherits(_class, _super);
var _super2 = _createSuper(_class);
_inherits(_class, __class);
var _super = _createSuper(_class);
function _class() {
var _this;
return _classCallCheck(this, _class), _this = _super2.apply(this, arguments), _this.b = 2, _this;
return _classCallCheck(this, _class), _this = _super.apply(this, arguments), _this.b = 2, _this;
}
return _class;
}(function _class() {

View File

@ -41,7 +41,7 @@ class A {
var _foo = {
writable: true,
value: true
} // error (duplicate)
}// error (duplicate)
;
class B {
test(x) {

View File

@ -59,7 +59,7 @@ var A = function A() {
var _foo = {
writable: true,
value: true
} // error (duplicate)
}// error (duplicate)
;
var B = /*#__PURE__*/ function() {
"use strict";

View File

@ -92,7 +92,12 @@ where
let pass = add!(
pass,
ClassProperties,
es2022::class_properties(es2022::class_properties::Config { loose })
es2022::class_properties(es2022::class_properties::Config {
private_as_properties: loose,
set_public_fields: loose,
constant_super: loose,
no_document_all: loose
})
);
let pass = add!(pass, PrivatePropertyInObject, es2022::private_in_object());

View File

@ -1 +1,5 @@
[1, 2, 3][flatMap];
[
1,
2,
3
][flatMap];

View File

@ -1,8 +1,9 @@
var __ = _classPrivateFieldLooseKey("__");
class A {
}
var __ = {
Object.defineProperty(A, __, {
writable: true,
value: (()=>{
A.abc = 123;
})()
};
});

View File

@ -20,8 +20,8 @@ use swc_ecma_ast::*;
use swc_ecma_codegen::Emitter;
use swc_ecma_parser::{EsConfig, Parser, Syntax};
use swc_ecma_preset_env::{preset_env, Config, FeatureOrModule, Mode, Targets, Version};
use swc_ecma_transforms::fixer;
use swc_ecma_utils::drop_span;
use swc_ecma_transforms::{fixer, helpers};
use swc_ecma_utils::{drop_span, HANDLER};
use swc_ecma_visit::{as_folder, FoldWith, VisitMut};
use testing::{NormalizedOutput, Tester};
@ -134,7 +134,6 @@ fn exec(c: PresetConfig, dir: PathBuf) -> Result<(), Error> {
v => unreachable!("invalid: {:?}", v),
},
skip: vec![],
// TODO
loose: true,
// TODO
dynamic_import: true,
@ -194,7 +193,9 @@ fn exec(c: PresetConfig, dir: PathBuf) -> Result<(), Error> {
e.into_diagnostic(&handler).emit()
}
let actual = module.fold_with(&mut pass);
let actual = helpers::HELPERS.set(&Default::default(), || {
HANDLER.set(&handler, || module.fold_with(&mut pass))
});
// debug mode?
if dir.join("stdout.txt").exists() {

View File

@ -40,7 +40,7 @@ fn syntax(decorators_before_export: bool) -> Syntax {
fn tr() -> impl Fold {
chain!(
decorators(Default::default()),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
)
}
@ -2023,7 +2023,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_constructors_return_new_constructor_exec,
r#"
@ -2181,7 +2181,7 @@ export { _class1 as default }
// "presets": ["env"],
// "plugins": [
// ["proposal-decorators", { "legacy": true }],
// [class_properties(class_properties::Config { loose: false }), { "loose":
// [class_properties(Default::default()), { "loose":
// true }] ]
//}
//"#),
@ -2208,7 +2208,7 @@ export { _class1 as default }
// "presets": ["env"],
// "plugins": [
// ["proposal-decorators", { "legacy": true }],
// [class_properties(class_properties::Config { loose: false }), { "loose":
// [class_properties(Default::default()), { "loose":
// true }] ]
//}
//"#),
@ -2343,7 +2343,7 @@ export { _class1 as default }
// "presets": ["env"],
// "plugins": [
// ["proposal-decorators", { "legacy": true }],
// [class_properties(class_properties::Config { loose: false }), { "loose":
// [class_properties(Default::default()), { "loose":
// true }] ]
//}
//"#),
@ -2480,7 +2480,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_methods_numeric_props_exec,
r#"
@ -2506,7 +2506,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_static_properties_mutate_descriptor_exec,
r#"
@ -2621,7 +2621,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_static_methods_string_props_exec,
r#"
@ -2647,7 +2647,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_properties_string_literal_properties_exec,
r#"
@ -2692,7 +2692,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_methods_mutate_descriptor_exec,
r#"
@ -2825,7 +2825,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_properties_numeric_props_exec,
r#"
@ -2882,7 +2882,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_properties_return_descriptor_exec,
r#"
@ -2999,7 +2999,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_properties_string_props_exec,
r#"
@ -3027,7 +3027,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_properties_return_descriptor_exec,
r#"
@ -3140,7 +3140,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_methods_string_props_exec,
r#"
@ -3166,7 +3166,7 @@ test!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_regression_8041,
r#"
@ -3196,7 +3196,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_methods_return_descriptor_exec,
r#"
@ -3331,7 +3331,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_ordering_reverse_order_exec,
r#"
@ -3375,7 +3375,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_methods_numeric_props_exec,
r#"
@ -3402,7 +3402,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_static_properties_return_descriptor_exec,
r#"
@ -3522,7 +3522,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_export_default_exec,
r#"
@ -3552,7 +3552,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_ordering_reverse_order_exec,
r#"
@ -3599,7 +3599,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_methods_mutate_descriptor_exec,
r#"
@ -3728,7 +3728,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_static_methods_return_descriptor_exec,
r#"
@ -3860,7 +3860,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_methods_return_descriptor_exec,
r#"
@ -3991,7 +3991,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_object_methods_string_props_exec,
r#"
@ -4019,7 +4019,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_prototype_properties_child_classes_properties_exec,
r#"
@ -4062,7 +4062,7 @@ test_exec!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
),
legacy_class_static_methods_mutate_descriptor_exec,
r#"
@ -5144,7 +5144,7 @@ test!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
classes(Some(t.comments.clone()), Default::default())
),
decorators_legacy_interop_local_define_property,

View File

@ -694,7 +694,7 @@ test!(
legacy: true,
..Default::default()
}),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
classes(Some(t.comments.clone()), Default::default()),
),
decorators_legacy_interop_strict,

View File

@ -3,5 +3,5 @@ function _classPrivateFieldBase(receiver, privateKey) {
throw new TypeError("attempted to use private field on non-instance");
}
return receiver;
return receiver[privateKey];
}

View File

@ -0,0 +1,5 @@
var id = 0;
function _classPrivateFieldLooseKey(name) {
return "__private_" + id++ + "_" + name;
}

View File

@ -186,7 +186,7 @@ define_helpers!(Helpers {
class_private_field_get: (class_extract_field_descriptor, class_apply_descriptor_get),
class_private_field_init: (check_private_redeclaration),
class_private_field_loose_base: (),
// class_private_field_loose_key: (),
class_private_field_loose_key: (),
class_private_field_set: (class_extract_field_descriptor, class_apply_descriptor_set),
class_private_method_get: (),
class_private_method_init: (check_private_redeclaration),

View File

@ -756,8 +756,8 @@ where
key: PropName::Ident(quote_ident!(key.span(), "key")),
value: match key {
PropName::Ident(i) => Box::new(Expr::Lit(Lit::Str(quote_str!(i.span, i.sym)))),
PropName::Str(s) => Box::new(Expr::Lit(Lit::Str(s))),
PropName::Num(n) => Box::new(Expr::Lit(Lit::Num(n))),
PropName::Str(s) => Box::new(Expr::from(s)),
PropName::Num(n) => Box::new(Expr::from(n)),
PropName::BigInt(b) => Box::new(Expr::Lit(
Str {
span: b.span,

View File

@ -7,7 +7,8 @@ use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::Check;
use swc_ecma_transforms_macros::fast_path;
use swc_ecma_utils::{
alias_if_required, prepend, private_ident, undefined, ExprFactory, IntoIndirectCall, StmtLike,
alias_if_required, opt_chain_test, prepend, private_ident, undefined, ExprFactory,
IntoIndirectCall, StmtLike,
};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith,
@ -447,31 +448,7 @@ impl OptChaining {
}
};
let test = Box::new(Expr::Bin(if self.c.no_document_all {
BinExpr {
span: obj_span,
left,
op: op!("=="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
}
} else {
BinExpr {
span,
left: Box::new(Expr::Bin(BinExpr {
span: obj_span,
left,
op: op!("==="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
})),
op: op!("||"),
right: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: right,
op: op!("==="),
right: undefined(span),
})),
}
}));
let test = Box::new(opt_chain_test(left, right, span, self.c.no_document_all));
CondExpr {
span,
@ -595,31 +572,7 @@ impl OptChaining {
}
};
let test = Box::new(Expr::Bin(if self.c.no_document_all {
BinExpr {
span: DUMMY_SP,
left,
op: op!("=="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
}
} else {
BinExpr {
span,
left: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left,
op: op!("==="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
})),
op: op!("||"),
right: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: right,
op: op!("==="),
right: undefined(span),
})),
}
}));
let test = Box::new(opt_chain_test(left, right, span, self.c.no_document_all));
CondExpr {
span: DUMMY_SP,

View File

@ -0,0 +1,356 @@
use swc_common::{Span, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::helper;
use swc_ecma_utils::{
prop_name_to_expr, prop_name_to_expr_value, quote_ident, undefined, ExprFactory,
};
use super::Config;
pub(super) enum MemberInit {
PubProp(PubProp),
PrivProp(PrivProp),
PrivMethod(PrivMethod),
PrivAccessor(PrivAccessor),
}
pub(super) struct PubProp {
pub span: Span,
pub name: PropName,
pub value: Box<Expr>,
}
pub(super) struct PrivProp {
pub span: Span,
pub name: Ident,
pub value: Box<Expr>,
}
pub(super) struct PrivMethod {
pub span: Span,
pub name: Ident,
// only used in loose mode
pub fn_name: Ident,
}
pub(super) struct PrivAccessor {
pub span: Span,
pub name: Ident,
pub getter: Option<Ident>,
pub setter: Option<Ident>,
}
pub(super) struct MemberInitRecord {
c: Config,
pub record: Vec<MemberInit>,
}
impl MemberInitRecord {
pub fn new(c: Config) -> Self {
Self {
c,
record: Vec::new(),
}
}
pub fn push(&mut self, member: MemberInit) -> bool {
// there shouldn't be many class field, so n^2 should be fine
if let MemberInit::PrivAccessor(accessor) = member {
if let Some(MemberInit::PrivAccessor(previous)) =
self.record.iter_mut().find(|item| match item {
MemberInit::PrivAccessor(PrivAccessor { name, .. })
if name.sym == accessor.name.sym =>
{
true
}
_ => false,
})
{
previous.getter = previous.getter.take().or(accessor.getter);
previous.setter = previous.setter.take().or(accessor.setter);
false
} else {
self.record.push(MemberInit::PrivAccessor(accessor));
true
}
} else {
self.record.push(member);
true
}
}
pub fn into_init(self) -> Vec<Box<Expr>> {
self.record
.into_iter()
.map(|init| {
match init {
MemberInit::PrivMethod(PrivMethod {
span,
name,
fn_name,
}) => {
let (callee, args) = if self.c.private_as_properties {
(
obj_def_prop(),
vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
name.as_arg(),
get_method_desc(Box::new(fn_name.into())).as_arg(),
],
)
} else {
(
helper!(class_private_method_init, "classPrivateMethodInit"),
vec![ThisExpr { span: DUMMY_SP }.as_arg(), name.as_arg()],
)
};
Expr::Call(CallExpr {
span,
callee,
args,
type_args: Default::default(),
})
}
MemberInit::PrivProp(PrivProp { span, name, value }) => Expr::Call(CallExpr {
span,
callee: if self.c.private_as_properties {
obj_def_prop()
} else {
helper!(class_private_field_init, "classPrivateFieldInit")
},
args: vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
name.as_arg(),
get_value_desc(value).as_arg(),
],
type_args: Default::default(),
}),
MemberInit::PrivAccessor(PrivAccessor {
span,
name,
getter,
setter,
}) => Expr::Call(CallExpr {
span,
callee: if self.c.private_as_properties {
obj_def_prop()
} else {
helper!(class_private_field_init, "classPrivateFieldInit")
},
args: vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
name.as_arg(),
get_accessor_desc(getter, setter).as_arg(),
],
type_args: Default::default(),
}),
MemberInit::PubProp(PubProp { span, name, value }) => {
if self.c.set_public_fields {
let this = ThisExpr { span: DUMMY_SP };
Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Expr(Box::new(match name {
PropName::Ident(id) => this.make_member(id),
_ => this.computed_member(prop_name_to_expr(name)),
})),
op: op!("="),
right: value,
})
} else {
Expr::Call(CallExpr {
span,
callee: helper!(define_property, "defineProperty"),
args: vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
prop_name_to_expr_value(name).as_arg(),
value.as_arg(),
],
type_args: Default::default(),
})
}
}
}
.into()
})
.collect()
}
pub fn into_init_static(self, class_ident: Ident) -> Vec<Stmt> {
self.record
.into_iter()
.map(|value| match value {
MemberInit::PubProp(PubProp { span, name, value }) => Stmt::Expr(ExprStmt {
span,
expr: (if self.c.set_public_fields {
let class = class_ident.clone();
Expr::Assign(AssignExpr {
span,
left: PatOrExpr::Expr(Box::new(match name {
PropName::Ident(id) => class.make_member(id),
_ => class.computed_member(prop_name_to_expr(name)),
})),
op: op!("="),
right: value,
})
} else {
Expr::Call(CallExpr {
span,
callee: helper!(define_property, "defineProperty"),
args: vec![
class_ident.clone().as_arg(),
prop_name_to_expr_value(name).as_arg(),
value.as_arg(),
],
type_args: Default::default(),
})
})
.into(),
}),
MemberInit::PrivProp(PrivProp { span, name, value }) => {
if self.c.private_as_properties {
Stmt::Expr(ExprStmt {
span,
expr: Box::new(Expr::Call(CallExpr {
span,
callee: obj_def_prop(),
args: vec![
class_ident.clone().as_arg(),
name.as_arg(),
get_value_desc(value).as_arg(),
],
type_args: None,
})),
})
} else {
Stmt::Decl(Decl::Var(VarDecl {
span,
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span,
name: name.into(),
init: Some(Expr::Object(get_value_desc(value)).into()),
definite: false,
}],
declare: false,
}))
}
}
MemberInit::PrivAccessor(PrivAccessor {
span,
name,
getter,
setter,
}) => {
if self.c.private_as_properties {
Stmt::Expr(ExprStmt {
span,
expr: Box::new(Expr::Call(CallExpr {
span,
callee: obj_def_prop(),
args: vec![
class_ident.clone().as_arg(),
name.as_arg(),
get_accessor_desc(getter, setter).as_arg(),
],
type_args: None,
})),
})
} else {
Stmt::Decl(Decl::Var(VarDecl {
span,
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span,
name: name.into(),
init: Some(Expr::Object(get_accessor_desc(getter, setter)).into()),
definite: false,
}],
declare: false,
}))
}
}
MemberInit::PrivMethod(PrivMethod {
span,
name,
fn_name,
}) => {
if self.c.private_as_properties {
Stmt::Expr(ExprStmt {
span,
expr: Expr::Call(CallExpr {
span,
callee: obj_def_prop(),
args: vec![
class_ident.clone().as_arg(),
name.as_arg(),
get_method_desc(Box::new(fn_name.into())).as_arg(),
],
type_args: None,
})
.into(),
})
} else {
unreachable!()
}
}
})
.collect()
}
}
fn get_value_desc(value: Box<Expr>) -> ObjectLit {
ObjectLit {
span: DUMMY_SP,
props: vec![
// writeable: true
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("writable")),
value: true.into(),
}))),
// value: value,
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("value")),
value,
}))),
],
}
}
fn get_accessor_desc(getter: Option<Ident>, setter: Option<Ident>) -> ObjectLit {
ObjectLit {
span: DUMMY_SP,
props: vec![
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("get")),
value: getter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
}))),
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("set")),
value: setter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
}))),
],
}
}
fn get_method_desc(value: Box<Expr>) -> ObjectLit {
ObjectLit {
span: DUMMY_SP,
props: vec![
// value: value,
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("value")),
value,
}))),
],
}
}
fn obj_def_prop() -> Callee {
quote_ident!("Object")
.make_member(quote_ident!("defineProperty"))
.as_callee()
}

View File

@ -1,10 +1,9 @@
#![allow(dead_code)]
use indexmap::IndexMap;
use swc_common::{
collections::{AHashMap, AHashSet},
util::take::Take,
Mark, Span, Spanned, SyntaxContext, DUMMY_SP,
Mark, Spanned, SyntaxContext, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::{helper, perf::Check};
@ -20,6 +19,7 @@ use swc_ecma_visit::{
use self::{
class_name_tdz::ClassNameTdzFolder,
member_init::{MemberInit, MemberInitRecord, PrivAccessor, PrivMethod, PrivProp, PubProp},
private_field::{
dup_private_method, visit_private_in_expr, BrandCheckHandler, Private,
PrivateAccessVisitor, PrivateKind, PrivateRecord,
@ -29,6 +29,7 @@ use self::{
};
mod class_name_tdz;
mod member_init;
mod private_field;
mod this_in_static;
mod used_name;
@ -42,30 +43,24 @@ mod used_name;
/// We use custom helper to handle export default class
pub fn class_properties(config: Config) -> impl Fold + VisitMut {
as_folder(ClassProperties {
config,
c: config,
private: PrivateRecord::new(),
})
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Config {
pub loose: bool,
pub private_as_properties: bool,
pub set_public_fields: bool,
pub constant_super: bool,
pub no_document_all: bool,
}
struct ClassProperties {
config: Config,
c: Config,
private: PrivateRecord,
}
enum MemberInit {
Prop(Span, Box<Expr>),
Private(Span, Box<Expr>),
PrivMethod(Span),
PrivAccessor(Span, Option<Ident>, Option<Ident>),
}
type MemberInitMap = IndexMap<Expr, MemberInit, ahash::RandomState>;
#[fast_path(ShouldWork)]
impl VisitMut for ClassProperties {
noop_visit_mut_type!();
@ -394,16 +389,15 @@ impl ClassProperties {
let has_super = class.super_class.is_some();
// we need a hash map to avoid generate two init for corresponding getter/setter
let mut constructor_inits = MemberInitMap::default();
let mut constructor_inits = MemberInitRecord::new(self.c);
let mut vars = vec![];
let mut extra_inits = MemberInitMap::default();
// same here
let mut extra_inits = MemberInitRecord::new(self.c);
let mut private_method_fn_decls = vec![];
let mut members = vec![];
let mut constructor = None;
let mut used_names = vec![];
let mut used_key_names = vec![];
let mut super_ident = None;
class.body.visit_mut_with(&mut BrandCheckHandler {
names: &mut AHashSet::default(),
@ -421,7 +415,7 @@ impl ClassProperties {
span: c_span,
mut expr,
}) => {
vars.extend(visit_private_in_expr(&mut expr, &self.private));
vars.extend(visit_private_in_expr(&mut expr, &self.private, self.c));
expr.visit_mut_with(&mut ClassNameTdzFolder {
class_name: &class_ident,
@ -462,21 +456,8 @@ impl ClassProperties {
});
}
let key = match prop.key {
PropName::Ident(i) => Expr::from(Lit::Str(Str {
span: i.span,
value: i.sym,
has_escape: false,
kind: StrKind::Normal {
contains_quote: false,
},
})),
PropName::Num(num) => Expr::from(num),
PropName::Str(s) => Expr::from(s),
PropName::BigInt(big_int) => Expr::from(big_int),
PropName::Computed(mut key) => {
vars.extend(visit_private_in_expr(&mut key.expr, &self.private));
if let PropName::Computed(key) = &mut prop.key {
vars.extend(visit_private_in_expr(&mut key.expr, &self.private, self.c));
let (ident, aliased) = if let Expr::Ident(i) = &*key.expr {
if used_key_names.contains(&i.sym) {
(alias_ident_for(&key.expr, "_ref"), true)
@ -492,21 +473,41 @@ impl ClassProperties {
vars.push(VarDeclarator {
span: DUMMY_SP,
name: ident.clone().into(),
init: Some(key.expr),
init: Some(key.expr.take()),
definite: false,
});
}
Expr::from(ident)
}
*key.expr = Expr::from(ident);
};
let mut value = prop.value.unwrap_or_else(|| undefined(prop_span));
value.visit_mut_with(&mut NewTargetInProp);
vars.extend(visit_private_in_expr(&mut value, &self.private));
vars.extend(visit_private_in_expr(&mut value, &self.private, self.c));
if prop.is_static {
if let (Some(super_class), None) = (&mut class.super_class, &super_ident) {
let (ident, aliased) = alias_if_required(&*super_class, "_ref");
super_ident = Some(ident.clone());
if aliased {
vars.push(VarDeclarator {
span: DUMMY_SP,
name: ident.clone().into(),
init: None,
definite: false,
});
let span = super_class.span();
**super_class = Expr::Assign(AssignExpr {
span,
op: op!("="),
left: PatOrExpr::Pat(Box::new(ident.into())),
right: super_class.take(),
})
}
}
value.visit_mut_with(&mut SuperFieldAccessFolder {
class_name: &class_ident,
vars: &mut vars,
@ -516,19 +517,23 @@ impl ClassProperties {
in_injected_define_property_call: false,
in_nested_scope: false,
this_alias_mark: None,
// TODO: add loose mode
constant_super: false,
super_class: &None,
constant_super: self.c.constant_super,
super_class: &super_ident,
});
value.visit_mut_with(&mut ThisInStaticFolder {
ident: class_ident.clone(),
});
}
let init = MemberInit::PubProp(PubProp {
span: prop_span,
name: prop.key,
value,
});
if prop.is_static {
extra_inits.insert(key, MemberInit::Prop(prop_span, value));
extra_inits.push(init);
} else {
constructor_inits.insert(key, MemberInit::Prop(prop_span, value));
constructor_inits.push(init);
}
}
ClassMember::PrivateProp(mut prop) => {
@ -542,7 +547,7 @@ impl ClassProperties {
if let Some(value) = &mut prop.value {
value.visit_mut_with(&mut NewTargetInProp);
vars.extend(visit_private_in_expr(&mut *value, &self.private));
vars.extend(visit_private_in_expr(&mut *value, &self.private, self.c));
}
prop.value.visit_with(&mut UsedNameCollector {
@ -556,12 +561,27 @@ impl ClassProperties {
let value = prop.value.unwrap_or_else(|| undefined(prop_span));
if prop.is_static {
extra_inits.insert(ident.into(), MemberInit::Private(prop_span, value));
} else {
constructor_inits
.insert(ident.clone().into(), MemberInit::Private(prop_span, value));
let init = MemberInit::PrivProp(PrivProp {
span: prop_span,
name: ident.clone(),
value,
});
if self.c.private_as_properties {
vars.push(VarDeclarator {
span: DUMMY_SP,
definite: false,
name: ident.clone().into(),
init: Some(Box::new(Expr::from(CallExpr {
span: DUMMY_SP,
callee: helper!(
class_private_field_loose_key,
"classPrivateFieldLooseKey"
),
args: vec![ident.sym.as_arg()],
type_args: Default::default(),
}))),
});
} else if !prop.is_static {
vars.push(VarDeclarator {
span: DUMMY_SP,
definite: false,
@ -574,6 +594,11 @@ impl ClassProperties {
}))),
});
};
if prop.is_static {
extra_inits.push(init);
} else {
constructor_inits.push(init);
};
}
ClassMember::Constructor(c) => {
@ -607,21 +632,22 @@ impl ClassProperties {
let extra_collect = match (method.kind, is_static) {
(MethodKind::Getter | MethodKind::Setter, false) => {
let mut inserted = false;
let mut key = weak_coll_var.clone();
key.span = DUMMY_SP.with_ctxt(key.span.ctxt);
let mut entry =
constructor_inits.entry(key.into()).or_insert_with(|| {
inserted = true;
MemberInit::PrivAccessor(prop_span, None, None)
});
if let MemberInit::PrivAccessor(_, getter, setter) = &mut entry {
if method.kind == MethodKind::Getter {
*getter = Some(fn_name.clone())
let is_getter = method.kind == MethodKind::Getter;
let inserted =
constructor_inits.push(MemberInit::PrivAccessor(PrivAccessor {
span: prop_span,
name: weak_coll_var.clone(),
getter: if is_getter {
Some(fn_name.clone())
} else {
*setter = Some(fn_name.clone())
}
};
None
},
setter: if !is_getter {
Some(fn_name.clone())
} else {
None
},
}));
if inserted {
Some(quote_ident!("WeakMap"))
@ -630,29 +656,53 @@ impl ClassProperties {
}
}
(MethodKind::Getter | MethodKind::Setter, true) => {
let mut key = weak_coll_var.clone();
key.span = DUMMY_SP.with_ctxt(key.span.ctxt);
let mut entry = extra_inits
.entry(key.into())
.or_insert(MemberInit::PrivAccessor(prop_span, None, None));
if let MemberInit::PrivAccessor(_, getter, setter) = &mut entry {
if method.kind == MethodKind::Getter {
*getter = Some(fn_name.clone())
let is_getter = method.kind == MethodKind::Getter;
let inserted =
extra_inits.push(MemberInit::PrivAccessor(PrivAccessor {
span: prop_span,
name: weak_coll_var.clone(),
getter: if is_getter {
Some(fn_name.clone())
} else {
*setter = Some(fn_name.clone())
}
}
None
},
setter: if !is_getter {
Some(fn_name.clone())
} else {
None
},
}));
if inserted && self.c.private_as_properties {
Some(Ident::dummy())
} else {
None
}
}
(MethodKind::Method, false) => {
constructor_inits.insert(
weak_coll_var.clone().into(),
MemberInit::PrivMethod(prop_span),
);
constructor_inits.push(MemberInit::PrivMethod(PrivMethod {
span: prop_span,
name: weak_coll_var.clone(),
fn_name: if self.c.private_as_properties {
fn_name.clone()
} else {
Ident::dummy()
},
}));
Some(quote_ident!("WeakSet"))
}
(MethodKind::Method, true) => None,
(MethodKind::Method, true) => {
if self.c.private_as_properties {
extra_inits.push(MemberInit::PrivMethod(PrivMethod {
span: prop_span,
name: weak_coll_var.clone(),
fn_name: fn_name.clone(),
}));
Some(Ident::dummy())
} else {
None
}
}
};
if let Some(extra) = extra_collect {
@ -660,12 +710,24 @@ impl ClassProperties {
span: DUMMY_SP,
definite: false,
name: weak_coll_var.clone().into(),
init: Some(Box::new(Expr::from(NewExpr {
init: Some(Box::new(if self.c.private_as_properties {
Expr::from(CallExpr {
span: DUMMY_SP,
callee: helper!(
class_private_field_loose_key,
"classPrivateFieldLooseKey"
),
args: vec![weak_coll_var.sym.as_arg()],
type_args: Default::default(),
})
} else {
Expr::New(NewExpr {
span: DUMMY_SP,
callee: Box::new(Expr::Ident(extra)),
args: Some(Default::default()),
type_args: Default::default(),
}))),
})
})),
})
};
@ -691,86 +753,18 @@ impl ClassProperties {
private: &self.private,
vars: vec![],
in_assign_pat: false,
c: self.c,
});
let extra_stmts = extra_inits
.into_iter()
.map(|(key, value)| match value {
MemberInit::Prop(span, value) => Stmt::Expr(ExprStmt {
span,
expr: Expr::Call(CallExpr {
span,
callee: helper!(define_property, "defineProperty"),
args: vec![class_ident.clone().as_arg(), key.as_arg(), value.as_arg()],
type_args: Default::default(),
})
.into(),
}),
MemberInit::Private(span, value) => Stmt::Decl(Decl::Var(VarDecl {
span,
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span,
name: key.expect_ident().into(),
init: Some(
Expr::Object(ObjectLit {
span,
props: vec![
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("writable")),
value: true.into(),
}))),
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("value")),
value,
}))),
],
})
.into(),
),
definite: false,
}],
declare: false,
})),
MemberInit::PrivAccessor(span, getter, setter) => Stmt::Decl(Decl::Var(VarDecl {
span,
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
span,
name: key.expect_ident().into(),
init: Some(
Expr::Object(ObjectLit {
span,
props: vec![
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("get")),
value: getter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
}))),
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("set")),
value: setter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
}))),
],
})
.into(),
),
definite: false,
}],
declare: false,
})),
MemberInit::PrivMethod(_) => unreachable!(),
})
.chain(private_method_fn_decls)
.collect();
let mut extra_stmts = extra_inits.into_init_static(class_ident.clone());
extra_stmts.extend(private_method_fn_decls);
members.visit_mut_with(&mut PrivateAccessVisitor {
private: &self.private,
vars: vec![],
in_assign_pat: false,
c: self.c,
});
self.private.pop();
@ -823,10 +817,10 @@ impl ClassProperties {
&mut self,
constructor: Option<Constructor>,
has_super: bool,
constructor_exprs: MemberInitMap,
constructor_exprs: MemberInitRecord,
) -> Option<Constructor> {
let constructor = constructor.or_else(|| {
if constructor_exprs.is_empty() {
if constructor_exprs.record.is_empty() {
None
} else {
Some(default_constructor(has_super))
@ -834,91 +828,7 @@ impl ClassProperties {
});
if let Some(mut c) = constructor {
let constructor_exprs = constructor_exprs
.into_iter()
.map(|(key, value)| {
let (span, callee, args) = match value {
MemberInit::PrivMethod(span) => (
span,
helper!(class_private_method_init, "classPrivateMethodInit"),
vec![ThisExpr { span: DUMMY_SP }.as_arg(), key.as_arg()],
),
MemberInit::Private(span, value) => (
span,
helper!(class_private_field_init, "classPrivateFieldInit"),
vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
key.as_arg(),
ObjectLit {
span: DUMMY_SP,
props: vec![
// writeable: true
PropOrSpread::Prop(Box::new(Prop::KeyValue(
KeyValueProp {
key: PropName::Ident(quote_ident!("writable")),
value: true.into(),
},
))),
// value: value,
PropOrSpread::Prop(Box::new(Prop::KeyValue(
KeyValueProp {
key: PropName::Ident(quote_ident!("value")),
value,
},
))),
],
}
.as_arg(),
],
),
MemberInit::PrivAccessor(span, getter, setter) => (
span,
helper!(class_private_field_init, "classPrivateFieldInit"),
vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
key.as_arg(),
ObjectLit {
span: DUMMY_SP,
props: vec![
PropOrSpread::Prop(Box::new(Prop::KeyValue(
KeyValueProp {
key: PropName::Ident(quote_ident!("get")),
value: getter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
},
))),
PropOrSpread::Prop(Box::new(Prop::KeyValue(
KeyValueProp {
key: PropName::Ident(quote_ident!("set")),
value: setter
.map(|id| Box::new(id.into()))
.unwrap_or_else(|| undefined(DUMMY_SP)),
},
))),
],
}
.as_arg(),
],
),
MemberInit::Prop(span, value) => (
span,
helper!(define_property, "defineProperty"),
vec![
ThisExpr { span: DUMMY_SP }.as_arg(),
key.as_arg(),
value.as_arg(),
],
),
};
Box::new(Expr::Call(CallExpr {
span,
callee,
args,
type_args: Default::default(),
}))
})
.collect();
let constructor_exprs = constructor_exprs.into_init();
// Prepend properties
inject_after_super(&mut c, constructor_exprs);
Some(c)

View File

@ -9,10 +9,13 @@ use swc_common::{
use swc_ecma_ast::*;
use swc_ecma_transforms_base::helper;
use swc_ecma_utils::{
alias_ident_for, alias_if_required, prepend, quote_ident, undefined, ExprFactory, HANDLER,
alias_ident_for, alias_if_required, opt_chain_test, prepend, quote_ident, undefined,
ExprFactory, HANDLER,
};
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
use super::Config;
pub(super) struct Private {
pub mark: Mark,
pub class_name: Ident,
@ -135,6 +138,7 @@ pub(super) struct PrivateAccessVisitor<'a> {
pub vars: Vec<VarDeclarator>,
pub private: &'a PrivateRecord,
pub in_assign_pat: bool,
pub c: Config,
}
macro_rules! take_vars {
@ -175,6 +179,30 @@ impl<'a> VisitMut for PrivateAccessVisitor<'a> {
take_vars!(visit_mut_constructor, Constructor);
fn visit_mut_expr(&mut self, e: &mut Expr) {
if self.c.private_as_properties {
if let Expr::Member(MemberExpr {
span,
obj,
prop: MemberProp::PrivateName(n),
}) = e
{
obj.visit_mut_children_with(self);
let (mark, _, _) = self.private.get(&n.id);
let ident = Ident::new(format!("_{}", n.id.sym).into(), n.id.span.apply_mark(mark));
*e = Expr::Call(CallExpr {
callee: helper!(class_private_field_loose_base, "classPrivateFieldLooseBase"),
span: *span,
args: vec![obj.take().as_arg(), ident.clone().as_arg()],
type_args: None,
})
.computed_member(ident);
} else {
e.visit_mut_children_with(self)
}
return;
}
match e {
Expr::Update(UpdateExpr {
span,
@ -539,22 +567,12 @@ impl<'a> VisitMut for PrivateAccessVisitor<'a> {
*e = Expr::Cond(CondExpr {
span: *span,
test: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: Box::new(ident.clone().into()),
op: op!("==="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
})),
op: op!("||"),
right: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: Box::new(ident.into()),
op: op!("==="),
right: undefined(DUMMY_SP),
})),
})),
test: Box::new(opt_chain_test(
Box::new(ident.clone().into()),
Box::new(ident.into()),
*span,
self.c.no_document_all,
)),
cons: undefined(DUMMY_SP),
alt: Box::new(expr),
})
@ -584,11 +602,13 @@ impl<'a> VisitMut for PrivateAccessVisitor<'a> {
pub(super) fn visit_private_in_expr(
expr: &mut Expr,
private: &PrivateRecord,
config: Config,
) -> Vec<VarDeclarator> {
let mut priv_visitor = PrivateAccessVisitor {
private,
vars: vec![],
in_assign_pat: false,
c: config,
};
expr.visit_mut_with(&mut priv_visitor);
@ -701,7 +721,9 @@ impl<'a> PrivateAccessVisitor<'a> {
);
}
let get = if kind.is_method {
let get = if self.c.private_as_properties {
helper!(class_private_field_loose_base, "classPrivateFieldLooseBase")
} else if kind.is_method {
helper!(class_private_method_get, "classPrivateMethodGet")
} else {
helper!(class_private_field_get, "classPrivateFieldGet")
@ -709,7 +731,7 @@ impl<'a> PrivateAccessVisitor<'a> {
match &*obj {
Expr::This(this) => (
if kind.is_method {
if kind.is_method && !self.c.private_as_properties {
CallExpr {
span: DUMMY_SP,
callee: get,

View File

@ -13,14 +13,12 @@ pub mod static_blocks;
pub fn es2022(config: Config) -> impl Fold {
chain!(
static_blocks(),
class_properties(class_properties::Config {
loose: config.loose,
}),
class_properties(config.class_properties),
private_in_object(),
)
}
#[derive(Debug, Clone, Default)]
pub struct Config {
pub loose: bool,
pub class_properties: class_properties::Config,
}

View File

@ -6549,7 +6549,7 @@ test!(
let global_mark = Mark::fresh(Mark::root());
chain!(
es2022::es2022(es2022::Config { loose: false }),
es2022::es2022(Default::default()),
es2018::es2018(Default::default()),
es2017::es2017(),
es2016::es2016(),
@ -6590,7 +6590,7 @@ test!(
let global_mark = Mark::fresh(Mark::root());
chain!(
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
es2015::es2015(
global_mark,
Some(t.comments.clone()),
@ -6673,7 +6673,7 @@ test!(
let global_mark = Mark::fresh(Mark::root());
chain!(
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
es2015::es2015(
global_mark,
Some(t.comments.clone()),
@ -6720,7 +6720,7 @@ test!(
let global_mark = Mark::fresh(Mark::root());
chain!(
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
es2015::es2015(
global_mark,
Some(t.comments.clone()),
@ -6768,7 +6768,7 @@ fn exec(input: PathBuf) {
Default::default(),
|t| {
chain!(
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
classes(Some(t.comments.clone()), Default::default())
)
},
@ -6784,7 +6784,7 @@ fn fixture(input: PathBuf) {
Default::default(),
&|t| {
chain!(
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
classes(Some(t.comments.clone()), Default::default())
)
},

View File

@ -44,18 +44,35 @@ fn fixture(input: PathBuf) {
let mut pass: Box<dyn Fold> = Box::new(noop());
for plugin in &options.plugins {
let (name, _option) = match plugin {
let (name, option) = match plugin {
PluginConfig::WithOption(name, config) => (name, config.clone()),
PluginConfig::Name(name) => (name, serde_json::Value::Null),
};
let loose = option
.as_object()
.and_then(|opt| opt.get("loose"))
.and_then(|loose| {
if let Some(true) = loose.as_bool() {
Some(())
} else {
None
}
})
.is_some();
match &**name {
"transform-new-target" => {}
"proposal-class-properties" => {
pass = Box::new(chain!(
pass,
class_properties(class_properties::Config { loose: false })
class_properties(class_properties::Config {
constant_super: loose,
set_public_fields: loose,
private_as_properties: loose,
no_document_all: loose
})
));
}

View File

@ -1824,7 +1824,7 @@ test!(
|_| {
let mark = Mark::fresh(Mark::root());
chain!(
es2022(es2022::Config { loose: false }),
es2022(Default::default()),
es2021(),
es2018(Default::default()),
es2017(),

View File

@ -2291,10 +2291,7 @@ test!(
test_exec!(
Syntax::default(),
|_| chain!(
class_properties(class_properties::Config { loose: false }),
async_to_generator()
),
|_| chain!(class_properties(Default::default()), async_to_generator()),
issue_1341_1_exec,
"
class A {
@ -2347,10 +2344,7 @@ test!(
test_exec!(
Syntax::default(),
|_| chain!(
class_properties(class_properties::Config { loose: false }),
async_to_generator()
),
|_| chain!(class_properties(Default::default()), async_to_generator()),
issue_1341_2_exec,
"
class A {

View File

@ -47,6 +47,8 @@ fn fixture(input: PathBuf) {
PluginConfig::Name(name) => (name, serde_json::Value::Null),
};
let loose = input.to_string_lossy().contains("private-loose");
match &**name {
"proposal-private-property-in-object" => {}
@ -56,7 +58,10 @@ fn fixture(input: PathBuf) {
pass = Box::new(chain!(
pass,
class_properties(class_properties::Config {
loose: input.to_string_lossy().contains("private-loose")
set_public_fields: loose,
constant_super: loose,
no_document_all: loose,
private_as_properties: loose
})
));
}
@ -68,7 +73,10 @@ fn fixture(input: PathBuf) {
pass = Box::new(chain!(
pass,
class_properties(class_properties::Config {
loose: input.to_string_lossy().contains("private-loose")
set_public_fields: loose,
constant_super: loose,
no_document_all: loose,
private_as_properties: loose
})
));
}

View File

@ -1,7 +0,0 @@
{
"plugins": [
"transform-new-target",
"transform-arrow-functions",
["proposal-class-properties", { "loose": true }]
]
}

View File

@ -1,35 +0,0 @@
class Foo {
constructor() {
var _newtarget = this.constructor,
_class,
_temp;
this.test = function _target() {
this instanceof _target ? this.constructor : void 0;
};
this.test2 = function () {
_newtarget;
};
this.Bar = (_temp = _class = class _target2 {
constructor() {
this.q = this.constructor;
} // should not replace
}, _class.p = void 0, _class.p1 = class _target3 {
constructor() {
this.constructor;
}
}, _class.p2 = new function _target4() {
this instanceof _target4 ? this.constructor : void 0;
}(), _class.p3 = function () {
void 0;
}, _class.p4 = function _target5() {
this instanceof _target5 ? this.constructor : void 0;
}, _temp);
}
}

View File

@ -0,0 +1,7 @@
{
"plugins": [
["proposal-class-properties", { "loose": true }],
"transform-new-target",
"transform-arrow-functions"
]
}

View File

@ -0,0 +1,33 @@
class Foo {
constructor(){
this.test = function _target() {
this.constructor;
};
this.test2 = function() {
void 0;
};
this.Bar = (function _target() {
class _class {
constructor(){
this.q = void 0;
}
}
_class.p = void 0;
_class.p1 = class _class {
constructor(){
this.constructor;
}
};
_class.p2 = new function _target() {
this.constructor;
};
_class.p3 = function() {
void 0;
};
_class.p4 = function _target() {
this.constructor;
};
return _class;
})();
}
}

View File

@ -548,7 +548,7 @@ test!(
decorators(Default::default()),
resolver_with_mark(mark),
strip(mark),
class_properties(class_properties::Config { loose: false }),
class_properties(Default::default()),
simplifier(Default::default()),
es2018(Default::default()),
es2017(),

View File

@ -96,11 +96,7 @@ fn common_reserved_word(b: &mut Bencher) {
#[bench]
fn es2020(b: &mut Bencher) {
run(b, || {
swc_ecma_transforms_compat::es2022(swc_ecma_transforms_compat::es2022::Config {
loose: false,
})
});
run(b, || swc_ecma_transforms_compat::es2022(Default::default()));
}
#[bench]

View File

@ -1617,6 +1617,9 @@ pub fn alias_ident_for(expr: &Expr, default: &str) -> Ident {
| Expr::Member(MemberExpr {
prop: MemberProp::Ident(ident),
..
})
| Expr::Class(ClassExpr {
ident: Some(ident), ..
}) => format!("_{}", ident.sym).into(),
Expr::Member(MemberExpr {
prop: MemberProp::Computed(computed),
@ -1736,6 +1739,39 @@ pub fn undefined(span: Span) -> Box<Expr> {
.into()
}
pub fn opt_chain_test(
left: Box<Expr>,
right: Box<Expr>,
span: Span,
no_document_all: bool,
) -> Expr {
if no_document_all {
Expr::Bin(BinExpr {
span,
left,
op: op!("=="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
})
} else {
Expr::Bin(BinExpr {
span,
left: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left,
op: op!("==="),
right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
})),
op: op!("||"),
right: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
left: right,
op: op!("==="),
right: undefined(DUMMY_SP),
})),
})
}
}
/// inject `branch` after directives
#[inline(never)]
pub fn prepend<T: StmtLike>(stmts: &mut Vec<T>, stmt: T) {

View File

@ -0,0 +1,5 @@
var id = 0;
export function _classPrivateFieldLooseKey(name) {
return "__private_" + id++ + "_" + name;
}