From 14155eb0e7f6295471c92067afa4dfb84b3224ca Mon Sep 17 00:00:00 2001 From: Austaras Date: Sat, 26 Feb 2022 23:09:02 +0800 Subject: [PATCH] feat(es/compat): Implement loose mode for `class_properties` (#3722) --- crates/swc/src/builder.rs | 9 +- .../issue-2011/no-minify/output/index.js | 15 +- .../issue-2011/reduced/output/index.js | 17 +- .../classExpression3_es5.1.normal.js | 16 +- .../classExpression3_es5.2.minified.js | 16 +- .../classExpressionES63_es5.1.normal.js | 16 +- .../classExpressionES63_es5.2.minified.js | 16 +- .../privateNamesUnique-3_es2015.1.normal.js | 2 +- .../privateNamesUnique-3_es5.1.normal.js | 2 +- crates/swc_ecma_preset_env/src/lib.rs | 7 +- .../corejs3/usage-false-positive/output.mjs | 6 +- .../transform/static-block/output.mjs | 5 +- crates/swc_ecma_preset_env/tests/test.rs | 9 +- .../swc_ecma_transforms/tests/decorators.rs | 58 +- .../tests/es2015_function_name.rs | 2 +- .../_class_private_field_loose_base.js | 2 +- .../helpers/_class_private_field_loose_key.js | 5 + .../src/helpers/mod.rs | 2 +- .../src/es2015/classes/mod.rs | 4 +- .../src/es2020/opt_chaining.rs | 55 +- .../es2022/class_properties/member_init.rs | 356 +++++++++ .../src/es2022/class_properties/mod.rs | 436 +++++------ .../es2022/class_properties/private_field.rs | 60 +- .../src/es2022/mod.rs | 6 +- .../tests/es2015_classes.rs | 12 +- .../tests/es2015_new_target.rs | 21 +- .../tests/es2015_regenerator.rs | 2 +- .../tests/es2017_async_to_generator.rs | 10 +- .../tests/es2022_class_properties.rs | 720 ++++++++++++++---- .../tests/es2022_private_in_object.rs | 12 +- .../.class-properties-loose/options.json | 7 - .../general/.class-properties-loose/output.js | 35 - .../exec.js | 0 .../input.js | 0 .../class-properties-loose/options.json | 7 + .../general/class-properties-loose/output.js | 33 + .../tests/simplify.rs | 2 +- .../benches/compat.rs | 6 +- crates/swc_ecma_utils/src/lib.rs | 36 + .../src/_class_private_field_loose_key.js | 5 + 40 files changed, 1388 insertions(+), 642 deletions(-) create mode 100644 crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js create mode 100644 crates/swc_ecma_transforms_compat/src/es2022/class_properties/member_init.rs delete mode 100644 crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/options.json delete mode 100644 crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/output.js rename crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/{.class-properties-loose => class-properties-loose}/exec.js (100%) rename crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/{.class-properties-loose => class-properties-loose}/input.js (100%) create mode 100644 crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/options.json create mode 100644 crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/output.js create mode 100644 packages/swc-helpers/src/_class_private_field_loose_key.js diff --git a/crates/swc/src/builder.rs b/crates/swc/src/builder.rs index 9380951a8b1d..3db532c5bacd 100644 --- a/crates/swc/src/builder.rs +++ b/crates/swc/src/builder.rs @@ -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( diff --git a/crates/swc/tests/fixture/issue-2011/no-minify/output/index.js b/crates/swc/tests/fixture/issue-2011/no-minify/output/index.js index 68a4cda5e3aa..220a47a7833a 100644 --- a/crates/swc/tests/fixture/issue-2011/no-minify/output/index.js +++ b/crates/swc/tests/fixture/issue-2011/no-minify/output/index.js @@ -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; })(); diff --git a/crates/swc/tests/fixture/issue-2011/reduced/output/index.js b/crates/swc/tests/fixture/issue-2011/reduced/output/index.js index bc29b34aee7d..29d9858771d0 100644 --- a/crates/swc/tests/fixture/issue-2011/reduced/output/index.js +++ b/crates/swc/tests/fixture/issue-2011/reduced/output/index.js @@ -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; })(); diff --git a/crates/swc/tests/tsc-references/classExpression3_es5.1.normal.js b/crates/swc/tests/tsc-references/classExpression3_es5.1.normal.js index 4a21a7ad978e..374544635647 100644 --- a/crates/swc/tests/tsc-references/classExpression3_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/classExpression3_es5.1.normal.js @@ -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; } diff --git a/crates/swc/tests/tsc-references/classExpression3_es5.2.minified.js b/crates/swc/tests/tsc-references/classExpression3_es5.2.minified.js index 4b1913252821..924144c3c1c4 100644 --- a/crates/swc/tests/tsc-references/classExpression3_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/classExpression3_es5.2.minified.js @@ -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() { diff --git a/crates/swc/tests/tsc-references/classExpressionES63_es5.1.normal.js b/crates/swc/tests/tsc-references/classExpressionES63_es5.1.normal.js index 1954af9b89b2..caaa0311becd 100644 --- a/crates/swc/tests/tsc-references/classExpressionES63_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/classExpressionES63_es5.1.normal.js @@ -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; } diff --git a/crates/swc/tests/tsc-references/classExpressionES63_es5.2.minified.js b/crates/swc/tests/tsc-references/classExpressionES63_es5.2.minified.js index 4b1913252821..924144c3c1c4 100644 --- a/crates/swc/tests/tsc-references/classExpressionES63_es5.2.minified.js +++ b/crates/swc/tests/tsc-references/classExpressionES63_es5.2.minified.js @@ -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() { diff --git a/crates/swc/tests/tsc-references/privateNamesUnique-3_es2015.1.normal.js b/crates/swc/tests/tsc-references/privateNamesUnique-3_es2015.1.normal.js index 337cf8a665ec..fa9c8729af8d 100644 --- a/crates/swc/tests/tsc-references/privateNamesUnique-3_es2015.1.normal.js +++ b/crates/swc/tests/tsc-references/privateNamesUnique-3_es2015.1.normal.js @@ -41,7 +41,7 @@ class A { var _foo = { writable: true, value: true -} // error (duplicate) +}// error (duplicate) ; class B { test(x) { diff --git a/crates/swc/tests/tsc-references/privateNamesUnique-3_es5.1.normal.js b/crates/swc/tests/tsc-references/privateNamesUnique-3_es5.1.normal.js index 8456d6d81365..c7ea2502e439 100644 --- a/crates/swc/tests/tsc-references/privateNamesUnique-3_es5.1.normal.js +++ b/crates/swc/tests/tsc-references/privateNamesUnique-3_es5.1.normal.js @@ -59,7 +59,7 @@ var A = function A() { var _foo = { writable: true, value: true -} // error (duplicate) +}// error (duplicate) ; var B = /*#__PURE__*/ function() { "use strict"; diff --git a/crates/swc_ecma_preset_env/src/lib.rs b/crates/swc_ecma_preset_env/src/lib.rs index c05db250f852..24d03a605cd7 100644 --- a/crates/swc_ecma_preset_env/src/lib.rs +++ b/crates/swc_ecma_preset_env/src/lib.rs @@ -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()); diff --git a/crates/swc_ecma_preset_env/tests/fixtures/corejs3/usage-false-positive/output.mjs b/crates/swc_ecma_preset_env/tests/fixtures/corejs3/usage-false-positive/output.mjs index 2b9513f8b830..b1e0cfc1f8b8 100644 --- a/crates/swc_ecma_preset_env/tests/fixtures/corejs3/usage-false-positive/output.mjs +++ b/crates/swc_ecma_preset_env/tests/fixtures/corejs3/usage-false-positive/output.mjs @@ -1 +1,5 @@ -[1, 2, 3][flatMap]; +[ + 1, + 2, + 3 +][flatMap]; diff --git a/crates/swc_ecma_preset_env/tests/fixtures/transform/static-block/output.mjs b/crates/swc_ecma_preset_env/tests/fixtures/transform/static-block/output.mjs index ff24e88d1750..3c2e005635c8 100644 --- a/crates/swc_ecma_preset_env/tests/fixtures/transform/static-block/output.mjs +++ b/crates/swc_ecma_preset_env/tests/fixtures/transform/static-block/output.mjs @@ -1,8 +1,9 @@ +var __ = _classPrivateFieldLooseKey("__"); class A { } -var __ = { +Object.defineProperty(A, __, { writable: true, value: (()=>{ A.abc = 123; })() -}; +}); diff --git a/crates/swc_ecma_preset_env/tests/test.rs b/crates/swc_ecma_preset_env/tests/test.rs index 9a0c277498c7..b482a1ee33af 100644 --- a/crates/swc_ecma_preset_env/tests/test.rs +++ b/crates/swc_ecma_preset_env/tests/test.rs @@ -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() { diff --git a/crates/swc_ecma_transforms/tests/decorators.rs b/crates/swc_ecma_transforms/tests/decorators.rs index c9997a86cb1e..9c1a0ca2a543 100644 --- a/crates/swc_ecma_transforms/tests/decorators.rs +++ b/crates/swc_ecma_transforms/tests/decorators.rs @@ -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, diff --git a/crates/swc_ecma_transforms/tests/es2015_function_name.rs b/crates/swc_ecma_transforms/tests/es2015_function_name.rs index 352e41c4c036..5e6af8627ba7 100644 --- a/crates/swc_ecma_transforms/tests/es2015_function_name.rs +++ b/crates/swc_ecma_transforms/tests/es2015_function_name.rs @@ -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, diff --git a/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js b/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js index 6ad0e0ee3047..8df5f6ef1ed4 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js +++ b/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_base.js @@ -3,5 +3,5 @@ function _classPrivateFieldBase(receiver, privateKey) { throw new TypeError("attempted to use private field on non-instance"); } - return receiver; + return receiver[privateKey]; } diff --git a/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js b/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js new file mode 100644 index 000000000000..2e49d2618fdf --- /dev/null +++ b/crates/swc_ecma_transforms_base/src/helpers/_class_private_field_loose_key.js @@ -0,0 +1,5 @@ +var id = 0; + +function _classPrivateFieldLooseKey(name) { + return "__private_" + id++ + "_" + name; +} diff --git a/crates/swc_ecma_transforms_base/src/helpers/mod.rs b/crates/swc_ecma_transforms_base/src/helpers/mod.rs index 371e0a346e0f..28326ce9c9a4 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/mod.rs +++ b/crates/swc_ecma_transforms_base/src/helpers/mod.rs @@ -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), diff --git a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs index 112a47d0468c..b20756cc927e 100644 --- a/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs +++ b/crates/swc_ecma_transforms_compat/src/es2015/classes/mod.rs @@ -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, diff --git a/crates/swc_ecma_transforms_compat/src/es2020/opt_chaining.rs b/crates/swc_ecma_transforms_compat/src/es2020/opt_chaining.rs index 409c7d37c7b1..e44c2ce9d078 100644 --- a/crates/swc_ecma_transforms_compat/src/es2020/opt_chaining.rs +++ b/crates/swc_ecma_transforms_compat/src/es2020/opt_chaining.rs @@ -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, diff --git a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/member_init.rs b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/member_init.rs new file mode 100644 index 000000000000..d048df40801d --- /dev/null +++ b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/member_init.rs @@ -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, +} + +pub(super) struct PrivProp { + pub span: Span, + pub name: Ident, + pub value: Box, +} + +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, + pub setter: Option, +} + +pub(super) struct MemberInitRecord { + c: Config, + pub record: Vec, +} + +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> { + 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 { + 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) -> 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, setter: Option) -> 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) -> 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() +} diff --git a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs index a75eff67ea9a..bf4b5aa063cc 100644 --- a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs +++ b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/mod.rs @@ -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), - Private(Span, Box), - PrivMethod(Span), - PrivAccessor(Span, Option, Option), -} - -type MemberInitMap = IndexMap; - #[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,51 +456,58 @@ 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)); - let (ident, aliased) = if let Expr::Ident(i) = &*key.expr { - if used_key_names.contains(&i.sym) { - (alias_ident_for(&key.expr, "_ref"), true) - } else { - alias_if_required(&key.expr, "_ref") - } + 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) } else { alias_if_required(&key.expr, "_ref") - }; - // ident.span = ident.span.apply_mark(Mark::fresh(Mark::root())); - if aliased { - // Handle computed property - vars.push(VarDeclarator { - span: DUMMY_SP, - name: ident.clone().into(), - init: Some(key.expr), - definite: false, - }); } - Expr::from(ident) + } else { + alias_if_required(&key.expr, "_ref") + }; + // ident.span = ident.span.apply_mark(Mark::fresh(Mark::root())); + if aliased { + // Handle computed property + vars.push(VarDeclarator { + span: DUMMY_SP, + name: ident.clone().into(), + init: Some(key.expr.take()), + definite: false, + }); } + *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()) - } else { - *setter = 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 { + 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()) - } else { - *setter = 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 { + None + }, + setter: if !is_getter { + Some(fn_name.clone()) + } else { + None + }, + })); + if inserted && self.c.private_as_properties { + Some(Ident::dummy()) + } else { + None } - 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 { - span: DUMMY_SP, - callee: Box::new(Expr::Ident(extra)), - args: Some(Default::default()), - type_args: Default::default(), - }))), + 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, has_super: bool, - constructor_exprs: MemberInitMap, + constructor_exprs: MemberInitRecord, ) -> Option { 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) diff --git a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/private_field.rs b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/private_field.rs index d384283c3831..1cf22b103319 100644 --- a/crates/swc_ecma_transforms_compat/src/es2022/class_properties/private_field.rs +++ b/crates/swc_ecma_transforms_compat/src/es2022/class_properties/private_field.rs @@ -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, 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 { 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, diff --git a/crates/swc_ecma_transforms_compat/src/es2022/mod.rs b/crates/swc_ecma_transforms_compat/src/es2022/mod.rs index 0552a6c75f4d..455711034734 100644 --- a/crates/swc_ecma_transforms_compat/src/es2022/mod.rs +++ b/crates/swc_ecma_transforms_compat/src/es2022/mod.rs @@ -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, } diff --git a/crates/swc_ecma_transforms_compat/tests/es2015_classes.rs b/crates/swc_ecma_transforms_compat/tests/es2015_classes.rs index 19722759ea59..1be3d16dccae 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2015_classes.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2015_classes.rs @@ -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()) ) }, diff --git a/crates/swc_ecma_transforms_compat/tests/es2015_new_target.rs b/crates/swc_ecma_transforms_compat/tests/es2015_new_target.rs index 763745f39eaa..eb622f16447c 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2015_new_target.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2015_new_target.rs @@ -44,18 +44,35 @@ fn fixture(input: PathBuf) { let mut pass: Box = 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 + }) )); } diff --git a/crates/swc_ecma_transforms_compat/tests/es2015_regenerator.rs b/crates/swc_ecma_transforms_compat/tests/es2015_regenerator.rs index 59107f208504..b8fd835a185a 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2015_regenerator.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2015_regenerator.rs @@ -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(), diff --git a/crates/swc_ecma_transforms_compat/tests/es2017_async_to_generator.rs b/crates/swc_ecma_transforms_compat/tests/es2017_async_to_generator.rs index 0069dc5bc7fd..eb6829cdf852 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2017_async_to_generator.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2017_async_to_generator.rs @@ -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 { diff --git a/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs b/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs index 274c3acd7184..aec025479357 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2022_class_properties.rs @@ -31,7 +31,7 @@ fn tr(t: &Tester) -> impl Fold { chain!( resolver(), function_name(), - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping(), reserved_words(false), @@ -164,7 +164,7 @@ test!( |_| chain!( resolver(), function_name(), - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), ), private_class_method, r#" @@ -2803,10 +2803,7 @@ var _x = { test!( syntax(), - |_| chain!( - resolver(), - class_properties(class_properties::Config { loose: false }) - ), + |_| chain!(resolver(), class_properties(Default::default())), issue_308, "function bar(props) {} class Foo { @@ -2836,7 +2833,7 @@ test!( syntax(), |t| chain!( resolver(), - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()) ), issue_342, @@ -2865,7 +2862,7 @@ test!( syntax(), |_| chain!( resolver(), - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), block_scoping() ), issue_443, @@ -2892,10 +2889,7 @@ _defineProperty(foo, 'MODE', MODE);" // public_regression_t7364 test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - async_to_generator() - ), + |_| chain!(class_properties(Default::default()), async_to_generator()), public_regression_t7364, r#" class MyClass { @@ -2951,10 +2945,7 @@ export default class MyClass3 { // private_regression_t6719 test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_regression_t6719, r#" function withContext(ComposedComponent) { @@ -3040,10 +3031,7 @@ function withContext(ComposedComponent) { // private_reevaluated test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_reevaluated, r#" function classFactory() { @@ -3107,10 +3095,7 @@ function classFactory() { // private_static test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_static, r#" class Foo { @@ -3157,7 +3142,7 @@ expect(Foo.test()).toBe("foo"); test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -3197,10 +3182,7 @@ var Foo = function Foo(props) { // private_static_inherited test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_static_inherited, r#" class Base { @@ -3279,7 +3261,7 @@ class Sub2 extends Base {} // private_destructuring_object_pattern_1_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_destructuring_object_pattern_1_exec, r#" class Foo { @@ -3306,10 +3288,7 @@ expect(foo.z).toBe('bar'); // private_static_undefined test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_static_undefined, r#" class Foo { @@ -3349,7 +3328,7 @@ var _bar = { test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -3384,10 +3363,7 @@ var Foo = function Foo(props) { // private_regression_t2983 test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_regression_t2983, r#" call(class { @@ -3425,7 +3401,7 @@ export { _class as default } test!( syntax(), |_| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), async_to_generator(), block_scoping() ), @@ -3498,7 +3474,7 @@ export { MyClass3 as default }; test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -3534,7 +3510,7 @@ var Foo = function Foo(props) { // regression_8882_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), regression_8882_exec, r#" const classes = []; @@ -3565,7 +3541,7 @@ for(let i=0; i<= 10; ++i) { test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_field_reinitialized, r#" class Base { @@ -3587,7 +3563,7 @@ expect(() => new Derived(foo)).toThrow() //// regression_6154 //test!(syntax(),|_| tr("{ // "presets": ["env"], -// "plugins": class_properties(class_properties::Config { loose: false }) +// "plugins": class_properties(Default::default()) //} //"), regression_6154, r#" //class Test { @@ -3693,10 +3669,7 @@ expect(() => new Derived(foo)).toThrow() // private_static_export test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_static_export, r#" export class MyClass { @@ -3728,7 +3701,7 @@ export { MyClass2 as default } test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()) ), static_property_tdz_edgest_case, @@ -3757,7 +3730,7 @@ _defineProperty(A, _x, void 0); test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()) ), static_property_tdz_false_alarm, @@ -3778,10 +3751,7 @@ _defineProperty(A, "A", 123) // regression_6153 test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - arrow() - ), + |_| chain!(class_properties(Default::default()), arrow()), regression_6153, r#" () => { @@ -3886,10 +3856,7 @@ var qux = (function () { // regression_7371 test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - arrow() - ), + |_| chain!(class_properties(Default::default()), arrow()), regression_7371, r#" "use strict"; @@ -4098,7 +4065,7 @@ new ComputedField(); test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_optional_chain_call, r#" class A { @@ -4128,7 +4095,7 @@ class A { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_optional_chain_member, r#" class MyClass { @@ -4158,7 +4125,7 @@ class MyClass { test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -4245,7 +4212,7 @@ function () { // regression_8882 test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), regression_8882, r#" const classes = []; @@ -4298,7 +4265,7 @@ for(let i = 0; i <= 10; ++i){ test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -4331,7 +4298,7 @@ var Foo = function Foo(props) { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), staic_private_destructuring_array_pattern, r#" class A { @@ -4361,7 +4328,7 @@ class A { // public_static_super_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), public_static_super_exec, r#" class A { @@ -4387,7 +4354,7 @@ expect(getPropA()).toBe(1); test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -4421,10 +4388,7 @@ var Foo = function Foo(props) { // private_non_block_arrow_func test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_non_block_arrow_func, r#" export default param => @@ -4464,7 +4428,7 @@ export default ((param)=>{ // regression_8110 test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), regression_8110, r#" const field = Symbol('field'); @@ -4490,7 +4454,7 @@ class A{ // public_computed_without_block_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), public_computed_without_block_exec, r#" const createClass = (k) => class { [k()] = 2 }; @@ -4505,7 +4469,7 @@ expect(instance.foo).toBe(2); test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), exponentation(), classes(Some(t.comments.clone()), Default::default()), block_scoping(), @@ -4536,7 +4500,7 @@ var Foo = function Foo() { test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()) ), static_property_tdz_general, @@ -4563,10 +4527,7 @@ _defineProperty(C, _ref, 3); // public_native_classes test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), public_native_classes, r#" class Foo { @@ -4617,10 +4578,7 @@ test!( // Seems useless, while being hard to implement. ignore, syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_static_infer_name, r#" var Foo = class { @@ -4642,10 +4600,7 @@ var Foo = (_temp = _class = class Foo {}, _num = { // regression_7951 test!( syntax(), - |_| chain!( - resolver(), - class_properties(class_properties::Config { loose: false }) - ), + |_| chain!(resolver(), class_properties(Default::default())), regression_7951, r#" export class Foo extends Bar { @@ -4671,10 +4626,7 @@ _defineProperty(Foo, "foo", {}); // private_native_classes test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - block_scoping() - ), + |_| chain!(class_properties(Default::default()), block_scoping()), private_native_classes, r#" class Foo { @@ -4722,7 +4674,7 @@ var _foo = { test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -4748,7 +4700,7 @@ var createClass = (k)=>{ // private_destructuring_array_pattern_2_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_destructuring_array_pattern_2_exec, r#" class Foo { @@ -4774,7 +4726,7 @@ expect(foo.getClient()).toEqual(['bar', 'baz', 'quu']); test!( syntax(), |t| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), classes(Some(t.comments.clone()), Default::default()), block_scoping() ), @@ -4825,7 +4777,7 @@ _defineProperty(B, "getPropA", () => _get(_getPrototypeOf(B), "prop", B)); // private_destructuring_array_pattern_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_destructuring_array_pattern_exec, r#" class Foo { @@ -4849,7 +4801,7 @@ expect(foo.getClient()).toBe('bar'); // private_destructuring_array_pattern_1_exec test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), private_destructuring_array_pattern_1_exec, r#" class Foo { @@ -4875,10 +4827,7 @@ expect(foo.y).toBe('bar'); test!( ts(), - |_| chain!( - resolver(), - class_properties(class_properties::Config { loose: false }) - ), + |_| chain!(resolver(), class_properties(Default::default())), issue_890_1, "const DURATION = 1000 @@ -4908,7 +4857,7 @@ export class HygieneTest { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1306_1, r#" class Animal { @@ -4942,7 +4891,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1306_2, r#" class Animal { @@ -4976,7 +4925,7 @@ class Animal { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_1, " class Foo { @@ -5010,7 +4959,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_2, " class Test { @@ -5193,7 +5142,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_3, " class Test { @@ -5251,7 +5200,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_4, " class Test { @@ -5296,7 +5245,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_5, " class Test { @@ -5324,7 +5273,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1333_6, " class Test { @@ -5352,7 +5301,7 @@ test!( test!( syntax(), - |_| { class_properties(class_properties::Config { loose: false }) }, + |_| { class_properties(Default::default()) }, issue_1660_1, " console.log(class { run() { } }); @@ -5367,7 +5316,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_3055_1, " export class Node { @@ -5406,7 +5355,7 @@ function baz(child) {} test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_3618, " class MyClass { @@ -5441,10 +5390,7 @@ function set_b(x) {} test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - async_to_generator() - ), + |_| chain!(class_properties(Default::default()), async_to_generator()), issue_1694_1, " class MyClass { @@ -5472,10 +5418,7 @@ test!( test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - async_to_generator() - ), + |_| chain!(class_properties(Default::default()), async_to_generator()), issue_1694_2, " class MyClass { @@ -5501,10 +5444,7 @@ class MyClass { test!( syntax(), - |_| chain!( - class_properties(class_properties::Config { loose: false }), - async_to_generator() - ), + |_| chain!(class_properties(Default::default()), async_to_generator()), issue_1702_1, " class Foo { @@ -5552,7 +5492,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1711_1, " class Foo { @@ -5584,7 +5524,7 @@ test!( test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1742_1, " class Foo { @@ -5609,7 +5549,7 @@ test_exec!( test_exec!( syntax(), |_| chain!( - class_properties(class_properties::Config { loose: false }), + class_properties(Default::default()), template_literal(Default::default()) ), issue_1742_2, @@ -5635,7 +5575,7 @@ test_exec!( test_exec!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), new_target_in_class_prop, " class Foo { @@ -5652,7 +5592,7 @@ expect(foo.baz).toBe(undefined); test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1742_3, " class Foo { @@ -5696,7 +5636,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1869_1, " class TestClass { @@ -5726,7 +5666,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_1869_2, " var _class; @@ -5759,7 +5699,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_2021_1, " class Item extends Component { @@ -5782,7 +5722,7 @@ test!( test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_3229_1, " class A { @@ -5815,7 +5755,7 @@ class A { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_3229_2, " class A { @@ -5850,7 +5790,7 @@ class A { test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_3368, " class A { @@ -5895,7 +5835,7 @@ function bar() {} test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), nested_class_in_arrow, " const a = () => class { @@ -5928,7 +5868,7 @@ const a = ()=>{ test!( syntax(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), issue_2481, " class Foo { @@ -5954,12 +5894,520 @@ var _prop2 = { " ); +test!( + syntax(), + |_| class_properties(class_properties::Config { + constant_super: true, + ..Default::default() + }), + constant_super_complex_super, + " +class A extends class B {} { + static x = super.x; +} +", + " +var _B; + +class A extends (_B = class B {}) {} + +_defineProperty(A, 'x', _B.x); +" +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + constant_super: true, + ..Default::default() + }), + constant_super_field, + " +class A extends B { + foo = super.bar; + static foo = super.bar; +} +", + " +class A extends B { + constructor(...args) { + super(...args); + _defineProperty(this, 'foo', super.bar); + } +} + +_defineProperty(A, 'foo', B.bar) +" +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + no_document_all: true, + ..Default::default() + }), + private_optional_chain_member_loose, + r#" +class MyClass { + #a + foo(o) { + o?.#a + } +} +"#, + r#" +var _a = new WeakMap(); +class MyClass { + foo(o) { + o == null ? void 0 : _classPrivateFieldGet(o, _a); + } + constructor(){ + _classPrivateFieldInit(this, _a, { + writable: true, + value: void 0 + }); + } +} +"# +); + +test_exec!( + syntax(), + |_| class_properties(class_properties::Config { + set_public_fields: true, + ..Default::default() + }), + set_public_fields_initialization_order, + r#" +const actualOrder = []; + +const track = i => { + actualOrder.push(i); + return i; +}; + +class MyClass { + static [track(1)] = track(10); + [track(2)] = track(13); + get [track(3)]() { + return "foo"; + } + set [track(4)](value) { + this.bar = value; + } + [track(5)] = track(14); + static [track(6)] = track(11); + static [track(7)] = track(12); + [track(8)]() {} + [track(9)] = track(15); +} + +const inst = new MyClass(); + +const expectedOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; +expect(actualOrder).toEqual(expectedOrder); + +expect(MyClass[1]).toBe(10); +expect(inst[2]).toBe(13); +expect(inst[3]).toBe("foo"); +inst[4] = "baz"; +expect(inst.bar).toBe("baz"); +expect(inst[5]).toBe(14); +expect(MyClass[6]).toBe(11); +expect(MyClass[7]).toBe(12); +expect(typeof inst[8]).toBe("function"); +expect(inst[9]).toBe(15); +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + set_public_fields: true, + ..Default::default() + }), + set_public_fields_computed, + r#" +const foo = "foo"; +const bar = () => {}; +const four = 4; + +class MyClass { + static [one()] = "test"; + static [2 * 4 + 7] = "247"; + static [2 * four + 7] = "247"; + static [2 * four + seven] = "247"; + [null] = "null"; + [undefined] = "undefined"; + [void 0] = "void 0"; + get ["whatever"]() {} + set ["whatever"](value) {} + get [computed()]() {} + set [computed()](value) {} + ["test" + one]() {} + static [10]() {} + [/regex/] = "regex"; + [foo] = "foo"; + [bar] = "bar"; + [baz] = "baz"; + [`template`] = "template"; + [`template${expression}`] = "template-with-expression"; +} +"#, + r#" +const foo = "foo"; +const bar = ()=>{}; +const four = 4; +var _ref = one(), _ref1 = 2 * 4 + 7, _ref2 = 2 * four + 7, _ref3 = 2 * four + seven, _ref4 = null, _undefined = undefined, _ref5 = void 0, tmp = "whatever", tmp1 = "whatever", tmp2 = computed(), tmp3 = computed(), tmp4 = "test" + one, tmp5 = 10, _ref6 = /regex/, _foo = foo, _bar = bar, _baz = baz, _ref7 = `template`, _ref8 = `template${expression}`; +class MyClass { + get [tmp]() {} + set [tmp1](value) {} + get [tmp2]() {} + set [tmp3](value) {} + [tmp4]() {} + static [tmp5]() {} + constructor(){ + this[_ref4] = "null"; + this[_undefined] = "undefined"; + this[_ref5] = "void 0"; + this[_ref6] = "regex"; + this[_foo] = "foo"; + this[_bar] = "bar"; + this[_baz] = "baz"; + this[_ref7] = "template"; + this[_ref8] = "template-with-expression"; + } +} +MyClass[_ref] = "test"; +MyClass[_ref1] = "247"; +MyClass[_ref2] = "247"; +MyClass[_ref3] = "247"; +"# +); + +test!( + syntax(), + |_| chain!( + resolver(), + class_properties(class_properties::Config { + set_public_fields: true, + ..Default::default() + }) + ), + set_public_constructor_collision, + r#" +var foo = "bar"; + +class Foo { + bar = foo; + static bar = baz; + + constructor() { + var foo = "foo"; + var baz = "baz"; + } +} +"#, + r#" +var foo = "bar"; + +class Foo { + constructor() { + this.bar = foo; + var foo1 = "foo"; + var baz = "baz"; + } +} + +Foo.bar = baz; +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + set_public_fields: true, + ..Default::default() + }), + set_public_static_undefined, + r#" +class Foo { + static bar; +} +"#, + r#" +class Foo {} + +Foo.bar = void 0; +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + private_as_properties: true, + ..Default::default() + }), + private_as_properties_basic, + r#" +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } +} +"#, + r#" +var _privateField = /*#__PURE__*/_classPrivateFieldLooseKey("_privateField"), _privateFieldValue = /*#__PURE__*/_classPrivateFieldLooseKey("_privateFieldValue"); + +class Cl { + publicGetPrivateField() { + return _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + } + + publicSetPrivateField(newValue) { + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue; + } + + constructor() { + Object.defineProperty(this, _privateField, { + writable: true, + value: "top secret string" + }); + Object.defineProperty(this, _privateFieldValue, { + get: get_privateFieldValue, + set: set_privateFieldValue + }); + this.publicField = "not secret string"; + } +} + +function get_privateFieldValue() { + return _classPrivateFieldLooseBase(this, _privateField)[_privateField]; +} + +function set_privateFieldValue(newValue) { + _classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue; +} +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + private_as_properties: true, + ..Default::default() + }), + private_as_properties_static, + r#" +class Cl { + static #foo() {}; + static #f = 123; + static get #bar() {}; +} +"#, + r#" +var _foo = _classPrivateFieldLooseKey("_foo"), _f = _classPrivateFieldLooseKey("_f"), _bar = _classPrivateFieldLooseKey("_bar"); +class Cl { } + +Object.defineProperty(Cl, _foo, { + value: foo +}); +Object.defineProperty(Cl, _f, { + writable: true, + value: 123 +}); +Object.defineProperty(Cl, _bar, { + get: get_bar, + set: void 0 +}); +function foo() {} +function get_bar() {} +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + private_as_properties: true, + ..Default::default() + }), + private_as_properties_getter_only, + r#" +class Cl { + #privateField = 0; + + get #privateFieldValue() { + return this.#privateField; + } + + constructor() { + this.#privateFieldValue = 1; + ([this.#privateFieldValue] = [1]); + } +} +"#, + r#" +var _privateField = /*#__PURE__*/_classPrivateFieldLooseKey("_privateField"), _privateFieldValue = /*#__PURE__*/_classPrivateFieldLooseKey("_privateFieldValue"); + +class Cl { + constructor() { + Object.defineProperty(this, _privateField, { + writable: true, + value: 0 + }); + Object.defineProperty(this, _privateFieldValue, { + get: get_privateFieldValue, + set: void 0 + }); + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = 1; + [_classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]] = [1]; + } + +} + +function get_privateFieldValue() { + return _classPrivateFieldLooseBase(this, _privateField)[_privateField]; +} +"# +); + +test!( + syntax(), + |_| class_properties(class_properties::Config { + private_as_properties: true, + set_public_fields: true, + ..Default::default() + }), + loose_update, + r#" +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } + + get publicFieldValue() { + return this.publicField; + } + + set publicFieldValue(newValue) { + this.publicField = newValue; + } + + testUpdates() { + this.#privateField = 0; + this.publicField = 0; + this.#privateFieldValue = this.#privateFieldValue++; + this.publicFieldValue = this.publicFieldValue++; + + ++this.#privateFieldValue; + ++this.publicFieldValue; + + this.#privateFieldValue += 1; + this.publicFieldValue += 1; + + this.#privateFieldValue = -(this.#privateFieldValue ** this.#privateFieldValue); + this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue); + } +} +"#, + r#" +var _privateField = /*#__PURE__*/_classPrivateFieldLooseKey("_privateField"), _privateFieldValue = /*#__PURE__*/_classPrivateFieldLooseKey("_privateFieldValue"); + +class Cl { + publicGetPrivateField() { + return _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + } + + publicSetPrivateField(newValue) { + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue; + } + + get publicFieldValue() { + return this.publicField; + } + + set publicFieldValue(newValue) { + this.publicField = newValue; + } + + testUpdates() { + _classPrivateFieldLooseBase(this, _privateField)[_privateField] = 0; + this.publicField = 0; + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]++; + this.publicFieldValue = this.publicFieldValue++; + ++_classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + ++this.publicFieldValue; + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] += 1; + this.publicFieldValue += 1; + _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = -(_classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] ** _classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]); + this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue); + } + + constructor() { + Object.defineProperty(this, _privateField, { + writable: true, + value: "top secret string" + }); + Object.defineProperty(this, _privateFieldValue, { + get: get_privateFieldValue, + set: set_privateFieldValue + }); + this.publicField = "not secret string"; + } +} + +function get_privateFieldValue() { + return _classPrivateFieldLooseBase(this, _privateField)[_privateField]; +} + +function set_privateFieldValue(newValue) { + _classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue; +} +"# +); + #[testing::fixture("tests/fixture/classes/**/exec.js")] fn exec(input: PathBuf) { let src = read_to_string(&input).unwrap(); compare_stdout( Default::default(), - |_| class_properties(class_properties::Config { loose: false }), + |_| class_properties(Default::default()), &src, ); } diff --git a/crates/swc_ecma_transforms_compat/tests/es2022_private_in_object.rs b/crates/swc_ecma_transforms_compat/tests/es2022_private_in_object.rs index 4c1cb62043ee..1ae47549be41 100644 --- a/crates/swc_ecma_transforms_compat/tests/es2022_private_in_object.rs +++ b/crates/swc_ecma_transforms_compat/tests/es2022_private_in_object.rs @@ -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 }) )); } diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/options.json b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/options.json deleted file mode 100644 index fafe51d4fbf0..000000000000 --- a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/options.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "plugins": [ - "transform-new-target", - "transform-arrow-functions", - ["proposal-class-properties", { "loose": true }] - ] -} diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/output.js b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/output.js deleted file mode 100644 index a64af0349e52..000000000000 --- a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/output.js +++ /dev/null @@ -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); - } - -} diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/exec.js b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/exec.js similarity index 100% rename from crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/exec.js rename to crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/exec.js diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/input.js b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/input.js similarity index 100% rename from crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/.class-properties-loose/input.js rename to crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/input.js diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/options.json b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/options.json new file mode 100644 index 000000000000..fb4423778386 --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + ["proposal-class-properties", { "loose": true }], + "transform-new-target", + "transform-arrow-functions" + ] +} diff --git a/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/output.js b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/output.js new file mode 100644 index 000000000000..4471cf0cc95c --- /dev/null +++ b/crates/swc_ecma_transforms_compat/tests/fixture/new-target/general/class-properties-loose/output.js @@ -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; + })(); + } +} diff --git a/crates/swc_ecma_transforms_optimization/tests/simplify.rs b/crates/swc_ecma_transforms_optimization/tests/simplify.rs index 298c7efcec26..5f574c775079 100644 --- a/crates/swc_ecma_transforms_optimization/tests/simplify.rs +++ b/crates/swc_ecma_transforms_optimization/tests/simplify.rs @@ -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(), diff --git a/crates/swc_ecma_transforms_typescript/benches/compat.rs b/crates/swc_ecma_transforms_typescript/benches/compat.rs index c87b33e0e37f..c2388b0d5fa0 100644 --- a/crates/swc_ecma_transforms_typescript/benches/compat.rs +++ b/crates/swc_ecma_transforms_typescript/benches/compat.rs @@ -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] diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index c1b962f1b0fb..838a5d8bbfa0 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -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 { .into() } +pub fn opt_chain_test( + left: Box, + right: Box, + 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(stmts: &mut Vec, stmt: T) { diff --git a/packages/swc-helpers/src/_class_private_field_loose_key.js b/packages/swc-helpers/src/_class_private_field_loose_key.js new file mode 100644 index 000000000000..8e7d4f6284f2 --- /dev/null +++ b/packages/swc-helpers/src/_class_private_field_loose_key.js @@ -0,0 +1,5 @@ +var id = 0; + +export function _classPrivateFieldLooseKey(name) { + return "__private_" + id++ + "_" + name; +}