From 9c029ef095f83783a3581dfcc165dd197308f538 Mon Sep 17 00:00:00 2001 From: Alessandro Chitolina Date: Mon, 16 Oct 2023 22:38:53 +0200 Subject: [PATCH] feat(es/compat): Implement decorator metadata proposal (#8097) **Description:** This PR implements the [decorator metadata](https://github.com/tc39/proposal-decorator-metadata) proposal, that is now at Stage 3. As the decorator metadata proposal is a small extension of the decorator proposal and is not possible to compile the metadata without transpiling decorators, I opted to implement it into the existing decorator transformer (and helper) **Related issue:** - Closes #7957 --- .../src/helpers/_apply_decs_2203_r.js | 47 ++++++++++++++----- .../src/decorator_2022_03.rs | 34 +++++++++++++- .../expressions-static-blocks/output.js | 10 ++-- .../expressions/output.js | 10 ++-- .../inheritance/output.js | 10 ++-- .../initializers/output.js | 13 ++--- .../expressions-static-blocks/output.js | 24 +++++----- .../2022-03-classes/expressions/output.js | 26 +++++----- .../2022-03-classes/inheritance/output.js | 12 ++--- .../2022-03-classes/initializers/output.js | 14 +++--- .../decorators/2022-03-metadata/class/exec.js | 11 +++++ .../2022-03-metadata/element/exec.js | 14 ++++++ .../2022-03-metadata/no-decorators/exec.js | 5 ++ .../decorators/2022-03-metadata/options.json | 8 ++++ .../subclass-no-super-decorators/exec.js | 15 ++++++ .../subclass-super-decorators/exec.js | 18 +++++++ .../output.js | 6 +-- packages/helpers/esm/_apply_decs_2203_r.js | 38 +++++++++------ 18 files changed, 226 insertions(+), 89 deletions(-) create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js create mode 100644 crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js diff --git a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js index 8662d6ff4fd..718c02a0680 100644 --- a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js +++ b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js @@ -35,6 +35,7 @@ function applyDecs2203RFactory() { kind, isStatic, isPrivate, + metadata, value ) { var kindStr; @@ -61,6 +62,7 @@ function applyDecs2203RFactory() { name: isPrivate ? "#" + name : name, static: isStatic, private: isPrivate, + metadata: metadata, }; var decoratorFinishedRef = { v: false }; @@ -168,7 +170,8 @@ function applyDecs2203RFactory() { kind, isStatic, isPrivate, - initializers + initializers, + metadata ) { var decs = decInfo[0]; @@ -221,6 +224,7 @@ function applyDecs2203RFactory() { kind, isStatic, isPrivate, + metadata, value ); @@ -251,6 +255,7 @@ function applyDecs2203RFactory() { kind, isStatic, isPrivate, + metadata, value ); @@ -345,7 +350,7 @@ function applyDecs2203RFactory() { } } - function applyMemberDecs(Class, decInfos) { + function applyMemberDecs(Class, decInfos, metadata) { var ret = []; var protoInitializers; var staticInitializers; @@ -415,7 +420,8 @@ function applyDecs2203RFactory() { kind, isStatic, isPrivate, - initializers + initializers, + metadata ); } @@ -435,7 +441,7 @@ function applyDecs2203RFactory() { } } - function applyClassDecs(targetClass, classDecs) { + function applyClassDecs(targetClass, classDecs, metadata) { if (classDecs.length > 0) { var initializers = []; var newClass = targetClass; @@ -452,6 +458,7 @@ function applyDecs2203RFactory() { initializers, decoratorFinishedRef ), + metadata, }); } finally { decoratorFinishedRef.v = true; @@ -464,7 +471,7 @@ function applyDecs2203RFactory() { } return [ - newClass, + defineMetadata(newClass, metadata), function () { for (var i = 0; i < initializers.length; i++) { initializers[i].call(newClass); @@ -476,6 +483,14 @@ function applyDecs2203RFactory() { // so we don't have to return an empty array here. } + function defineMetadata(Class, metadata) { + return Object.defineProperty( + Class, + Symbol.metadata || Symbol.for("Symbol.metadata"), + { configurable: true, enumerable: true, value: metadata } + ); + } + /** Basic usage: @@ -622,21 +637,31 @@ function applyDecs2203RFactory() { initializeClass(Class); */ - return function applyDecs2203R(targetClass, memberDecs, classDecs) { + return function applyDecs2203R(targetClass, memberDecs, classDecs, parentClass) { + if (parentClass !== void 0) { + var parentMetadata = + parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; + } + var metadata = Object.create( + parentMetadata === void 0 ? null : parentMetadata + ); + var e = applyMemberDecs(targetClass, memberDecs, metadata); + if (!classDecs.length) defineMetadata(targetClass, metadata); return { - e: applyMemberDecs(targetClass, memberDecs), + e: e, // Lazily apply class decorations so that member init locals can be properly bound. get c() { - return applyClassDecs(targetClass, classDecs); + return applyClassDecs(targetClass, classDecs, metadata); }, }; }; } -function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { +function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { return (_apply_decs_2203_r = applyDecs2203RFactory())( targetClass, memberDecs, - classDecs + classDecs, + parentClass ); -} \ No newline at end of file +} diff --git a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs index 987d85aed10..5368144b84c 100644 --- a/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs +++ b/crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs @@ -9,8 +9,9 @@ use swc_common::{util::take::Take, Spanned, SyntaxContext, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_transforms_base::{helper, helper_expr}; use swc_ecma_utils::{ - constructor::inject_after_super, default_constructor, prepend_stmt, private_ident, - prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt, IdentRenamer, + alias_ident_for, constructor::inject_after_super, default_constructor, prepend_stmt, + private_ident, prop_name_to_expr_value, quote_ident, replace_ident, ExprFactory, IdentExt, + IdentRenamer, }; use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith}; @@ -53,6 +54,8 @@ struct ClassState { class_lhs: Vec>, class_decorators: Vec>, + + super_class: Option, } impl Decorator202203 { @@ -154,6 +157,10 @@ impl Decorator202203 { .as_arg(), ); + if let Some(super_class) = self.state.super_class.as_ref() { + combined_args.push(super_class.clone().as_arg()); + } + let e_pat = if e_lhs.is_empty() { None } else { @@ -323,6 +330,27 @@ impl Decorator202203 { unreachable!() } + fn handle_super_class(&mut self, class: &mut Class) { + if let Some(super_class) = class.super_class.take() { + let id = alias_ident_for(&super_class, "_super"); + self.extra_vars.push(VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(id.clone().into()), + init: None, + definite: false, + }); + + class.super_class = Some(Box::new(Expr::Assign(AssignExpr { + span: DUMMY_SP, + op: AssignOp::Assign, + left: PatOrExpr::Pat(Box::new(Pat::Ident(id.clone().into()))), + right: super_class, + }))); + + self.state.super_class = Some(id); + } + } + fn handle_class_expr(&mut self, class: &mut Class, ident: Option<&Ident>) -> Ident { debug_assert!( !class.decorators.is_empty(), @@ -361,6 +389,7 @@ impl Decorator202203 { let decorators = self.preserve_side_effect_of_decorators(class.decorators.take()); self.state.class_decorators.extend(decorators); + self.handle_super_class(class); { let call_stmt = CallExpr { @@ -417,6 +446,7 @@ impl Decorator202203 { self.state.class_lhs.push(Some(init_class.clone().into())); self.state.class_decorators.extend(decorators); + self.handle_super_class(&mut c.class); let mut body = c.class.body.take(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js index 2cf2118bd77..9ec0bb7ff70 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions-static-blocks/output.js @@ -1,5 +1,5 @@ var _A, __, __1, __2, _C, __3, __11, __21, _class, __4, __12, __22, _class1, __5, __13, __23, _G, __6, __14, __24, _class2, __7, __15, __25, _class3, __8, __16, __26, _K, __9, __17, __27; -var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1; +var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L; const dec = ()=>{}; const A = ((_A = class A { }, __ = { @@ -81,12 +81,12 @@ const F = [ value: _initClass5() }, _class2), _class6) ]; -const H = ((_class3 = class extends I { +const H = ((_class3 = class extends (_I = I) { }, __8 = { writable: true, value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [ dec - ]) + ], _I) }, __16 = { writable: true, value: (()=>{})() @@ -94,12 +94,12 @@ const H = ((_class3 = class extends I { writable: true, value: _initClass6() }, _class3), _class7); -const J = ((_K = class K extends L { +const J = ((_K = class K extends (_L = L) { }, __9 = { writable: true, value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [ dec - ]) + ], _L) }, __17 = { writable: true, value: (()=>{})() diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js index ecfa44ae226..25fb680ba4f 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/expressions/output.js @@ -1,5 +1,5 @@ var _A, __, __1, _C, __2, __11, _class, __3, __12, _class1, __4, __13, _G, __5, __14, _class2, __6, __15, _class3, __7, __16, _K, __8, __17; -var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _initClass7, _K1; +var _initClass, _A1, _initClass1, _C1, _initClass2, _class4, _initClass3, _class5, _initClass4, _G1, _initClass5, _class6, _initClass6, _class7, _I, _initClass7, _K1, _L; const dec = ()=>{}; const A = ((_A = class A { }, __ = { @@ -63,22 +63,22 @@ const F = [ value: _initClass5() }, _class2), _class6) ]; -const H = ((_class3 = class extends I { +const H = ((_class3 = class extends (_I = I) { }, __7 = { writable: true, value: { c: [_class7, _initClass6] } = _apply_decs_2203_r(_class3, [], [ dec - ]) + ], _I) }, __16 = { writable: true, value: _initClass6() }, _class3), _class7); -const J = ((_K = class K extends L { +const J = ((_K = class K extends (_L = L) { }, __8 = { writable: true, value: { c: [_K1, _initClass7] } = _apply_decs_2203_r(_K, [], [ dec - ]) + ], _L) }, __17 = { writable: true, value: _initClass7() diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js index 1f50e12bf56..b4f3e46de22 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/inheritance/output.js @@ -1,12 +1,12 @@ -var _initClass, _initClass1; +var _initClass, _initClass1, _Bar; const dec1 = ()=>{}; const dec2 = ()=>{}; -let _Bar; +let _Bar1; class Bar { } var __ = { writable: true, - value: { c: [_Bar, _initClass] } = _apply_decs_2203_r(Bar, [], [ + value: { c: [_Bar1, _initClass] } = _apply_decs_2203_r(Bar, [], [ dec1 ]) }; @@ -15,13 +15,13 @@ var __1 = { value: _initClass() }; let _Foo; -class Foo extends _Bar { +class Foo extends (_Bar = _Bar1) { } var __2 = { writable: true, value: { c: [_Foo, _initClass1] } = _apply_decs_2203_r(Foo, [], [ dec2 - ]) + ], _Bar) }; var __11 = { writable: true, diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js index a24a9c65058..d543f75ae6a 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes--to-es2015/initializers/output.js @@ -1,10 +1,10 @@ var _class, __, _class1, __1; -var _initClass, _initClass1; +var _initClass, _initClass1, _Foo; const dec = ()=>{}; -let _Foo; +let _Foo1; new (_class = class extends _identity { constructor(){ - super(_Foo), _initClass(); + super(_Foo1), _initClass(); } }, __ = { writable: true, @@ -13,7 +13,7 @@ new (_class = class extends _identity { } var __ = { writable: true, - value: { c: [_Foo, _initClass] } = _apply_decs_2203_r(Foo, [], [ + value: { c: [_Foo1, _initClass] } = _apply_decs_2203_r(Foo, [], [ dec ]) }; @@ -28,13 +28,14 @@ new (_class1 = class extends _identity { }, __1 = { writable: true, value: (()=>{ - class Bar extends _Foo { + var _ref; + class Bar extends (_ref = _Foo = _Foo1) { } var __ = { writable: true, value: { c: [_Bar, _initClass1] } = _apply_decs_2203_r(Bar, [], [ dec - ]) + ], _Foo) }; _define_property(Bar, "field", ((()=>{ Bar.otherField = 456; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js index bf851aa8573..1e5b39d6519 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions-static-blocks/output.js @@ -1,8 +1,8 @@ -var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _initClass7, _K; +var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _I, _initClass7, _K, _L; const dec = ()=>{}; const A = (class A { static{ - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -13,7 +13,7 @@ const A = (class A { }, _A); const B = (class C { static{ - ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ + ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -24,7 +24,7 @@ const B = (class C { }, _C); const D = (class { static{ - ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -35,7 +35,7 @@ const D = (class { }, _class); const E = ((class { static{ - ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -47,7 +47,7 @@ const E = ((class { const F = [ (class G { static{ - ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ + ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -58,7 +58,7 @@ const F = [ }, _G), (class { static{ - ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -68,22 +68,22 @@ const F = [ } }, _class2) ]; -const H = (class extends I { +const H = (class extends (_I = I) { static{ ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _I)); } static{} static{ _initClass6(); } }, _class3); -const J = (class K extends L { +const J = (class K extends (_L = L) { static{ ({ c: [_K, _initClass7] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _L)); } static{} static{ @@ -94,7 +94,7 @@ function classFactory() { var _initClass, _class; return class { static{ - ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ dec ])); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js index 52fcbe50074..7e7ad388901 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/expressions/output.js @@ -1,8 +1,8 @@ -var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _initClass7, _K; +var _initClass, _A, _initClass1, _C, _initClass2, _class, _initClass3, _class1, _initClass4, _G, _initClass5, _class2, _initClass6, _class3, _I, _initClass7, _K, _L; const dec = ()=>{}; const A = (class A { static{ - ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_A, _initClass] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -12,7 +12,7 @@ const A = (class A { }, _A); const B = (class C { static{ - ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ + ({ c: [_C, _initClass1] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -22,7 +22,7 @@ const B = (class C { }, _C); const D = (class { static{ - ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class, _initClass2] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -32,7 +32,7 @@ const D = (class { }, _class); const E = ((class { static{ - ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class1, _initClass3] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -43,7 +43,7 @@ const E = ((class { const F = [ (class G { static{ - ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ + ({ c: [_G, _initClass4] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -53,7 +53,7 @@ const F = [ }, _G), (class { static{ - ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class2, _initClass5] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -62,21 +62,21 @@ const F = [ } }, _class2) ]; -const H = (class extends I { +const H = (class extends (_I = I) { static{ - ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class3, _initClass6] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _I)); } static{ _initClass6(); } }, _class3); -const J = (class K extends L { +const J = (class K extends (_L = L) { static{ ({ c: [_K, _initClass7] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _L)); } static{ _initClass7(); @@ -86,7 +86,7 @@ function classFactory() { var _initClass, _class; return class { static{ - ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_class, _initClass] } = _apply_decs_2203_r(this, [], [ dec ])); } diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js index 14ad93309f5..4cc40167c6c 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/inheritance/output.js @@ -1,9 +1,9 @@ -var _initClass, _initClass1; +var _initClass, _initClass1, _Bar; const dec = ()=>{}; -let _Bar; +let _Bar1; class Bar { static{ - ({ c: [_Bar, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_Bar1, _initClass] } = _apply_decs_2203_r(this, [], [ dec1 ])); } @@ -12,11 +12,11 @@ class Bar { } } let _Foo; -class Foo extends _Bar { +class Foo extends (_Bar = _Bar1) { static{ - ({ c: [_Foo, _initClass1] } = _apply_decs_2203_r(this, [], [ + ({ c: [_Foo, _initClass1] } = _apply_decs_2203_r(this, [], [ dec2 - ])); + ], _Bar)); } static{ _initClass1(); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js index 031046371ee..772fbce8465 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-classes/initializers/output.js @@ -1,14 +1,14 @@ -var _initClass, _initClass1; +var _initClass, _initClass1, _Foo; const dec = ()=>{}; -let _Foo; +let _Foo1; new class extends _identity { constructor(){ - super(_Foo), _initClass(); + super(_Foo1), _initClass(); } static{ class Foo { static{ - ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ + ({ c: [_Foo1, _initClass] } = _apply_decs_2203_r(this, [], [ dec ])); } @@ -22,11 +22,11 @@ new class extends _identity { super(_Bar), _initClass1(); } static{ - class Bar extends _Foo { + class Bar extends (_Foo = _Foo1) { static{ - ({ c: [_Bar, _initClass1] } = _apply_decs_2203_r(this, [], [ + ({ c: [_Bar, _initClass1] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _Foo)); } static field = ((()=>{ this.otherField = 456; diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js new file mode 100644 index 00000000000..267e0221851 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/class/exec.js @@ -0,0 +1,11 @@ +function dec(_, ctx) { + ctx.metadata.foo = 3; +} + +Symbol.metadata = Symbol(); + +@dec +class A {} + +expect(A[Symbol.metadata]).toEqual({ foo: 3 }); +expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js new file mode 100644 index 00000000000..c70d840c5f8 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/element/exec.js @@ -0,0 +1,14 @@ +function dec(_, ctx) { + console.error(ctx); + ctx.metadata.foo = 3; +} + +Symbol.metadata = Symbol(); + +class A { + @dec + foo; +} + +expect(A[Symbol.metadata]).toEqual({ foo: 3 }); +expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js new file mode 100644 index 00000000000..9f2d6b450bc --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/no-decorators/exec.js @@ -0,0 +1,5 @@ +Symbol.metadata = Symbol(); + +class A {} + +expect(A.hasOwnProperty(Symbol.metadata)).toBe(false); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json new file mode 100644 index 00000000000..4e9da044d2d --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-decorators", { "version": "2022-03" }], + "proposal-class-properties", + "proposal-private-methods", + "proposal-class-static-block" + ] +} diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js new file mode 100644 index 00000000000..3949427e772 --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-no-super-decorators/exec.js @@ -0,0 +1,15 @@ +function dec(v) { + return (_, ctx) => { + ctx.metadata.foo = v; + }; +} + +Symbol.metadata = Symbol(); + +class B {} + +@dec(3) +class A extends B {} + +expect(A[Symbol.metadata]).toEqual({ foo: 3 }); +expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(null); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js new file mode 100644 index 00000000000..c77dbb2dbea --- /dev/null +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-metadata/subclass-super-decorators/exec.js @@ -0,0 +1,18 @@ +function dec(v) { + return (_, ctx) => { + ctx.metadata.foo = v; + }; +} + +Symbol.metadata = Symbol(); + +@dec(2) +class B {} + +@dec(3) +class A extends B {} + +expect(A[Symbol.metadata]).toEqual({ foo: 3 }); +expect(Object.getPrototypeOf(A[Symbol.metadata])).toBe(B[Symbol.metadata]); +expect(B[Symbol.metadata]).toEqual({ foo: 2 }); +expect(Object.getPrototypeOf(B[Symbol.metadata])).toBe(null); diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js index 3594e7f2549..1266b57cb05 100644 --- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js +++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/super-in-nested-constructor-expression/output.js @@ -1,11 +1,11 @@ -var _initClass; +var _initClass, _Bar; const dec = ()=>{}; let _Foo; -class Foo extends Bar { +class Foo extends (_Bar = Bar) { static{ ({ c: [_Foo, _initClass] } = _apply_decs_2203_r(this, [], [ dec - ])); + ], _Bar)); } constructor(){ let foo = super(); diff --git a/packages/helpers/esm/_apply_decs_2203_r.js b/packages/helpers/esm/_apply_decs_2203_r.js index a3c4396df4e..6ac65fd3b01 100644 --- a/packages/helpers/esm/_apply_decs_2203_r.js +++ b/packages/helpers/esm/_apply_decs_2203_r.js @@ -18,7 +18,7 @@ CLASS = 10; // only used in assertValidReturnValue */ -export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { +export function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) { function createAddInitializerMethod(initializers, decoratorFinishedRef) { return function addInitializer(initializer) { assertNotFinished(decoratorFinishedRef, "addInitializer"); @@ -27,7 +27,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { }; } - function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, value) { + function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) { var kindStr; switch (kind) { @@ -136,7 +136,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { } } - function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers) { + function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) { var decs = decInfo[0]; var desc, init, value; @@ -168,7 +168,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { var newValue, get, set; if (typeof decs === "function") { - newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, value); + newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); @@ -189,7 +189,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { for (var i = decs.length - 1; i >= 0; i--) { var dec = decs[i]; - newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, value); + newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value); if (newValue !== void 0) { assertValidReturnValue(kind, newValue); @@ -280,7 +280,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { } } - function applyMemberDecs(Class, decInfos) { + function applyMemberDecs(Class, decInfos, metadata) { var ret = []; var protoInitializers; var staticInitializers; @@ -336,7 +336,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { } } - applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers); + applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata); } pushInitializers(ret, protoInitializers); @@ -353,7 +353,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { } } - function applyClassDecs(targetClass, classDecs) { + function applyClassDecs(targetClass, classDecs, metadata) { if (classDecs.length > 0) { var initializers = []; var newClass = targetClass; @@ -363,7 +363,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { var decoratorFinishedRef = { v: false }; try { - var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef) }); + var nextNewClass = classDecs[i](newClass, { kind: "class", name: name, addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef), metadata }); } finally { decoratorFinishedRef.v = true; } @@ -374,7 +374,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { } } - return [newClass, function() { + return [defineMetadata(newClass, metadata), function() { for (var i = 0; i < initializers.length; i++) initializers[i].call(newClass); }]; } @@ -382,6 +382,10 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { // so we don't have to return an empty array here. } + function defineMetadata(Class, metadata) { + return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: true, enumerable: true, value: metadata }); + } + /** Basic usage: @@ -528,17 +532,23 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs) { initializeClass(Class); */ - _apply_decs_2203_r = function(targetClass, memberDecs, classDecs) { + _apply_decs_2203_r = function(targetClass, memberDecs, classDecs, parentClass) { + if (parentClass !== void 0) { + var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")]; + } + var metadata = Object.create(parentMetadata === void 0 ? null : parentMetadata); + var e = applyMemberDecs(targetClass, memberDecs, metadata); + if (!classDecs.length) defineMetadata(targetClass, metadata); return { - e: applyMemberDecs(targetClass, memberDecs), + e: e, // Lazily apply class decorations so that member init locals can be properly bound. get c() { - return applyClassDecs(targetClass, classDecs); + return applyClassDecs(targetClass, classDecs, metadata); } }; }; - return _apply_decs_2203_r(targetClass, memberDecs, classDecs); + return _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass); } export { _apply_decs_2203_r as _ };